llvm-objcopy rejects OS-specific reserved `st_shndx` such as Linux `SHN_LIVEPATCH` (`0xff20`)
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Behavior difference
I have an ELF object containing a symbol whose `st_shndx` is `0xff20`.
On Linux, `0xff20` is not an arbitrary value: it is `SHN_LIVEPATCH`, used by the kernel livepatch module ELF format for certain `.klp.sym.*` symbols.
`readelf -sW` shows the symbol as an OS-specific section index:
FUNC GLOBAL DEFAULT OS [0xff20] foo
GNU objcopy accepts the object and can perform a simple transformation:
objcopy --add-section .note.test=empty.bin repro.osff20 repro.gnu.addsec
llvm-objcopy rejects the same input:
llvm-objcopy --add-section .note.test=empty.bin repro.osff20 repro.llvm.addsec
with:
llvm-objcopy: error: symbol 'foo' has unsupported value greater than or equal to SHN_LORESERVE: 65312
65312 == 0xff20.
## Code blocks:
The failure appears to come from llvm/lib/ObjCopy/ELF/ELFObject.cpp.
`isValidReservedSectionIndex()` uses a small whitelist:
```c
static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) {
switch (Index) {
case SHN_ABS:
case SHN_COMMON:
return true;
}
if (Machine == EM_AMDGPU)
return Index == SHN_AMDGPU_LDS;
if (Machine == EM_MIPS) {
switch (Index) {
case SHN_MIPS_ACOMMON:
case SHN_MIPS_SCOMMON:
case SHN_MIPS_SUNDEFINED:
return true;
}
}
if (Machine == EM_HEXAGON) {
switch (Index) {
case SHN_HEXAGON_SCOMMON:
case SHN_HEXAGON_SCOMMON_1:
case SHN_HEXAGON_SCOMMON_2:
case SHN_HEXAGON_SCOMMON_4:
case SHN_HEXAGON_SCOMMON_8:
return true;
}
}
return false;
}
```
Then symbol-table loading hard-fails for any other value greater than or equal to SHN_LORESERVE:
```
} else if (Sym.st_shndx >= SHN_LORESERVE) {
if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
return createStringError(
errc::invalid_argument,
"symbol '" + *Name +
"' has unsupported value greater than or equal "
"to SHN_LORESERVE: " +
Twine(Sym.st_shndx));
}
}
```
Therefore:
```
Sym.st_shndx = 0xff20
0xff20 >= SHN_LORESERVE
0xff20 is not in the whitelist
```
=> llvm-objcopy rejects the object
## ELF expectation
My understanding is that st_shndx >= SHN_LORESERVE and SHN_LOOS..SHN_HIOS is reserved for OS-specific semantics.
Linux uses one of those values:
```
#define SHN_LIVEPATCH 0xff20
```
This is used by Linux livepatch modules and documented in the kernel livepatch module ELF format.
So this is not a synthetic invalid section index. The minimal reproducer only constructs the smallest object that carries the same real-world ABI condition: an OS-specific reserved symbol section index used by Linux livepatch.
## Questions
Is llvm-objcopy intentionally rejecting all reserved st_shndx values except for a narrow whitelist?
For an object-copying tool, should OS-specific reserved indexes such as SHN_LOOS..SHN_HIOS be preserved rather than rejected, especially when the transformation does not need to interpret the symbol?
At minimum, should LLVM accept Linux SHN_LIVEPATCH (0xff20)?
Possible fixes could be either:
```
if (Index == 0xff20) // Linux SHN_LIVEPATCH: include/uapi/linux/elf.h:#define SHN_LIVEPATCH 0xff20
return true;
```
or, more generally:
```
if (Index >= SHN_LOOS && Index <= SHN_HIOS) // #define SHN_LOOS 0xFF20 /* OS specific semantics, lo */
return true;
```
The latter seems closer to the ELF idea that this range is available for OS-specific semantics, while the former is a narrower Linux-specific compatibility fix.
Contributor guide
Assessment
This issue has not been assessed yet.