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 symbol_count(&self) -> u32 {
393 self.symtab_num
394 }
395
396 pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
400 debug_assert_eq!(self.strtab_offset, 0);
401 self.strtab.add(name)
402 }
403
404 pub fn add_name(&mut self, name: &'a [u8]) -> Name {
408 if name.len() > 8 {
409 Name::Long(self.add_string(name))
410 } else {
411 let mut short_name = [0; 8];
412 short_name[..name.len()].copy_from_slice(name);
413 Name::Short(short_name)
414 }
415 }
416
417 pub fn reserve_symtab_strtab(&mut self) {
422 debug_assert_eq!(self.symtab_offset, 0);
423 self.symtab_offset = self.reserve(self.symtab_num as usize * pe::IMAGE_SIZEOF_SYMBOL, 1);
424
425 debug_assert_eq!(self.strtab_offset, 0);
426 self.strtab.write(4, &mut self.strtab_data);
428 self.strtab_len = self.strtab_data.len() + 4;
429 self.strtab_offset = self.reserve(self.strtab_len, 1);
430 }
431
432 pub fn write_strtab(&mut self) {
434 debug_assert_eq!(self.strtab_offset, self.buffer.len() as u32);
435 self.buffer
436 .write_bytes(&u32::to_le_bytes(self.strtab_len as u32));
437 self.buffer.write_bytes(&self.strtab_data);
438 }
439}
440
441#[allow(missing_docs)]
443#[derive(Debug, Default, Clone)]
444pub struct FileHeader {
445 pub machine: u16,
446 pub time_date_stamp: u32,
447 pub characteristics: u16,
448}
449
450#[derive(Debug, Clone, Copy)]
452pub enum Name {
453 Short([u8; 8]),
455 Long(StringId),
457}
458
459impl Default for Name {
460 fn default() -> Name {
461 Name::Short([0; 8])
462 }
463}
464
465#[allow(clippy::from_over_into)]
467impl<'a> Into<Name> for &'a [u8; 8] {
468 fn into(self) -> Name {
469 Name::Short(*self)
470 }
471}
472
473#[allow(missing_docs)]
475#[derive(Debug, Default, Clone)]
476pub struct SectionHeader {
477 pub name: Name,
478 pub size_of_raw_data: u32,
479 pub pointer_to_raw_data: u32,
480 pub pointer_to_relocations: u32,
481 pub pointer_to_linenumbers: u32,
482 pub number_of_relocations: u32,
484 pub number_of_linenumbers: u16,
485 pub characteristics: u32,
486}
487
488#[allow(missing_docs)]
490#[derive(Debug, Default, Clone)]
491pub struct Symbol {
492 pub name: Name,
493 pub value: u32,
494 pub section_number: u16,
495 pub typ: u16,
496 pub storage_class: u8,
497 pub number_of_aux_symbols: u8,
498}
499
500#[allow(missing_docs)]
502#[derive(Debug, Default, Clone)]
503pub struct AuxSymbolSection {
504 pub length: u32,
505 pub number_of_relocations: u32,
507 pub number_of_linenumbers: u16,
508 pub check_sum: u32,
509 pub number: u32,
510 pub selection: u8,
511}
512
513#[allow(missing_docs)]
515#[derive(Debug, Default, Clone)]
516pub struct Relocation {
517 pub virtual_address: u32,
518 pub symbol: u32,
519 pub typ: u16,
520}