1use 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#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct SectionIndex(pub u32);
23
24#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub struct SymbolIndex(pub u32);
27
28#[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 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 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 fn class(&self) -> Class {
222 Class { is_64: self.is_64 }
223 }
224
225 pub fn reserved_len(&self) -> usize {
227 self.len
228 }
229
230 #[allow(clippy::len_without_is_empty)]
232 pub fn len(&self) -> usize {
233 self.buffer.len()
234 }
235
236 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 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 pub fn write(&mut self, data: &[u8]) {
261 self.buffer.write_bytes(data);
262 }
263
264 pub fn reserve_until(&mut self, offset: usize) {
266 debug_assert!(self.len <= offset);
267 self.len = offset;
268 }
269
270 pub fn pad_until(&mut self, offset: usize) {
272 debug_assert!(self.buffer.len() <= offset);
273 self.buffer.resize(offset);
274 }
275
276 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 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 self.buffer
297 .reserve(self.len)
298 .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
299
300 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 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 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 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 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 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 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 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 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 sh_info: 0,
514 sh_addralign: 0,
515 sh_entsize: 0,
516 });
517 }
518
519 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(§ion);
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(§ion);
555 }
556 }
557
558 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 pub fn reserve_shstrtab(&mut self) {
576 debug_assert_eq!(self.shstrtab_offset, 0);
577 if self.section_num == 0 {
578 return;
579 }
580 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 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 pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex {
602 self.reserve_shstrtab_section_index_with_name(&b".shstrtab"[..])
603 }
604
605 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 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 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 pub fn strtab_needed(&self) -> bool {
650 self.need_strtab
651 }
652
653 pub fn require_strtab(&mut self) {
655 self.need_strtab = true;
656 }
657
658 pub fn reserve_strtab(&mut self) {
665 debug_assert_eq!(self.strtab_offset, 0);
666 if !self.need_strtab {
667 return;
668 }
669 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 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 pub fn reserve_strtab_section_index(&mut self) -> SectionIndex {
693 self.reserve_strtab_section_index_with_name(&b".strtab"[..])
694 }
695
696 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 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 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 self.need_strtab = true;
744 SymbolIndex(0)
745 }
746
747 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 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 pub fn symbol_count(&self) -> u32 {
781 self.symtab_num
782 }
783
784 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 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 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 pub fn reserve_symtab_section_index(&mut self) -> SectionIndex {
872 self.reserve_symtab_section_index_with_name(&b".symtab"[..])
873 }
874
875 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 pub fn symtab_index(&mut self) -> SectionIndex {
887 self.symtab_index
888 }
889
890 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 pub fn symtab_shndx_needed(&self) -> bool {
913 self.need_symtab_shndx
914 }
915
916 pub fn require_symtab_shndx(&mut self) {
919 self.need_symtab_shndx = true;
920 }
921
922 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 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 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 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 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 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 pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId {
1014 self.dynstr.get_id(name)
1015 }
1016
1017 pub fn dynstr_needed(&self) -> bool {
1019 self.need_dynstr
1020 }
1021
1022 pub fn require_dynstr(&mut self) {
1024 self.need_dynstr = true;
1025 }
1026
1027 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 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 pub fn dynstr_len(&mut self) -> usize {
1049 debug_assert_ne!(self.dynstr_offset, 0);
1050 self.dynstr_data.len()
1051 }
1052
1053 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 pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex {
1071 self.reserve_dynstr_section_index_with_name(&b".dynstr"[..])
1072 }
1073
1074 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 pub fn dynstr_index(&mut self) -> SectionIndex {
1089 self.dynstr_index
1090 }
1091
1092 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 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 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 pub fn dynamic_symbol_count(&mut self) -> u32 {
1151 self.dynsym_num
1152 }
1153
1154 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 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 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 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 pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex {
1237 self.reserve_dynsym_section_index_with_name(&b".dynsym"[..])
1238 }
1239
1240 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 pub fn dynsym_index(&mut self) -> SectionIndex {
1252 self.dynsym_index
1253 }
1254
1255 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 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 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 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 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 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 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 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 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 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 pub fn reserve_hash_section_index(&mut self) -> SectionIndex {
1405 self.reserve_hash_section_index_with_name(&b".hash"[..])
1406 }
1407
1408 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 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 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 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 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 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 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 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 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 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 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 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 pub fn write_gnu_versym(&mut self, versym: u16) {
1594 self.buffer.write(&U16::new(self.endian, versym));
1595 }
1596
1597 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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, sh_addralign: self.elf_align as u64,
1895 sh_entsize: 0,
1896 });
1897 }
1898
1899 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 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 pub fn write_align_relocation(&mut self) {
1918 util::write_align(self.buffer, self.elf_align);
1919 }
1920
1921 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 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 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 pub fn reserve_comdat(&mut self, count: usize) -> usize {
2019 self.reserve((count + 1) * 4, 4)
2020 }
2021
2022 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 pub fn write_comdat_entry(&mut self, entry: SectionIndex) {
2030 self.buffer.write(&U32::new(self.endian, entry.0));
2031 }
2032
2033 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 pub fn attributes_writer(&self) -> AttributesWriter {
2058 AttributesWriter::new(self.endian)
2059 }
2060}
2061
2062#[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 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 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 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 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 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 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 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 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 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 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 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 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#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
2189pub struct Class {
2190 pub is_64: bool,
2192}
2193
2194impl Class {
2195 pub fn align(self) -> usize {
2197 if self.is_64 {
2198 8
2199 } else {
2200 4
2201 }
2202 }
2203
2204 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 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 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 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 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 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 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 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 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 pub fn gnu_versym_size(self, symbol_count: usize) -> usize {
2293 symbol_count * 2
2294 }
2295
2296 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 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#[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#[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#[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#[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#[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#[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 pub name: StringId,
2384}
2385
2386#[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#[allow(missing_docs)]
2397#[derive(Debug, Clone)]
2398pub struct Vernaux {
2399 pub flags: u16,
2400 pub index: u16,
2401 pub name: StringId,
2402}