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}
398
399impl ElfBuilder {
400 pub fn new_arm32() -> Self {
402 Self {
403 class: ElfClass::Elf32,
404 data: ElfData::LittleEndian,
405 elf_type: ElfType::Exec,
406 machine: ElfMachine::Arm,
407 entry: 0,
408 e_flags: EF_ARM_EABI_VER5,
409 sections: Vec::new(),
410 symbols: Vec::new(),
411 program_headers: Vec::new(),
412 relocations: Vec::new(),
413 extra_relocations: Vec::new(),
414 }
415 }
416
417 pub fn with_entry(mut self, entry: u32) -> Self {
422 self.entry = if self.machine == ElfMachine::Arm {
423 entry | 1 } else {
425 entry
426 };
427 self
428 }
429
430 pub fn set_flags(&mut self, flags: u32) {
432 self.e_flags = flags;
433 }
434
435 pub fn with_type(mut self, elf_type: ElfType) -> Self {
437 self.elf_type = elf_type;
438 self
439 }
440
441 pub fn add_section(&mut self, section: Section) {
443 self.sections.push(section);
444 }
445
446 pub fn add_symbol(&mut self, symbol: Symbol) {
448 self.symbols.push(symbol);
449 }
450
451 pub fn add_symbol_indexed(&mut self, symbol: Symbol) -> u32 {
456 let index = self.symbols.len() as u32 + 1;
457 self.symbols.push(symbol);
458 index
459 }
460
461 pub fn add_program_header(&mut self, ph: ProgramHeader) {
463 self.program_headers.push(ph);
464 }
465
466 pub fn add_relocation(&mut self, reloc: Relocation) {
468 self.relocations.push(reloc);
469 }
470
471 pub fn add_section_relocations(&mut self, target_section: &str, relocs: Vec<Relocation>) {
478 if relocs.is_empty() {
479 return;
480 }
481 self.extra_relocations
482 .push((target_section.to_string(), relocs));
483 }
484
485 pub fn add_undefined_symbol(&mut self, name: &str) -> u32 {
488 let index = self.symbols.len() as u32 + 1; self.symbols.push(Symbol {
490 name: name.to_string(),
491 value: 0,
492 size: 0,
493 binding: SymbolBinding::Global,
494 symbol_type: SymbolType::Func,
495 section: 0, });
497 index
498 }
499
500 pub fn build(&self) -> Result<Vec<u8>> {
502 let mut output = Vec::new();
503
504 let header_size = 52;
506 let ph_entry_size = 32;
508 let ph_count = self.program_headers.len();
509 let ph_table_size = ph_entry_size * ph_count;
510
511 output.resize(header_size + ph_table_size, 0);
513
514 let (shstrtab_data, section_name_offsets, extra_rel_name_offsets) =
516 self.build_section_string_table();
517
518 let (strtab_data, symbol_name_offsets) = self.build_symbol_string_table();
520
521 let mut current_offset = header_size + ph_table_size;
523
524 let shstrtab_offset = current_offset;
526 current_offset += shstrtab_data.len();
527
528 let strtab_offset = current_offset;
530 current_offset += strtab_data.len();
531
532 let mut section_offsets = Vec::new();
534 for section in &self.sections {
535 section_offsets.push(current_offset);
536 current_offset += section.data.len();
537 }
538
539 let symtab_offset = current_offset;
541 let symtab_data = self.build_symbol_table(&symbol_name_offsets);
542 current_offset += symtab_data.len();
543
544 let rel_data = self.build_relocation_table();
546 let rel_offset = current_offset;
547 current_offset += rel_data.len();
548
549 let mut extra_rel: Vec<ExtraRelSection> = Vec::new();
554 for (i, (target, relocs)) in self.extra_relocations.iter().enumerate() {
555 let Some(target_idx) = self.section_index_by_name(target) else {
556 continue;
557 };
558 let data = Self::encode_rel_entries(relocs);
559 let name_offset = extra_rel_name_offsets.get(i).copied().unwrap_or(0);
560 extra_rel.push(ExtraRelSection {
561 name_offset,
562 target_idx,
563 offset: current_offset,
564 data,
565 });
566 current_offset += extra_rel.last().unwrap().data.len();
567 }
568
569 let sh_offset = current_offset;
571
572 output.extend_from_slice(&shstrtab_data);
574 output.extend_from_slice(&strtab_data);
575
576 for section in &self.sections {
577 output.extend_from_slice(§ion.data);
578 }
579
580 output.extend_from_slice(&symtab_data);
581 output.extend_from_slice(&rel_data);
582 for er in &extra_rel {
583 output.extend_from_slice(&er.data);
584 }
585
586 let section_headers = self.build_section_headers_with_rel(
588 §ion_name_offsets,
589 shstrtab_offset,
590 &shstrtab_data,
591 strtab_offset,
592 &strtab_data,
593 symtab_offset,
594 &symtab_data,
595 §ion_offsets,
596 rel_offset,
597 &rel_data,
598 &extra_rel,
599 );
600 output.extend_from_slice(§ion_headers);
601
602 for (i, ph) in self.program_headers.iter().enumerate() {
605 let ph_offset = header_size + i * ph_entry_size;
606 let mut corrected_ph = ph.clone();
607 if corrected_ph.filesz > 0 {
608 for (si, section) in self.sections.iter().enumerate() {
610 if section.addr == corrected_ph.vaddr && si < section_offsets.len() {
611 corrected_ph.offset = section_offsets[si] as u32;
612 break;
613 }
614 }
615 }
616 self.write_program_header(
617 &mut output[ph_offset..ph_offset + ph_entry_size],
618 &corrected_ph,
619 );
620 }
621
622 let has_rel = !self.relocations.is_empty();
624 let num_sections = 4 + self.sections.len() + if has_rel { 1 } else { 0 } + extra_rel.len();
625 let ph_offset = if ph_count > 0 { header_size as u32 } else { 0 };
626 self.write_elf_header_with_phdrs(
627 &mut output[0..header_size],
628 ph_offset,
629 ph_count as u16,
630 sh_offset as u32,
631 num_sections as u16,
632 )?;
633
634 Ok(output)
635 }
636
637 fn write_program_header(&self, output: &mut [u8], ph: &ProgramHeader) {
639 let mut cursor = 0;
640
641 output[cursor..cursor + 4].copy_from_slice(&(ph.p_type as u32).to_le_bytes());
643 cursor += 4;
644
645 output[cursor..cursor + 4].copy_from_slice(&ph.offset.to_le_bytes());
647 cursor += 4;
648
649 output[cursor..cursor + 4].copy_from_slice(&ph.vaddr.to_le_bytes());
651 cursor += 4;
652
653 output[cursor..cursor + 4].copy_from_slice(&ph.paddr.to_le_bytes());
655 cursor += 4;
656
657 output[cursor..cursor + 4].copy_from_slice(&ph.filesz.to_le_bytes());
659 cursor += 4;
660
661 output[cursor..cursor + 4].copy_from_slice(&ph.memsz.to_le_bytes());
663 cursor += 4;
664
665 output[cursor..cursor + 4].copy_from_slice(&ph.flags.to_le_bytes());
667 cursor += 4;
668
669 output[cursor..cursor + 4].copy_from_slice(&ph.align.to_le_bytes());
671 }
672
673 fn write_elf_header_with_phdrs(
675 &self,
676 output: &mut [u8],
677 ph_offset: u32,
678 ph_count: u16,
679 sh_offset: u32,
680 sh_count: u16,
681 ) -> Result<()> {
682 let mut cursor = 0;
683
684 output[cursor..cursor + 4].copy_from_slice(&[0x7f, b'E', b'L', b'F']);
686 cursor += 4;
687
688 output[cursor] = self.class as u8;
690 cursor += 1;
691
692 output[cursor] = self.data as u8;
694 cursor += 1;
695
696 output[cursor] = 1;
698 cursor += 1;
699
700 output[cursor] = 0; cursor += 1;
703
704 output[cursor] = 0;
706 cursor += 1;
707
708 output[cursor..cursor + 7].copy_from_slice(&[0; 7]);
710 cursor += 7;
711
712 let etype = self.elf_type as u16;
714 output[cursor..cursor + 2].copy_from_slice(&etype.to_le_bytes());
715 cursor += 2;
716
717 let machine = self.machine as u16;
719 output[cursor..cursor + 2].copy_from_slice(&machine.to_le_bytes());
720 cursor += 2;
721
722 output[cursor..cursor + 4].copy_from_slice(&1u32.to_le_bytes());
724 cursor += 4;
725
726 output[cursor..cursor + 4].copy_from_slice(&self.entry.to_le_bytes());
728 cursor += 4;
729
730 output[cursor..cursor + 4].copy_from_slice(&ph_offset.to_le_bytes());
732 cursor += 4;
733
734 output[cursor..cursor + 4].copy_from_slice(&sh_offset.to_le_bytes());
736 cursor += 4;
737
738 output[cursor..cursor + 4].copy_from_slice(&self.e_flags.to_le_bytes());
740 cursor += 4;
741
742 output[cursor..cursor + 2].copy_from_slice(&52u16.to_le_bytes());
744 cursor += 2;
745
746 let ph_entry_size: u16 = if ph_count > 0 { 32 } else { 0 };
748 output[cursor..cursor + 2].copy_from_slice(&ph_entry_size.to_le_bytes());
749 cursor += 2;
750
751 output[cursor..cursor + 2].copy_from_slice(&ph_count.to_le_bytes());
753 cursor += 2;
754
755 output[cursor..cursor + 2].copy_from_slice(&40u16.to_le_bytes());
757 cursor += 2;
758
759 output[cursor..cursor + 2].copy_from_slice(&sh_count.to_le_bytes());
761 cursor += 2;
762
763 output[cursor..cursor + 2].copy_from_slice(&1u16.to_le_bytes());
765
766 Ok(())
767 }
768
769 fn build_section_string_table(&self) -> (Vec<u8>, Vec<usize>, Vec<usize>) {
775 let mut strtab = vec![0]; let mut offsets = Vec::new();
777
778 strtab.extend_from_slice(b".shstrtab\0");
780 strtab.extend_from_slice(b".strtab\0");
781 strtab.extend_from_slice(b".symtab\0");
782
783 for section in &self.sections {
785 let offset = strtab.len();
786 offsets.push(offset);
787 strtab.extend_from_slice(section.name.as_bytes());
788 strtab.push(0);
789 }
790
791 if !self.relocations.is_empty() {
793 strtab.extend_from_slice(b".rel.text\0");
794 }
795
796 let mut extra_rel_offsets = Vec::new();
798 for (target, _) in &self.extra_relocations {
799 let offset = strtab.len();
800 extra_rel_offsets.push(offset);
801 strtab.extend_from_slice(format!(".rel{target}\0").as_bytes());
802 }
803
804 (strtab, offsets, extra_rel_offsets)
805 }
806
807 fn build_symbol_string_table(&self) -> (Vec<u8>, Vec<usize>) {
809 let mut strtab = vec![0]; let mut offsets = Vec::new();
811
812 for symbol in &self.symbols {
813 let offset = strtab.len();
814 offsets.push(offset);
815 strtab.extend_from_slice(symbol.name.as_bytes());
816 strtab.push(0);
817 }
818
819 (strtab, offsets)
820 }
821
822 fn build_relocation_table(&self) -> Vec<u8> {
824 Self::encode_rel_entries(&self.relocations)
825 }
826
827 fn encode_rel_entries(relocs: &[Relocation]) -> Vec<u8> {
830 let mut rel_data = Vec::new();
831 for reloc in relocs {
832 rel_data.extend_from_slice(&reloc.offset.to_le_bytes());
834 let r_info = (reloc.symbol_index << 8) | (reloc.reloc_type as u32);
836 rel_data.extend_from_slice(&r_info.to_le_bytes());
837 }
838 rel_data
839 }
840
841 fn section_index_by_name(&self, name: &str) -> Option<u32> {
845 self.sections
846 .iter()
847 .position(|s| s.name == name)
848 .map(|pos| 4 + pos as u32)
849 }
850
851 fn build_symbol_table(&self, name_offsets: &[usize]) -> Vec<u8> {
853 let mut symtab = Vec::new();
854
855 symtab.extend_from_slice(&[0u8; 16]); for (i, symbol) in self.symbols.iter().enumerate() {
860 let name_offset = if i < name_offsets.len() {
861 name_offsets[i] as u32
862 } else {
863 0
864 };
865
866 symtab.extend_from_slice(&name_offset.to_le_bytes());
868
869 let value = if self.machine == ElfMachine::Arm && symbol.symbol_type == SymbolType::Func
872 {
873 symbol.value | 1
874 } else {
875 symbol.value
876 };
877 symtab.extend_from_slice(&value.to_le_bytes());
878
879 symtab.extend_from_slice(&symbol.size.to_le_bytes());
881
882 let info = ((symbol.binding as u8) << 4) | (symbol.symbol_type as u8 & 0xf);
884 symtab.push(info);
885
886 symtab.push(0);
888
889 symtab.extend_from_slice(&symbol.section.to_le_bytes());
891 }
892
893 symtab
894 }
895
896 #[allow(clippy::too_many_arguments)]
898 fn build_section_headers_with_rel(
899 &self,
900 section_name_offsets: &[usize],
901 shstrtab_offset: usize,
902 shstrtab_data: &[u8],
903 strtab_offset: usize,
904 strtab_data: &[u8],
905 symtab_offset: usize,
906 symtab_data: &[u8],
907 section_offsets: &[usize],
908 rel_offset: usize,
909 rel_data: &[u8],
910 extra_rel: &[ExtraRelSection],
911 ) -> Vec<u8> {
912 let mut headers = Vec::new();
913
914 headers.extend_from_slice(&[0u8; 40]);
918
919 self.write_section_header(
921 &mut headers,
922 1,
923 SectionType::StrTab as u32,
924 0,
925 0,
926 shstrtab_offset as u32,
927 shstrtab_data.len() as u32,
928 0,
929 0,
930 1,
931 0,
932 );
933
934 let strtab_name_offset = ".shstrtab\0".len();
936 self.write_section_header(
937 &mut headers,
938 strtab_name_offset as u32,
939 SectionType::StrTab as u32,
940 0,
941 0,
942 strtab_offset as u32,
943 strtab_data.len() as u32,
944 0,
945 0,
946 1,
947 0,
948 );
949
950 let symtab_name_offset = ".shstrtab\0.strtab\0".len();
952 self.write_section_header(
953 &mut headers,
954 symtab_name_offset as u32,
955 SectionType::SymTab as u32,
956 0,
957 0,
958 symtab_offset as u32,
959 symtab_data.len() as u32,
960 2,
961 1,
962 4,
963 16,
964 );
965
966 for (i, section) in self.sections.iter().enumerate() {
968 let name_offset = if i < section_name_offsets.len() {
969 section_name_offsets[i] as u32
970 } else {
971 0
972 };
973 let offset = if i < section_offsets.len() {
974 section_offsets[i] as u32
975 } else {
976 0
977 };
978
979 self.write_section_header(
980 &mut headers,
981 name_offset,
982 section.section_type as u32,
983 section.flags,
984 section.addr,
985 offset,
986 section.size(),
987 0,
988 0,
989 section.align,
990 0,
991 );
992 }
993
994 if !rel_data.is_empty() {
996 let rel_name_offset = self.rel_text_shstrtab_offset();
997 let text_section_idx = 4u32; self.write_section_header(
1000 &mut headers,
1001 rel_name_offset as u32,
1002 SectionType::Rel as u32,
1003 0,
1004 0,
1005 rel_offset as u32,
1006 rel_data.len() as u32,
1007 3, text_section_idx, 4,
1010 8, );
1012 }
1013
1014 for er in extra_rel {
1017 self.write_section_header(
1018 &mut headers,
1019 er.name_offset as u32,
1020 SectionType::Rel as u32,
1021 0,
1022 0,
1023 er.offset as u32,
1024 er.data.len() as u32,
1025 3, er.target_idx, 4,
1028 8, );
1030 }
1031
1032 headers
1033 }
1034
1035 fn rel_text_shstrtab_offset(&self) -> usize {
1037 let mut offset = 1 + ".shstrtab\0".len() + ".strtab\0".len() + ".symtab\0".len();
1039 for section in &self.sections {
1040 offset += section.name.len() + 1;
1041 }
1042 offset
1043 }
1044
1045 #[allow(clippy::too_many_arguments)]
1047 fn write_section_header(
1048 &self,
1049 output: &mut Vec<u8>,
1050 name: u32,
1051 sh_type: u32,
1052 flags: u32,
1053 addr: u32,
1054 offset: u32,
1055 size: u32,
1056 link: u32,
1057 info: u32,
1058 align: u32,
1059 entsize: u32,
1060 ) {
1061 output.extend_from_slice(&name.to_le_bytes());
1062 output.extend_from_slice(&sh_type.to_le_bytes());
1063 output.extend_from_slice(&flags.to_le_bytes());
1064 output.extend_from_slice(&addr.to_le_bytes());
1065 output.extend_from_slice(&offset.to_le_bytes());
1066 output.extend_from_slice(&size.to_le_bytes());
1067 output.extend_from_slice(&link.to_le_bytes());
1068 output.extend_from_slice(&info.to_le_bytes());
1069 output.extend_from_slice(&align.to_le_bytes());
1070 output.extend_from_slice(&entsize.to_le_bytes());
1071 }
1072
1073 #[allow(dead_code)]
1075 fn write_elf_header(&self, output: &mut Vec<u8>) -> Result<()> {
1076 output.extend_from_slice(&[0x7f, b'E', b'L', b'F']);
1078
1079 output.push(self.class as u8);
1081
1082 output.push(self.data as u8);
1084
1085 output.push(1);
1087
1088 output.push(0); output.push(0);
1093
1094 output.extend_from_slice(&[0; 7]);
1096
1097 let etype = self.elf_type as u16;
1099 output.extend_from_slice(&etype.to_le_bytes());
1100
1101 let machine = self.machine as u16;
1103 output.extend_from_slice(&machine.to_le_bytes());
1104
1105 output.extend_from_slice(&1u32.to_le_bytes());
1107
1108 output.extend_from_slice(&self.entry.to_le_bytes());
1110
1111 output.extend_from_slice(&0u32.to_le_bytes());
1113
1114 output.extend_from_slice(&0u32.to_le_bytes());
1116
1117 output.extend_from_slice(&0u32.to_le_bytes());
1119
1120 output.extend_from_slice(&52u16.to_le_bytes());
1122
1123 output.extend_from_slice(&0u16.to_le_bytes());
1125
1126 output.extend_from_slice(&0u16.to_le_bytes());
1128
1129 output.extend_from_slice(&40u16.to_le_bytes());
1131
1132 output.extend_from_slice(&0u16.to_le_bytes());
1134
1135 output.extend_from_slice(&0u16.to_le_bytes());
1137
1138 Ok(())
1139 }
1140}
1141
1142#[cfg(test)]
1143mod tests {
1144 use super::*;
1145
1146 #[test]
1147 fn test_elf_builder_creation() {
1148 let builder = ElfBuilder::new_arm32();
1149 assert_eq!(builder.class, ElfClass::Elf32);
1150 assert_eq!(builder.data, ElfData::LittleEndian);
1151 assert_eq!(builder.machine, ElfMachine::Arm);
1152 }
1153
1154 #[test]
1155 fn test_section_creation() {
1156 let section = Section::new(".text", SectionType::ProgBits)
1157 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
1158 .with_addr(0x8000)
1159 .with_align(4);
1160
1161 assert_eq!(section.name, ".text");
1162 assert_eq!(section.section_type, SectionType::ProgBits);
1163 assert_eq!(section.addr, 0x8000);
1164 assert_eq!(section.align, 4);
1165 }
1166
1167 #[test]
1168 fn test_symbol_creation() {
1169 let symbol = Symbol::new("main")
1170 .with_value(0x8000)
1171 .with_size(128)
1172 .with_binding(SymbolBinding::Global)
1173 .with_type(SymbolType::Func)
1174 .with_section(1);
1175
1176 assert_eq!(symbol.name, "main");
1177 assert_eq!(symbol.value, 0x8000);
1178 assert_eq!(symbol.size, 128);
1179 assert_eq!(symbol.binding, SymbolBinding::Global);
1180 assert_eq!(symbol.symbol_type, SymbolType::Func);
1181 }
1182
1183 #[test]
1184 fn test_elf_header_generation() {
1185 let builder = ElfBuilder::new_arm32().with_entry(0x8000);
1186 let elf = builder.build().unwrap();
1187
1188 assert_eq!(&elf[0..4], &[0x7f, b'E', b'L', b'F']);
1190
1191 assert_eq!(elf[4], 1);
1193
1194 assert_eq!(elf[5], 1);
1196
1197 assert_eq!(elf[6], 1);
1199 }
1200
1201 #[test]
1202 fn test_add_sections() {
1203 let mut builder = ElfBuilder::new_arm32();
1204
1205 let text = Section::new(".text", SectionType::ProgBits)
1206 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC);
1207
1208 let data = Section::new(".data", SectionType::ProgBits)
1209 .with_flags(SectionFlags::ALLOC | SectionFlags::WRITE);
1210
1211 builder.add_section(text);
1212 builder.add_section(data);
1213
1214 assert_eq!(builder.sections.len(), 2);
1215 }
1216
1217 #[test]
1218 fn test_add_symbols() {
1219 let mut builder = ElfBuilder::new_arm32();
1220
1221 let main_sym = Symbol::new("main")
1222 .with_binding(SymbolBinding::Global)
1223 .with_type(SymbolType::Func);
1224
1225 let data_sym = Symbol::new("data")
1226 .with_binding(SymbolBinding::Local)
1227 .with_type(SymbolType::Object);
1228
1229 builder.add_symbol(main_sym);
1230 builder.add_symbol(data_sym);
1231
1232 assert_eq!(builder.symbols.len(), 2);
1233 }
1234
1235 #[test]
1236 fn test_complete_elf_generation() {
1237 let mut builder = ElfBuilder::new_arm32()
1239 .with_entry(0x8000)
1240 .with_type(ElfType::Exec);
1241
1242 let text_code = vec![
1244 0x00, 0x48, 0x2d, 0xe9, 0x04, 0xb0, 0x8d, 0xe2, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x88, 0xbd, 0xe8, ];
1249 let text = Section::new(".text", SectionType::ProgBits)
1250 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
1251 .with_addr(0x8000)
1252 .with_align(4)
1253 .with_data(text_code);
1254
1255 builder.add_section(text);
1256
1257 let data_content = vec![0x01, 0x02, 0x03, 0x04];
1259 let data = Section::new(".data", SectionType::ProgBits)
1260 .with_flags(SectionFlags::ALLOC | SectionFlags::WRITE)
1261 .with_addr(0x8100)
1262 .with_align(4)
1263 .with_data(data_content);
1264
1265 builder.add_section(data);
1266
1267 let bss = Section::new(".bss", SectionType::NoBits)
1269 .with_flags(SectionFlags::ALLOC | SectionFlags::WRITE)
1270 .with_addr(0x8200)
1271 .with_align(4);
1272
1273 builder.add_section(bss);
1274
1275 let main_sym = Symbol::new("main")
1277 .with_value(0x8000)
1278 .with_size(16)
1279 .with_binding(SymbolBinding::Global)
1280 .with_type(SymbolType::Func)
1281 .with_section(4); builder.add_symbol(main_sym);
1284
1285 let data_var = Symbol::new("global_var")
1286 .with_value(0x8100)
1287 .with_size(4)
1288 .with_binding(SymbolBinding::Global)
1289 .with_type(SymbolType::Object)
1290 .with_section(5); builder.add_symbol(data_var);
1293
1294 let elf = builder.build().unwrap();
1296
1297 assert_eq!(&elf[0..4], &[0x7f, b'E', b'L', b'F']);
1299 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];
1309 let entry = u32::from_le_bytes([
1310 entry_bytes[0],
1311 entry_bytes[1],
1312 entry_bytes[2],
1313 entry_bytes[3],
1314 ]);
1315 assert_eq!(entry, 0x8001); let sh_off_bytes = &elf[32..36];
1319 let sh_off = u32::from_le_bytes([
1320 sh_off_bytes[0],
1321 sh_off_bytes[1],
1322 sh_off_bytes[2],
1323 sh_off_bytes[3],
1324 ]);
1325 assert!(sh_off > 0);
1326
1327 let sh_num_bytes = &elf[48..50];
1329 let sh_num = u16::from_le_bytes([sh_num_bytes[0], sh_num_bytes[1]]);
1330 assert_eq!(sh_num, 7);
1331
1332 let shstrndx_bytes = &elf[50..52];
1334 let shstrndx = u16::from_le_bytes([shstrndx_bytes[0], shstrndx_bytes[1]]);
1335 assert_eq!(shstrndx, 1);
1336 }
1337
1338 #[test]
1339 fn test_string_table_generation() {
1340 let mut builder = ElfBuilder::new_arm32();
1341
1342 builder.add_section(Section::new(".text", SectionType::ProgBits));
1343 builder.add_section(Section::new(".data", SectionType::ProgBits));
1344
1345 let (strtab, offsets, _extra_rel_offsets) = builder.build_section_string_table();
1346
1347 assert_eq!(strtab[0], 0);
1349
1350 let strtab_str = String::from_utf8_lossy(&strtab);
1352 assert!(strtab_str.contains(".shstrtab"));
1353 assert!(strtab_str.contains(".strtab"));
1354 assert!(strtab_str.contains(".symtab"));
1355 assert!(strtab_str.contains(".text"));
1356 assert!(strtab_str.contains(".data"));
1357
1358 assert_eq!(offsets.len(), 2);
1360 }
1361
1362 #[test]
1363 fn test_relocation_support() {
1364 let mut builder = ElfBuilder::new_arm32()
1365 .with_entry(0x8000)
1366 .with_type(ElfType::Rel);
1367
1368 let text_code = vec![0x00u8; 16]; let text = Section::new(".text", SectionType::ProgBits)
1371 .with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
1372 .with_addr(0x8000)
1373 .with_align(4)
1374 .with_data(text_code);
1375 builder.add_section(text);
1376
1377 let sym_idx = builder.add_undefined_symbol("__meld_dispatch_import");
1379 assert!(sym_idx > 0);
1380
1381 builder.add_relocation(Relocation {
1383 offset: 4,
1384 symbol_index: sym_idx,
1385 reloc_type: ArmRelocationType::Call,
1386 });
1387
1388 let elf = builder.build().unwrap();
1389
1390 assert_eq!(&elf[0..4], &[0x7f, b'E', b'L', b'F']);
1392
1393 let sh_num = u16::from_le_bytes([elf[48], elf[49]]);
1396 assert_eq!(sh_num, 6);
1397
1398 let has_undef = elf
1401 .windows(b"__meld_dispatch_import".len())
1402 .any(|w| w == b"__meld_dispatch_import");
1403 assert!(
1404 has_undef,
1405 "ELF should contain __meld_dispatch_import symbol name"
1406 );
1407 }
1408
1409 #[test]
1410 fn test_symbol_table_encoding() {
1411 let mut builder = ElfBuilder::new_arm32();
1412
1413 let sym = Symbol::new("test_func")
1414 .with_value(0x1000)
1415 .with_size(64)
1416 .with_binding(SymbolBinding::Global)
1417 .with_type(SymbolType::Func)
1418 .with_section(1);
1419
1420 builder.add_symbol(sym);
1421
1422 let (_strtab, offsets) = builder.build_symbol_string_table();
1423 let symtab = builder.build_symbol_table(&offsets);
1424
1425 assert_eq!(symtab.len(), 32);
1427
1428 assert!(symtab[0..16].iter().all(|&b| b == 0));
1430
1431 let value_bytes = &symtab[20..24];
1435 let value = u32::from_le_bytes([
1436 value_bytes[0],
1437 value_bytes[1],
1438 value_bytes[2],
1439 value_bytes[3],
1440 ]);
1441 assert_eq!(value, 0x1001); let size_bytes = &symtab[24..28];
1445 let size = u32::from_le_bytes([size_bytes[0], size_bytes[1], size_bytes[2], size_bytes[3]]);
1446 assert_eq!(size, 64);
1447
1448 let info = symtab[28];
1450 let binding = info >> 4;
1451 let sym_type = info & 0xf;
1452 assert_eq!(binding, SymbolBinding::Global as u8);
1453 assert_eq!(sym_type, SymbolType::Func as u8);
1454 }
1455}