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