summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Config.h2
-rw-r--r--lld/ELF/Driver.cpp9
-rw-r--r--lld/ELF/LinkerScript.cpp9
-rw-r--r--lld/ELF/SyntheticSections.cpp2
-rw-r--r--lld/ELF/Target.cpp7
-rw-r--r--lld/ELF/Target.h13
-rw-r--r--lld/test/ELF/linkerscript/image-base.s18
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
OpenPOWER on IntegriCloud