Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -581,6 +581,12 @@ if (!Config->Relocatable) Config->Strip = getStripOption(Args); + // When user gives -Ttext/-Tdata/-Tbss GNU linkers either set addresses + // of corresponding sections or addressed for PT_LOADs. That means we want + // to have "text segment" to work with. It includes RO sections as well. + if (!Config->SectionStartMap.empty()) + Config->SingleRoRx = true; + // Config->Pic is true if we are generating position-independent code. Config->Pic = Config->Pie || Config->Shared; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -569,6 +569,13 @@ if (AIsNoBits != BIsNoBits) return BIsNoBits; + // We want to put section specified by -T option first, so we + // can start assigning VA starting from them later. + bool AHasAddrSet = Config->SectionStartMap.count(A->getName()); + bool BHasAddrSet = Config->SectionStartMap.count(B->getName()); + if (AHasAddrSet != BHasAddrSet) + return AHasAddrSet; + // We place RelRo section before plain r/w ones. bool AIsRelRo = isRelroSection(A); bool BIsRelRo = isRelroSection(B); @@ -1285,6 +1292,22 @@ } } +template static uint64_t getVABase() { + if (Config->SectionStartMap.empty()) + return Config->ImageBase; + + uint64_t VA = (uint64_t)-1; + for (auto I = Config->SectionStartMap.begin(); + I != Config->SectionStartMap.end(); ++I) { + if (VA > I->second) + VA = I->second; + } + uint64_t HeadersSize = getHeaderSize(); + if (VA > HeadersSize) + return VA - HeadersSize; + return VA; +} + // We should set file offsets and VAs for elf header and program headers // sections. These are special, we do not include them into output sections // list, but have them to simplify the code. @@ -1293,14 +1316,14 @@ // If the script has SECTIONS, assignAddresses will compute the values. if (ScriptConfig->HasSections) return; - uintX_t BaseVA = Config->ImageBase; + uintX_t BaseVA = getVABase(); Out::ElfHeader->Addr = BaseVA; Out::ProgramHeaders->Addr = BaseVA + Out::ElfHeader->Size; } // Assign VAs (addresses at run-time) to output sections. template void Writer::assignAddresses() { - uintX_t VA = Config->ImageBase + getHeaderSize(); + uintX_t VA = getVABase() + getHeaderSize(); uintX_t ThreadBssOffset = 0; for (OutputSectionBase *Sec : OutputSections) { uintX_t Alignment = Sec->Addralign; @@ -1343,7 +1366,10 @@ // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). - return First->Offset + Sec->Addr - First->Addr; + // We take max value here for case when user set VA of section using -T + // below address of headers. We do not align offsets then, that is + // consistent with bfd behavior. + return std::max(Off, First->Offset + Sec->Addr - First->Addr); } template Index: test/ELF/ttext-tdata-tbss.s =================================================================== --- test/ELF/ttext-tdata-tbss.s +++ test/ELF/ttext-tdata-tbss.s @@ -0,0 +1,43 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +## Show what regular output gives to us. +# RUN: ld.lld %t -o %t1 +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .rodata 00000008 0000000000200158 DATA +# CHECK-NEXT: 2 .text 00000001 0000000000201000 TEXT DATA +# CHECK-NEXT: 3 .aw 00000008 0000000000202000 DATA +# CHECK-NEXT: 4 .data 00000008 0000000000202008 DATA +# CHECK-NEXT: 5 .bss 00000008 0000000000202010 BSS + +## Check that user can assing addressed for sections using -T option. +# RUN: ld.lld -Ttext 0x0 -Tdata 0x2000 -Tbss 0x4000 %t -o %t1 +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s --check-prefix=USERADDR +# USERADDR: Sections: +# USERADDR-NEXT: Idx Name Size Address Type +# USERADDR-NEXT: 0 00000000 0000000000000000 +# USERADDR-NEXT: 1 .text 00000001 0000000000000000 TEXT DATA +# USERADDR-NEXT: 2 .rodata 00000008 0000000000000001 DATA +# USERADDR-NEXT: 3 .data 00000008 0000000000002000 DATA +# USERADDR-NEXT: 4 .aw 00000008 0000000000002008 DATA +# USERADDR-NEXT: 5 .bss 00000008 0000000000004000 BSS + +.text +.globl _start +_start: + nop + +.section .rodata,"a" + .quad 0 + +.section .aw,"aw" + .quad 0 + +.section .data,"aw" + .quad 0 + +.section .bss,"",@nobits + .quad 0