[llvm-objcopy] llvm-objcopy --change-section-lma shifts unaddressed segments (e.g. PT_RISCV_ATTRIBUTES), causing spurious underflow
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
`--change-section-lma` shifts every segment with `MemSize > 0`, without checking whether the segment was ever assigned a real address. A segment that legitimately has `VAddr == PAddr == 0` (never placed in memory by the linker) but a nonzero size — e.g. a `PT_RISCV_ATTRIBUTES` segment — gets shifted anyway, and a large-enough negative shift underflows and aborts the entire operation, even though other real segments in the same file would have shifted correctly.
### Repro
```
$ cat repro.yaml
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Sections:
- Name: .text
Type: SHT_PROGBITS
Size: 0x10
- Name: .riscv.attributes
Type: SHT_PROGBITS
Size: 0x38
ProgramHeaders:
- Type: PT_LOAD
VAddr: 0x1000
FirstSec: .text
LastSec: .text
- Type: 0x70000003 # PT_RISCV_ATTRIBUTES
Flags: [ PF_R ]
VAddr: 0x0
PAddr: 0x0
Align: 0x1
FirstSec: .riscv.attributes
LastSec: .riscv.attributes
$ yaml2obj repro.yaml -o repro.elf
$ llvm-objcopy --change-section-lma *-0x30 repro.elf shifted.elf
error: address 0x0 cannot be decreased by 0x30. The result would underflow
```
I discovered the problem while trying to build a real-world RISC-V ELF (a Zephyr RTOS build for a RISC-V VPR coprocessor core) containing a genuine PT_RISCV_ATTRIBUTES segment using an LLVM toolchain built from the current main (24.0.0). The problem also reproduces with LLVM 19.1.7 that is bundled with Zephyr-SDK-1.0.1. and on current main.
If I configure my build to use the GNU objcopy (also bundled with the same Zephyr SDK) the problem doesn't arise and I get a working executable.
I used Claude to analyze the problem and have created a PR (#218414) with a proposed fix + a new test. The fix is very small and solves the Zephyr problem and passes the llvm-objcopy tests, so it seems that nothing obvious is broken. As I am not versed in the llvm-objcopy nor ELFs there can obviously be something that I don't understand. There seems to have been a previous issue (#124680) that made changes to `--change-section-lma`
### Expected
A segment with no real address `(VAddr == 0 && PAddr == 0)` shouldn't participate in the shift, regardless of its size.
Contributor guide
Research direction
Start with llvm-objcopy's --change-section-lma handling and reproduce the failure using repro.yaml, yaml2obj, and the command shown. Confirm that the unaddressed PT_RISCV_ATTRIBUTES segment does not participate in the shift, while real segments still shift and the operation completes without an underflow error.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 30/100