diff options
| author | Ian McIntyre <ianpmcintyre@gmail.com> | 2023-09-29 15:11:55 -0400 |
|---|---|---|
| committer | Ian McIntyre <ianpmcintyre@gmail.com> | 2023-09-29 16:42:38 -0400 |
| commit | cfaac90ddfbab00aa5709c1f6dc2b796e63c6d77 (patch) | |
| tree | 2d49b97146fddb2d1c96a9a53a2f1f0939215552 /tests | |
| parent | c485a9090a3b623a5de0c2e6da6c857770bf079a (diff) | |
Refactor LMA computation in inspect_elf
Depending on the ordering and contents of program headers, the previous
predicate for "is this the program header for this section?" could
select the wrong header. GNU's ld and LLVM's lld produce that different
header ordering and contents, causing select asserts to fail when using
GNU's linker.
This commit changes how we select the program header, approximating the
way GNU objdump figures the value. This new approach needs more
information from the section header, so I'm changing the API to make it
easier to call the section_header method.
The previous approach was influenced by LLVM objdump. Turns out that
LLVM objdump will also compute the wrong LMA for these binaries when
they're linked with GNU ld. GNU objdump always produces the correct
section LMA, no matter the LLVM or GNU linker.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/inspect_elf.rs | 79 |
1 files changed, 45 insertions, 34 deletions
diff --git a/tests/inspect_elf.rs b/tests/inspect_elf.rs index fa2c11d..5638801 100644 --- a/tests/inspect_elf.rs +++ b/tests/inspect_elf.rs @@ -134,16 +134,27 @@ impl<'a> ImxrtBinary<'a> { .ok_or_else(|| format!("Could not find {section_name} in program").into()) } - fn section_lma(&self, section: &Section) -> u64 { + fn section_lma(&self, section_name: &str) -> u64 { + let sec = self + .section_header(section_name) + .unwrap_or_else(|| panic!("Section {section_name} not found")); + + let contains_section = |phdr: &&goblin::elf::ProgramHeader| { + // The section resides in this part of the program. + sec.sh_offset >= phdr.p_offset + && (sec.sh_offset - phdr.p_offset) + sec.sh_size <= phdr.p_filesz + // The section's address fits in the program's memory. + && sec.sh_addr >= phdr.p_vaddr + && (sec.sh_addr - phdr.p_vaddr) + sec.sh_size <= phdr.p_memsz + }; + self.elf .program_headers .iter() .filter(|phdr| goblin::elf::program_header::PT_LOAD == phdr.p_type) - .find(|phdr| { - phdr.p_vaddr <= section.address && (phdr.p_vaddr + phdr.p_memsz) > section.address - }) - .map(|phdr| section.address - phdr.p_vaddr + phdr.p_paddr) - .unwrap_or(section.address) // VMA == LMA + .find(contains_section) + .map(|phdr| sec.sh_addr + phdr.p_paddr - phdr.p_vaddr) + .unwrap_or(sec.sh_addr) // VMA == LMA } } @@ -205,7 +216,7 @@ fn imxrt1010evk() { stack, "stack not at ORIGIN(DTCM), or not 8 KiB large" ); - assert_eq!(binary.section_lma(&stack), stack.address); + assert_eq!(binary.section_lma(".stack"), stack.address); let vector_table = binary.section(".vector_table").unwrap(); assert_eq!( @@ -220,12 +231,12 @@ fn imxrt1010evk() { vector_table.address % 1024 == 0, "vector table is not 1024-byte aligned" ); - assert_eq!(binary.section_lma(&vector_table), 0x6000_2000); + assert_eq!(binary.section_lma(".vector_table"), 0x6000_2000); let text = binary.section(".text").unwrap(); assert_eq!(text.address, ITCM, "text"); assert_eq!( - binary.section_lma(&text), + binary.section_lma(".text"), 0x6000_2000 + vector_table.size, "text VMA expected behind vector table" ); @@ -236,7 +247,7 @@ fn imxrt1010evk() { 0x6000_2000 + vector_table.size + aligned(text.size, 16), "rodata LMA & VMA expected behind text" ); - assert_eq!(rodata.address, binary.section_lma(&rodata)); + assert_eq!(rodata.address, binary.section_lma(".rodata")); let data = binary.section(".data").unwrap(); assert_eq!(data.address, 0x2020_0000, "data VMA in OCRAM"); @@ -245,7 +256,7 @@ fn imxrt1010evk() { "blink-rtic expected to have a single static mut u32" ); assert_eq!( - binary.section_lma(&data), + binary.section_lma(".data"), rodata.address + aligned(rodata.size, 4), "data LMA starts behind rodata" ); @@ -256,7 +267,7 @@ fn imxrt1010evk() { data.address + aligned(data.size, 4), "bss in OCRAM behind data" ); - assert_eq!(binary.section_lma(&bss), bss.address, "bss is NOLOAD"); + assert_eq!(binary.section_lma(".bss"), bss.address, "bss is NOLOAD"); let uninit = binary.section(".uninit").unwrap(); assert_eq!( @@ -265,7 +276,7 @@ fn imxrt1010evk() { "uninit in OCRAM behind bss" ); assert_eq!( - binary.section_lma(&uninit), + binary.section_lma(".uninit"), uninit.address, "uninit is NOLOAD" ); @@ -280,7 +291,7 @@ fn imxrt1010evk() { "1 KiB heap in DTCM behind vector table" ); assert_eq!(heap.size, 1024); - assert_eq!(binary.section_lma(&heap), heap.address, "Heap is NOLOAD"); + assert_eq!(binary.section_lma(".heap"), heap.address, "Heap is NOLOAD"); } fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { @@ -314,7 +325,7 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { stack, "stack not at ORIGIN(DTCM), or not 8 KiB large" ); - assert_eq!(binary.section_lma(&stack), stack.address); + assert_eq!(binary.section_lma(".stack"), stack.address); let vector_table = binary.section(".vector_table").unwrap(); assert_eq!( @@ -329,16 +340,16 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { vector_table.address % 1024 == 0, "vector table is not 1024-byte aligned" ); - assert_eq!(binary.section_lma(&vector_table), 0x6000_2000); + assert_eq!(binary.section_lma(".vector_table"), 0x6000_2000); let text = binary.section(".text").unwrap(); assert_eq!( text.address, - binary.section_lma(&vector_table) + vector_table.size, + binary.section_lma(".vector_table") + vector_table.size, "text" ); assert_eq!( - binary.section_lma(&text), + binary.section_lma(".text"), 0x6000_2000 + vector_table.size, "text VMA expected behind vector table" ); @@ -350,8 +361,8 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { "rodata LMA & VMA expected behind text" ); assert_eq!( - binary.section_lma(&rodata), - binary.section_lma(&text) + aligned(text.size, 16) + binary.section_lma(".rodata"), + binary.section_lma(".text") + aligned(text.size, 16) ); let data = binary.section(".data").unwrap(); @@ -365,8 +376,8 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { "blink-rtic expected to have a single static mut u32" ); assert_eq!( - binary.section_lma(&data), - binary.section_lma(&rodata) + aligned(rodata.size, 4), + binary.section_lma(".data"), + binary.section_lma(".rodata") + aligned(rodata.size, 4), "data LMA starts behind rodata" ); @@ -376,7 +387,7 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { data.address + aligned(data.size, 4), "bss in DTCM behind data" ); - assert_eq!(binary.section_lma(&bss), bss.address, "bss is NOLOAD"); + assert_eq!(binary.section_lma(".bss"), bss.address, "bss is NOLOAD"); let uninit = binary.section(".uninit").unwrap(); assert_eq!( @@ -385,7 +396,7 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { "uninit in DTCM behind bss" ); assert_eq!( - binary.section_lma(&uninit), + binary.section_lma(".uninit"), uninit.address, "uninit is NOLOAD" ); @@ -399,7 +410,7 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { heap, "1 KiB heap in DTCM behind uninit" ); - assert_eq!(binary.section_lma(&heap), heap.address, "Heap is NOLOAD"); + assert_eq!(binary.section_lma(".heap"), heap.address, "Heap is NOLOAD"); } #[test] @@ -492,7 +503,7 @@ fn imxrt1170evk_cm7() { stack, "stack not at ORIGIN(DTCM), or not 8 KiB large" ); - assert_eq!(binary.section_lma(&stack), stack.address); + assert_eq!(binary.section_lma(".stack"), stack.address); let vector_table = binary.section(".vector_table").unwrap(); assert_eq!( @@ -507,12 +518,12 @@ fn imxrt1170evk_cm7() { vector_table.address % 1024 == 0, "vector table is not 1024-byte aligned" ); - assert_eq!(binary.section_lma(&vector_table), 0x3000_2000); + assert_eq!(binary.section_lma(".vector_table"), 0x3000_2000); let text = binary.section(".text").unwrap(); assert_eq!(text.address, ITCM, "text"); assert_eq!( - binary.section_lma(&text), + binary.section_lma(".text"), 0x3000_2000 + vector_table.size, "text VMA expected behind vector table" ); @@ -524,7 +535,7 @@ fn imxrt1170evk_cm7() { "rodata moved to DTCM behind vector table" ); assert_eq!( - binary.section_lma(&rodata), + binary.section_lma(".rodata"), 0x3000_2000 + vector_table.size + aligned(text.size, 16), ); @@ -535,8 +546,8 @@ fn imxrt1170evk_cm7() { "blink-rtic expected to have a single static mut u32" ); assert_eq!( - binary.section_lma(&data), - binary.section_lma(&rodata) + aligned(rodata.size, 4), + binary.section_lma(".data"), + binary.section_lma(".rodata") + aligned(rodata.size, 4), "data LMA starts behind rodata" ); @@ -546,7 +557,7 @@ fn imxrt1170evk_cm7() { data.address + aligned(data.size, 4), "bss in OCRAM behind data" ); - assert_eq!(binary.section_lma(&bss), bss.address, "bss is NOLOAD"); + assert_eq!(binary.section_lma(".bss"), bss.address, "bss is NOLOAD"); let uninit = binary.section(".uninit").unwrap(); assert_eq!( @@ -555,7 +566,7 @@ fn imxrt1170evk_cm7() { "uninit in OCRAM behind bss" ); assert_eq!( - binary.section_lma(&uninit), + binary.section_lma(".uninit"), uninit.address, "uninit is NOLOAD" ); @@ -569,5 +580,5 @@ fn imxrt1170evk_cm7() { heap, "0 byte heap in DTCM behind rodata table" ); - assert_eq!(binary.section_lma(&heap), heap.address, "Heap is NOLOAD"); + assert_eq!(binary.section_lma(".heap"), heap.address, "Heap is NOLOAD"); } |
