[ELF] Set Dot initially to --image-base value when using linker scripts
authorJames Henderson <jh7370@my.bristol.ac.uk>
Tue, 10 Oct 2017 10:09:35 +0000 (10:09 +0000)
committerJames Henderson <jh7370@my.bristol.ac.uk>
Tue, 10 Oct 2017 10:09:35 +0000 (10:09 +0000)
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
lld/ELF/Driver.cpp
lld/ELF/LinkerScript.cpp
lld/ELF/SyntheticSections.cpp
lld/ELF/Target.cpp
lld/ELF/Target.h
lld/test/ELF/linkerscript/image-base.s [new file with mode: 0644]

index a8d0dd46b52cdd8220d5fa73d9389ba6efa6a40c..83c25faa31e1f374801740170fea0c19feb6edab 100644 (file)
@@ -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;
index c259a172084fbab3b90a877c2c0ab57d497fd7fa..61bf93def89cbb701b23b44cfb61aa6c1028b492 100644 (file)
@@ -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;
index 591e6ffabb29451b8f9134f09084d32734811369..c7e103abc1ff02c9bd3e36575e1098acb5041ad3 100644 (file)
@@ -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
index ff81852a4ca182010321f0d43eda1314814b9eac..bc76c9648b27cea77f4dc36bbe20b44067a3542d 100644 (file)
@@ -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())
index 11986efc746f02a38b93c90488bb129e9c806a80..5434e14cf1e4e8c43cc5198839b4df51ad65bcb8 100644 (file)
@@ -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;
+}
index 7720e1b94e67a15e95f6f3edda31ba79424b2db5..45773f4163f2a848b4e4363445be5a8c1d09ad51 100644 (file)
@@ -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 (file)
index 0000000..34ed4ef
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86\r
+\r
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o\r
+# RUN: echo "SECTIONS { mysym = .; }" > %t.script\r
+\r
+# RUN: ld.lld %t.o -o %t-default.elf -T %t.script\r
+# RUN: llvm-readobj --symbols %t-default.elf | FileCheck %s --check-prefix=DEFAULT\r
+# DEFAULT: Name: mysym\r
+# DEFAULT-NEXT: Value: 0x0\r
+\r
+# RUN: ld.lld %t.o -o %t-switch.elf -T %t.script --image-base=0x100000\r
+# RUN: llvm-readobj --symbols %t-switch.elf | FileCheck %s --check-prefix=SWITCH\r
+# SWITCH: Name: mysym\r
+# SWITCH-NEXT: Value: 0x100000\r
+\r
+.global _start\r
+_start:\r
+    nop\r