mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[ELF] Make dot in .tbss correct
GNU ld doesn't support multiple SHF_TLS SHT_NOBITS output sections (it restores the address after an SHF_TLS SHT_NOBITS section, so consecutive SHF_TLS SHT_NOBITS sections will have conflicting address ranges). That said, `threadBssOffset` implements limited support for consecutive SHF_TLS SHT_NOBITS sections. (SHF_TLS SHT_PROGBITS following a SHF_TLS SHT_NOBITS can still be incorrect.) `.` in an output section description of an SHF_TLS SHT_NOBITS section is incorrect. (https://lists.llvm.org/pipermail/llvm-dev/2021-July/151974.html) This patch saves the end address of the previous tbss section in `ctx->tbssAddr`, changes `dot` in the beginning of `assignOffset` so that `.` evaluation will be correct. Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D107208
This commit is contained in:
parent
b4a1eab941
commit
9bd29a73d1
@ -849,17 +849,8 @@ void LinkerScript::diagnoseOrphanHandling() const {
|
||||
}
|
||||
|
||||
uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) {
|
||||
bool isTbss =
|
||||
(ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS;
|
||||
uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot;
|
||||
start = alignTo(start, alignment);
|
||||
uint64_t end = start + size;
|
||||
|
||||
if (isTbss)
|
||||
ctx->threadBssOffset = end - dot;
|
||||
else
|
||||
dot = end;
|
||||
return end;
|
||||
dot = alignTo(dot, alignment) + size;
|
||||
return dot;
|
||||
}
|
||||
|
||||
void LinkerScript::output(InputSection *s) {
|
||||
@ -931,13 +922,24 @@ static OutputSection *findFirstSection(PhdrEntry *load) {
|
||||
// This function assigns offsets to input sections and an output section
|
||||
// for a single sections command (e.g. ".text { *(.text); }").
|
||||
void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
const bool isTbss = (sec->flags & SHF_TLS) && sec->type == SHT_NOBITS;
|
||||
const bool sameMemRegion = ctx->memRegion == sec->memRegion;
|
||||
const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
|
||||
const uint64_t savedDot = dot;
|
||||
ctx->memRegion = sec->memRegion;
|
||||
ctx->lmaRegion = sec->lmaRegion;
|
||||
|
||||
if (sec->flags & SHF_ALLOC) {
|
||||
if (!(sec->flags & SHF_ALLOC)) {
|
||||
// Non-SHF_ALLOC sections have zero addresses.
|
||||
dot = 0;
|
||||
} else if (isTbss) {
|
||||
// Allow consecutive SHF_TLS SHT_NOBITS output sections. The address range
|
||||
// starts from the end address of the previous tbss section.
|
||||
if (ctx->tbssAddr == 0)
|
||||
ctx->tbssAddr = dot;
|
||||
else
|
||||
dot = ctx->tbssAddr;
|
||||
} else {
|
||||
if (ctx->memRegion)
|
||||
dot = ctx->memRegion->curPos;
|
||||
if (sec->addrExpr)
|
||||
@ -950,9 +952,6 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
if (ctx->memRegion && ctx->memRegion->curPos < dot)
|
||||
expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
|
||||
ctx->memRegion->name, sec->name);
|
||||
} else {
|
||||
// Non-SHF_ALLOC sections have zero addresses.
|
||||
dot = 0;
|
||||
}
|
||||
|
||||
switchTo(sec);
|
||||
@ -1008,8 +1007,13 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
|
||||
// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
|
||||
// as they are not part of the process image.
|
||||
if (!(sec->flags & SHF_ALLOC))
|
||||
if (!(sec->flags & SHF_ALLOC)) {
|
||||
dot = savedDot;
|
||||
} else if (isTbss) {
|
||||
// NOBITS TLS sections are similar. Additionally save the end address.
|
||||
ctx->tbssAddr = dot;
|
||||
dot = savedDot;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isDiscardable(OutputSection &sec) {
|
||||
|
@ -247,11 +247,11 @@ class LinkerScript final {
|
||||
// not be used outside of the scope of a call to the above functions.
|
||||
struct AddressState {
|
||||
AddressState();
|
||||
uint64_t threadBssOffset = 0;
|
||||
OutputSection *outSec = nullptr;
|
||||
MemoryRegion *memRegion = nullptr;
|
||||
MemoryRegion *lmaRegion = nullptr;
|
||||
uint64_t lmaOffset = 0;
|
||||
uint64_t tbssAddr = 0;
|
||||
};
|
||||
|
||||
llvm::DenseMap<StringRef, OutputSection *> nameToOutputSection;
|
||||
|
@ -1,42 +1,43 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
# RUN: echo "SECTIONS { \
|
||||
# RUN: echo 'SECTIONS { \
|
||||
# RUN: . = SIZEOF_HEADERS; \
|
||||
# RUN: .text : { *(.text) } \
|
||||
# RUN: foo : { *(foo) } \
|
||||
# RUN: .tbss : { __tbss_start = .; *(.tbss) __tbss_end = .; } \
|
||||
# RUN: second_tbss : { second_tbss_start = .; *(second_tbss) second_tbss_end = .; } \
|
||||
# RUN: bar : { *(bar) } \
|
||||
# RUN: }" > %t.script
|
||||
# RUN: ld.lld -T %t.script %t.o -o %t
|
||||
# RUN: llvm-readobj -S %t | FileCheck %s
|
||||
# RUN: }' > %t.lds
|
||||
# RUN: ld.lld -T %t.lds %t.o -o %t1
|
||||
# RUN: llvm-readelf -S -s %t1 | FileCheck %s
|
||||
|
||||
# test that a tbss section doesn't use address space.
|
||||
# RUN: echo 'PHDRS { text PT_LOAD; }' > %th.lds
|
||||
# RUN: cat %th.lds %t.lds > %t2.lds
|
||||
# RUN: ld.lld -T %t.lds %t.o -o %t2
|
||||
# RUN: llvm-readelf -S -s %t2 | FileCheck %s
|
||||
|
||||
# CHECK: Name: foo
|
||||
# CHECK-NEXT: Type: SHT_NOBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_TLS
|
||||
# CHECK-NEXT: SHF_WRITE
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x[[ADDR:.*]]
|
||||
# CHECK-NEXT: Offset: 0x[[ADDR]]
|
||||
# CHECK-NEXT: Size: 4
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index:
|
||||
# CHECK-NEXT: Name: bar
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_WRITE
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x[[ADDR]]
|
||||
## Test that a tbss section doesn't affect the start address of the next section.
|
||||
|
||||
.section foo,"awT",@nobits
|
||||
.long 0
|
||||
.section bar, "aw"
|
||||
.long 0
|
||||
# CHECK: Name Type Address Off Size ES Flg
|
||||
# CHECK: .tbss NOBITS [[#%x,ADDR:]] [[#%x,OFF:]] 000004 00 WAT
|
||||
# CHECK: second_tbss NOBITS {{0+}}[[#%x,ADDR+4]] {{0+}}[[#%x,OFF]] 000001 00 WAT
|
||||
# CHECK: bar PROGBITS {{0+}}[[#%x,ADDR]] {{0+}}[[#%x,OFF]] 000004 00 WA
|
||||
|
||||
## Test that . in a tbss section represents the current location, even if the
|
||||
## address will be reset.
|
||||
|
||||
# CHECK: Value {{.*}} Name
|
||||
# CHECK: {{0+}}[[#%x,ADDR]] {{.*}} __tbss_start
|
||||
# CHECK: {{0+}}[[#%x,ADDR+4]] {{.*}} __tbss_end
|
||||
# CHECK: {{0+}}[[#%x,ADDR+4]] {{.*}} second_tbss_start
|
||||
# CHECK: {{0+}}[[#%x,ADDR+5]] {{.*}} second_tbss_end
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
nop
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.long 0
|
||||
.section second_tbss,"awT",@nobits
|
||||
.byte 0
|
||||
.section bar, "aw"
|
||||
.long 0
|
||||
|
Loading…
Reference in New Issue
Block a user