object/write/coff/
writer.rs

1//! Helper for writing COFF files.
2use 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/// A helper for writing COFF files.
13///
14/// Writing uses a two phase approach. The first phase builds up all of the information
15/// that may need to be known ahead of time:
16/// - build string table
17/// - reserve section indices
18/// - reserve symbol indices
19/// - reserve file ranges for headers and sections
20///
21/// Some of the information has ordering requirements. For example, strings must be added
22/// to the string table before reserving the file range for the string table. There are debug
23/// asserts to check some of these requirements.
24///
25/// The second phase writes everything out in order. Thus the caller must ensure writing
26/// is in the same order that file ranges were reserved. There are debug asserts to assist
27/// with checking this.
28#[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    /// Create a new `Writer`.
46    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    /// Return the current file length that has been reserved.
64    pub fn reserved_len(&self) -> usize {
65        self.len
66    }
67
68    /// Return the current file length that has been written.
69    #[allow(clippy::len_without_is_empty)]
70    pub fn len(&self) -> usize {
71        self.buffer.len()
72    }
73
74    /// Reserve a file range with the given size and starting alignment.
75    ///
76    /// Returns the aligned offset of the start of the range.
77    ///
78    /// `align_start` must be a power of two.
79    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    /// Write alignment padding bytes.
89    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    /// Write data.
96    pub fn write(&mut self, data: &[u8]) {
97        self.buffer.write_bytes(data);
98    }
99
100    /// Reserve the file range up to the given file offset.
101    pub fn reserve_until(&mut self, offset: usize) {
102        debug_assert!(self.len <= offset);
103        self.len = offset;
104    }
105
106    /// Write padding up to the given file offset.
107    pub fn pad_until(&mut self, offset: usize) {
108        debug_assert!(self.buffer.len() <= offset);
109        self.buffer.resize(offset);
110    }
111
112    /// Reserve the range for the file header.
113    ///
114    /// This must be at the start of the file.
115    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    /// Write the file header.
121    ///
122    /// This must be at the start of the file.
123    ///
124    /// Fields that can be derived from known information are automatically set by this function.
125    pub fn write_file_header(&mut self, header: FileHeader) -> Result<()> {
126        debug_assert_eq!(self.buffer.len(), 0);
127
128        // Start writing.
129        self.buffer
130            .reserve(self.len)
131            .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
132
133        // Write file header.
134        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    /// Reserve the range for the section headers.
149    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    /// Write a section header.
159    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    /// Reserve the range for the section data.
221    ///
222    /// Returns the aligned offset of the start of the range.
223    /// Does nothing and returns 0 if the length is zero.
224    pub fn reserve_section(&mut self, len: usize) -> u32 {
225        if len == 0 {
226            return 0;
227        }
228        // TODO: not sure what alignment is required here, but this seems to match LLVM
229        self.reserve(len, 4)
230    }
231
232    /// Write the alignment bytes prior to section data.
233    ///
234    /// This is unneeded if you are using `write_section` or `write_section_zeroes`
235    /// for the data.
236    pub fn write_section_align(&mut self) {
237        util::write_align(self.buffer, 4);
238    }
239
240    /// Write the section data.
241    ///
242    /// Writes alignment bytes prior to the data.
243    /// Does nothing if the data is empty.
244    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    /// Write the section data using zero bytes.
253    ///
254    /// Writes alignment bytes prior to the data.
255    /// Does nothing if the length is zero.
256    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    /// Reserve a file range for the given number of relocations.
265    ///
266    /// This will automatically reserve an extra relocation if there are more than 0xffff.
267    ///
268    /// Returns the offset of the range.
269    /// Does nothing and returns 0 if the count is zero.
270    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    /// Write a relocation containing the count if required.
281    ///
282    /// This should be called before writing the first relocation for a section.
283    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    /// Write a relocation.
295    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    /// Reserve a symbol table entry.
305    ///
306    /// This must be called before [`Self::reserve_symtab_strtab`].
307    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    /// Reserve a number of symbol table entries.
315    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    /// Write a symbol table entry.
321    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    /// Reserve auxiliary symbols for a file name.
341    ///
342    /// Returns the number of auxiliary symbols required.
343    ///
344    /// This must be called before [`Self::reserve_symtab_strtab`].
345    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    /// Write auxiliary symbols for a file name.
353    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    /// Reserve an auxiliary symbol for a section.
362    ///
363    /// Returns the number of auxiliary symbols required.
364    ///
365    /// This must be called before [`Self::reserve_symtab_strtab`].
366    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    /// Write an auxiliary symbol for a section.
373    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    /// Reserve an auxiliary symbol for a weak external.
392    ///
393    /// Returns the number of auxiliary symbols required.
394    ///
395    /// This must be called before [`Self::reserve_symtab_strtab`].
396    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    /// Write an auxiliary symbol for a weak external.
403    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        // write padding for the unused field
410        const PAD_LEN: usize = pe::IMAGE_SIZEOF_SYMBOL - mem::size_of::<pe::ImageAuxSymbolWeak>();
411        self.buffer.write_bytes(&[0u8; PAD_LEN]);
412    }
413
414    /// Return the number of reserved symbol table entries.
415    pub fn symbol_count(&self) -> u32 {
416        self.symtab_num
417    }
418
419    /// Add a string to the string table.
420    ///
421    /// This must be called before [`Self::reserve_symtab_strtab`].
422    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    /// Add a section or symbol name to the string table if required.
428    ///
429    /// This must be called before [`Self::reserve_symtab_strtab`].
430    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    /// Reserve the range for the symbol table and string table.
441    ///
442    /// This must be called after functions that reserve symbol
443    /// indices or add strings.
444    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        // First 4 bytes of strtab are the length.
450        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    /// Write the string table.
456    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/// Shortened and native endian version of [`pe::ImageFileHeader`].
465#[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/// A section or symbol name.
474#[derive(Debug, Clone, Copy)]
475pub enum Name {
476    /// An inline name.
477    Short([u8; 8]),
478    /// An id of a string table entry.
479    Long(StringId),
480}
481
482impl Default for Name {
483    fn default() -> Name {
484        Name::Short([0; 8])
485    }
486}
487
488// From isn't useful.
489#[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/// Native endian version of [`pe::ImageSectionHeader`].
497#[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    /// This will automatically be clamped if there are more than 0xffff.
506    pub number_of_relocations: u32,
507    pub number_of_linenumbers: u16,
508    pub characteristics: u32,
509}
510
511/// Native endian version of [`pe::ImageSymbol`].
512#[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/// Native endian version of [`pe::ImageAuxSymbolSection`].
524#[allow(missing_docs)]
525#[derive(Debug, Default, Clone)]
526pub struct AuxSymbolSection {
527    pub length: u32,
528    /// This will automatically be clamped if there are more than 0xffff.
529    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/// Native endian version of [`pe::ImageAuxSymbolWeak`].
537#[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/// Native endian version of [`pe::ImageRelocation`].
545#[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}