From b5ca92ef7385e39c9bf3b5eaf8c76343397b54e4 Mon Sep 17 00:00:00 2001 From: James Henderson Date: Tue, 10 Oct 2017 10:09:35 +0000 Subject: [PATCH] [ELF] Set Dot initially to --image-base value when using linker scripts When parsing linker scripts, LLD previously started with a '.' value of 0, regardless of the internal default image base for the target, and regardless of switches such as --image-base. It seems reasonable to use a different image base value when using linker scripts and --image-base is specified, since otherwise the switch has no effect. This change does this, as well as removing unnecessary initialisation of Dot where it is not used. The default image base should not be used when processing linker scripts, because this will change the behaviour for existing linker script users, and potentially result in invalid output being produced, as a subsequent assignment to Dot could move the location counter backwards. Instead, we maintain the existing behaviour of starting from 0 if --image-base is not specified. Reviewers: ruiu Differential Revision: https://reviews.llvm.org/D38360 llvm-svn: 315293 --- lld/ELF/Config.h | 2 +- lld/ELF/Driver.cpp | 9 ++++----- lld/ELF/LinkerScript.cpp | 9 +++++---- lld/ELF/SyntheticSections.cpp | 2 +- lld/ELF/Target.cpp | 7 +++++++ lld/ELF/Target.h | 13 ++++++++----- lld/test/ELF/linkerscript/image-base.s | 18 ++++++++++++++++++ 7 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 lld/test/ELF/linkerscript/image-base.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index a8d0dd46b52c..83c25faa31e1 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -166,7 +166,7 @@ struct Configuration { 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; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index c259a172084f..61bf93def89c 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -908,13 +908,12 @@ static uint64_t getMaxPageSize(opt::InputArgList &Args) { } // 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; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 591e6ffabb29..c7e103abc1ff 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -365,7 +365,6 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // 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. @@ -438,7 +437,7 @@ void LinkerScript::fabricateDefaultCommands() { 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, "")); @@ -780,9 +779,11 @@ LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) { } } +// 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 diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index ff81852a4ca1..bc76c9648b27 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1166,7 +1166,7 @@ template void DynamicSection::finalizeContents() { 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()) diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 11986efc746f..5434e14cf1e4 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -165,3 +165,10 @@ void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, 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 : DefaultImageBase; +} diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 7720e1b94e67..45773f4163f2 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -64,11 +64,7 @@ public: 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 @@ public: 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(); diff --git a/lld/test/ELF/linkerscript/image-base.s b/lld/test/ELF/linkerscript/image-base.s new file mode 100644 index 000000000000..34ed4efdae38 --- /dev/null +++ b/lld/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 -- 2.34.1