1use alloc::string::String;
3use alloc::vec::Vec;
4use core::mem;
5
6use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
7use crate::pe;
8use crate::write::string::{StringId, StringTable};
9use crate::write::util;
10use crate::write::{Error, Result, WritableBuffer};
11
12#[allow(missing_debug_implementations)]
29pub struct Writer<'a> {
30 buffer: &'a mut dyn WritableBuffer,
31 len: usize,
32
33 section_num: u16,
34
35 symtab_offset: u32,
36 symtab_num: u32,
37
38 strtab: StringTable<'a>,
39 strtab_len: usize,
40 strtab_offset: u32,
41 strtab_data: Vec<u8>,
42}
43
44impl<'a> Writer<'a> {
45 pub fn new(buffer: &'a mut dyn WritableBuffer) -> Self {
47 Writer {
48 buffer,
49 len: 0,
50
51 section_num: 0,
52
53 symtab_offset: 0,
54 symtab_num: 0,
55
56 strtab: StringTable::default(),
57 strtab_len: 0,
58 strtab_offset: 0,
59 strtab_data: Vec::new(),
60 }
61 }
62
63 pub fn reserved_len(&self) -> usize {
65 self.len
66 }
67
68 #[allow(clippy::len_without_is_empty)]
70 pub fn len(&self) -> usize {
71 self.buffer.len()
72 }
73
74 pub fn reserve(&mut self, len: usize, align_start: usize) -> u32 {
80 if align_start > 1 {
81 self.len = util::align(self.len, align_start);
82 }
83 let offset = self.len;
84 self.len += len;
85 offset as u32
86 }
87
88 pub fn write_align(&mut self, align_start: usize) {
90 if align_start > 1 {
91 util::write_align(self.buffer, align_start);
92 }
93 }
94
95 pub fn write(&mut self, data: &[u8]) {
97 self.buffer.write_bytes(data);
98 }
99
100 pub fn reserve_until(&mut self, offset: usize) {
102 debug_assert!(self.len <= offset);
103 self.len = offset;
104 }
105
106 pub fn pad_until(&mut self, offset: usize) {
108 debug_assert!(self.buffer.len() <= offset);
109 self.buffer.resize(offset);
110 }
111
112 pub fn reserve_file_header(&mut self) {
116 debug_assert_eq!(self.len, 0);
117 self.reserve(mem::size_of::<pe::ImageFileHeader>(), 1);
118 }
119
120 pub fn write_file_header(&mut self, header: FileHeader) -> Result<()> {
126 debug_assert_eq!(self.buffer.len(), 0);
127
128 self.buffer
130 .reserve(self.len)
131 .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
132
133 let header = pe::ImageFileHeader {
135 machine: U16::new(LE, header.machine),
136 number_of_sections: U16::new(LE, self.section_num),
137 time_date_stamp: U32::new(LE, header.time_date_stamp),
138 pointer_to_symbol_table: U32::new(LE, self.symtab_offset),
139 number_of_symbols: U32::new(LE, self.symtab_num),
140 size_of_optional_header: U16::default(),
141 characteristics: U16::new(LE, header.characteristics),
142 };
143 self.buffer.write(&header);
144
145 Ok(())
146 }
147
148 pub fn reserve_section_headers(&mut self, section_num: u16) {
150 debug_assert_eq!(self.section_num, 0);
151 self.section_num = section_num;
152 self.reserve(
153 section_num as usize * mem::size_of::<pe::ImageSectionHeader>(),
154 1,
155 );
156 }
157
158 pub fn write_section_header(&mut self, section: SectionHeader) {
160 let mut coff_section = pe::ImageSectionHeader {
161 name: [0; 8],
162 virtual_size: U32::default(),
163 virtual_address: U32::default(),
164 size_of_raw_data: U32::new(LE, section.size_of_raw_data),
165 pointer_to_raw_data: U32::new(LE, section.pointer_to_raw_data),
166 pointer_to_relocations: U32::new(LE, section.pointer_to_relocations),
167 pointer_to_linenumbers: U32::new(LE, section.pointer_to_linenumbers),
168 number_of_relocations: if section.number_of_relocations > 0xffff {
169 U16::new(LE, 0xffff)
170 } else {
171 U16::new(LE, section.number_of_relocations as u16)
172 },
173 number_of_linenumbers: U16::default(),
174 characteristics: U32::new(LE, section.characteristics),
175 };
176 match section.name {
177 Name::Short(name) => coff_section.name = name,
178 Name::Long(str_id) => {
179 let mut str_offset = self.strtab.get_offset(str_id);
180 if str_offset <= 9_999_999 {
181 let mut name = [0; 7];
182 let mut len = 0;
183 if str_offset == 0 {
184 name[6] = b'0';
185 len = 1;
186 } else {
187 while str_offset != 0 {
188 let rem = (str_offset % 10) as u8;
189 str_offset /= 10;
190 name[6 - len] = b'0' + rem;
191 len += 1;
192 }
193 }
194 coff_section.name = [0; 8];
195 coff_section.name[0] = b'/';
196 coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]);
197 } else {
198 debug_assert!(str_offset as u64 <= 0xf_ffff_ffff);
199 coff_section.name[0] = b'/';
200 coff_section.name[1] = b'/';
201 for i in 0..6 {
202 let rem = (str_offset % 64) as u8;
203 str_offset /= 64;
204 let c = match rem {
205 0..=25 => b'A' + rem,
206 26..=51 => b'a' + rem - 26,
207 52..=61 => b'0' + rem - 52,
208 62 => b'+',
209 63 => b'/',
210 _ => unreachable!(),
211 };
212 coff_section.name[7 - i] = c;
213 }
214 }
215 }
216 }
217 self.buffer.write(&coff_section);
218 }
219
220 pub fn reserve_section(&mut self, len: usize) -> u32 {
225 if len == 0 {
226 return 0;
227 }
228 self.reserve(len, 4)
230 }
231
232 pub fn write_section_align(&mut self) {
237 util::write_align(self.buffer, 4);
238 }
239
240 pub fn write_section(&mut self, data: &[u8]) {
245 if data.is_empty() {
246 return;
247 }
248 self.write_section_align();
249 self.buffer.write_bytes(data);
250 }
251
252 pub fn write_section_zeroes(&mut self, len: usize) {
257 if len == 0 {
258 return;
259 }
260 self.write_section_align();
261 self.buffer.resize(self.buffer.len() + len);
262 }
263
264 pub fn reserve_relocations(&mut self, mut count: usize) -> u32 {
271 if count == 0 {
272 return 0;
273 }
274 if count > 0xffff {
275 count += 1;
276 }
277 self.reserve(count * mem::size_of::<pe::ImageRelocation>(), 1)
278 }
279
280 pub fn write_relocations_count(&mut self, count: usize) {
284 if count > 0xffff {
285 let coff_relocation = pe::ImageRelocation {
286 virtual_address: U32Bytes::new(LE, count as u32 + 1),
287 symbol_table_index: U32Bytes::new(LE, 0),
288 typ: U16Bytes::new(LE, 0),
289 };
290 self.buffer.write(&coff_relocation);
291 }
292 }
293
294 pub fn write_relocation(&mut self, reloc: Relocation) {
296 let coff_relocation = pe::ImageRelocation {
297 virtual_address: U32Bytes::new(LE, reloc.virtual_address),
298 symbol_table_index: U32Bytes::new(LE, reloc.symbol),
299 typ: U16Bytes::new(LE, reloc.typ),
300 };
301 self.buffer.write(&coff_relocation);
302 }
303
304 pub fn reserve_symbol_index(&mut self) -> u32 {
308 debug_assert_eq!(self.symtab_offset, 0);
309 let index = self.symtab_num;
310 self.symtab_num += 1;
311 index
312 }
313
314 pub fn reserve_symbol_indices(&mut self, count: u32) {
316 debug_assert_eq!(self.symtab_offset, 0);
317 self.symtab_num += count;
318 }
319
320 pub fn write_symbol(&mut self, symbol: Symbol) {
322 let mut coff_symbol = pe::ImageSymbol {
323 name: [0; 8],
324 value: U32Bytes::new(LE, symbol.value),
325 section_number: U16Bytes::new(LE, symbol.section_number),
326 typ: U16Bytes::new(LE, symbol.typ),
327 storage_class: symbol.storage_class,
328 number_of_aux_symbols: symbol.number_of_aux_symbols,
329 };
330 match symbol.name {
331 Name::Short(name) => coff_symbol.name = name,
332 Name::Long(str_id) => {
333 let str_offset = self.strtab.get_offset(str_id);
334 coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
335 }
336 }
337 self.buffer.write(&coff_symbol);
338 }
339
340 pub fn reserve_aux_file_name(&mut self, name: &[u8]) -> u8 {
346 debug_assert_eq!(self.symtab_offset, 0);
347 let aux_count = (name.len() + pe::IMAGE_SIZEOF_SYMBOL - 1) / pe::IMAGE_SIZEOF_SYMBOL;
348 self.symtab_num += aux_count as u32;
349 aux_count as u8
350 }
351
352 pub fn write_aux_file_name(&mut self, name: &[u8], aux_count: u8) {
354 let aux_len = aux_count as usize * pe::IMAGE_SIZEOF_SYMBOL;
355 debug_assert!(aux_len >= name.len());
356 let old_len = self.buffer.len();
357 self.buffer.write_bytes(name);
358 self.buffer.resize(old_len + aux_len);
359 }
360
361 pub fn reserve_aux_section(&mut self) -> u8 {
367 debug_assert_eq!(self.symtab_offset, 0);
368 self.symtab_num += 1;
369 1
370 }
371
372 pub fn write_aux_section(&mut self, section: AuxSymbolSection) {
374 let aux = pe::ImageAuxSymbolSection {
375 length: U32Bytes::new(LE, section.length),
376 number_of_relocations: if section.number_of_relocations > 0xffff {
377 U16Bytes::new(LE, 0xffff)
378 } else {
379 U16Bytes::new(LE, section.number_of_relocations as u16)
380 },
381 number_of_linenumbers: U16Bytes::new(LE, section.number_of_linenumbers),
382 check_sum: U32Bytes::new(LE, section.check_sum),
383 number: U16Bytes::new(LE, section.number as u16),
384 selection: section.selection,
385 reserved: 0,
386 high_number: U16Bytes::new(LE, (section.number >> 16) as u16),
387 };
388 self.buffer.write(&aux);
389 }
390
391 pub fn reserve_aux_weak_external(&mut self) -> u8 {
397 debug_assert_eq!(self.symtab_offset, 0);
398 self.symtab_num += 1;
399 1
400 }
401
402 pub fn write_aux_weak_external(&mut self, weak: AuxSymbolWeak) {
404 let aux = pe::ImageAuxSymbolWeak {
405 weak_default_sym_index: U32Bytes::new(LE, weak.weak_default_sym_index),
406 weak_search_type: U32Bytes::new(LE, weak.weak_search_type),
407 };
408 self.buffer.write(&aux);
409 const PAD_LEN: usize = pe::IMAGE_SIZEOF_SYMBOL - mem::size_of::<pe::ImageAuxSymbolWeak>();
411 self.buffer.write_bytes(&[0u8; PAD_LEN]);
412 }
413
414 pub fn symbol_count(&self) -> u32 {
416 self.symtab_num
417 }
418
419 pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
423 debug_assert_eq!(self.strtab_offset, 0);
424 self.strtab.add(name)
425 }
426
427 pub fn add_name(&mut self, name: &'a [u8]) -> Name {
431 if name.len() > 8 {
432 Name::Long(self.add_string(name))
433 } else {
434 let mut short_name = [0; 8];
435 short_name[..name.len()].copy_from_slice(name);
436 Name::Short(short_name)
437 }
438 }
439
440 pub fn reserve_symtab_strtab(&mut self) {
445 debug_assert_eq!(self.symtab_offset, 0);
446 self.symtab_offset = self.reserve(self.symtab_num as usize * pe::IMAGE_SIZEOF_SYMBOL, 1);
447
448 debug_assert_eq!(self.strtab_offset, 0);
449 self.strtab.write(4, &mut self.strtab_data);
451 self.strtab_len = self.strtab_data.len() + 4;
452 self.strtab_offset = self.reserve(self.strtab_len, 1);
453 }
454
455 pub fn write_strtab(&mut self) {
457 debug_assert_eq!(self.strtab_offset, self.buffer.len() as u32);
458 self.buffer
459 .write_bytes(&u32::to_le_bytes(self.strtab_len as u32));
460 self.buffer.write_bytes(&self.strtab_data);
461 }
462}
463
464#[allow(missing_docs)]
466#[derive(Debug, Default, Clone)]
467pub struct FileHeader {
468 pub machine: u16,
469 pub time_date_stamp: u32,
470 pub characteristics: u16,
471}
472
473#[derive(Debug, Clone, Copy)]
475pub enum Name {
476 Short([u8; 8]),
478 Long(StringId),
480}
481
482impl Default for Name {
483 fn default() -> Name {
484 Name::Short([0; 8])
485 }
486}
487
488#[allow(clippy::from_over_into)]
490impl<'a> Into<Name> for &'a [u8; 8] {
491 fn into(self) -> Name {
492 Name::Short(*self)
493 }
494}
495
496#[allow(missing_docs)]
498#[derive(Debug, Default, Clone)]
499pub struct SectionHeader {
500 pub name: Name,
501 pub size_of_raw_data: u32,
502 pub pointer_to_raw_data: u32,
503 pub pointer_to_relocations: u32,
504 pub pointer_to_linenumbers: u32,
505 pub number_of_relocations: u32,
507 pub number_of_linenumbers: u16,
508 pub characteristics: u32,
509}
510
511#[allow(missing_docs)]
513#[derive(Debug, Default, Clone)]
514pub struct Symbol {
515 pub name: Name,
516 pub value: u32,
517 pub section_number: u16,
518 pub typ: u16,
519 pub storage_class: u8,
520 pub number_of_aux_symbols: u8,
521}
522
523#[allow(missing_docs)]
525#[derive(Debug, Default, Clone)]
526pub struct AuxSymbolSection {
527 pub length: u32,
528 pub number_of_relocations: u32,
530 pub number_of_linenumbers: u16,
531 pub check_sum: u32,
532 pub number: u32,
533 pub selection: u8,
534}
535
536#[allow(missing_docs)]
538#[derive(Debug, Default, Clone)]
539pub struct AuxSymbolWeak {
540 pub weak_default_sym_index: u32,
541 pub weak_search_type: u32,
542}
543
544#[allow(missing_docs)]
546#[derive(Debug, Default, Clone)]
547pub struct Relocation {
548 pub virtual_address: u32,
549 pub symbol: u32,
550 pub typ: u16,
551}