An empty output section specified in the `SECTIONS` command (e.g.
`empty : { *(empty) }`) may be discarded. Due to phase ordering, we
might define `__start_empty`/`__stop_empty` symbols with incorrect
section indexes (usually benign, but could go out of bounds and cause
`readelf -s` to print `BAD`).
```
finalizeSections
addStartStopSymbols // __start_empty is defined
// __start_empty is added to .symtab
sortSections
adjustOutputSections // `empty` is discarded
writeSections
// __start_empty is Defined with an invalid section index
```
Loaders use `st_value` members of the start/stop symbols and expect no
"undefined symbol" linker error, but do not particularly care whether
the symbols are defined or undefined. Let's retain the associated empty
output section so that start/stop symbols will have correct section
indexes.
The approach allows us to remove `LinkerScript::isDiscarded`
(https://reviews.llvm.org/D114179). Also delete the
`findSection(".text")` special case from https://reviews.llvm.org/D46200,
which is unnecessary even before this patch (`elfHeader` would be fine
even with very large executables).
Note: we should be careful not to unnecessarily retain .ARM.exidx, which
would create an empty PT_ARM_EXIDX. ~40 tests would need to be updated.
---
An alternative is to discard the empty output section and keep the
start/stop symbols undefined. This approach needs more code and requires
`LinkerScript::isDiscarded` before we discard empty sections in
``adjustOutputSections`.
Pull Request: https://github.com/llvm/llvm-project/pull/96343
45 lines
1.4 KiB
Plaintext
45 lines
1.4 KiB
Plaintext
# REQUIRES: x86
|
|
# RUN: split-file %s %t
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/t.s -o %t.o
|
|
|
|
## PR52534: https://bugs.llvm.org/show_bug.cgi?id=52534
|
|
## Check case where .preinit_array would be discarded in the absence of the
|
|
## start/stop symbols.
|
|
## Link should succeed without causing an out of range relocation error.
|
|
# RUN: ld.lld -T %t/discarded.script %t.o -o %t1 --image-base=0x80000000
|
|
# RUN: llvm-readelf -s %t1 | FileCheck --check-prefixes=CHECK,DISCARDED %s
|
|
|
|
## Check case where .preinit_array is emitted but empty.
|
|
# RUN: ld.lld -T %t/empty.script %t.o -o %t2
|
|
# RUN: llvm-readelf -s %t2 | FileCheck --check-prefixes=CHECK,EMPTY %s
|
|
|
|
# CHECK: [[#%x,ADDR:]] 0 NOTYPE LOCAL HIDDEN [[#]] __preinit_array_start
|
|
# CHECK-NEXT: [[#ADDR]] 0 NOTYPE LOCAL HIDDEN [[#]] __preinit_array_end
|
|
|
|
# DISCARDED-NEXT: {{0*}}[[#ADDR-14]] 0 NOTYPE GLOBAL DEFAULT [[#]] _start
|
|
|
|
# EMPTY-NOT: [[#ADDR]] 0 NOTYPE GLOBAL DEFAULT [[#]] _start
|
|
# EMPTY: [[#ADDR]] 0 NOTYPE GLOBAL DEFAULT [[#]] ADDR
|
|
|
|
#--- t.s
|
|
.global _start
|
|
_start:
|
|
movq __preinit_array_start@GOTPCREL(%rip),%rax
|
|
movq __preinit_array_end@GOTPCREL(%rip),%rax
|
|
|
|
.section .rodata,"a"
|
|
.byte 0
|
|
|
|
#--- discarded.script
|
|
SECTIONS {
|
|
.rodata : { *(.rodata); }
|
|
.text : { *(.text); }
|
|
.preinit_array : { *(.preinit_array); }
|
|
}
|
|
|
|
#--- empty.script
|
|
SECTIONS {
|
|
.text : { *(.text); }
|
|
.preinit_array : { ADDR = .; *(.preinit_array); }
|
|
}
|