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 None; StringRef S = Arg->getValue(); uint64_t V; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -365,7 +365,6 @@ // script parser. CurAddressState = State.get(); CurAddressState->OutSec = Aether; - Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { // Handle symbol assignments outside of any output section. @@ -437,7 +436,7 @@ StartAddr = std::min(StartAddr, KV.second); auto Expr = [=] { - return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize()); + return std::min(StartAddr, Target->getImageBase() + elf::getHeaderSize()); }; Opt.Commands.insert(Opt.Commands.begin(), make(".", Expr, "")); @@ -773,9 +772,11 @@ } } +// Assign addresses as instructed by linker script SECTIONS sub-commands. void LinkerScript::assignAddresses() { - // Assign addresses as instructed by linker script SECTIONS sub-commands. - Dot = 0; + // By default linker scripts use an initial value of 0 for '.', but prefer + // -image-base if set. + Dot = Config->ImageBase ? *Config->ImageBase : 0; 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, Target->getImageBase()}); add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()}); add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry()) Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -64,11 +64,7 @@ unsigned PageSize = 4096; unsigned DefaultMaxPageSize = 4096; - // On FreeBSD x86_64 the first page cannot be mmaped. - // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64 - // installs that is 65536, so the first 15 pages cannot be used. - // Given that, the smallest value that can be used in here is 0x10000. - uint64_t DefaultImageBase = 0x10000; + uint64_t getImageBase(); // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for // end of .got @@ -108,6 +104,13 @@ virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; + +protected: + // On FreeBSD x86_64 the first page cannot be mmaped. + // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64 + // installs that is 65536, so the first 15 pages cannot be used. + // Given that, the smallest value that can be used in here is 0x10000. + uint64_t DefaultImageBase = 0x10000; }; TargetInfo *getAArch64TargetInfo(); Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -165,3 +165,10 @@ uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } + +uint64_t TargetInfo::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; +} 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