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