[llvm-branch-commits] [lld] 73ea825 - [ELF] Make dot in .tbss correct
Fangrui Song via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Aug 4 09:17:35 PDT 2021
Author: Fangrui Song
Date: 2021-08-04T09:06:59-07:00
New Revision: 73ea8254d2d7177e84814688a4523144bdbd2fbb
URL: https://github.com/llvm/llvm-project/commit/73ea8254d2d7177e84814688a4523144bdbd2fbb
DIFF: https://github.com/llvm/llvm-project/commit/73ea8254d2d7177e84814688a4523144bdbd2fbb.diff
LOG: [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
(cherry picked from commit 9bd29a73d17add45234a35de5f6ad7ca8321f7f9)
Added:
Modified:
lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/test/ELF/linkerscript/tbss.s
Removed:
################################################################################
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index a938984ad945e..01785f39ed759 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -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) {
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index 0592c52acb84d..d2487ae0f9d28 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -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;
diff --git a/lld/test/ELF/linkerscript/tbss.s b/lld/test/ELF/linkerscript/tbss.s
index 1560ad5d039a2..1113a797b9170 100644
--- a/lld/test/ELF/linkerscript/tbss.s
+++ b/lld/test/ELF/linkerscript/tbss.s
@@ -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", at 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", at nobits
+ .long 0
+.section second_tbss,"awT", at nobits
+ .byte 0
+.section bar, "aw"
+ .long 0
More information about the llvm-branch-commits
mailing list