Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -101,6 +101,7 @@ bool SysvHash = true; bool Threads; bool Trace; + uint64_t VAStart = -1; bool Verbose; bool VersionScriptGlobalByDefault = true; bool WarnCommon; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -531,6 +531,14 @@ Config->EntrySym = Symtab.addUndefined(S); } + if (auto *Arg = Args.getLastArg(OPT_Ttext_segment)) { + StringRef S = Arg->getValue(); + if (S.getAsInteger(0, Config->VAStart)) + error(Arg->getSpelling() + ": number expected, but got " + S); + else if ((Config->VAStart % Target->PageSize) != 0) + warning(Arg->getSpelling() + ": address isn't multiple of page size"); + } + for (std::unique_ptr &F : Files) Symtab.addFile(std::move(F)); if (HasError) Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -150,6 +150,8 @@ def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">; +def Ttext_segment : J<"Ttext-segment=">, HelpText<"Set the base address">; + def undefined: J<"undefined=">, HelpText<"Force undefined symbol during linking">; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1126,11 +1126,15 @@ } } +static uint64_t getVAStart() { + return Config->VAStart != uint64_t(-1) ? Config->VAStart : Target->getVAStart(); +} + // 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. template void Writer::fixHeaders() { - uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : Target->getVAStart(); + uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : getVAStart(); Out::ElfHeader->setVA(BaseVA); uintX_t Off = Out::ElfHeader->getSize(); Out::ProgramHeaders->setVA(Off + BaseVA); @@ -1138,7 +1142,7 @@ // Assign VAs (addresses at run-time) to output sections. template void Writer::assignAddresses() { - uintX_t VA = Target->getVAStart() + Out::ElfHeader->getSize() + + uintX_t VA = getVAStart() + Out::ElfHeader->getSize() + Out::ProgramHeaders->getSize(); uintX_t ThreadBssOffset = 0; Index: test/ELF/ttext-segment.s =================================================================== --- /dev/null +++ test/ELF/ttext-segment.s @@ -0,0 +1,60 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld -Ttext-segment=0x1000000 %t -o %t1 +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s + +.global _start +_start: + nop + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_PHDR (0x6) +# CHECK-NEXT: Offset: 0x40 +# CHECK-NEXT: VirtualAddress: 0x1000040 +# CHECK-NEXT: PhysicalAddress: 0x1000040 +# CHECK-NEXT: FileSize: 224 +# CHECK-NEXT: MemSize: 224 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 8 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x1000000 +# CHECK-NEXT: PhysicalAddress: 0x1000000 +# CHECK-NEXT: FileSize: 288 +# CHECK-NEXT: MemSize: 288 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1001000 +# CHECK-NEXT: PhysicalAddress: 0x1001000 +# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: MemSize: 1 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 0 +# CHECK-NEXT: MemSize: 0 +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 0 +# CHECK-NEXT: }