Skip to main content

object/write/elf/
writer.rs

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