diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -908,13 +908,29 @@ uint32_t sectionIndex = 0; for (OutputSegment *seg : outputSegments) { seg->sortOutputSections(); + // References from thread-local variable sections are treated as offsets + // relative to the start of the thread-local data memory area, which + // is initialized via copying all the TLV data sections (which are all + // contiguous). If later data sections require a greater alignment than + // earlier ones, the offsets of data within those sections won't be + // guaranteed to aligned unless we normalize alignments. We use the largest + // alignment for all TLV data sections. + uint32_t tlv_align = 0; + for (OutputSection *osec : seg->getSections()) { + if (isThreadLocalData(osec->flags) && osec->align > tlv_align) { + tlv_align = osec->align; + } + } for (OutputSection *osec : seg->getSections()) { // Now that the output sections are sorted, assign the final // output section indices. if (!osec->isHidden()) osec->index = ++sectionIndex; - if (!firstTLVDataSection && isThreadLocalData(osec->flags)) - firstTLVDataSection = osec; + if (isThreadLocalData(osec->flags)) { + if (!firstTLVDataSection) + firstTLVDataSection = osec; + osec->align = tlv_align; + } if (!isecPriorities.empty()) { if (auto *merged = dyn_cast(osec)) { diff --git a/lld/test/MachO/tlv.s b/lld/test/MachO/tlv.s --- a/lld/test/MachO/tlv.s +++ b/lld/test/MachO/tlv.s @@ -41,6 +41,7 @@ # TBSS: <_f>: # TBSS-NEXT: leaq {{.*}}(%rip), %rax ## {{.*}} <_baz> # TBSS-NEXT: leaq {{.*}}(%rip), %rax ## {{.*}} <_qux> +# TBSS-NEXT: leaq {{.*}}(%rip), %rax ## {{.*}} <_hoge> # TBSS-NEXT: retq # REG-TLVP: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @@ -53,10 +54,12 @@ # REG-TBSS-TLVP: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 +# REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 # REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# REG-TBSS-TLVP-NEXT: 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 +# REG-TBSS-TLVP-NEXT: 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 +# REG-TBSS-TLVP-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# REG-TBSS-TLVP-NEXT: 30 00 00 00 00 00 00 00 ## Make sure we don't emit rebase opcodes for relocations in __thread_vars. # LINKEDIT: Rebase table: @@ -102,10 +105,12 @@ _f: mov _baz@TLVP(%rip), %rax mov _qux@TLVP(%rip), %rax + mov _hoge@TLVP(%rip), %rax ret .tbss _baz$tlv$init, 8, 3 .tbss _qux$tlv$init, 8, 3 +.tbss _hoge$tlv$init, 16, 4 .section __DATA,__thread_vars,thread_local_variables _baz: @@ -116,3 +121,7 @@ .quad __tlv_bootstrap .quad 0 .quad _qux$tlv$init +_hoge: + .quad __tlv_bootstrap + .quad 0 + .quad _hoge$tlv$init