object/write/elf/
writer.rs

1//! Helper for writing ELF files.
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::mem;
5
6use crate::elf;
7use crate::endian::*;
8use crate::pod;
9use crate::write::string::{StringId, StringTable};
10use crate::write::util;
11use crate::write::{Error, Result, WritableBuffer};
12
13const ALIGN_SYMTAB_SHNDX: usize = 4;
14const ALIGN_HASH: usize = 4;
15const ALIGN_GNU_VERSYM: usize = 2;
16const ALIGN_GNU_VERDEF: usize = 4;
17const ALIGN_GNU_VERNEED: usize = 4;
18
19/// The index of an ELF section.
20#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct SectionIndex(pub u32);
22
23/// The index of an ELF symbol.
24#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub struct SymbolIndex(pub u32);
26
27/// A helper for writing ELF files.
28///
29/// Writing uses a two phase approach. The first phase builds up all of the information
30/// that may need to be known ahead of time:
31/// - build string tables
32/// - reserve section indices
33/// - reserve symbol indices
34/// - reserve file ranges for headers and sections
35///
36/// Some of the information has ordering requirements. For example, strings must be added
37/// to string tables before reserving the file range for the string table. Symbol indices
38/// must be reserved after reserving the section indices they reference. There are debug
39/// asserts to check some of these requirements.
40///
41/// The second phase writes everything out in order. Thus the caller must ensure writing
42/// is in the same order that file ranges were reserved. There are debug asserts to assist
43/// with checking this.
44#[allow(missing_debug_implementations)]
45pub struct Writer<'a> {
46    endian: Endianness,
47    is_64: bool,
48    is_mips64el: bool,
49    elf_align: usize,
50
51    buffer: &'a mut dyn WritableBuffer,
52    len: usize,
53
54    segment_offset: usize,
55    segment_num: u32,
56
57    section_offset: usize,
58    section_num: u32,
59
60    shstrtab: StringTable<'a>,
61    shstrtab_str_id: Option<StringId>,
62    shstrtab_index: SectionIndex,
63    shstrtab_offset: usize,
64    shstrtab_data: Vec<u8>,
65
66    need_strtab: bool,
67    strtab: StringTable<'a>,
68    strtab_str_id: Option<StringId>,
69    strtab_index: SectionIndex,
70    strtab_offset: usize,
71    strtab_data: Vec<u8>,
72
73    symtab_str_id: Option<StringId>,
74    symtab_index: SectionIndex,
75    symtab_offset: usize,
76    symtab_num: u32,
77
78    need_symtab_shndx: bool,
79    symtab_shndx_str_id: Option<StringId>,
80    symtab_shndx_offset: usize,
81    symtab_shndx_data: Vec<u8>,
82
83    need_dynstr: bool,
84    dynstr: StringTable<'a>,
85    dynstr_str_id: Option<StringId>,
86    dynstr_index: SectionIndex,
87    dynstr_offset: usize,
88    dynstr_data: Vec<u8>,
89
90    dynsym_str_id: Option<StringId>,
91    dynsym_index: SectionIndex,
92    dynsym_offset: usize,
93    dynsym_num: u32,
94
95    dynamic_str_id: Option<StringId>,
96    dynamic_offset: usize,
97    dynamic_num: usize,
98
99    hash_str_id: Option<StringId>,
100    hash_offset: usize,
101    hash_size: usize,
102
103    gnu_hash_str_id: Option<StringId>,
104    gnu_hash_offset: usize,
105    gnu_hash_size: usize,
106
107    gnu_versym_str_id: Option<StringId>,
108    gnu_versym_offset: usize,
109
110    gnu_verdef_str_id: Option<StringId>,
111    gnu_verdef_offset: usize,
112    gnu_verdef_size: usize,
113    gnu_verdef_count: u16,
114    gnu_verdef_remaining: u16,
115    gnu_verdaux_remaining: u16,
116
117    gnu_verneed_str_id: Option<StringId>,
118    gnu_verneed_offset: usize,
119    gnu_verneed_size: usize,
120    gnu_verneed_count: u16,
121    gnu_verneed_remaining: u16,
122    gnu_vernaux_remaining: u16,
123
124    gnu_attributes_str_id: Option<StringId>,
125    gnu_attributes_offset: usize,
126    gnu_attributes_size: usize,
127}
128
129impl<'a> Writer<'a> {
130    /// Create a new `Writer` for the given endianness and ELF class.
131    pub fn new(endian: Endianness, is_64: bool, buffer: &'a mut dyn WritableBuffer) -> Self {
132        let elf_align = if is_64 { 8 } else { 4 };
133        Writer {
134            endian,
135            is_64,
136            // Determined later.
137            is_mips64el: false,
138            elf_align,
139
140            buffer,
141            len: 0,
142
143            segment_offset: 0,
144            segment_num: 0,
145
146            section_offset: 0,
147            section_num: 0,
148
149            shstrtab: StringTable::default(),
150            shstrtab_str_id: None,
151            shstrtab_index: SectionIndex(0),
152            shstrtab_offset: 0,
153            shstrtab_data: Vec::new(),
154
155            need_strtab: false,
156            strtab: StringTable::default(),
157            strtab_str_id: None,
158            strtab_index: SectionIndex(0),
159            strtab_offset: 0,
160            strtab_data: Vec::new(),
161
162            symtab_str_id: None,
163            symtab_index: SectionIndex(0),
164            symtab_offset: 0,
165            symtab_num: 0,
166
167            need_symtab_shndx: false,
168            symtab_shndx_str_id: None,
169            symtab_shndx_offset: 0,
170            symtab_shndx_data: Vec::new(),
171
172            need_dynstr: false,
173            dynstr: StringTable::default(),
174            dynstr_str_id: None,
175            dynstr_index: SectionIndex(0),
176            dynstr_offset: 0,
177            dynstr_data: Vec::new(),
178
179            dynsym_str_id: None,
180            dynsym_index: SectionIndex(0),
181            dynsym_offset: 0,
182            dynsym_num: 0,
183
184            dynamic_str_id: None,
185            dynamic_offset: 0,
186            dynamic_num: 0,
187
188            hash_str_id: None,
189            hash_offset: 0,
190            hash_size: 0,
191
192            gnu_hash_str_id: None,
193            gnu_hash_offset: 0,
194            gnu_hash_size: 0,
195
196            gnu_versym_str_id: None,
197            gnu_versym_offset: 0,
198
199            gnu_verdef_str_id: None,
200            gnu_verdef_offset: 0,
201            gnu_verdef_size: 0,
202            gnu_verdef_count: 0,
203            gnu_verdef_remaining: 0,
204            gnu_verdaux_remaining: 0,
205
206            gnu_verneed_str_id: None,
207            gnu_verneed_offset: 0,
208            gnu_verneed_size: 0,
209            gnu_verneed_count: 0,
210            gnu_verneed_remaining: 0,
211            gnu_vernaux_remaining: 0,
212
213            gnu_attributes_str_id: None,
214            gnu_attributes_offset: 0,
215            gnu_attributes_size: 0,
216        }
217    }
218
219    /// Get the file class that will be written.
220    fn class(&self) -> Class {
221        Class { is_64: self.is_64 }
222    }
223
224    /// Return the current file length that has been reserved.
225    pub fn reserved_len(&self) -> usize {
226        self.len
227    }
228
229    /// Return the current file length that has been written.
230    #[allow(clippy::len_without_is_empty)]
231    pub fn len(&self) -> usize {
232        self.buffer.len()
233    }
234
235    /// Reserve a file range with the given size and starting alignment.
236    ///
237    /// Returns the aligned offset of the start of the range.
238    ///
239    /// `align_start` must be a power of two.
240    pub fn reserve(&mut self, len: usize, align_start: usize) -> usize {
241        if align_start > 1 {
242            self.len = util::align(self.len, align_start);
243        }
244        let offset = self.len;
245        self.len += len;
246        offset
247    }
248
249    /// Write alignment padding bytes.
250    pub fn write_align(&mut self, align_start: usize) {
251        if align_start > 1 {
252            util::write_align(self.buffer, align_start);
253        }
254    }
255
256    /// Write data.
257    ///
258    /// This is typically used to write section data.
259    pub fn write(&mut self, data: &[u8]) {
260        self.buffer.write_bytes(data);
261    }
262
263    /// Reserve the file range up to the given file offset.
264    pub fn reserve_until(&mut self, offset: usize) {
265        debug_assert!(self.len <= offset);
266        self.len = offset;
267    }
268
269    /// Write padding up to the given file offset.
270    pub fn pad_until(&mut self, offset: usize) {
271        debug_assert!(self.buffer.len() <= offset);
272        self.buffer.resize(offset);
273    }
274
275    /// Reserve the range for the file header.
276    ///
277    /// This must be at the start of the file.
278    pub fn reserve_file_header(&mut self) {
279        debug_assert_eq!(self.len, 0);
280        self.reserve(self.class().file_header_size(), 1);
281    }
282
283    /// Write the file header.
284    ///
285    /// This must be at the start of the file.
286    ///
287    /// Fields that can be derived from known information are automatically set by this function.
288    pub fn write_file_header(&mut self, header: &FileHeader) -> Result<()> {
289        debug_assert_eq!(self.buffer.len(), 0);
290
291        self.is_mips64el =
292            self.is_64 && self.endian.is_little_endian() && header.e_machine == elf::EM_MIPS;
293
294        // Start writing.
295        self.buffer
296            .reserve(self.len)
297            .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
298
299        // Write file header.
300        let e_ident = elf::Ident {
301            magic: elf::ELFMAG,
302            class: if self.is_64 {
303                elf::ELFCLASS64
304            } else {
305                elf::ELFCLASS32
306            },
307            data: if self.endian.is_little_endian() {
308                elf::ELFDATA2LSB
309            } else {
310                elf::ELFDATA2MSB
311            },
312            version: elf::EV_CURRENT,
313            os_abi: header.os_abi,
314            abi_version: header.abi_version,
315            padding: [0; 7],
316        };
317
318        let e_ehsize = self.class().file_header_size() as u16;
319
320        let e_phoff = self.segment_offset as u64;
321        let e_phentsize = if self.segment_num == 0 {
322            0
323        } else {
324            self.class().program_header_size() as u16
325        };
326        // TODO: overflow
327        let e_phnum = self.segment_num as u16;
328
329        let e_shoff = self.section_offset as u64;
330        let e_shentsize = if self.section_num == 0 {
331            0
332        } else {
333            self.class().section_header_size() as u16
334        };
335        let e_shnum = if self.section_num >= elf::SHN_LORESERVE.into() {
336            0
337        } else {
338            self.section_num as u16
339        };
340        let e_shstrndx = if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() {
341            elf::SHN_XINDEX
342        } else {
343            self.shstrtab_index.0 as u16
344        };
345
346        let endian = self.endian;
347        if self.is_64 {
348            let file = elf::FileHeader64 {
349                e_ident,
350                e_type: U16::new(endian, header.e_type),
351                e_machine: U16::new(endian, header.e_machine),
352                e_version: U32::new(endian, elf::EV_CURRENT.into()),
353                e_entry: U64::new(endian, header.e_entry),
354                e_phoff: U64::new(endian, e_phoff),
355                e_shoff: U64::new(endian, e_shoff),
356                e_flags: U32::new(endian, header.e_flags),
357                e_ehsize: U16::new(endian, e_ehsize),
358                e_phentsize: U16::new(endian, e_phentsize),
359                e_phnum: U16::new(endian, e_phnum),
360                e_shentsize: U16::new(endian, e_shentsize),
361                e_shnum: U16::new(endian, e_shnum),
362                e_shstrndx: U16::new(endian, e_shstrndx),
363            };
364            self.buffer.write(&file)
365        } else {
366            let file = elf::FileHeader32 {
367                e_ident,
368                e_type: U16::new(endian, header.e_type),
369                e_machine: U16::new(endian, header.e_machine),
370                e_version: U32::new(endian, elf::EV_CURRENT.into()),
371                e_entry: U32::new(endian, header.e_entry as u32),
372                e_phoff: U32::new(endian, e_phoff as u32),
373                e_shoff: U32::new(endian, e_shoff as u32),
374                e_flags: U32::new(endian, header.e_flags),
375                e_ehsize: U16::new(endian, e_ehsize),
376                e_phentsize: U16::new(endian, e_phentsize),
377                e_phnum: U16::new(endian, e_phnum),
378                e_shentsize: U16::new(endian, e_shentsize),
379                e_shnum: U16::new(endian, e_shnum),
380                e_shstrndx: U16::new(endian, e_shstrndx),
381            };
382            self.buffer.write(&file);
383        }
384
385        Ok(())
386    }
387
388    /// Reserve the range for the program headers.
389    pub fn reserve_program_headers(&mut self, num: u32) {
390        debug_assert_eq!(self.segment_offset, 0);
391        if num == 0 {
392            return;
393        }
394        self.segment_num = num;
395        self.segment_offset = self.reserve(
396            num as usize * self.class().program_header_size(),
397            self.elf_align,
398        );
399    }
400
401    /// Write alignment padding bytes prior to the program headers.
402    pub fn write_align_program_headers(&mut self) {
403        if self.segment_offset == 0 {
404            return;
405        }
406        util::write_align(self.buffer, self.elf_align);
407        debug_assert_eq!(self.segment_offset, self.buffer.len());
408    }
409
410    /// Write a program header.
411    pub fn write_program_header(&mut self, header: &ProgramHeader) {
412        let endian = self.endian;
413        if self.is_64 {
414            let header = elf::ProgramHeader64 {
415                p_type: U32::new(endian, header.p_type),
416                p_flags: U32::new(endian, header.p_flags),
417                p_offset: U64::new(endian, header.p_offset),
418                p_vaddr: U64::new(endian, header.p_vaddr),
419                p_paddr: U64::new(endian, header.p_paddr),
420                p_filesz: U64::new(endian, header.p_filesz),
421                p_memsz: U64::new(endian, header.p_memsz),
422                p_align: U64::new(endian, header.p_align),
423            };
424            self.buffer.write(&header);
425        } else {
426            let header = elf::ProgramHeader32 {
427                p_type: U32::new(endian, header.p_type),
428                p_offset: U32::new(endian, header.p_offset as u32),
429                p_vaddr: U32::new(endian, header.p_vaddr as u32),
430                p_paddr: U32::new(endian, header.p_paddr as u32),
431                p_filesz: U32::new(endian, header.p_filesz as u32),
432                p_memsz: U32::new(endian, header.p_memsz as u32),
433                p_flags: U32::new(endian, header.p_flags),
434                p_align: U32::new(endian, header.p_align as u32),
435            };
436            self.buffer.write(&header);
437        }
438    }
439
440    /// Reserve the section index for the null section header.
441    ///
442    /// The null section header is usually automatically reserved,
443    /// but this can be used to force an empty section table.
444    ///
445    /// This must be called before [`Self::reserve_section_headers`].
446    pub fn reserve_null_section_index(&mut self) -> SectionIndex {
447        debug_assert_eq!(self.section_num, 0);
448        if self.section_num == 0 {
449            self.section_num = 1;
450        }
451        SectionIndex(0)
452    }
453
454    /// Reserve a section table index.
455    ///
456    /// Automatically also reserves the null section header if required.
457    ///
458    /// This must be called before [`Self::reserve_section_headers`].
459    pub fn reserve_section_index(&mut self) -> SectionIndex {
460        debug_assert_eq!(self.section_offset, 0);
461        if self.section_num == 0 {
462            self.section_num = 1;
463        }
464        let index = self.section_num;
465        self.section_num += 1;
466        SectionIndex(index)
467    }
468
469    /// Reserve the range for the section headers.
470    ///
471    /// This function does nothing if no sections were reserved.
472    /// This must be called after [`Self::reserve_section_index`]
473    /// and other functions that reserve section indices.
474    pub fn reserve_section_headers(&mut self) {
475        debug_assert_eq!(self.section_offset, 0);
476        if self.section_num == 0 {
477            return;
478        }
479        self.section_offset = self.reserve(
480            self.section_num as usize * self.class().section_header_size(),
481            self.elf_align,
482        );
483    }
484
485    /// Write the null section header.
486    ///
487    /// This must be the first section header that is written.
488    /// This function does nothing if no sections were reserved.
489    pub fn write_null_section_header(&mut self) {
490        if self.section_num == 0 {
491            return;
492        }
493        util::write_align(self.buffer, self.elf_align);
494        debug_assert_eq!(self.section_offset, self.buffer.len());
495        self.write_section_header(&SectionHeader {
496            name: None,
497            sh_type: 0,
498            sh_flags: 0,
499            sh_addr: 0,
500            sh_offset: 0,
501            sh_size: if self.section_num >= elf::SHN_LORESERVE.into() {
502                self.section_num.into()
503            } else {
504                0
505            },
506            sh_link: if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() {
507                self.shstrtab_index.0
508            } else {
509                0
510            },
511            // TODO: e_phnum overflow
512            sh_info: 0,
513            sh_addralign: 0,
514            sh_entsize: 0,
515        });
516    }
517
518    /// Write a section header.
519    pub fn write_section_header(&mut self, section: &SectionHeader) {
520        let sh_name = if let Some(name) = section.name {
521            self.shstrtab.get_offset(name) as u32
522        } else {
523            0
524        };
525        let endian = self.endian;
526        if self.is_64 {
527            let section = elf::SectionHeader64 {
528                sh_name: U32::new(endian, sh_name),
529                sh_type: U32::new(endian, section.sh_type),
530                sh_flags: U64::new(endian, section.sh_flags),
531                sh_addr: U64::new(endian, section.sh_addr),
532                sh_offset: U64::new(endian, section.sh_offset),
533                sh_size: U64::new(endian, section.sh_size),
534                sh_link: U32::new(endian, section.sh_link),
535                sh_info: U32::new(endian, section.sh_info),
536                sh_addralign: U64::new(endian, section.sh_addralign),
537                sh_entsize: U64::new(endian, section.sh_entsize),
538            };
539            self.buffer.write(&section);
540        } else {
541            let section = elf::SectionHeader32 {
542                sh_name: U32::new(endian, sh_name),
543                sh_type: U32::new(endian, section.sh_type),
544                sh_flags: U32::new(endian, section.sh_flags as u32),
545                sh_addr: U32::new(endian, section.sh_addr as u32),
546                sh_offset: U32::new(endian, section.sh_offset as u32),
547                sh_size: U32::new(endian, section.sh_size as u32),
548                sh_link: U32::new(endian, section.sh_link),
549                sh_info: U32::new(endian, section.sh_info),
550                sh_addralign: U32::new(endian, section.sh_addralign as u32),
551                sh_entsize: U32::new(endian, section.sh_entsize as u32),
552            };
553            self.buffer.write(&section);
554        }
555    }
556
557    /// Add a section name to the section header string table.
558    ///
559    /// This will be stored in the `.shstrtab` section.
560    ///
561    /// This must be called before [`Self::reserve_shstrtab`].
562    pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId {
563        debug_assert_eq!(self.shstrtab_offset, 0);
564        self.shstrtab.add(name)
565    }
566
567    /// Reserve the range for the section header string table.
568    ///
569    /// This range is used for a section named `.shstrtab`.
570    ///
571    /// This function does nothing if no sections were reserved.
572    /// This must be called after [`Self::add_section_name`].
573    /// and other functions that reserve section names and indices.
574    pub fn reserve_shstrtab(&mut self) {
575        debug_assert_eq!(self.shstrtab_offset, 0);
576        if self.section_num == 0 {
577            return;
578        }
579        // Start with null section name.
580        self.shstrtab_data = vec![0];
581        self.shstrtab.write(1, &mut self.shstrtab_data);
582        self.shstrtab_offset = self.reserve(self.shstrtab_data.len(), 1);
583    }
584
585    /// Write the section header string table.
586    ///
587    /// This function does nothing if the section was not reserved.
588    pub fn write_shstrtab(&mut self) {
589        if self.shstrtab_offset == 0 {
590            return;
591        }
592        debug_assert_eq!(self.shstrtab_offset, self.buffer.len());
593        self.buffer.write_bytes(&self.shstrtab_data);
594    }
595
596    /// Reserve the section index for the section header string table.
597    ///
598    /// This must be called before [`Self::reserve_shstrtab`]
599    /// and [`Self::reserve_section_headers`].
600    pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex {
601        self.reserve_shstrtab_section_index_with_name(&b".shstrtab"[..])
602    }
603
604    /// Reserve the section index for the section header string table.
605    ///
606    /// This must be called before [`Self::reserve_shstrtab`]
607    /// and [`Self::reserve_section_headers`].
608    pub fn reserve_shstrtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
609        debug_assert_eq!(self.shstrtab_index, SectionIndex(0));
610        self.shstrtab_str_id = Some(self.add_section_name(name));
611        self.shstrtab_index = self.reserve_section_index();
612        self.shstrtab_index
613    }
614
615    /// Write the section header for the section header string table.
616    ///
617    /// This function does nothing if the section index was not reserved.
618    pub fn write_shstrtab_section_header(&mut self) {
619        if self.shstrtab_index == SectionIndex(0) {
620            return;
621        }
622        self.write_section_header(&SectionHeader {
623            name: self.shstrtab_str_id,
624            sh_type: elf::SHT_STRTAB,
625            sh_flags: 0,
626            sh_addr: 0,
627            sh_offset: self.shstrtab_offset as u64,
628            sh_size: self.shstrtab_data.len() as u64,
629            sh_link: 0,
630            sh_info: 0,
631            sh_addralign: 1,
632            sh_entsize: 0,
633        });
634    }
635
636    /// Add a string to the string table.
637    ///
638    /// This will be stored in the `.strtab` section.
639    ///
640    /// This must be called before [`Self::reserve_strtab`].
641    pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
642        debug_assert_eq!(self.strtab_offset, 0);
643        self.need_strtab = true;
644        self.strtab.add(name)
645    }
646
647    /// Return true if `.strtab` is needed.
648    pub fn strtab_needed(&self) -> bool {
649        self.need_strtab
650    }
651
652    /// Require the string table even if no strings were added.
653    pub fn require_strtab(&mut self) {
654        self.need_strtab = true;
655    }
656
657    /// Reserve the range for the string table.
658    ///
659    /// This range is used for a section named `.strtab`.
660    ///
661    /// This function does nothing if a string table is not required.
662    /// This must be called after [`Self::add_string`].
663    pub fn reserve_strtab(&mut self) {
664        debug_assert_eq!(self.strtab_offset, 0);
665        if !self.need_strtab {
666            return;
667        }
668        // Start with null string.
669        self.strtab_data = vec![0];
670        self.strtab.write(1, &mut self.strtab_data);
671        self.strtab_offset = self.reserve(self.strtab_data.len(), 1);
672    }
673
674    /// Write the string table.
675    ///
676    /// This function does nothing if the section was not reserved.
677    pub fn write_strtab(&mut self) {
678        if self.strtab_offset == 0 {
679            return;
680        }
681        debug_assert_eq!(self.strtab_offset, self.buffer.len());
682        self.buffer.write_bytes(&self.strtab_data);
683    }
684
685    /// Reserve the section index for the string table.
686    ///
687    /// You should check [`Self::strtab_needed`] before calling this
688    /// unless you have other means of knowing if this section is needed.
689    ///
690    /// This must be called before [`Self::reserve_section_headers`].
691    pub fn reserve_strtab_section_index(&mut self) -> SectionIndex {
692        self.reserve_strtab_section_index_with_name(&b".strtab"[..])
693    }
694
695    /// Reserve the section index for the string table.
696    ///
697    /// You should check [`Self::strtab_needed`] before calling this
698    /// unless you have other means of knowing if this section is needed.
699    ///
700    /// This must be called before [`Self::reserve_section_headers`].
701    pub fn reserve_strtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
702        debug_assert_eq!(self.strtab_index, SectionIndex(0));
703        self.strtab_str_id = Some(self.add_section_name(name));
704        self.strtab_index = self.reserve_section_index();
705        self.strtab_index
706    }
707
708    /// Write the section header for the string table.
709    ///
710    /// This function does nothing if the section index was not reserved.
711    pub fn write_strtab_section_header(&mut self) {
712        if self.strtab_index == SectionIndex(0) {
713            return;
714        }
715        self.write_section_header(&SectionHeader {
716            name: self.strtab_str_id,
717            sh_type: elf::SHT_STRTAB,
718            sh_flags: 0,
719            sh_addr: 0,
720            sh_offset: self.strtab_offset as u64,
721            sh_size: self.strtab_data.len() as u64,
722            sh_link: 0,
723            sh_info: 0,
724            sh_addralign: 1,
725            sh_entsize: 0,
726        });
727    }
728
729    /// Reserve the null symbol table entry.
730    ///
731    /// This will be stored in the `.symtab` section.
732    ///
733    /// The null symbol table entry is usually automatically reserved,
734    /// but this can be used to force an empty symbol table.
735    ///
736    /// This must be called before [`Self::reserve_symtab`].
737    pub fn reserve_null_symbol_index(&mut self) -> SymbolIndex {
738        debug_assert_eq!(self.symtab_offset, 0);
739        debug_assert_eq!(self.symtab_num, 0);
740        self.symtab_num = 1;
741        // The symtab must link to a strtab.
742        self.need_strtab = true;
743        SymbolIndex(0)
744    }
745
746    /// Reserve a symbol table entry.
747    ///
748    /// This will be stored in the `.symtab` section.
749    ///
750    /// `section_index` is used to determine whether `.symtab_shndx` is required.
751    ///
752    /// Automatically also reserves the null symbol if required.
753    /// Callers may assume that the returned indices will be sequential
754    /// starting at 1.
755    ///
756    /// This must be called before [`Self::reserve_symtab`] and
757    /// [`Self::reserve_symtab_shndx`].
758    pub fn reserve_symbol_index(&mut self, section_index: Option<SectionIndex>) -> SymbolIndex {
759        debug_assert_eq!(self.symtab_offset, 0);
760        debug_assert_eq!(self.symtab_shndx_offset, 0);
761        if self.symtab_num == 0 {
762            self.symtab_num = 1;
763            // The symtab must link to a strtab.
764            self.need_strtab = true;
765        }
766        let index = self.symtab_num;
767        self.symtab_num += 1;
768        if let Some(section_index) = section_index {
769            if section_index.0 >= elf::SHN_LORESERVE.into() {
770                self.need_symtab_shndx = true;
771            }
772        }
773        SymbolIndex(index)
774    }
775
776    /// Return the number of reserved symbol table entries.
777    ///
778    /// Includes the null symbol.
779    pub fn symbol_count(&self) -> u32 {
780        self.symtab_num
781    }
782
783    /// Reserve the range for the symbol table.
784    ///
785    /// This range is used for a section named `.symtab`.
786    /// This function does nothing if no symbols were reserved.
787    /// This must be called after [`Self::reserve_symbol_index`].
788    pub fn reserve_symtab(&mut self) {
789        debug_assert_eq!(self.symtab_offset, 0);
790        if self.symtab_num == 0 {
791            return;
792        }
793        self.symtab_offset = self.reserve(
794            self.symtab_num as usize * self.class().sym_size(),
795            self.elf_align,
796        );
797    }
798
799    /// Write the null symbol.
800    ///
801    /// This must be the first symbol that is written.
802    /// This function does nothing if no symbols were reserved.
803    pub fn write_null_symbol(&mut self) {
804        if self.symtab_num == 0 {
805            return;
806        }
807        util::write_align(self.buffer, self.elf_align);
808        debug_assert_eq!(self.symtab_offset, self.buffer.len());
809        if self.is_64 {
810            self.buffer.write(&elf::Sym64::<Endianness>::default());
811        } else {
812            self.buffer.write(&elf::Sym32::<Endianness>::default());
813        }
814
815        if self.need_symtab_shndx {
816            self.symtab_shndx_data.write_pod(&U32::new(self.endian, 0));
817        }
818    }
819
820    /// Write a symbol.
821    pub fn write_symbol(&mut self, sym: &Sym) {
822        let st_name = if let Some(name) = sym.name {
823            self.strtab.get_offset(name) as u32
824        } else {
825            0
826        };
827        let st_shndx = if let Some(section) = sym.section {
828            if section.0 >= elf::SHN_LORESERVE as u32 {
829                elf::SHN_XINDEX
830            } else {
831                section.0 as u16
832            }
833        } else {
834            sym.st_shndx
835        };
836
837        let endian = self.endian;
838        if self.is_64 {
839            let sym = elf::Sym64 {
840                st_name: U32::new(endian, st_name),
841                st_info: sym.st_info,
842                st_other: sym.st_other,
843                st_shndx: U16::new(endian, st_shndx),
844                st_value: U64::new(endian, sym.st_value),
845                st_size: U64::new(endian, sym.st_size),
846            };
847            self.buffer.write(&sym);
848        } else {
849            let sym = elf::Sym32 {
850                st_name: U32::new(endian, st_name),
851                st_info: sym.st_info,
852                st_other: sym.st_other,
853                st_shndx: U16::new(endian, st_shndx),
854                st_value: U32::new(endian, sym.st_value as u32),
855                st_size: U32::new(endian, sym.st_size as u32),
856            };
857            self.buffer.write(&sym);
858        }
859
860        if self.need_symtab_shndx {
861            let section_index = sym.section.unwrap_or(SectionIndex(0));
862            self.symtab_shndx_data
863                .write_pod(&U32::new(self.endian, section_index.0));
864        }
865    }
866
867    /// Reserve the section index for the symbol table.
868    ///
869    /// This must be called before [`Self::reserve_section_headers`].
870    pub fn reserve_symtab_section_index(&mut self) -> SectionIndex {
871        self.reserve_symtab_section_index_with_name(&b".symtab"[..])
872    }
873
874    /// Reserve the section index for the symbol table.
875    ///
876    /// This must be called before [`Self::reserve_section_headers`].
877    pub fn reserve_symtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
878        debug_assert_eq!(self.symtab_index, SectionIndex(0));
879        self.symtab_str_id = Some(self.add_section_name(name));
880        self.symtab_index = self.reserve_section_index();
881        self.symtab_index
882    }
883
884    /// Return the section index of the symbol table.
885    pub fn symtab_index(&mut self) -> SectionIndex {
886        self.symtab_index
887    }
888
889    /// Write the section header for the symbol table.
890    ///
891    /// This function does nothing if the section index was not reserved.
892    pub fn write_symtab_section_header(&mut self, num_local: u32) {
893        if self.symtab_index == SectionIndex(0) {
894            return;
895        }
896        self.write_section_header(&SectionHeader {
897            name: self.symtab_str_id,
898            sh_type: elf::SHT_SYMTAB,
899            sh_flags: 0,
900            sh_addr: 0,
901            sh_offset: self.symtab_offset as u64,
902            sh_size: self.symtab_num as u64 * self.class().sym_size() as u64,
903            sh_link: self.strtab_index.0,
904            sh_info: num_local,
905            sh_addralign: self.elf_align as u64,
906            sh_entsize: self.class().sym_size() as u64,
907        });
908    }
909
910    /// Return true if `.symtab_shndx` is needed.
911    pub fn symtab_shndx_needed(&self) -> bool {
912        self.need_symtab_shndx
913    }
914
915    /// Require the extended section indices for the symbol table even
916    /// if no section indices are too large.
917    pub fn require_symtab_shndx(&mut self) {
918        self.need_symtab_shndx = true;
919    }
920
921    /// Reserve the range for the extended section indices for the symbol table.
922    ///
923    /// This range is used for a section named `.symtab_shndx`.
924    /// This also reserves a section index.
925    ///
926    /// This function does nothing if extended section indices are not needed.
927    /// This must be called after [`Self::reserve_symbol_index`].
928    pub fn reserve_symtab_shndx(&mut self) {
929        debug_assert_eq!(self.symtab_shndx_offset, 0);
930        if !self.need_symtab_shndx {
931            return;
932        }
933        self.symtab_shndx_offset = self.reserve(self.symtab_num as usize * 4, ALIGN_SYMTAB_SHNDX);
934        self.symtab_shndx_data.reserve(self.symtab_num as usize * 4);
935    }
936
937    /// Write the extended section indices for the symbol table.
938    ///
939    /// This function does nothing if the section was not reserved.
940    pub fn write_symtab_shndx(&mut self) {
941        if self.symtab_shndx_offset == 0 {
942            return;
943        }
944        util::write_align(self.buffer, ALIGN_SYMTAB_SHNDX);
945        debug_assert_eq!(self.symtab_shndx_offset, self.buffer.len());
946        debug_assert_eq!(self.symtab_num as usize * 4, self.symtab_shndx_data.len());
947        self.buffer.write_bytes(&self.symtab_shndx_data);
948    }
949
950    /// Reserve the section index for the extended section indices symbol table.
951    ///
952    /// You should check [`Self::symtab_shndx_needed`] before calling this
953    /// unless you have other means of knowing if this section is needed.
954    ///
955    /// This must be called before [`Self::reserve_section_headers`].
956    pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex {
957        self.reserve_symtab_shndx_section_index_with_name(&b".symtab_shndx"[..])
958    }
959
960    /// Reserve the section index for the extended section indices symbol table.
961    ///
962    /// You should check [`Self::symtab_shndx_needed`] before calling this
963    /// unless you have other means of knowing if this section is needed.
964    ///
965    /// This must be called before [`Self::reserve_section_headers`].
966    pub fn reserve_symtab_shndx_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
967        debug_assert!(self.symtab_shndx_str_id.is_none());
968        self.symtab_shndx_str_id = Some(self.add_section_name(name));
969        self.reserve_section_index()
970    }
971
972    /// Write the section header for the extended section indices for the symbol table.
973    ///
974    /// This function does nothing if the section index was not reserved.
975    pub fn write_symtab_shndx_section_header(&mut self) {
976        if self.symtab_shndx_str_id.is_none() {
977            return;
978        }
979        let sh_size = if self.symtab_shndx_offset == 0 {
980            0
981        } else {
982            (self.symtab_num * 4) as u64
983        };
984        self.write_section_header(&SectionHeader {
985            name: self.symtab_shndx_str_id,
986            sh_type: elf::SHT_SYMTAB_SHNDX,
987            sh_flags: 0,
988            sh_addr: 0,
989            sh_offset: self.symtab_shndx_offset as u64,
990            sh_size,
991            sh_link: self.symtab_index.0,
992            sh_info: 0,
993            sh_addralign: ALIGN_SYMTAB_SHNDX as u64,
994            sh_entsize: 4,
995        });
996    }
997
998    /// Add a string to the dynamic string table.
999    ///
1000    /// This will be stored in the `.dynstr` section.
1001    ///
1002    /// This must be called before [`Self::reserve_dynstr`].
1003    pub fn add_dynamic_string(&mut self, name: &'a [u8]) -> StringId {
1004        debug_assert_eq!(self.dynstr_offset, 0);
1005        self.need_dynstr = true;
1006        self.dynstr.add(name)
1007    }
1008
1009    /// Get a string that was previously added to the dynamic string table.
1010    ///
1011    /// Panics if the string was not added.
1012    pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId {
1013        self.dynstr.get_id(name)
1014    }
1015
1016    /// Return true if `.dynstr` is needed.
1017    pub fn dynstr_needed(&self) -> bool {
1018        self.need_dynstr
1019    }
1020
1021    /// Require the dynamic string table even if no strings were added.
1022    pub fn require_dynstr(&mut self) {
1023        self.need_dynstr = true;
1024    }
1025
1026    /// Reserve the range for the dynamic string table.
1027    ///
1028    /// This range is used for a section named `.dynstr`.
1029    ///
1030    /// This function does nothing if no dynamic strings were defined.
1031    /// This must be called after [`Self::add_dynamic_string`].
1032    pub fn reserve_dynstr(&mut self) -> usize {
1033        debug_assert_eq!(self.dynstr_offset, 0);
1034        if !self.need_dynstr {
1035            return 0;
1036        }
1037        // Start with null string.
1038        self.dynstr_data = vec![0];
1039        self.dynstr.write(1, &mut self.dynstr_data);
1040        self.dynstr_offset = self.reserve(self.dynstr_data.len(), 1);
1041        self.dynstr_offset
1042    }
1043
1044    /// Return the size of the dynamic string table.
1045    ///
1046    /// This must be called after [`Self::reserve_dynstr`].
1047    pub fn dynstr_len(&mut self) -> usize {
1048        debug_assert_ne!(self.dynstr_offset, 0);
1049        self.dynstr_data.len()
1050    }
1051
1052    /// Write the dynamic string table.
1053    ///
1054    /// This function does nothing if the section was not reserved.
1055    pub fn write_dynstr(&mut self) {
1056        if self.dynstr_offset == 0 {
1057            return;
1058        }
1059        debug_assert_eq!(self.dynstr_offset, self.buffer.len());
1060        self.buffer.write_bytes(&self.dynstr_data);
1061    }
1062
1063    /// Reserve the section index for the dynamic string table.
1064    ///
1065    /// You should check [`Self::dynstr_needed`] before calling this
1066    /// unless you have other means of knowing if this section is needed.
1067    ///
1068    /// This must be called before [`Self::reserve_section_headers`].
1069    pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex {
1070        self.reserve_dynstr_section_index_with_name(&b".dynstr"[..])
1071    }
1072
1073    /// Reserve the section index for the dynamic string table.
1074    ///
1075    /// You should check [`Self::dynstr_needed`] before calling this
1076    /// unless you have other means of knowing if this section is needed.
1077    ///
1078    /// This must be called before [`Self::reserve_section_headers`].
1079    pub fn reserve_dynstr_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1080        debug_assert_eq!(self.dynstr_index, SectionIndex(0));
1081        self.dynstr_str_id = Some(self.add_section_name(name));
1082        self.dynstr_index = self.reserve_section_index();
1083        self.dynstr_index
1084    }
1085
1086    /// Return the section index of the dynamic string table.
1087    pub fn dynstr_index(&mut self) -> SectionIndex {
1088        self.dynstr_index
1089    }
1090
1091    /// Write the section header for the dynamic string table.
1092    ///
1093    /// This function does nothing if the section index was not reserved.
1094    pub fn write_dynstr_section_header(&mut self, sh_addr: u64) {
1095        if self.dynstr_index == SectionIndex(0) {
1096            return;
1097        }
1098        self.write_section_header(&SectionHeader {
1099            name: self.dynstr_str_id,
1100            sh_type: elf::SHT_STRTAB,
1101            sh_flags: elf::SHF_ALLOC.into(),
1102            sh_addr,
1103            sh_offset: self.dynstr_offset as u64,
1104            sh_size: self.dynstr_data.len() as u64,
1105            sh_link: 0,
1106            sh_info: 0,
1107            sh_addralign: 1,
1108            sh_entsize: 0,
1109        });
1110    }
1111
1112    /// Reserve the null dynamic symbol table entry.
1113    ///
1114    /// This will be stored in the `.dynsym` section.
1115    ///
1116    /// The null dynamic symbol table entry is usually automatically reserved,
1117    /// but this can be used to force an empty dynamic symbol table.
1118    ///
1119    /// This must be called before [`Self::reserve_dynsym`].
1120    pub fn reserve_null_dynamic_symbol_index(&mut self) -> SymbolIndex {
1121        debug_assert_eq!(self.dynsym_offset, 0);
1122        debug_assert_eq!(self.dynsym_num, 0);
1123        self.dynsym_num = 1;
1124        SymbolIndex(0)
1125    }
1126
1127    /// Reserve a dynamic symbol table entry.
1128    ///
1129    /// This will be stored in the `.dynsym` section.
1130    ///
1131    /// Automatically also reserves the null symbol if required.
1132    /// Callers may assume that the returned indices will be sequential
1133    /// starting at 1.
1134    ///
1135    /// This must be called before [`Self::reserve_dynsym`].
1136    pub fn reserve_dynamic_symbol_index(&mut self) -> SymbolIndex {
1137        debug_assert_eq!(self.dynsym_offset, 0);
1138        if self.dynsym_num == 0 {
1139            self.dynsym_num = 1;
1140        }
1141        let index = self.dynsym_num;
1142        self.dynsym_num += 1;
1143        SymbolIndex(index)
1144    }
1145
1146    /// Return the number of reserved dynamic symbols.
1147    ///
1148    /// Includes the null symbol.
1149    pub fn dynamic_symbol_count(&mut self) -> u32 {
1150        self.dynsym_num
1151    }
1152
1153    /// Reserve the range for the dynamic symbol table.
1154    ///
1155    /// This range is used for a section named `.dynsym`.
1156    ///
1157    /// This function does nothing if no dynamic symbols were reserved.
1158    /// This must be called after [`Self::reserve_dynamic_symbol_index`].
1159    pub fn reserve_dynsym(&mut self) -> usize {
1160        debug_assert_eq!(self.dynsym_offset, 0);
1161        if self.dynsym_num == 0 {
1162            return 0;
1163        }
1164        self.dynsym_offset = self.reserve(
1165            self.dynsym_num as usize * self.class().sym_size(),
1166            self.elf_align,
1167        );
1168        self.dynsym_offset
1169    }
1170
1171    /// Write the null dynamic symbol.
1172    ///
1173    /// This must be the first dynamic symbol that is written.
1174    /// This function does nothing if no dynamic symbols were reserved.
1175    pub fn write_null_dynamic_symbol(&mut self) {
1176        if self.dynsym_num == 0 {
1177            return;
1178        }
1179        util::write_align(self.buffer, self.elf_align);
1180        debug_assert_eq!(self.dynsym_offset, self.buffer.len());
1181        if self.is_64 {
1182            self.buffer.write(&elf::Sym64::<Endianness>::default());
1183        } else {
1184            self.buffer.write(&elf::Sym32::<Endianness>::default());
1185        }
1186    }
1187
1188    /// Write a dynamic symbol.
1189    pub fn write_dynamic_symbol(&mut self, sym: &Sym) {
1190        let st_name = if let Some(name) = sym.name {
1191            self.dynstr.get_offset(name) as u32
1192        } else {
1193            0
1194        };
1195
1196        let st_shndx = if let Some(section) = sym.section {
1197            if section.0 >= elf::SHN_LORESERVE as u32 {
1198                // TODO: we don't actually write out .dynsym_shndx yet.
1199                // This is unlikely to be needed though.
1200                elf::SHN_XINDEX
1201            } else {
1202                section.0 as u16
1203            }
1204        } else {
1205            sym.st_shndx
1206        };
1207
1208        let endian = self.endian;
1209        if self.is_64 {
1210            let sym = elf::Sym64 {
1211                st_name: U32::new(endian, st_name),
1212                st_info: sym.st_info,
1213                st_other: sym.st_other,
1214                st_shndx: U16::new(endian, st_shndx),
1215                st_value: U64::new(endian, sym.st_value),
1216                st_size: U64::new(endian, sym.st_size),
1217            };
1218            self.buffer.write(&sym);
1219        } else {
1220            let sym = elf::Sym32 {
1221                st_name: U32::new(endian, st_name),
1222                st_info: sym.st_info,
1223                st_other: sym.st_other,
1224                st_shndx: U16::new(endian, st_shndx),
1225                st_value: U32::new(endian, sym.st_value as u32),
1226                st_size: U32::new(endian, sym.st_size as u32),
1227            };
1228            self.buffer.write(&sym);
1229        }
1230    }
1231
1232    /// Reserve the section index for the dynamic symbol table.
1233    ///
1234    /// This must be called before [`Self::reserve_section_headers`].
1235    pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex {
1236        self.reserve_dynsym_section_index_with_name(&b".dynsym"[..])
1237    }
1238
1239    /// Reserve the section index for the dynamic symbol table.
1240    ///
1241    /// This must be called before [`Self::reserve_section_headers`].
1242    pub fn reserve_dynsym_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1243        debug_assert_eq!(self.dynsym_index, SectionIndex(0));
1244        self.dynsym_str_id = Some(self.add_section_name(name));
1245        self.dynsym_index = self.reserve_section_index();
1246        self.dynsym_index
1247    }
1248
1249    /// Return the section index of the dynamic symbol table.
1250    pub fn dynsym_index(&mut self) -> SectionIndex {
1251        self.dynsym_index
1252    }
1253
1254    /// Write the section header for the dynamic symbol table.
1255    ///
1256    /// This function does nothing if the section index was not reserved.
1257    pub fn write_dynsym_section_header(&mut self, sh_addr: u64, num_local: u32) {
1258        if self.dynsym_index == SectionIndex(0) {
1259            return;
1260        }
1261        self.write_section_header(&SectionHeader {
1262            name: self.dynsym_str_id,
1263            sh_type: elf::SHT_DYNSYM,
1264            sh_flags: elf::SHF_ALLOC.into(),
1265            sh_addr,
1266            sh_offset: self.dynsym_offset as u64,
1267            sh_size: self.dynsym_num as u64 * self.class().sym_size() as u64,
1268            sh_link: self.dynstr_index.0,
1269            sh_info: num_local,
1270            sh_addralign: self.elf_align as u64,
1271            sh_entsize: self.class().sym_size() as u64,
1272        });
1273    }
1274
1275    /// Reserve the range for the `.dynamic` section.
1276    ///
1277    /// This function does nothing if `dynamic_num` is zero.
1278    pub fn reserve_dynamic(&mut self, dynamic_num: usize) -> usize {
1279        debug_assert_eq!(self.dynamic_offset, 0);
1280        if dynamic_num == 0 {
1281            return 0;
1282        }
1283        self.dynamic_num = dynamic_num;
1284        self.dynamic_offset = self.reserve_dynamics(dynamic_num);
1285        self.dynamic_offset
1286    }
1287
1288    /// Write alignment padding bytes prior to the `.dynamic` section.
1289    ///
1290    /// This function does nothing if the section was not reserved.
1291    pub fn write_align_dynamic(&mut self) {
1292        if self.dynamic_offset == 0 {
1293            return;
1294        }
1295        util::write_align(self.buffer, self.elf_align);
1296        debug_assert_eq!(self.dynamic_offset, self.buffer.len());
1297    }
1298
1299    /// Reserve a file range for the given number of dynamic entries.
1300    ///
1301    /// Returns the offset of the range.
1302    pub fn reserve_dynamics(&mut self, dynamic_num: usize) -> usize {
1303        self.reserve(dynamic_num * self.class().dyn_size(), self.elf_align)
1304    }
1305
1306    /// Write a dynamic string entry.
1307    pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) {
1308        self.write_dynamic(tag, self.dynstr.get_offset(id) as u64);
1309    }
1310
1311    /// Write a dynamic value entry.
1312    pub fn write_dynamic(&mut self, d_tag: u32, d_val: u64) {
1313        let endian = self.endian;
1314        if self.is_64 {
1315            let d = elf::Dyn64 {
1316                d_tag: U64::new(endian, d_tag.into()),
1317                d_val: U64::new(endian, d_val),
1318            };
1319            self.buffer.write(&d);
1320        } else {
1321            let d = elf::Dyn32 {
1322                d_tag: U32::new(endian, d_tag),
1323                d_val: U32::new(endian, d_val as u32),
1324            };
1325            self.buffer.write(&d);
1326        }
1327    }
1328
1329    /// Reserve the section index for the dynamic table.
1330    pub fn reserve_dynamic_section_index(&mut self) -> SectionIndex {
1331        debug_assert!(self.dynamic_str_id.is_none());
1332        self.dynamic_str_id = Some(self.add_section_name(&b".dynamic"[..]));
1333        self.reserve_section_index()
1334    }
1335
1336    /// Write the section header for the dynamic table.
1337    ///
1338    /// This function does nothing if the section index was not reserved.
1339    pub fn write_dynamic_section_header(&mut self, sh_addr: u64) {
1340        if self.dynamic_str_id.is_none() {
1341            return;
1342        }
1343        self.write_section_header(&SectionHeader {
1344            name: self.dynamic_str_id,
1345            sh_type: elf::SHT_DYNAMIC,
1346            sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC).into(),
1347            sh_addr,
1348            sh_offset: self.dynamic_offset as u64,
1349            sh_size: (self.dynamic_num * self.class().dyn_size()) as u64,
1350            sh_link: self.dynstr_index.0,
1351            sh_info: 0,
1352            sh_addralign: self.elf_align as u64,
1353            sh_entsize: self.class().dyn_size() as u64,
1354        });
1355    }
1356
1357    /// Reserve a file range for a SysV hash section.
1358    ///
1359    /// `symbol_count` is the number of symbols in the hash,
1360    /// not the total number of symbols.
1361    pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) -> usize {
1362        self.hash_size = self.class().hash_size(bucket_count, chain_count);
1363        self.hash_offset = self.reserve(self.hash_size, ALIGN_HASH);
1364        self.hash_offset
1365    }
1366
1367    /// Write a SysV hash section.
1368    ///
1369    /// `chain_count` is the number of symbols in the hash.
1370    /// The argument to `hash` will be in the range `0..chain_count`.
1371    pub fn write_hash<F>(&mut self, bucket_count: u32, chain_count: u32, hash: F)
1372    where
1373        F: Fn(u32) -> Option<u32>,
1374    {
1375        let mut buckets = vec![U32::new(self.endian, 0); bucket_count as usize];
1376        let mut chains = vec![U32::new(self.endian, 0); chain_count as usize];
1377        for i in 0..chain_count {
1378            if let Some(hash) = hash(i) {
1379                let bucket = hash % bucket_count;
1380                chains[i as usize] = buckets[bucket as usize];
1381                buckets[bucket as usize] = U32::new(self.endian, i);
1382            }
1383        }
1384
1385        util::write_align(self.buffer, ALIGN_HASH);
1386        debug_assert_eq!(self.hash_offset, self.buffer.len());
1387        self.buffer.write(&elf::HashHeader {
1388            bucket_count: U32::new(self.endian, bucket_count),
1389            chain_count: U32::new(self.endian, chain_count),
1390        });
1391        self.buffer.write_slice(&buckets);
1392        self.buffer.write_slice(&chains);
1393    }
1394
1395    /// Reserve the section index for the SysV hash table.
1396    pub fn reserve_hash_section_index(&mut self) -> SectionIndex {
1397        self.reserve_hash_section_index_with_name(&b".hash"[..])
1398    }
1399
1400    /// Reserve the section index for the SysV hash table.
1401    pub fn reserve_hash_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1402        debug_assert!(self.hash_str_id.is_none());
1403        self.hash_str_id = Some(self.add_section_name(name));
1404        self.reserve_section_index()
1405    }
1406
1407    /// Write the section header for the SysV hash table.
1408    ///
1409    /// This function does nothing if the section index was not reserved.
1410    pub fn write_hash_section_header(&mut self, sh_addr: u64) {
1411        if self.hash_str_id.is_none() {
1412            return;
1413        }
1414        self.write_section_header(&SectionHeader {
1415            name: self.hash_str_id,
1416            sh_type: elf::SHT_HASH,
1417            sh_flags: elf::SHF_ALLOC.into(),
1418            sh_addr,
1419            sh_offset: self.hash_offset as u64,
1420            sh_size: self.hash_size as u64,
1421            sh_link: self.dynsym_index.0,
1422            sh_info: 0,
1423            sh_addralign: ALIGN_HASH as u64,
1424            sh_entsize: 4,
1425        });
1426    }
1427
1428    /// Reserve a file range for a GNU hash section.
1429    ///
1430    /// `symbol_count` is the number of symbols in the hash,
1431    /// not the total number of symbols.
1432    pub fn reserve_gnu_hash(
1433        &mut self,
1434        bloom_count: u32,
1435        bucket_count: u32,
1436        symbol_count: u32,
1437    ) -> usize {
1438        self.gnu_hash_size = self
1439            .class()
1440            .gnu_hash_size(bloom_count, bucket_count, symbol_count);
1441        self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align);
1442        self.gnu_hash_offset
1443    }
1444
1445    /// Write a GNU hash section.
1446    ///
1447    /// `symbol_count` is the number of symbols in the hash.
1448    /// The argument to `hash` will be in the range `0..symbol_count`.
1449    ///
1450    /// This requires that symbols are already sorted by bucket.
1451    pub fn write_gnu_hash<F>(
1452        &mut self,
1453        symbol_base: u32,
1454        bloom_shift: u32,
1455        bloom_count: u32,
1456        bucket_count: u32,
1457        symbol_count: u32,
1458        hash: F,
1459    ) where
1460        F: Fn(u32) -> u32,
1461    {
1462        util::write_align(self.buffer, self.elf_align);
1463        debug_assert_eq!(self.gnu_hash_offset, self.buffer.len());
1464        self.buffer.write(&elf::GnuHashHeader {
1465            bucket_count: U32::new(self.endian, bucket_count),
1466            symbol_base: U32::new(self.endian, symbol_base),
1467            bloom_count: U32::new(self.endian, bloom_count),
1468            bloom_shift: U32::new(self.endian, bloom_shift),
1469        });
1470
1471        // Calculate and write bloom filter.
1472        if self.is_64 {
1473            let mut bloom_filters = vec![0; bloom_count as usize];
1474            for i in 0..symbol_count {
1475                let h = hash(i);
1476                bloom_filters[((h / 64) & (bloom_count - 1)) as usize] |=
1477                    1 << (h % 64) | 1 << ((h >> bloom_shift) % 64);
1478            }
1479            for bloom_filter in bloom_filters {
1480                self.buffer.write(&U64::new(self.endian, bloom_filter));
1481            }
1482        } else {
1483            let mut bloom_filters = vec![0; bloom_count as usize];
1484            for i in 0..symbol_count {
1485                let h = hash(i);
1486                bloom_filters[((h / 32) & (bloom_count - 1)) as usize] |=
1487                    1 << (h % 32) | 1 << ((h >> bloom_shift) % 32);
1488            }
1489            for bloom_filter in bloom_filters {
1490                self.buffer.write(&U32::new(self.endian, bloom_filter));
1491            }
1492        }
1493
1494        // Write buckets.
1495        //
1496        // This requires that symbols are already sorted by bucket.
1497        let mut bucket = 0;
1498        for i in 0..symbol_count {
1499            let symbol_bucket = hash(i) % bucket_count;
1500            while bucket < symbol_bucket {
1501                self.buffer.write(&U32::new(self.endian, 0));
1502                bucket += 1;
1503            }
1504            if bucket == symbol_bucket {
1505                self.buffer.write(&U32::new(self.endian, symbol_base + i));
1506                bucket += 1;
1507            }
1508        }
1509        while bucket < bucket_count {
1510            self.buffer.write(&U32::new(self.endian, 0));
1511            bucket += 1;
1512        }
1513
1514        // Write hash values.
1515        for i in 0..symbol_count {
1516            let mut h = hash(i);
1517            if i == symbol_count - 1 || h % bucket_count != hash(i + 1) % bucket_count {
1518                h |= 1;
1519            } else {
1520                h &= !1;
1521            }
1522            self.buffer.write(&U32::new(self.endian, h));
1523        }
1524    }
1525
1526    /// Reserve the section index for the GNU hash table.
1527    pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex {
1528        self.reserve_gnu_hash_section_index_with_name(&b".gnu.hash"[..])
1529    }
1530
1531    /// Reserve the section index for the GNU hash table.
1532    pub fn reserve_gnu_hash_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1533        debug_assert!(self.gnu_hash_str_id.is_none());
1534        self.gnu_hash_str_id = Some(self.add_section_name(name));
1535        self.reserve_section_index()
1536    }
1537
1538    /// Write the section header for the GNU hash table.
1539    ///
1540    /// This function does nothing if the section index was not reserved.
1541    pub fn write_gnu_hash_section_header(&mut self, sh_addr: u64) {
1542        if self.gnu_hash_str_id.is_none() {
1543            return;
1544        }
1545        self.write_section_header(&SectionHeader {
1546            name: self.gnu_hash_str_id,
1547            sh_type: elf::SHT_GNU_HASH,
1548            sh_flags: elf::SHF_ALLOC.into(),
1549            sh_addr,
1550            sh_offset: self.gnu_hash_offset as u64,
1551            sh_size: self.gnu_hash_size as u64,
1552            sh_link: self.dynsym_index.0,
1553            sh_info: 0,
1554            sh_addralign: self.elf_align as u64,
1555            sh_entsize: if self.is_64 { 0 } else { 4 },
1556        });
1557    }
1558
1559    /// Reserve the range for the `.gnu.version` section.
1560    ///
1561    /// This function does nothing if no dynamic symbols were reserved.
1562    pub fn reserve_gnu_versym(&mut self) -> usize {
1563        debug_assert_eq!(self.gnu_versym_offset, 0);
1564        if self.dynsym_num == 0 {
1565            return 0;
1566        }
1567        self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, ALIGN_GNU_VERSYM);
1568        self.gnu_versym_offset
1569    }
1570
1571    /// Write the null symbol version entry.
1572    ///
1573    /// This must be the first symbol version that is written.
1574    /// This function does nothing if no dynamic symbols were reserved.
1575    pub fn write_null_gnu_versym(&mut self) {
1576        if self.dynsym_num == 0 {
1577            return;
1578        }
1579        util::write_align(self.buffer, ALIGN_GNU_VERSYM);
1580        debug_assert_eq!(self.gnu_versym_offset, self.buffer.len());
1581        self.write_gnu_versym(0);
1582    }
1583
1584    /// Write a symbol version entry.
1585    pub fn write_gnu_versym(&mut self, versym: u16) {
1586        self.buffer.write(&U16::new(self.endian, versym));
1587    }
1588
1589    /// Reserve the section index for the `.gnu.version` section.
1590    pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex {
1591        self.reserve_gnu_versym_section_index_with_name(&b".gnu.version"[..])
1592    }
1593
1594    /// Reserve the section index for the `.gnu.version` section.
1595    pub fn reserve_gnu_versym_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1596        debug_assert!(self.gnu_versym_str_id.is_none());
1597        self.gnu_versym_str_id = Some(self.add_section_name(name));
1598        self.reserve_section_index()
1599    }
1600
1601    /// Write the section header for the `.gnu.version` section.
1602    ///
1603    /// This function does nothing if the section index was not reserved.
1604    pub fn write_gnu_versym_section_header(&mut self, sh_addr: u64) {
1605        if self.gnu_versym_str_id.is_none() {
1606            return;
1607        }
1608        self.write_section_header(&SectionHeader {
1609            name: self.gnu_versym_str_id,
1610            sh_type: elf::SHT_GNU_VERSYM,
1611            sh_flags: elf::SHF_ALLOC.into(),
1612            sh_addr,
1613            sh_offset: self.gnu_versym_offset as u64,
1614            sh_size: self.class().gnu_versym_size(self.dynsym_num as usize) as u64,
1615            sh_link: self.dynsym_index.0,
1616            sh_info: 0,
1617            sh_addralign: ALIGN_GNU_VERSYM as u64,
1618            sh_entsize: 2,
1619        });
1620    }
1621
1622    /// Reserve the range for the `.gnu.version_d` section.
1623    pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) -> usize {
1624        debug_assert_eq!(self.gnu_verdef_offset, 0);
1625        if verdef_count == 0 {
1626            return 0;
1627        }
1628        self.gnu_verdef_size = self.class().gnu_verdef_size(verdef_count, verdaux_count);
1629        self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, ALIGN_GNU_VERDEF);
1630        self.gnu_verdef_count = verdef_count as u16;
1631        self.gnu_verdef_remaining = self.gnu_verdef_count;
1632        self.gnu_verdef_offset
1633    }
1634
1635    /// Write alignment padding bytes prior to a `.gnu.version_d` section.
1636    pub fn write_align_gnu_verdef(&mut self) {
1637        if self.gnu_verdef_offset == 0 {
1638            return;
1639        }
1640        util::write_align(self.buffer, ALIGN_GNU_VERDEF);
1641        debug_assert_eq!(self.gnu_verdef_offset, self.buffer.len());
1642    }
1643
1644    /// Write a version definition entry.
1645    pub fn write_gnu_verdef(&mut self, verdef: &Verdef) {
1646        debug_assert_ne!(self.gnu_verdef_remaining, 0);
1647        self.gnu_verdef_remaining -= 1;
1648        let vd_next = if self.gnu_verdef_remaining == 0 {
1649            0
1650        } else {
1651            mem::size_of::<elf::Verdef<Endianness>>() as u32
1652                + verdef.aux_count as u32 * mem::size_of::<elf::Verdaux<Endianness>>() as u32
1653        };
1654
1655        debug_assert_ne!(verdef.aux_count, 0);
1656        self.gnu_verdaux_remaining = verdef.aux_count;
1657        let vd_aux = mem::size_of::<elf::Verdef<Endianness>>() as u32;
1658
1659        self.buffer.write(&elf::Verdef {
1660            vd_version: U16::new(self.endian, verdef.version),
1661            vd_flags: U16::new(self.endian, verdef.flags),
1662            vd_ndx: U16::new(self.endian, verdef.index),
1663            vd_cnt: U16::new(self.endian, verdef.aux_count),
1664            vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))),
1665            vd_aux: U32::new(self.endian, vd_aux),
1666            vd_next: U32::new(self.endian, vd_next),
1667        });
1668        self.write_gnu_verdaux(verdef.name);
1669    }
1670
1671    /// Write a version definition entry that shares the names of the next definition.
1672    ///
1673    /// This is typically useful when there are only two versions (including the base)
1674    /// and they have the same name.
1675    pub fn write_gnu_verdef_shared(&mut self, verdef: &Verdef) {
1676        debug_assert_ne!(self.gnu_verdef_remaining, 0);
1677        self.gnu_verdef_remaining -= 1;
1678        debug_assert_ne!(self.gnu_verdef_remaining, 0);
1679        let vd_next = mem::size_of::<elf::Verdef<Endianness>>() as u32;
1680
1681        debug_assert_ne!(verdef.aux_count, 0);
1682        self.gnu_verdaux_remaining = 0;
1683        let vd_aux = 2 * mem::size_of::<elf::Verdef<Endianness>>() as u32;
1684
1685        self.buffer.write(&elf::Verdef {
1686            vd_version: U16::new(self.endian, verdef.version),
1687            vd_flags: U16::new(self.endian, verdef.flags),
1688            vd_ndx: U16::new(self.endian, verdef.index),
1689            vd_cnt: U16::new(self.endian, verdef.aux_count),
1690            vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))),
1691            vd_aux: U32::new(self.endian, vd_aux),
1692            vd_next: U32::new(self.endian, vd_next),
1693        });
1694    }
1695
1696    /// Write a version definition auxiliary entry.
1697    pub fn write_gnu_verdaux(&mut self, name: StringId) {
1698        debug_assert_ne!(self.gnu_verdaux_remaining, 0);
1699        self.gnu_verdaux_remaining -= 1;
1700        let vda_next = if self.gnu_verdaux_remaining == 0 {
1701            0
1702        } else {
1703            mem::size_of::<elf::Verdaux<Endianness>>() as u32
1704        };
1705        self.buffer.write(&elf::Verdaux {
1706            vda_name: U32::new(self.endian, self.dynstr.get_offset(name) as u32),
1707            vda_next: U32::new(self.endian, vda_next),
1708        });
1709    }
1710
1711    /// Reserve the section index for the `.gnu.version_d` section.
1712    pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex {
1713        self.reserve_gnu_verdef_section_index_with_name(&b".gnu.version_d"[..])
1714    }
1715
1716    /// Reserve the section index for the `.gnu.version_d` section.
1717    pub fn reserve_gnu_verdef_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1718        debug_assert!(self.gnu_verdef_str_id.is_none());
1719        self.gnu_verdef_str_id = Some(self.add_section_name(name));
1720        self.reserve_section_index()
1721    }
1722
1723    /// Write the section header for the `.gnu.version_d` section.
1724    ///
1725    /// This function does nothing if the section index was not reserved.
1726    pub fn write_gnu_verdef_section_header(&mut self, sh_addr: u64) {
1727        if self.gnu_verdef_str_id.is_none() {
1728            return;
1729        }
1730        self.write_section_header(&SectionHeader {
1731            name: self.gnu_verdef_str_id,
1732            sh_type: elf::SHT_GNU_VERDEF,
1733            sh_flags: elf::SHF_ALLOC.into(),
1734            sh_addr,
1735            sh_offset: self.gnu_verdef_offset as u64,
1736            sh_size: self.gnu_verdef_size as u64,
1737            sh_link: self.dynstr_index.0,
1738            sh_info: self.gnu_verdef_count.into(),
1739            sh_addralign: ALIGN_GNU_VERDEF as u64,
1740            sh_entsize: 0,
1741        });
1742    }
1743
1744    /// Reserve the range for the `.gnu.version_r` section.
1745    pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) -> usize {
1746        debug_assert_eq!(self.gnu_verneed_offset, 0);
1747        if verneed_count == 0 {
1748            return 0;
1749        }
1750        self.gnu_verneed_size = self.class().gnu_verneed_size(verneed_count, vernaux_count);
1751        self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, ALIGN_GNU_VERNEED);
1752        self.gnu_verneed_count = verneed_count as u16;
1753        self.gnu_verneed_remaining = self.gnu_verneed_count;
1754        self.gnu_verneed_offset
1755    }
1756
1757    /// Write alignment padding bytes prior to a `.gnu.version_r` section.
1758    pub fn write_align_gnu_verneed(&mut self) {
1759        if self.gnu_verneed_offset == 0 {
1760            return;
1761        }
1762        util::write_align(self.buffer, ALIGN_GNU_VERNEED);
1763        debug_assert_eq!(self.gnu_verneed_offset, self.buffer.len());
1764    }
1765
1766    /// Write a version need entry.
1767    pub fn write_gnu_verneed(&mut self, verneed: &Verneed) {
1768        debug_assert_ne!(self.gnu_verneed_remaining, 0);
1769        self.gnu_verneed_remaining -= 1;
1770        let vn_next = if self.gnu_verneed_remaining == 0 {
1771            0
1772        } else {
1773            mem::size_of::<elf::Verneed<Endianness>>() as u32
1774                + verneed.aux_count as u32 * mem::size_of::<elf::Vernaux<Endianness>>() as u32
1775        };
1776
1777        self.gnu_vernaux_remaining = verneed.aux_count;
1778        let vn_aux = if verneed.aux_count == 0 {
1779            0
1780        } else {
1781            mem::size_of::<elf::Verneed<Endianness>>() as u32
1782        };
1783
1784        self.buffer.write(&elf::Verneed {
1785            vn_version: U16::new(self.endian, verneed.version),
1786            vn_cnt: U16::new(self.endian, verneed.aux_count),
1787            vn_file: U32::new(self.endian, self.dynstr.get_offset(verneed.file) as u32),
1788            vn_aux: U32::new(self.endian, vn_aux),
1789            vn_next: U32::new(self.endian, vn_next),
1790        });
1791    }
1792
1793    /// Write a version need auxiliary entry.
1794    pub fn write_gnu_vernaux(&mut self, vernaux: &Vernaux) {
1795        debug_assert_ne!(self.gnu_vernaux_remaining, 0);
1796        self.gnu_vernaux_remaining -= 1;
1797        let vna_next = if self.gnu_vernaux_remaining == 0 {
1798            0
1799        } else {
1800            mem::size_of::<elf::Vernaux<Endianness>>() as u32
1801        };
1802        self.buffer.write(&elf::Vernaux {
1803            vna_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(vernaux.name))),
1804            vna_flags: U16::new(self.endian, vernaux.flags),
1805            vna_other: U16::new(self.endian, vernaux.index),
1806            vna_name: U32::new(self.endian, self.dynstr.get_offset(vernaux.name) as u32),
1807            vna_next: U32::new(self.endian, vna_next),
1808        });
1809    }
1810
1811    /// Reserve the section index for the `.gnu.version_r` section.
1812    pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex {
1813        self.reserve_gnu_verneed_section_index_with_name(&b".gnu.version_r"[..])
1814    }
1815
1816    /// Reserve the section index for the `.gnu.version_r` section.
1817    pub fn reserve_gnu_verneed_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
1818        debug_assert!(self.gnu_verneed_str_id.is_none());
1819        self.gnu_verneed_str_id = Some(self.add_section_name(name));
1820        self.reserve_section_index()
1821    }
1822
1823    /// Write the section header for the `.gnu.version_r` section.
1824    ///
1825    /// This function does nothing if the section index was not reserved.
1826    pub fn write_gnu_verneed_section_header(&mut self, sh_addr: u64) {
1827        if self.gnu_verneed_str_id.is_none() {
1828            return;
1829        }
1830        self.write_section_header(&SectionHeader {
1831            name: self.gnu_verneed_str_id,
1832            sh_type: elf::SHT_GNU_VERNEED,
1833            sh_flags: elf::SHF_ALLOC.into(),
1834            sh_addr,
1835            sh_offset: self.gnu_verneed_offset as u64,
1836            sh_size: self.gnu_verneed_size as u64,
1837            sh_link: self.dynstr_index.0,
1838            sh_info: self.gnu_verneed_count.into(),
1839            sh_addralign: ALIGN_GNU_VERNEED as u64,
1840            sh_entsize: 0,
1841        });
1842    }
1843
1844    /// Reserve the section index for the `.gnu.attributes` section.
1845    pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex {
1846        self.reserve_gnu_attributes_section_index_with_name(&b".gnu.attributes"[..])
1847    }
1848
1849    /// Reserve the section index for the `.gnu.attributes` section.
1850    pub fn reserve_gnu_attributes_section_index_with_name(
1851        &mut self,
1852        name: &'a [u8],
1853    ) -> SectionIndex {
1854        debug_assert!(self.gnu_attributes_str_id.is_none());
1855        self.gnu_attributes_str_id = Some(self.add_section_name(name));
1856        self.reserve_section_index()
1857    }
1858
1859    /// Reserve the range for the `.gnu.attributes` section.
1860    pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) -> usize {
1861        debug_assert_eq!(self.gnu_attributes_offset, 0);
1862        if gnu_attributes_size == 0 {
1863            return 0;
1864        }
1865        self.gnu_attributes_size = gnu_attributes_size;
1866        self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align);
1867        self.gnu_attributes_offset
1868    }
1869
1870    /// Write the section header for the `.gnu.attributes` section.
1871    ///
1872    /// This function does nothing if the section index was not reserved.
1873    pub fn write_gnu_attributes_section_header(&mut self) {
1874        if self.gnu_attributes_str_id.is_none() {
1875            return;
1876        }
1877        self.write_section_header(&SectionHeader {
1878            name: self.gnu_attributes_str_id,
1879            sh_type: elf::SHT_GNU_ATTRIBUTES,
1880            sh_flags: 0,
1881            sh_addr: 0,
1882            sh_offset: self.gnu_attributes_offset as u64,
1883            sh_size: self.gnu_attributes_size as u64,
1884            sh_link: self.dynstr_index.0,
1885            sh_info: 0, // TODO
1886            sh_addralign: self.elf_align as u64,
1887            sh_entsize: 0,
1888        });
1889    }
1890
1891    /// Write the data for the `.gnu.attributes` section.
1892    pub fn write_gnu_attributes(&mut self, data: &[u8]) {
1893        if self.gnu_attributes_offset == 0 {
1894            return;
1895        }
1896        util::write_align(self.buffer, self.elf_align);
1897        debug_assert_eq!(self.gnu_attributes_offset, self.buffer.len());
1898        self.buffer.write_bytes(data);
1899    }
1900
1901    /// Reserve a file range for the given number of relocations.
1902    ///
1903    /// Returns the offset of the range.
1904    pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize {
1905        self.reserve(count * self.class().rel_size(is_rela), self.elf_align)
1906    }
1907
1908    /// Write alignment padding bytes prior to a relocation section.
1909    pub fn write_align_relocation(&mut self) {
1910        util::write_align(self.buffer, self.elf_align);
1911    }
1912
1913    /// Write a relocation.
1914    pub fn write_relocation(&mut self, is_rela: bool, rel: &Rel) {
1915        let endian = self.endian;
1916        if self.is_64 {
1917            if is_rela {
1918                let rel = elf::Rela64 {
1919                    r_offset: U64::new(endian, rel.r_offset),
1920                    r_info: elf::Rela64::r_info(endian, self.is_mips64el, rel.r_sym, rel.r_type),
1921                    r_addend: I64::new(endian, rel.r_addend),
1922                };
1923                self.buffer.write(&rel);
1924            } else {
1925                let rel = elf::Rel64 {
1926                    r_offset: U64::new(endian, rel.r_offset),
1927                    r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type),
1928                };
1929                self.buffer.write(&rel);
1930            }
1931        } else {
1932            if is_rela {
1933                let rel = elf::Rela32 {
1934                    r_offset: U32::new(endian, rel.r_offset as u32),
1935                    r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
1936                    r_addend: I32::new(endian, rel.r_addend as i32),
1937                };
1938                self.buffer.write(&rel);
1939            } else {
1940                let rel = elf::Rel32 {
1941                    r_offset: U32::new(endian, rel.r_offset as u32),
1942                    r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
1943                };
1944                self.buffer.write(&rel);
1945            }
1946        }
1947    }
1948
1949    /// Write the section header for a relocation section.
1950    ///
1951    /// `section` is the index of the section the relocations apply to,
1952    /// or 0 if none.
1953    ///
1954    /// `symtab` is the index of the symbol table the relocations refer to,
1955    /// or 0 if none.
1956    ///
1957    /// `offset` is the file offset of the relocations.
1958    pub fn write_relocation_section_header(
1959        &mut self,
1960        name: StringId,
1961        section: SectionIndex,
1962        symtab: SectionIndex,
1963        offset: usize,
1964        count: usize,
1965        is_rela: bool,
1966    ) {
1967        self.write_section_header(&SectionHeader {
1968            name: Some(name),
1969            sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL },
1970            sh_flags: elf::SHF_INFO_LINK.into(),
1971            sh_addr: 0,
1972            sh_offset: offset as u64,
1973            sh_size: (count * self.class().rel_size(is_rela)) as u64,
1974            sh_link: symtab.0,
1975            sh_info: section.0,
1976            sh_addralign: self.elf_align as u64,
1977            sh_entsize: self.class().rel_size(is_rela) as u64,
1978        });
1979    }
1980
1981    /// Write the section header for a relative relocation section.
1982    ///
1983    /// `offset` is the file offset of the relocations.
1984    /// `size` is the size of the section in bytes.
1985    pub fn write_relative_relocation_section_header(
1986        &mut self,
1987        name: StringId,
1988        offset: usize,
1989        size: usize,
1990    ) {
1991        self.write_section_header(&SectionHeader {
1992            name: Some(name),
1993            sh_type: elf::SHT_RELA,
1994            sh_flags: 0,
1995            sh_addr: 0,
1996            sh_offset: offset as u64,
1997            sh_size: size as u64,
1998            sh_link: 0,
1999            sh_info: 0,
2000            sh_addralign: self.elf_align as u64,
2001            sh_entsize: self.class().relr_size() as u64,
2002        });
2003    }
2004
2005    /// Reserve a file range for a COMDAT section.
2006    ///
2007    /// `count` is the number of sections in the COMDAT group.
2008    ///
2009    /// Returns the offset of the range.
2010    pub fn reserve_comdat(&mut self, count: usize) -> usize {
2011        self.reserve((count + 1) * 4, 4)
2012    }
2013
2014    /// Write `GRP_COMDAT` at the start of the COMDAT section.
2015    pub fn write_comdat_header(&mut self) {
2016        util::write_align(self.buffer, 4);
2017        self.buffer.write(&U32::new(self.endian, elf::GRP_COMDAT));
2018    }
2019
2020    /// Write an entry in a COMDAT section.
2021    pub fn write_comdat_entry(&mut self, entry: SectionIndex) {
2022        self.buffer.write(&U32::new(self.endian, entry.0));
2023    }
2024
2025    /// Write the section header for a COMDAT section.
2026    pub fn write_comdat_section_header(
2027        &mut self,
2028        name: StringId,
2029        symtab: SectionIndex,
2030        symbol: SymbolIndex,
2031        offset: usize,
2032        count: usize,
2033    ) {
2034        self.write_section_header(&SectionHeader {
2035            name: Some(name),
2036            sh_type: elf::SHT_GROUP,
2037            sh_flags: 0,
2038            sh_addr: 0,
2039            sh_offset: offset as u64,
2040            sh_size: ((count + 1) * 4) as u64,
2041            sh_link: symtab.0,
2042            sh_info: symbol.0,
2043            sh_addralign: 4,
2044            sh_entsize: 4,
2045        });
2046    }
2047
2048    /// Return a helper for writing an attributes section.
2049    pub fn attributes_writer(&self) -> AttributesWriter {
2050        AttributesWriter::new(self.endian)
2051    }
2052}
2053
2054/// A helper for writing an attributes section.
2055///
2056/// Attributes have a variable length encoding, so it is awkward to write them in a
2057/// single pass. Instead, we build the entire attributes section data in memory, using
2058/// placeholders for unknown lengths that are filled in later.
2059#[allow(missing_debug_implementations)]
2060pub struct AttributesWriter {
2061    endian: Endianness,
2062    data: Vec<u8>,
2063    subsection_offset: usize,
2064    subsubsection_offset: usize,
2065}
2066
2067impl AttributesWriter {
2068    /// Create a new `AttributesWriter` for the given endianness.
2069    pub fn new(endian: Endianness) -> Self {
2070        AttributesWriter {
2071            endian,
2072            data: vec![0x41],
2073            subsection_offset: 0,
2074            subsubsection_offset: 0,
2075        }
2076    }
2077
2078    /// Start a new subsection with the given vendor name.
2079    pub fn start_subsection(&mut self, vendor: &[u8]) {
2080        debug_assert_eq!(self.subsection_offset, 0);
2081        debug_assert_eq!(self.subsubsection_offset, 0);
2082        self.subsection_offset = self.data.len();
2083        self.data.extend_from_slice(&[0; 4]);
2084        self.data.extend_from_slice(vendor);
2085        self.data.push(0);
2086    }
2087
2088    /// End the subsection.
2089    ///
2090    /// The subsection length is automatically calculated and written.
2091    pub fn end_subsection(&mut self) {
2092        debug_assert_ne!(self.subsection_offset, 0);
2093        debug_assert_eq!(self.subsubsection_offset, 0);
2094        let length = self.data.len() - self.subsection_offset;
2095        self.data[self.subsection_offset..][..4]
2096            .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
2097        self.subsection_offset = 0;
2098    }
2099
2100    /// Start a new sub-subsection with the given tag.
2101    pub fn start_subsubsection(&mut self, tag: u8) {
2102        debug_assert_ne!(self.subsection_offset, 0);
2103        debug_assert_eq!(self.subsubsection_offset, 0);
2104        self.subsubsection_offset = self.data.len();
2105        self.data.push(tag);
2106        self.data.extend_from_slice(&[0; 4]);
2107    }
2108
2109    /// Write a section or symbol index to the sub-subsection.
2110    ///
2111    /// The user must also call this function to write the terminating 0 index.
2112    pub fn write_subsubsection_index(&mut self, index: u32) {
2113        debug_assert_ne!(self.subsection_offset, 0);
2114        debug_assert_ne!(self.subsubsection_offset, 0);
2115        util::write_uleb128(&mut self.data, u64::from(index));
2116    }
2117
2118    /// Write raw index data to the sub-subsection.
2119    ///
2120    /// The terminating 0 index is automatically written.
2121    pub fn write_subsubsection_indices(&mut self, indices: &[u8]) {
2122        debug_assert_ne!(self.subsection_offset, 0);
2123        debug_assert_ne!(self.subsubsection_offset, 0);
2124        self.data.extend_from_slice(indices);
2125        self.data.push(0);
2126    }
2127
2128    /// Write an attribute tag to the sub-subsection.
2129    pub fn write_attribute_tag(&mut self, tag: u64) {
2130        debug_assert_ne!(self.subsection_offset, 0);
2131        debug_assert_ne!(self.subsubsection_offset, 0);
2132        util::write_uleb128(&mut self.data, tag);
2133    }
2134
2135    /// Write an attribute integer value to the sub-subsection.
2136    pub fn write_attribute_integer(&mut self, value: u64) {
2137        debug_assert_ne!(self.subsection_offset, 0);
2138        debug_assert_ne!(self.subsubsection_offset, 0);
2139        util::write_uleb128(&mut self.data, value);
2140    }
2141
2142    /// Write an attribute string value to the sub-subsection.
2143    ///
2144    /// The value must not include the null terminator.
2145    pub fn write_attribute_string(&mut self, value: &[u8]) {
2146        debug_assert_ne!(self.subsection_offset, 0);
2147        debug_assert_ne!(self.subsubsection_offset, 0);
2148        self.data.extend_from_slice(value);
2149        self.data.push(0);
2150    }
2151
2152    /// Write raw attribute data to the sub-subsection.
2153    pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) {
2154        debug_assert_ne!(self.subsection_offset, 0);
2155        debug_assert_ne!(self.subsubsection_offset, 0);
2156        self.data.extend_from_slice(attributes);
2157    }
2158
2159    /// End the sub-subsection.
2160    ///
2161    /// The sub-subsection length is automatically calculated and written.
2162    pub fn end_subsubsection(&mut self) {
2163        debug_assert_ne!(self.subsection_offset, 0);
2164        debug_assert_ne!(self.subsubsection_offset, 0);
2165        let length = self.data.len() - self.subsubsection_offset;
2166        self.data[self.subsubsection_offset + 1..][..4]
2167            .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
2168        self.subsubsection_offset = 0;
2169    }
2170
2171    /// Return the completed section data.
2172    pub fn data(self) -> Vec<u8> {
2173        debug_assert_eq!(self.subsection_offset, 0);
2174        debug_assert_eq!(self.subsubsection_offset, 0);
2175        self.data
2176    }
2177}
2178
2179/// An ELF file class.
2180#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
2181pub struct Class {
2182    /// Whether the file is 64-bit.
2183    pub is_64: bool,
2184}
2185
2186impl Class {
2187    /// Return the alignment size.
2188    pub fn align(self) -> usize {
2189        if self.is_64 {
2190            8
2191        } else {
2192            4
2193        }
2194    }
2195
2196    /// Return the size of the file header.
2197    pub fn file_header_size(self) -> usize {
2198        if self.is_64 {
2199            mem::size_of::<elf::FileHeader64<Endianness>>()
2200        } else {
2201            mem::size_of::<elf::FileHeader32<Endianness>>()
2202        }
2203    }
2204
2205    /// Return the size of a program header.
2206    pub fn program_header_size(self) -> usize {
2207        if self.is_64 {
2208            mem::size_of::<elf::ProgramHeader64<Endianness>>()
2209        } else {
2210            mem::size_of::<elf::ProgramHeader32<Endianness>>()
2211        }
2212    }
2213
2214    /// Return the size of a section header.
2215    pub fn section_header_size(self) -> usize {
2216        if self.is_64 {
2217            mem::size_of::<elf::SectionHeader64<Endianness>>()
2218        } else {
2219            mem::size_of::<elf::SectionHeader32<Endianness>>()
2220        }
2221    }
2222
2223    /// Return the size of a symbol.
2224    pub fn sym_size(self) -> usize {
2225        if self.is_64 {
2226            mem::size_of::<elf::Sym64<Endianness>>()
2227        } else {
2228            mem::size_of::<elf::Sym32<Endianness>>()
2229        }
2230    }
2231
2232    /// Return the size of a relocation entry.
2233    pub fn rel_size(self, is_rela: bool) -> usize {
2234        if self.is_64 {
2235            if is_rela {
2236                mem::size_of::<elf::Rela64<Endianness>>()
2237            } else {
2238                mem::size_of::<elf::Rel64<Endianness>>()
2239            }
2240        } else {
2241            if is_rela {
2242                mem::size_of::<elf::Rela32<Endianness>>()
2243            } else {
2244                mem::size_of::<elf::Rel32<Endianness>>()
2245            }
2246        }
2247    }
2248
2249    /// Return the size of a relative relocation entry.
2250    pub fn relr_size(self) -> usize {
2251        if self.is_64 {
2252            mem::size_of::<elf::Relr64<Endianness>>()
2253        } else {
2254            mem::size_of::<elf::Relr32<Endianness>>()
2255        }
2256    }
2257
2258    /// Return the size of a dynamic entry.
2259    pub fn dyn_size(self) -> usize {
2260        if self.is_64 {
2261            mem::size_of::<elf::Dyn64<Endianness>>()
2262        } else {
2263            mem::size_of::<elf::Dyn32<Endianness>>()
2264        }
2265    }
2266
2267    /// Return the size of a hash table.
2268    pub fn hash_size(self, bucket_count: u32, chain_count: u32) -> usize {
2269        mem::size_of::<elf::HashHeader<Endianness>>()
2270            + bucket_count as usize * 4
2271            + chain_count as usize * 4
2272    }
2273
2274    /// Return the size of a GNU hash table.
2275    pub fn gnu_hash_size(self, bloom_count: u32, bucket_count: u32, symbol_count: u32) -> usize {
2276        let bloom_size = if self.is_64 { 8 } else { 4 };
2277        mem::size_of::<elf::GnuHashHeader<Endianness>>()
2278            + bloom_count as usize * bloom_size
2279            + bucket_count as usize * 4
2280            + symbol_count as usize * 4
2281    }
2282
2283    /// Return the size of a GNU symbol version section.
2284    pub fn gnu_versym_size(self, symbol_count: usize) -> usize {
2285        symbol_count * 2
2286    }
2287
2288    /// Return the size of a GNU version definition section.
2289    pub fn gnu_verdef_size(self, verdef_count: usize, verdaux_count: usize) -> usize {
2290        verdef_count * mem::size_of::<elf::Verdef<Endianness>>()
2291            + verdaux_count * mem::size_of::<elf::Verdaux<Endianness>>()
2292    }
2293
2294    /// Return the size of a GNU version dependency section.
2295    pub fn gnu_verneed_size(self, verneed_count: usize, vernaux_count: usize) -> usize {
2296        verneed_count * mem::size_of::<elf::Verneed<Endianness>>()
2297            + vernaux_count * mem::size_of::<elf::Vernaux<Endianness>>()
2298    }
2299}
2300
2301/// Native endian version of [`elf::FileHeader64`].
2302#[allow(missing_docs)]
2303#[derive(Debug, Clone)]
2304pub struct FileHeader {
2305    pub os_abi: u8,
2306    pub abi_version: u8,
2307    pub e_type: u16,
2308    pub e_machine: u16,
2309    pub e_entry: u64,
2310    pub e_flags: u32,
2311}
2312
2313/// Native endian version of [`elf::ProgramHeader64`].
2314#[allow(missing_docs)]
2315#[derive(Debug, Clone)]
2316pub struct ProgramHeader {
2317    pub p_type: u32,
2318    pub p_flags: u32,
2319    pub p_offset: u64,
2320    pub p_vaddr: u64,
2321    pub p_paddr: u64,
2322    pub p_filesz: u64,
2323    pub p_memsz: u64,
2324    pub p_align: u64,
2325}
2326
2327/// Native endian version of [`elf::SectionHeader64`].
2328#[allow(missing_docs)]
2329#[derive(Debug, Clone)]
2330pub struct SectionHeader {
2331    pub name: Option<StringId>,
2332    pub sh_type: u32,
2333    pub sh_flags: u64,
2334    pub sh_addr: u64,
2335    pub sh_offset: u64,
2336    pub sh_size: u64,
2337    pub sh_link: u32,
2338    pub sh_info: u32,
2339    pub sh_addralign: u64,
2340    pub sh_entsize: u64,
2341}
2342
2343/// Native endian version of [`elf::Sym64`].
2344#[allow(missing_docs)]
2345#[derive(Debug, Clone)]
2346pub struct Sym {
2347    pub name: Option<StringId>,
2348    pub section: Option<SectionIndex>,
2349    pub st_info: u8,
2350    pub st_other: u8,
2351    pub st_shndx: u16,
2352    pub st_value: u64,
2353    pub st_size: u64,
2354}
2355
2356/// Unified native endian version of [`elf::Rel64`] and [`elf::Rela64`].
2357#[allow(missing_docs)]
2358#[derive(Debug, Clone)]
2359pub struct Rel {
2360    pub r_offset: u64,
2361    pub r_sym: u32,
2362    pub r_type: u32,
2363    pub r_addend: i64,
2364}
2365
2366/// Information required for writing [`elf::Verdef`].
2367#[allow(missing_docs)]
2368#[derive(Debug, Clone)]
2369pub struct Verdef {
2370    pub version: u16,
2371    pub flags: u16,
2372    pub index: u16,
2373    pub aux_count: u16,
2374    /// The name for the first [`elf::Verdaux`] entry.
2375    pub name: StringId,
2376}
2377
2378/// Information required for writing [`elf::Verneed`].
2379#[allow(missing_docs)]
2380#[derive(Debug, Clone)]
2381pub struct Verneed {
2382    pub version: u16,
2383    pub aux_count: u16,
2384    pub file: StringId,
2385}
2386
2387/// Information required for writing [`elf::Vernaux`].
2388#[allow(missing_docs)]
2389#[derive(Debug, Clone)]
2390pub struct Vernaux {
2391    pub flags: u16,
2392    pub index: u16,
2393    pub name: StringId,
2394}