diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -247,7 +247,6 @@ // 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; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -849,17 +849,8 @@ } 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) { @@ -1008,7 +999,11 @@ // 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)) + // + // NOBITS TLS sections reset the location as well. Having another TLS section + // below sec is unsupported and regarded as user error. + if (!(sec->flags & SHF_ALLOC) || + ((sec->flags & SHF_TLS) && sec->type == SHT_NOBITS)) dot = savedDot; } diff --git a/lld/test/ELF/linkerscript/multiple-tbss.s b/lld/test/ELF/linkerscript/multiple-tbss.s --- a/lld/test/ELF/linkerscript/multiple-tbss.s +++ b/lld/test/ELF/linkerscript/multiple-tbss.s @@ -1,4 +1,7 @@ # REQUIRES: x86 +## Having another TLS section below a SHF_TLS SHT_NOBITS is unsupported. +## This test just demonstrates the behavior. + # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS { }" > %t.script # RUN: ld.lld -T %t.script %t.o -o %t @@ -37,7 +40,7 @@ # CHECK-NEXT: VirtualAddress: # CHECK-NEXT: PhysicalAddress: # CHECK-NEXT: FileSize: 0 -# CHECK-NEXT: MemSize: 9 +# CHECK-NEXT: MemSize: 1 .section .tbss,"awT",@nobits .quad 0 diff --git a/lld/test/ELF/linkerscript/tbss.s b/lld/test/ELF/linkerscript/tbss.s --- a/lld/test/ELF/linkerscript/tbss.s +++ b/lld/test/ELF/linkerscript/tbss.s @@ -3,38 +3,24 @@ # RUN: echo "SECTIONS { \ # RUN: . = SIZEOF_HEADERS; \ # RUN: .text : { *(.text) } \ -# RUN: foo : { *(foo) } \ +# RUN: foo : { __tbss_start = .; *(foo) __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: llvm-readelf -S -s %t | FileCheck %s -# test that a tbss section doesn't use address space. +## Test that a tbss section doesn't affect the start address of the next section. -# 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]] +# CHECK: Name Type Address Off Size ES Flg +# CHECK: foo NOBITS [[#%x,ADDR:]] [[#%x,OFF:]] 000004 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 .section foo,"awT",@nobits .long 0 diff --git a/lld/test/ELF/tls.s b/lld/test/ELF/tls.s --- a/lld/test/ELF/tls.s +++ b/lld/test/ELF/tls.s @@ -31,6 +31,10 @@ movl %fs:c@tpoff, %eax movl %fs:d@tpoff, %eax +/// There are more than two SHF_TLS SHT_NOBITS sections (user error). +/// The first SHF_TLS SHT_NOBITS collides with the following SHF_TLS +/// in addresses, so the output is not meaningful. +/// The GNU ld output is similar. .global a .section .tbss,"awT",@nobits a: @@ -112,7 +116,7 @@ // 0x2021F4 = TBSS_ADDR + 4 -// CHECK-NEXT: Address: 0x2021F4 +// CHECK-NEXT: Address: 0x2021F0 // CHECK-NEXT: Offset: // CHECK-NEXT: Size: 4 // CHECK-NEXT: Link: @@ -138,7 +142,7 @@ // CHECK-NEXT: VirtualAddress: [[TDATA_ADDR]] // CHECK-NEXT: PhysicalAddress: [[TDATA_ADDR]] // CHECK-NEXT: FileSize: 8 -// CHECK-NEXT: MemSize: 16 +// CHECK-NEXT: MemSize: 12 // CHECK-NEXT: Flags [ // CHECK-NEXT: PF_R // CHECK-NEXT: ] @@ -165,7 +169,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: c -// CHECK-NEXT: Value: 0xC +// CHECK-NEXT: Value: 0x8 // CHECK-NEXT: Size: // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: TLS @@ -185,7 +189,7 @@ // DIS: Disassembly of section .text: // DIS-EMPTY: // DIS-NEXT: <_start>: -// DIS-NEXT: movl %fs:-8, %eax -// DIS-NEXT: movl %fs:-16, %eax // DIS-NEXT: movl %fs:-4, %eax // DIS-NEXT: movl %fs:-12, %eax +// DIS-NEXT: movl %fs:-4, %eax +// DIS-NEXT: movl %fs:-8, %eax