diff options
| -rw-r--r-- | lld/ELF/Config.h | 2 | ||||
| -rw-r--r-- | lld/ELF/Driver.cpp | 9 | ||||
| -rw-r--r-- | lld/ELF/LinkerScript.cpp | 9 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/Target.cpp | 7 | ||||
| -rw-r--r-- | lld/ELF/Target.h | 13 | ||||
| -rw-r--r-- | lld/test/ELF/linkerscript/image-base.s | 18 |
7 files changed, 44 insertions, 16 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index a8d0dd46b52..83c25faa31e 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<uint64_t> ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; unsigned LTOPartitions; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index c259a172084..61bf93def89 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<uint64_t> 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 591e6ffabb2..c7e103abc1f 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<SymbolAssignment>(".", 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<AddressState>(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 ff81852a4ca..bc76c9648b2 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1166,7 +1166,7 @@ template <class ELFT> void DynamicSection<ELFT>::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 11986efc746..5434e14cf1e 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 7720e1b94e6..45773f4163f 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 00000000000..34ed4efdae3 --- /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
|

