1use synth_core::Result;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum ElfClass {
10 Elf32 = 1,
12 Elf64 = 2,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum ElfData {
19 LittleEndian = 1,
21 BigEndian = 2,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum ElfType {
28 Rel = 1,
30 Exec = 2,
32 Dyn = 3,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum ElfMachine {
39 Arm = 40,
41 AArch64 = 183,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum SectionType {
48 Null = 0,
50 ProgBits = 1,
52 SymTab = 2,
54 StrTab = 3,
56 Rela = 4,
58 Hash = 5,
60 Dynamic = 6,
62 Note = 7,
64 NoBits = 8,
66 Rel = 9,
68}
69
70#[derive(Debug, Clone, Copy)]
72pub struct SectionFlags(pub u32);
73
74impl SectionFlags {
75 pub const WRITE: u32 = 0x1;
77 pub const ALLOC: u32 = 0x2;
79 pub const EXEC: u32 = 0x4;
81 pub const MERGE: u32 = 0x10;
83 pub const STRINGS: u32 = 0x20;
85}
86
87#[derive(Debug, Clone)]
89pub struct Section {
90 pub name: String,
92 pub section_type: SectionType,
94 pub flags: u32,
96 pub addr: u32,
98 pub data: Vec<u8>,
100 pub align: u32,
102 pub explicit_size: Option<u32>,
104}
105
106impl Section {
107 pub fn new(name: &str, section_type: SectionType) -> Self {
109 Self {
110 name: name.to_string(),
111 section_type,
112 flags: 0,
113 addr: 0,
114 data: Vec::new(),
115 align: 1,
116 explicit_size: None,
117 }
118 }
119
120 pub fn with_flags(mut self, flags: u32) -> Self {
122 self.flags = flags;
123 self
124 }
125
126 pub fn with_addr(mut self, addr: u32) -> Self {
128 self.addr = addr;
129 self
130 }
131
132 pub fn with_align(mut self, align: u32) -> Self {
134 self.align = align;
135 self
136 }
137
138 pub fn with_data(mut self, data: Vec<u8>) -> Self {
140 self.data = data;
141 self
142 }
143
144 pub fn with_size(mut self, size: u32) -> Self {
146 self.explicit_size = Some(size);
147 self
148 }
149
150 pub fn size(&self) -> u32 {
152 self.explicit_size.unwrap_or(self.data.len() as u32)
153 }
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
158pub enum SymbolBinding {
159 Local = 0,
161 Global = 1,
163 Weak = 2,
165}
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub enum SymbolType {
170 NoType = 0,
172 Object = 1,
174 Func = 2,
176 Section = 3,
178 File = 4,
180}
181
182#[derive(Debug, Clone)]
184pub struct Symbol {
185 pub name: String,
187 pub value: u32,
189 pub size: u32,
191 pub binding: SymbolBinding,
193 pub symbol_type: SymbolType,
195 pub section: u16,
197}
198
199impl Symbol {
200 pub fn new(name: &str) -> Self {
202 Self {
203 name: name.to_string(),
204 value: 0,
205 size: 0,
206 binding: SymbolBinding::Local,
207 symbol_type: SymbolType::NoType,
208 section: 0,
209 }
210 }
211
212 pub fn with_value(mut self, value: u32) -> Self {
214 self.value = value;
215 self
216 }
217
218 pub fn with_size(mut self, size: u32) -> Self {
220 self.size = size;
221 self
222 }
223
224 pub fn with_binding(mut self, binding: SymbolBinding) -> Self {
226 self.binding = binding;
227 self
228 }
229
230 pub fn with_type(mut self, symbol_type: SymbolType) -> Self {
232 self.symbol_type = symbol_type;
233 self
234 }
235
236 pub fn with_section(mut self, section: u16) -> Self {
238 self.section = section;
239 self
240 }
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
245pub enum ProgramType {
246 Null = 0,
248 Load = 1,
250 Dynamic = 2,
252 Interp = 3,
254 Note = 4,
256}
257
258pub struct ProgramFlags;
260
261impl ProgramFlags {
262 pub const EXEC: u32 = 0x1;
264 pub const WRITE: u32 = 0x2;
266 pub const READ: u32 = 0x4;
268}
269
270#[derive(Debug, Clone)]
272pub struct ProgramHeader {
273 pub p_type: ProgramType,
275 pub offset: u32,
277 pub vaddr: u32,
279 pub paddr: u32,
281 pub filesz: u32,
283 pub memsz: u32,
285 pub flags: u32,
287 pub align: u32,
289}
290
291impl ProgramHeader {
292 pub fn load(vaddr: u32, offset: u32, size: u32, flags: u32) -> Self {
294 Self {
295 p_type: ProgramType::Load,
296 offset,
297 vaddr,
298 paddr: vaddr, filesz: size,
300 memsz: size,
301 flags,
302 align: 4,
303 }
304 }
305
306 pub fn load_nobits(vaddr: u32, memsz: u32, flags: u32) -> Self {
309 Self {
310 p_type: ProgramType::Load,
311 offset: 0, vaddr,
313 paddr: vaddr, filesz: 0, memsz, flags,
317 align: 4,
318 }
319 }
320}
321
322#[derive(Debug, Clone, Copy, PartialEq, Eq)]
324pub enum ArmRelocationType {
325 ThmCall = 10,
329 Call = 28,
331 Jump24 = 29,
333 Abs32 = 2,
335 MovwAbsNc = 43,
337 MovtAbs = 44,
339}
340
341struct ExtraRelSection {
345 name_offset: usize,
346 target_idx: u32,
347 offset: usize,
348 data: Vec<u8>,
349}
350
351#[derive(Debug, Clone)]
353pub struct Relocation {
354 pub offset: u32,
356 pub symbol_index: u32,
358 pub reloc_type: ArmRelocationType,
360}
361
362pub const EF_ARM_EABI_VER5: u32 = 0x05000000;
364pub const EF_ARM_ABI_FLOAT_HARD: u32 = 0x00000400;
366pub const EF_ARM_ABI_FLOAT_SOFT: u32 = 0x00000200;
368
369pub struct ElfBuilder {
371 class: ElfClass,
373 data: ElfData,
375 elf_type: ElfType,
377 machine: ElfMachine,
379 entry: u32,
381 e_flags: u32,
383 sections: Vec<Section>,
385 symbols: Vec<Symbol>,
387 program_headers: Vec<ProgramHeader>,
389 relocations: Vec<Relocation>,
391 extra_relocations: Vec<(String, Vec<Relocation>)>,
397 thumb_funcs: bool,
403}
404
405impl ElfBuilder {
406 pub fn new_arm32() -> Self {
408 Self {
409 class: ElfClass::Elf32,
410 data: ElfData::LittleEndian,
411 elf_type: ElfType::Exec,
412 machine: ElfMachine::Arm,
413 entry: 0,
414 e_flags: EF_ARM_EABI_VER5,
415 sections: Vec::new(),
416 symbols: Vec::new(),
417 program_headers: Vec::new(),
418 relocations: Vec::new(),
419 extra_relocations: Vec::new(),
420 thumb_funcs: true,
421 }
422 }
423
424 pub fn with_thumb_funcs(mut self, thumb: bool) -> Self {
428 self.thumb_funcs = thumb;
429 self
430 }
431
432 pub fn with_entry(mut self, entry: u32) -> Self {
438 self.entry = if self.machine == ElfMachine::Arm && self.thumb_funcs {
439 entry | 1 } else {
441 entry
442 };
443 self
444 }
445
446 pub fn set_flags(&mut self, flags: u32) {
448 self.e_flags = flags;
449 }
450
451 pub fn with_type(mut self, elf_type: ElfType) -> Self {
453 self.elf_type = elf_type;
454 self
455 }
456
457 pub fn add_section(&mut self, section: Section) {
459 self.sections.push(section);
460 }
461
462 pub fn add_symbol(&mut self, symbol: Symbol) {
464 self.symbols.push(symbol);
465 }
466
467 pub fn add_symbol_indexed(&mut self, symbol: Symbol) -> u32 {
472 let index = self.symbols.len() as u32 + 1;
473 self.symbols.push(symbol);
474 index
475 }
476
477 pub fn add_program_header(&mut self, ph: ProgramHeader) {
479 self.program_headers.push(ph);
480 }
481
482 pub fn add_relocation(&mut self, reloc: Relocation) {
484 self.relocations.push(reloc);
485 }
486
487 pub fn add_section_relocations(&mut self, target_section: &str, relocs: Vec<Relocation>) {
494 if relocs.is_empty() {
495 return;
496 }
497 self.extra_relocations
498 .push((target_section.to_string(), relocs));
499 }
500
501 pub fn add_undefined_symbol(&mut self, name: &str) -> u32 {
504 let index = self.symbols.len() as u32 + 1; self.symbols.push(Symbol {
506 name: name.to_string(),
507 value: 0,
508 size: 0,
509 binding: SymbolBinding::Global,
510 symbol_type: SymbolType::Func,
511 section: 0, });
513 index
514 }
515
516 pub fn build(&self) -> Result<Vec<u8>> {
518 let mut output = Vec::new();
519
520 let header_size = 52;
522 let ph_entry_size = 32;
524 let ph_count = self.program_headers.len();
525 let ph_table_size = ph_entry_size * ph_count;
526
527 output.resize(header_size + ph_table_size, 0);
529
530 let (shstrtab_data, section_name_offsets, extra_rel_name_offsets) =
532 self.build_section_string_table();
533
534 let (strtab_data, symbol_name_offsets) = self.build_symbol_string_table();
536
537 let mut current_offset = header_size + ph_table_size;
539
540 let shstrtab_offset = current_offset;
542 current_offset += shstrtab_data.len();
543
544 let strtab_offset = current_offset;
546 current_offset += strtab_data.len();
547
548 let mut section_offsets = Vec::new();
550 for section in &self.sections {
551 section_offsets.push(current_offset);
552 current_offset += section.data.len();
553 }
554
555 let symtab_offset = current_offset;
557 let symtab_data = self.build_symbol_table(&symbol_name_offsets);
558 current_offset += symtab_data.len();
559
560 let rel_data = self.build_relocation_table();
562 let rel_offset = current_offset;
563 current_offset += rel_data.len();
564
565 let mut extra_rel: Vec<ExtraRelSection> = Vec::new();
570 for (i, (target, relocs)) in self.extra_relocations.iter().enumerate() {
571 let Some(target_idx) = self.section_index_by_name(target) else {
572 continue;
573 };
574 let data = Self::encode_rel_entries(relocs);
575 let name_offset = extra_rel_name_offsets.get(i).copied().unwrap_or(0);
576 extra_rel.push(ExtraRelSection {
577 name_offset,
578 target_idx,
579 offset: current_offset,
580 data,
581 });
582 current_offset += extra_rel.last().unwrap().data.len();
583 }
584
585 let sh_offset = current_offset;
587
588 output.extend_from_slice(&shstrtab_data);
590 output.extend_from_slice(&strtab_data);
591
592 for section in &self.sections {
593 output.extend_from_slice(§ion.data);
594 }
595
596 output.extend_from_slice(&symtab_data);
597 output.extend_from_slice(&rel_data);
598 for er in &extra_rel {
599 output.extend_from_slice(&er.data);
600 }
601
602 let section_headers = self.build_section_headers_with_rel(
604 §ion_name_offsets,
605 shstrtab_offset,
606 &shstrtab_data,
607 strtab_offset,
608 &strtab_data,
609 symtab_offset,
610 &symtab_data,
611 §ion_offsets,
612 rel_offset,
613 &rel_data,
614 &extra_rel,
615 );
616 output.extend_from_slice(§ion_headers);
617
618 for (i, ph) in self.program_headers.iter().enumerate() {
621 let ph_offset = header_size + i * ph_entry_size;
622 let mut corrected_ph = ph.clone();
623 if corrected_ph.filesz > 0 {
624 for (si, section) in self.sections.iter().enumerate() {
626 if section.addr == corrected_ph.vaddr && si < section_offsets.len() {
627 corrected_ph.offset = section_offsets[si] as u32;
628 break;
629 }
630 }
631 }
632 self.write_program_header(
633 &mut output[ph_offset..ph_offset + ph_entry_size],
634 &corrected_ph,
635 );
636 }
637
638 let has_rel = !self.relocations.is_empty();
640 let num_sections = 4 + self.sections.len() + if has_rel { 1 } else { 0 } + extra_rel.len();
641 let ph_offset = if ph_count > 0 { header_size as u32 } else { 0 };
642 self.write_elf_header_with_phdrs(
643 &mut output[0..header_size],
644 ph_offset,
645 ph_count as u16,
646 sh_offset as u32,
647 num_sections as u16,
648 )?;
649
650 Ok(output)
651 }
652
653 fn write_program_header(&self, output: &mut [u8], ph: &ProgramHeader) {
655 let mut cursor = 0;
656
657 output[cursor..cursor + 4].copy_from_slice(&(ph.p_type as u32).to_le_bytes());
659 cursor += 4;
660
661 output[cursor..cursor + 4].copy_from_slice(&ph.offset.to_le_bytes());
663 cursor += 4;
664
665 output[cursor..cursor + 4].copy_from_slice(&ph.vaddr.to_le_bytes());
667 cursor += 4;
668
669 output[cursor..cursor + 4].copy_from_slice(&ph.paddr.to_le_bytes());
671 cursor += 4;
672
673 output[cursor..cursor + 4].copy_from_slice(&ph.filesz.to_le_bytes());
675 cursor += 4;
676
677 output[cursor..cursor + 4].copy_from_slice(&ph.memsz.to_le_bytes());
679 cursor += 4;
680
681 output[cursor..cursor + 4].copy_from_slice(&ph.flags.to_le_bytes());
683 cursor += 4;
684
685 output[cursor..cursor + 4].copy_from_slice(&ph.align.to_le_bytes());
687 }
688
689 fn write_elf_header_with_phdrs(
691 &self,
692 output: &mut [u8],
693 ph_offset: u32,
694 ph_count: u16,
695 sh_offset: u32,
696 sh_count: u16,
697 ) -> Result<()> {
698 let mut cursor = 0;
699
700 output[cursor..cursor + 4].copy_from_slice(&[0x7f, b'E', b'L', b'F']);
702 cursor += 4;
703
704 output[cursor] = self.class as u8;
706 cursor += 1;
707
708 output[cursor] = self.data as u8;
710 cursor += 1;
711
712 output[cursor] = 1;
714 cursor += 1;
715
716 output[cursor] = 0; cursor += 1;
719
720 output[cursor] = 0;
722 cursor += 1;
723
724 output[cursor..cursor + 7].copy_from_slice(&[0; 7]);
726 cursor += 7;
727
728 let etype = self.elf_type as u16;
730 output[cursor..cursor + 2].copy_from_slice(&etype.to_le_bytes());
731 cursor += 2;
732
733 let machine = self.machine as u16;
735 output[cursor..cursor + 2].copy_from_slice(&machine.to_le_bytes());
736 cursor += 2;
737
738 output[cursor..cursor + 4].copy_from_slice(&1u32.to_le_bytes());
740 cursor += 4;
741
742 output[cursor..cursor + 4].copy_from_slice(&self.entry.to_le_bytes());
744 cursor += 4;
745
746 output[cursor..cursor + 4].copy_from_slice(&ph_offset.to_le_bytes());
748 cursor += 4;
749
750 output[cursor..cursor + 4].copy_from_slice(&sh_offset.to_le_bytes());
752 cursor += 4;
753
754 output[cursor..cursor + 4].copy_from_slice(&self.e_flags.to_le_bytes());
756 cursor += 4;
757
758 output[cursor..cursor + 2].copy_from_slice(&52u16.to_le_bytes());
760 cursor += 2;
761
762 let ph_entry_size: u16 = if ph_count > 0 { 32 } else { 0 };
764 output[cursor..cursor + 2].copy_from_slice(&ph_entry_size.to_le_bytes());
765 cursor += 2;
766
767 output[cursor..cursor + 2].copy_from_slice(&ph_count.to_le_bytes());
769 cursor += 2;
770
771 output[cursor..cursor + 2].copy_from_slice(&40u16.to_le_bytes());
773 cursor += 2;
774
775 output[cursor..cursor + 2].copy_from_slice(&sh_count.to_le_bytes());
777 cursor += 2;
778
779 output[cursor..cursor + 2].copy_from_slice(&1u16.to_le_bytes());
781
782 Ok(())
783 }
784
785 fn build_section_string_table(&self) -> (Vec<u8>, Vec<usize>, Vec<usize>) {
791 let mut strtab = vec![0]; let mut offsets = Vec::new();
793
794 strtab.extend_from_slice(b".shstrtab\0");
796 strtab.extend_from_slice(b".strtab\0");
797 strtab.extend_from_slice(b".symtab\0");
798
799 for section in &self.sections {
801 let offset = strtab.len();
802 offsets.push(offset);
803 strtab.extend_from_slice(section.name.as_bytes());
804 strtab.push(0);
805 }
806
807 if !self.relocations.is_empty() {
809 strtab.extend_from_slice(b".rel.text\0");
810 }
811
812 let mut extra_rel_offsets = Vec::new();
814 for (target, _) in &self.extra_relocations {
815 let offset = strtab.len();
816 extra_rel_offsets.push(offset);
817 strtab.extend_from_slice(format!(".rel{target}\0").as_bytes());
818 }
819
820 (strtab, offsets, extra_rel_offsets)
821 }
822
823 fn build_symbol_string_table(&self) -> (Vec<u8>, Vec<usize>) {
825 let mut strtab = vec![0]; let mut offsets = Vec::new();
827
828 for symbol in &self.symbols {
829 let offset = strtab.len();
830 offsets.push(offset);
831 strtab.extend_from_slice(symbol.name.as_bytes());
832 strtab.push(0);
833 }
834
835 (strtab, offsets)
836 }
837
838 fn build_relocation_table(&self) -> Vec<u8> {
840 Self::encode_rel_entries(&self.relocations)
841 }
842
843 fn encode_rel_entries(relocs: &[Relocation]) -> Vec<u8> {
846 let mut rel_data = Vec::new();
847 for reloc in relocs {
848 rel_data.extend_from_slice(&reloc.offset.to_le_bytes());
850 let r_info = (reloc.symbol_index << 8) | (reloc.reloc_type as u32);
852 rel_data.extend_from_slice(&r_info.to_le_bytes());
853 }
854 rel_data
855 }
856
857 fn section_index_by_name(&self, name: &str) -> Option<u32> {
861 self.sections
862 .iter()
863 .position(|s| s.name == name)
864 .map(|pos| 4 + pos as u32)
865 }
866
867 fn build_symbol_table(&self, name_offsets: &[usize]) -> Vec<u8> {
869 let mut symtab = Vec::new();
870
871 symtab.extend_from_slice(&[0u8; 16]); for (i, symbol) in self.symbols.iter().enumerate() {
876 let name_offset = if i < name_offsets.len() {
877 name_offsets[i] as u32
878 } else {
879 0
880 };
881
882 symtab.extend_from_slice(&name_offset.to_le_bytes());
884
885 let value = if self.machine == ElfMachine::Arm
892 && self.thumb_funcs
893 && symbol.symbol_type == SymbolType::Func
894 {
895 symbol.value | 1
896 } else {
897 symbol.value
898 };
899 symtab.extend_from_slice(&value.to_le_bytes());
900
901 symtab.extend_from_slice(&symbol.size.to_le_bytes());
903
904 let info = ((symbol.binding as u8) << 4) | (symbol.symbol_type as u8 & 0xf);
906 symtab.push(info);
907
908 symtab.push(0);
910
911 symtab.extend_from_slice(&symbol.section.to_le_bytes());
913 }
914
915 symtab
916 }
917
918 #[allow(clippy::too_many_arguments)]
920 fn build_section_headers_with_rel(
921 &self,
922 section_name_offsets: &[usize],
923 shstrtab_offset: usize,
924 shstrtab_data: &[u8],
925 strtab_offset: usize,
926 strtab_data: &[u8],
927 symtab_offset: usize,
928 symtab_data: &[u8],
929 section_offsets: &[usize],
930 rel_offset: usize,
931 rel_data: &[u8],
932 extra_rel: &[ExtraRelSection],
933 ) -> Vec<u8> {
934 let mut headers = Vec::new();
935
936 headers.extend_from_slice(&[0u8; 40]);
940
941 self.write_section_header(
943 &mut headers,
944 1,
945 SectionType::StrTab as u32,
946 0,
947 0,
948 shstrtab_offset as u32,
949 shstrtab_data.len() as u32,
950 0,
951 0,
952 1,
953 0,
954 );
955
956 let strtab_name_offset = ".shstrtab\0".len();
958 self.write_section_header(
959 &mut headers,
960 strtab_name_offset as u32,
961 SectionType::StrTab as u32,
962 0,
963 0,
964 strtab_offset as u32,
965 strtab_data.len() as u32,
966 0,
967 0,
968 1,
969 0,
970 );
971
972 let symtab_name_offset = ".shstrtab\0.strtab\0".len();
974 self.write_section_header(
975 &mut headers,
976 symtab_name_offset as u32,
977 SectionType::SymTab as u32,
978 0,
979 0,
980 symtab_offset as u32,
981 symtab_data.len() as u32,
982 2,
983 1,
984 4,
985 16,
986 );
987
988 for (i, section) in self.sections.iter().enumerate() {
990 let name_offset = if i < section_name_offsets.len() {
991 section_name_offsets[i] as u32
992 } else {
993 0
994 };
995 let offset = if i < section_offsets.len() {
996 section_offsets[i] as u32
997 } else {
998 0
999 };
1000
1001 self.write_section_header(
1002 &mut headers,
1003 name_offset,
1004 section.section_type as u32,
1005 section.flags,
1006 section.addr,
1007 offset,
1008 section.size(),
1009 0,
1010 0,
1011 section.align,
1012 0,
1013 );
1014 }
1015
1016 if !rel_data.is_empty() {
1018 let rel_name_offset = self.rel_text_shstrtab_offset();
1019 let text_section_idx = 4u32; self.write_section_header(
1022 &mut headers,
1023 rel_name_offset as u32,
1024 SectionType::Rel as u32,
1025 0,
1026 0,
1027 rel_offset as u32,
1028 rel_data.len() as u32,
1029 3, text_section_idx, 4,
1032 8, );
1034 }
1035
1036 for er in extra_rel {
1039 self.write_section_header(
1040 &mut headers,
1041 er.name_offset as u32,
1042 SectionType::Rel as u32,
1043 0,
1044 0,
1045 er.offset as u32,
1046 er.data.len() as u32,
1047 3, er.target_idx, 4,
1050 8, );
1052 }
1053
1054 headers
1055 }
1056
1057 fn rel_text_shstrtab_offset(&self) -> usize {
1059 let mut offset = 1 + ".shstrtab\0".len() + ".strtab\0".len() + ".symtab\0".len();
1061 for section in &self.sections {
1062 offset += section.name.len() + 1;
1063 }
1064 offset
1065 }
1066
1067 #[allow(clippy::too_many_arguments)]
1069 fn write_section_header(
1070 &self,
1071 output: &mut Vec<u8>,
1072 name: u32,
1073 sh_type: u32,
1074 flags: u32,
1075 addr: u32,
1076 offset: u32,
1077 size: u32,
1078 link: u32,
1079 info: u32,
1080 align: u32,
1081 entsize: u32,
1082 ) {
1083 output.extend_from_slice(&name.to_le_bytes());
1084 output.extend_from_slice(&sh_type.to_le_bytes());
1085 output.extend_from_slice(&flags.to_le_bytes());
1086 output.extend_from_slice(&addr.to_le_bytes());
1087 output.extend_from_slice(&offset.to_le_bytes());
1088 output.extend_from_slice(&size.to_le_bytes());
1089 output.extend_from_slice(&link.to_le_bytes());
1090 output.extend_from_slice(&info.to_le_bytes());
1091 output.extend_from_slice(&align.to_le_bytes());
1092 output.extend_from_slice(&entsize.to_le_bytes());
1093 }
1094
1095 #[allow(dead_code)]
1097 fn write_elf_header(&self, output: &mut Vec<u8>) -> Result<()> {
1098 output.extend_from_slice(&[0x7f, b'E', b'L', b'F']);
1100
1101 output.push(self.class as u8);
1103
1104 output.push(self.data as u8);
1106
1107 output.push(1);
1109
1110 output.push(0); output.push(0);
1115
1116 output.extend_from_slice(&[0; 7]);
1118
1119 let etype = self.elf_type as u16;
1121 output.extend_from_slice(&etype.to_le_bytes());
1122
1123 let machine = self.machine as u16;
1125 output.extend_from_slice(&machine.to_le_bytes());
1126
1127 output.extend_from_slice(&1u32.to_le_bytes());
1129
1130 output.extend_from_slice(&self.entry.to_le_bytes());
1132
1133 output.extend_from_slice(&0u32.to_le_bytes());
1135
1136 output.extend_from_slice(&0u32.to_le_bytes());
1138
1139 output.extend_from_slice(&0u32.to_le_bytes());
1141
1142 output.extend_from_slice(&52u16.to_le_bytes());
1144
1145 output.extend_from_slice(&0u16.to_le_bytes());
1147
1148 output.extend_from_slice(&0u16.to_le_bytes());
1150
1151 output.extend_from_slice(&40u16.to_le_bytes());
1153
1154 output.extend_from_slice(&0u16.to_le_bytes());
1156
1157 output.extend_from_slice(&0u16.to_le_bytes());
1159
1160 Ok(())
1161 }
1162}
1163
1164#[cfg(test)]
1165mod tests {
1166 use super::*;
1167
1168 #[test]
1169 fn test_elf_builder_creation() {
1170 let builder = ElfBuilder::new_arm32();
1171 assert_eq!(builder.class, ElfClass::Elf32);
1172 assert_eq!(builder.data, ElfData::LittleEndian);
1173 assert_eq!(builder.machine, ElfMachine::Arm);
1174 }
1175
1176 #[test]
1177 fn test_section_creation() {
1178 let section = Section::new(".text", SectionType::ProgBits)
1179 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
1180 .with_addr(0x8000)
1181 .with_align(4);
1182
1183 assert_eq!(section.name, ".text");
1184 assert_eq!(section.section_type, SectionType::ProgBits);
1185 assert_eq!(section.addr, 0x8000);
1186 assert_eq!(section.align, 4);
1187 }
1188
1189 #[test]
1190 fn test_symbol_creation() {
1191 let symbol = Symbol::new("main")
1192 .with_value(0x8000)
1193 .with_size(128)
1194 .with_binding(SymbolBinding::Global)
1195 .with_type(SymbolType::Func)
1196 .with_section(1);
1197
1198 assert_eq!(symbol.name, "main");
1199 assert_eq!(symbol.value, 0x8000);
1200 assert_eq!(symbol.size, 128);
1201 assert_eq!(symbol.binding, SymbolBinding::Global);
1202 assert_eq!(symbol.symbol_type, SymbolType::Func);
1203 }
1204
1205 #[test]
1206 fn test_elf_header_generation() {
1207 let builder = ElfBuilder::new_arm32().with_entry(0x8000);
1208 let elf = builder.build().unwrap();
1209
1210 assert_eq!(&elf[0..4], &[0x7f, b'E', b'L', b'F']);
1212
1213 assert_eq!(elf[4], 1);
1215
1216 assert_eq!(elf[5], 1);
1218
1219 assert_eq!(elf[6], 1);
1221 }
1222
1223 #[test]
1224 fn test_add_sections() {
1225 let mut builder = ElfBuilder::new_arm32();
1226
1227 let text = Section::new(".text", SectionType::ProgBits)
1228 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC);
1229
1230 let data = Section::new(".data", SectionType::ProgBits)
1231 .with_flags(SectionFlags::ALLOC | SectionFlags::WRITE);
1232
1233 builder.add_section(text);
1234 builder.add_section(data);
1235
1236 assert_eq!(builder.sections.len(), 2);
1237 }
1238
1239 #[test]
1240 fn test_add_symbols() {
1241 let mut builder = ElfBuilder::new_arm32();
1242
1243 let main_sym = Symbol::new("main")
1244 .with_binding(SymbolBinding::Global)
1245 .with_type(SymbolType::Func);
1246
1247 let data_sym = Symbol::new("data")
1248 .with_binding(SymbolBinding::Local)
1249 .with_type(SymbolType::Object);
1250
1251 builder.add_symbol(main_sym);
1252 builder.add_symbol(data_sym);
1253
1254 assert_eq!(builder.symbols.len(), 2);
1255 }
1256
1257 #[test]
1258 fn test_complete_elf_generation() {
1259 let mut builder = ElfBuilder::new_arm32()
1261 .with_entry(0x8000)
1262 .with_type(ElfType::Exec);
1263
1264 let text_code = vec![
1266 0x00, 0x48, 0x2d, 0xe9, 0x04, 0xb0, 0x8d, 0xe2, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x88, 0xbd, 0xe8, ];
1271 let text = Section::new(".text", SectionType::ProgBits)
1272 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
1273 .with_addr(0x8000)
1274 .with_align(4)
1275 .with_data(text_code);
1276
1277 builder.add_section(text);
1278
1279 let data_content = vec![0x01, 0x02, 0x03, 0x04];
1281 let data = Section::new(".data", SectionType::ProgBits)
1282 .with_flags(SectionFlags::ALLOC | SectionFlags::WRITE)
1283 .with_addr(0x8100)
1284 .with_align(4)
1285 .with_data(data_content);
1286
1287 builder.add_section(data);
1288
1289 let bss = Section::new(".bss", SectionType::NoBits)
1291 .with_flags(SectionFlags::ALLOC | SectionFlags::WRITE)
1292 .with_addr(0x8200)
1293 .with_align(4);
1294
1295 builder.add_section(bss);
1296
1297 let main_sym = Symbol::new("main")
1299 .with_value(0x8000)
1300 .with_size(16)
1301 .with_binding(SymbolBinding::Global)
1302 .with_type(SymbolType::Func)
1303 .with_section(4); builder.add_symbol(main_sym);
1306
1307 let data_var = Symbol::new("global_var")
1308 .with_value(0x8100)
1309 .with_size(4)
1310 .with_binding(SymbolBinding::Global)
1311 .with_type(SymbolType::Object)
1312 .with_section(5); builder.add_symbol(data_var);
1315
1316 let elf = builder.build().unwrap();
1318
1319 assert_eq!(&elf[0..4], &[0x7f, b'E', b'L', b'F']);
1321 assert_eq!(elf[4], 1); assert_eq!(elf[5], 1); assert_eq!(elf[6], 1); assert!(elf.len() > 52); assert!(elf.len() < 10000); let entry_bytes = &elf[24..28];
1331 let entry = u32::from_le_bytes([
1332 entry_bytes[0],
1333 entry_bytes[1],
1334 entry_bytes[2],
1335 entry_bytes[3],
1336 ]);
1337 assert_eq!(entry, 0x8001); let sh_off_bytes = &elf[32..36];
1341 let sh_off = u32::from_le_bytes([
1342 sh_off_bytes[0],
1343 sh_off_bytes[1],
1344 sh_off_bytes[2],
1345 sh_off_bytes[3],
1346 ]);
1347 assert!(sh_off > 0);
1348
1349 let sh_num_bytes = &elf[48..50];
1351 let sh_num = u16::from_le_bytes([sh_num_bytes[0], sh_num_bytes[1]]);
1352 assert_eq!(sh_num, 7);
1353
1354 let shstrndx_bytes = &elf[50..52];
1356 let shstrndx = u16::from_le_bytes([shstrndx_bytes[0], shstrndx_bytes[1]]);
1357 assert_eq!(shstrndx, 1);
1358 }
1359
1360 #[test]
1361 fn test_string_table_generation() {
1362 let mut builder = ElfBuilder::new_arm32();
1363
1364 builder.add_section(Section::new(".text", SectionType::ProgBits));
1365 builder.add_section(Section::new(".data", SectionType::ProgBits));
1366
1367 let (strtab, offsets, _extra_rel_offsets) = builder.build_section_string_table();
1368
1369 assert_eq!(strtab[0], 0);
1371
1372 let strtab_str = String::from_utf8_lossy(&strtab);
1374 assert!(strtab_str.contains(".shstrtab"));
1375 assert!(strtab_str.contains(".strtab"));
1376 assert!(strtab_str.contains(".symtab"));
1377 assert!(strtab_str.contains(".text"));
1378 assert!(strtab_str.contains(".data"));
1379
1380 assert_eq!(offsets.len(), 2);
1382 }
1383
1384 #[test]
1385 fn test_relocation_support() {
1386 let mut builder = ElfBuilder::new_arm32()
1387 .with_entry(0x8000)
1388 .with_type(ElfType::Rel);
1389
1390 let text_code = vec![0x00u8; 16]; let text = Section::new(".text", SectionType::ProgBits)
1393 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
1394 .with_addr(0x8000)
1395 .with_align(4)
1396 .with_data(text_code);
1397 builder.add_section(text);
1398
1399 let sym_idx = builder.add_undefined_symbol("__meld_dispatch_import");
1401 assert!(sym_idx > 0);
1402
1403 builder.add_relocation(Relocation {
1405 offset: 4,
1406 symbol_index: sym_idx,
1407 reloc_type: ArmRelocationType::Call,
1408 });
1409
1410 let elf = builder.build().unwrap();
1411
1412 assert_eq!(&elf[0..4], &[0x7f, b'E', b'L', b'F']);
1414
1415 let sh_num = u16::from_le_bytes([elf[48], elf[49]]);
1418 assert_eq!(sh_num, 6);
1419
1420 let has_undef = elf
1423 .windows(b"__meld_dispatch_import".len())
1424 .any(|w| w == b"__meld_dispatch_import");
1425 assert!(
1426 has_undef,
1427 "ELF should contain __meld_dispatch_import symbol name"
1428 );
1429 }
1430
1431 #[test]
1432 fn test_symbol_table_encoding() {
1433 let mut builder = ElfBuilder::new_arm32();
1434
1435 let sym = Symbol::new("test_func")
1436 .with_value(0x1000)
1437 .with_size(64)
1438 .with_binding(SymbolBinding::Global)
1439 .with_type(SymbolType::Func)
1440 .with_section(1);
1441
1442 builder.add_symbol(sym);
1443
1444 let (_strtab, offsets) = builder.build_symbol_string_table();
1445 let symtab = builder.build_symbol_table(&offsets);
1446
1447 assert_eq!(symtab.len(), 32);
1449
1450 assert!(symtab[0..16].iter().all(|&b| b == 0));
1452
1453 let value_bytes = &symtab[20..24];
1457 let value = u32::from_le_bytes([
1458 value_bytes[0],
1459 value_bytes[1],
1460 value_bytes[2],
1461 value_bytes[3],
1462 ]);
1463 assert_eq!(value, 0x1001); let size_bytes = &symtab[24..28];
1467 let size = u32::from_le_bytes([size_bytes[0], size_bytes[1], size_bytes[2], size_bytes[3]]);
1468 assert_eq!(size, 64);
1469
1470 let info = symtab[28];
1472 let binding = info >> 4;
1473 let sym_type = info & 0xf;
1474 assert_eq!(binding, SymbolBinding::Global as u8);
1475 assert_eq!(sym_type, SymbolType::Func as u8);
1476 }
1477
1478 #[test]
1483 fn test_a32_symbols_have_no_thumb_bit_598() {
1484 let mut builder = ElfBuilder::new_arm32().with_thumb_funcs(false);
1485
1486 let func_sym = Symbol::new("a32_func")
1487 .with_value(0x1000)
1488 .with_size(64)
1489 .with_binding(SymbolBinding::Global)
1490 .with_type(SymbolType::Func)
1491 .with_section(1);
1492 builder.add_symbol(func_sym);
1493
1494 let (_strtab, offsets) = builder.build_symbol_string_table();
1495 let symtab = builder.build_symbol_table(&offsets);
1496 let value = u32::from_le_bytes(symtab[20..24].try_into().unwrap());
1497 assert_eq!(value, 0x1000, "A32 STT_FUNC st_value must keep bit 0 clear");
1498
1499 let builder = ElfBuilder::new_arm32()
1501 .with_thumb_funcs(false)
1502 .with_entry(0x8000);
1503 assert_eq!(builder.entry, 0x8000, "A32 e_entry must keep bit 0 clear");
1504
1505 let builder = ElfBuilder::new_arm32().with_entry(0x8000);
1507 assert_eq!(builder.entry, 0x8001, "Thumb e_entry keeps the bit");
1508 }
1509}