Skip to content

Commit 9bd29a7

Browse files
committed
[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
1 parent b4a1eab commit 9bd29a7

File tree

3 files changed

+56
-51
lines changed

3 files changed

+56
-51
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -849,17 +849,8 @@ void LinkerScript::diagnoseOrphanHandling() const {
849849
}
850850

851851
uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) {
852-
bool isTbss =
853-
(ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS;
854-
uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot;
855-
start = alignTo(start, alignment);
856-
uint64_t end = start + size;
857-
858-
if (isTbss)
859-
ctx->threadBssOffset = end - dot;
860-
else
861-
dot = end;
862-
return end;
852+
dot = alignTo(dot, alignment) + size;
853+
return dot;
863854
}
864855

865856
void LinkerScript::output(InputSection *s) {
@@ -931,13 +922,24 @@ static OutputSection *findFirstSection(PhdrEntry *load) {
931922
// This function assigns offsets to input sections and an output section
932923
// for a single sections command (e.g. ".text { *(.text); }").
933924
void LinkerScript::assignOffsets(OutputSection *sec) {
925+
const bool isTbss = (sec->flags & SHF_TLS) && sec->type == SHT_NOBITS;
934926
const bool sameMemRegion = ctx->memRegion == sec->memRegion;
935927
const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
936928
const uint64_t savedDot = dot;
937929
ctx->memRegion = sec->memRegion;
938930
ctx->lmaRegion = sec->lmaRegion;
939931

940-
if (sec->flags & SHF_ALLOC) {
932+
if (!(sec->flags & SHF_ALLOC)) {
933+
// Non-SHF_ALLOC sections have zero addresses.
934+
dot = 0;
935+
} else if (isTbss) {
936+
// Allow consecutive SHF_TLS SHT_NOBITS output sections. The address range
937+
// starts from the end address of the previous tbss section.
938+
if (ctx->tbssAddr == 0)
939+
ctx->tbssAddr = dot;
940+
else
941+
dot = ctx->tbssAddr;
942+
} else {
941943
if (ctx->memRegion)
942944
dot = ctx->memRegion->curPos;
943945
if (sec->addrExpr)
@@ -950,9 +952,6 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
950952
if (ctx->memRegion && ctx->memRegion->curPos < dot)
951953
expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
952954
ctx->memRegion->name, sec->name);
953-
} else {
954-
// Non-SHF_ALLOC sections have zero addresses.
955-
dot = 0;
956955
}
957956

958957
switchTo(sec);
@@ -1008,8 +1007,13 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
10081007

10091008
// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
10101009
// as they are not part of the process image.
1011-
if (!(sec->flags & SHF_ALLOC))
1010+
if (!(sec->flags & SHF_ALLOC)) {
10121011
dot = savedDot;
1012+
} else if (isTbss) {
1013+
// NOBITS TLS sections are similar. Additionally save the end address.
1014+
ctx->tbssAddr = dot;
1015+
dot = savedDot;
1016+
}
10131017
}
10141018

10151019
static bool isDiscardable(OutputSection &sec) {

lld/ELF/LinkerScript.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,11 @@ class LinkerScript final {
247247
// not be used outside of the scope of a call to the above functions.
248248
struct AddressState {
249249
AddressState();
250-
uint64_t threadBssOffset = 0;
251250
OutputSection *outSec = nullptr;
252251
MemoryRegion *memRegion = nullptr;
253252
MemoryRegion *lmaRegion = nullptr;
254253
uint64_t lmaOffset = 0;
254+
uint64_t tbssAddr = 0;
255255
};
256256

257257
llvm::DenseMap<StringRef, OutputSection *> nameToOutputSection;

lld/test/ELF/linkerscript/tbss.s

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,43 @@
11
# REQUIRES: x86
22
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
3-
# RUN: echo "SECTIONS { \
3+
# RUN: echo 'SECTIONS { \
44
# RUN: . = SIZEOF_HEADERS; \
55
# RUN: .text : { *(.text) } \
6-
# RUN: foo : { *(foo) } \
6+
# RUN: .tbss : { __tbss_start = .; *(.tbss) __tbss_end = .; } \
7+
# RUN: second_tbss : { second_tbss_start = .; *(second_tbss) second_tbss_end = .; } \
78
# RUN: bar : { *(bar) } \
8-
# RUN: }" > %t.script
9-
# RUN: ld.lld -T %t.script %t.o -o %t
10-
# RUN: llvm-readobj -S %t | FileCheck %s
9+
# RUN: }' > %t.lds
10+
# RUN: ld.lld -T %t.lds %t.o -o %t1
11+
# RUN: llvm-readelf -S -s %t1 | FileCheck %s
1112

12-
# test that a tbss section doesn't use address space.
13+
# RUN: echo 'PHDRS { text PT_LOAD; }' > %th.lds
14+
# RUN: cat %th.lds %t.lds > %t2.lds
15+
# RUN: ld.lld -T %t.lds %t.o -o %t2
16+
# RUN: llvm-readelf -S -s %t2 | FileCheck %s
1317

14-
# CHECK: Name: foo
15-
# CHECK-NEXT: Type: SHT_NOBITS
16-
# CHECK-NEXT: Flags [
17-
# CHECK-NEXT: SHF_ALLOC
18-
# CHECK-NEXT: SHF_TLS
19-
# CHECK-NEXT: SHF_WRITE
20-
# CHECK-NEXT: ]
21-
# CHECK-NEXT: Address: 0x[[ADDR:.*]]
22-
# CHECK-NEXT: Offset: 0x[[ADDR]]
23-
# CHECK-NEXT: Size: 4
24-
# CHECK-NEXT: Link: 0
25-
# CHECK-NEXT: Info: 0
26-
# CHECK-NEXT: AddressAlignment: 1
27-
# CHECK-NEXT: EntrySize: 0
28-
# CHECK-NEXT: }
29-
# CHECK-NEXT: Section {
30-
# CHECK-NEXT: Index:
31-
# CHECK-NEXT: Name: bar
32-
# CHECK-NEXT: Type: SHT_PROGBITS
33-
# CHECK-NEXT: Flags [
34-
# CHECK-NEXT: SHF_ALLOC
35-
# CHECK-NEXT: SHF_WRITE
36-
# CHECK-NEXT: ]
37-
# CHECK-NEXT: Address: 0x[[ADDR]]
18+
## Test that a tbss section doesn't affect the start address of the next section.
3819

39-
.section foo,"awT",@nobits
40-
.long 0
41-
.section bar, "aw"
42-
.long 0
20+
# CHECK: Name Type Address Off Size ES Flg
21+
# CHECK: .tbss NOBITS [[#%x,ADDR:]] [[#%x,OFF:]] 000004 00 WAT
22+
# CHECK: second_tbss NOBITS {{0+}}[[#%x,ADDR+4]] {{0+}}[[#%x,OFF]] 000001 00 WAT
23+
# CHECK: bar PROGBITS {{0+}}[[#%x,ADDR]] {{0+}}[[#%x,OFF]] 000004 00 WA
24+
25+
## Test that . in a tbss section represents the current location, even if the
26+
## address will be reset.
27+
28+
# CHECK: Value {{.*}} Name
29+
# CHECK: {{0+}}[[#%x,ADDR]] {{.*}} __tbss_start
30+
# CHECK: {{0+}}[[#%x,ADDR+4]] {{.*}} __tbss_end
31+
# CHECK: {{0+}}[[#%x,ADDR+4]] {{.*}} second_tbss_start
32+
# CHECK: {{0+}}[[#%x,ADDR+5]] {{.*}} second_tbss_end
33+
34+
.globl _start
35+
_start:
36+
nop
37+
38+
.section .tbss,"awT",@nobits
39+
.long 0
40+
.section second_tbss,"awT",@nobits
41+
.byte 0
42+
.section bar, "aw"
43+
.long 0

0 commit comments

Comments
 (0)