Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -65,6 +65,7 @@ struct Configuration { Symbol *EntrySym = nullptr; InputFile *FirstElf = nullptr; + llvm::StringMap SectionStartMap; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -380,6 +380,33 @@ return StripPolicy::None; } +static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { + uint64_t VA = 0; + if (S.startswith("0x")) + S = S.drop_front(2); + if (S.getAsInteger(16, VA)) + error("invalid argument: " + stringize(Arg)); + return VA; +} + +static StringMap getSectionStartMap(opt::InputArgList &Args) { + StringMap Ret; + for (auto *Arg : Args.filtered(OPT_section_start)) { + StringRef Name; + StringRef Addr; + std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); + Ret[Name] = parseSectionAddress(Addr, Arg); + } + + if (auto *Arg = Args.getLastArg(OPT_Ttext)) + Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg); + if (auto *Arg = Args.getLastArg(OPT_Tdata)) + Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg); + if (auto *Arg = Args.getLastArg(OPT_Tbss)) + Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg); + return Ret; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -391,6 +418,8 @@ if (!RPaths.empty()) Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); + Config->SectionStartMap = getSectionStartMap(Args); + if (auto *Arg = Args.getLastArg(OPT_m)) { // Parse ELF{32,64}{LE,BE} and CPU type. StringRef S = Arg->getValue(); Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -27,6 +27,12 @@ def O: Joined<["-"], "O">, HelpText<"Optimize output file size">; +def Tbss: J<"Tbss=">, HelpText<"Same as --section-start with .bss as the sectionname">; + +def Tdata: J<"Tdata=">, HelpText<"Same as --section-start with .data as the sectionname">; + +def Ttext: J<"Ttext=">, HelpText<"Same as --section-start with .text as the sectionname">; + def allow_multiple_definition: F<"allow-multiple-definition">, HelpText<"Allow multiple definitions">; @@ -147,6 +153,9 @@ def script: S<"script">, HelpText<"Read linker script">; +def section_start: S<"section-start">, MetaVarName<"
">, + HelpText<"Set address of section">; + def shared: F<"shared">, HelpText<"Build a shared object">; def soname: J<"soname=">, HelpText<"Set DT_SONAME">; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -1080,6 +1080,10 @@ if (Sec->PageAlign) Alignment = std::max(Alignment, Target->PageSize); + auto I = Config->SectionStartMap.find(Sec->getName()); + if (I != Config->SectionStartMap.end()) + VA = I->second; + // We only assign VAs to allocated sections. if (needsPtLoad(Sec)) { VA = alignTo(VA, Alignment); Index: lld/trunk/test/ELF/sectionstart.s =================================================================== --- lld/trunk/test/ELF/sectionstart.s +++ lld/trunk/test/ELF/sectionstart.s @@ -0,0 +1,57 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o --section-start .text=0x100000 \ +# RUN: --section-start .data=0x110000 --section-start .bss=0x200000 -o %t +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT DATA +# CHECK-NEXT: 2 .data 00000004 0000000000110000 DATA +# CHECK-NEXT: 3 .bss 00000004 0000000000200000 BSS + +## The same, but dropped "0x" prefix. +# RUN: ld.lld %t.o --section-start .text=100000 \ +# RUN: --section-start .data=110000 --section-start .bss=0x200000 -o %t1 +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s + +## Use -Ttext, -Tdata, -Tbss as replacement for --section-start: +# RUN: ld.lld %t.o -Ttext=0x100000 -Tdata=0x110000 -Tbss=0x200000 -o %t4 +# RUN: llvm-objdump -section-headers %t4 | FileCheck %s + +## The same, but dropped "0x" prefix. +# RUN: ld.lld %t.o -Ttext=100000 -Tdata=110000 -Tbss=200000 -o %t5 +# RUN: llvm-objdump -section-headers %t5 | FileCheck %s + +## Errors: +# RUN: not ld.lld %t.o --section-start .text100000 -o %t2 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR1 %s +# ERR1: invalid argument: --section-start .text100000 + +# RUN: not ld.lld %t.o --section-start .text=1Q0000 -o %t3 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR2 %s +# ERR2: invalid argument: --section-start .text=1Q0000 + +# RUN: not ld.lld %t.o -Ttext=1w0000 -o %t6 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR3 %s +# ERR3: invalid argument: -Ttext=1w0000 + +# RUN: not ld.lld %t.o -Tbss=1w0000 -o %t6 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR4 %s +# ERR4: invalid argument: -Tbss=1w0000 + +# RUN: not ld.lld %t.o -Tdata=1w0000 -o %t6 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR5 %s +# ERR5: invalid argument: -Tdata=1w0000 + +.text +.globl _start +_start: + nop + +.data +.long 0 + +.bss +.zero 4