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; @@ -738,6 +744,18 @@ // Parses -image-base option. static uint64_t getImageBase(opt::InputArgList &Args) { + // When -T
option is specified, lowest VA value + // becomes the image base address. + if (!Config->SectionStartMap.empty()) { + uint64_t VA = (uint64_t)-1; + for (auto I = Config->SectionStartMap.begin(); + I != Config->SectionStartMap.end(); ++I) { + if (VA > I->second) + VA = I->second; + } + return VA; + } + // Use default if no -image-base option is given. // Because we are using "Target" here, this function // has to be called after the variable is initialized. 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); @@ -1343,7 +1350,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