Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -166,7 +166,7 @@ uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t ErrorLimit = 20; - uint64_t ImageBase; + llvm::Optional ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; unsigned LTOPartitions; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -916,13 +916,12 @@ } // Parses -image-base option. -static uint64_t getImageBase(opt::InputArgList &Args) { - // 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. +static Optional getImageBase(opt::InputArgList &Args) { + // Because we are using "Config->MaxPageSize" here, this function has to be + // called after the variable is initialized. auto *Arg = Args.getLastArg(OPT_image_base); if (!Arg) - return Config->Pic ? 0 : Target->DefaultImageBase; + return Optional(); StringRef S = Arg->getValue(); uint64_t V; Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -238,6 +238,7 @@ bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } + uint64_t getImageBase(); void discard(ArrayRef V); ExprValue getSymbolValue(const Twine &Loc, StringRef S); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -346,6 +346,19 @@ return Ret; } +static uint64_t getInitialDot() { + // By default linker scripts use an initial value of 0 for '.', but prefer + // -image-base if set. + return Config->ImageBase ? *Config->ImageBase : 0; +} + +uint64_t LinkerScript::getImageBase() { + // Use -image-base if set. Fall back to the target default if not. + if (Config->ImageBase) + return *Config->ImageBase; + return Config->Pic ? 0 : Target->DefaultImageBase; +} + void LinkerScript::processCommands(OutputSectionFactory &Factory) { // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important @@ -365,7 +378,7 @@ // script parser. CurAddressState = State.get(); CurAddressState->OutSec = Aether; - Dot = 0; + Dot = getInitialDot(); for (size_t I = 0; I < Opt.Commands.size(); ++I) { // Handle symbol assignments outside of any output section. @@ -437,7 +450,7 @@ StartAddr = std::min(StartAddr, KV.second); auto Expr = [=] { - return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize()); + return std::min(StartAddr, getImageBase() + elf::getHeaderSize()); }; Opt.Commands.insert(Opt.Commands.begin(), make(".", Expr, "")); @@ -775,7 +788,7 @@ void LinkerScript::assignAddresses() { // Assign addresses as instructed by linker script SECTIONS sub-commands. - Dot = 0; + Dot = getInitialDot(); auto State = make_unique(Opt); // CurAddressState captures the local AddressState and makes it accessible // deliberately. This is needed as there are some cases where we cannot just Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1159,7 +1159,7 @@ if (Config->EMachine == EM_MIPS) { add({DT_MIPS_RLD_VERSION, 1}); add({DT_MIPS_FLAGS, RHF_NOTPOT}); - add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); + add({DT_MIPS_BASE_ADDRESS, Script->getImageBase()}); add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()}); add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry()) Index: test/ELF/linkerscript/image-base.s =================================================================== --- test/ELF/linkerscript/image-base.s +++ test/ELF/linkerscript/image-base.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { mysym = .; }" > %t.script + +# RUN: ld.lld %t.o -o %t-default.elf -T %t.script +# RUN: llvm-readobj --symbols %t-default.elf | FileCheck %s --check-prefix=DEFAULT +# DEFAULT: Name: mysym +# DEFAULT-NEXT: Value: 0x0 + +# RUN: ld.lld %t.o -o %t-switch.elf -T %t.script --image-base=0x100000 +# RUN: llvm-readobj --symbols %t-switch.elf | FileCheck %s --check-prefix=SWITCH +# SWITCH: Name: mysym +# SWITCH-NEXT: Value: 0x100000 + +.global _start +_start: + nop