[ELF] - Implemented --defsym option.
authorGeorge Rimar <grimar@accesssoftek.com>
Wed, 26 Apr 2017 10:40:02 +0000 (10:40 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Wed, 26 Apr 2017 10:40:02 +0000 (10:40 +0000)
gnu ld description of option is:

--defsym=symbol=expression
Create a global symbol in the output file, containing the absolute address given
by expression. You may use this option as many times as necessary to define multiple
symbols in the command line. A limited form of arithmetic is supported for the
expression in this context: you may give a hexadecimal constant or the name of an
existing symbol, or use "+" and "-" to add or subtract hexadecimal constants or
symbols. If you need more elaborate expressions, consider using the linker command
language from a script. Note: there should be no white space between symbol,
the equals sign ("="), and expression.

In compare with D32082, this patch does not support math expressions and absolute
symbols. It implemented via code similar to --wrap. That covers 1 of 3 possible
--defsym cases.

Differential revision: https://reviews.llvm.org/D32171

llvm-svn: 301391

lld/ELF/Driver.cpp
lld/ELF/Options.td
lld/ELF/SymbolTable.cpp
lld/ELF/SymbolTable.h
lld/test/ELF/defsym.s [new file with mode: 0644]

index 7dad960..0c62d77 100644 (file)
@@ -880,6 +880,21 @@ static uint64_t getImageBase(opt::InputArgList &Args) {
   return V;
 }
 
+// Parses --defsym=alias option.
+static std::vector<std::pair<StringRef, StringRef>>
+getDefsym(opt::InputArgList &Args) {
+  std::vector<std::pair<StringRef, StringRef>> Ret;
+  for (auto *Arg : Args.filtered(OPT_defsym)) {
+    StringRef From;
+    StringRef To;
+    std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+    if (!isValidCIdentifier(To))
+      error("--defsym: symbol name expected, but got " + To);
+    Ret.push_back({From, To});
+  }
+  return Ret;
+}
+
 // Do actual linking. Note that when this function is called,
 // all linker scripts have already been parsed.
 template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
@@ -945,6 +960,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
   for (auto *Arg : Args.filtered(OPT_wrap))
     Symtab.wrap(Arg->getValue());
 
+  // Handle --defsym=sym=alias option.
+  for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
+    Symtab.alias(Def.first, Def.second);
+
   // Now that we have a complete list of input files.
   // Beyond this point, no new files are added.
   // Aggregate all input sections into one place.
index 4cf14c9..fda6754 100644 (file)
@@ -25,6 +25,8 @@ def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
 def compress_debug_sections : J<"compress-debug-sections=">,
   HelpText<"Compress DWARF debug sections">;
 
+def defsym: J<"defsym=">, HelpText<"Define a symbol alias">;
+
 def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
   HelpText<"Add a directory to the library search path">;
 
index 874e4ef..e55b8bf 100644 (file)
@@ -168,6 +168,19 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
   memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
 }
 
+// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
+template <class ELFT>
+void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) {
+  SymbolBody *B = find(Name);
+  if (!B) {
+    error("-defsym: undefined symbol: " + Name);
+    return;
+  }
+  Symbol *Sym = B->symbol();
+  Symbol *AliasSym = addUndefined(Alias);
+  memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body));
+}
+
 static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
   if (VA == STV_DEFAULT)
     return VB;
index a5395f5..1a745f9 100644 (file)
@@ -86,6 +86,7 @@ public:
 
   void trace(StringRef Name);
   void wrap(StringRef Name);
+  void alias(StringRef Alias, StringRef Name);
 
 private:
   std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
diff --git a/lld/test/ELF/defsym.s b/lld/test/ELF/defsym.s
new file mode 100644 (file)
index 0000000..cafc514
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t %t.o --defsym=foo2=foo1
+# RUN: llvm-readobj -t -s %t | FileCheck %s
+# RUN: llvm-objdump -d -print-imm-hex %t | FileCheck %s --check-prefix=USE
+
+## In compare with GNU linkers, symbol defined with --defsym does
+## not get aliased name in symbol table:
+# CHECK:      Symbol {
+# CHECK:        Name: foo1
+# CHECK-NEXT:   Value: 0x123
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type:
+# CHECK-NEXT:   Other:
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: foo1
+# CHECK-NEXT:   Value: 0x123
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type:
+# CHECK-NEXT:   Other:
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+
+## Check we can use foo2 and it that it is an alias for foo1.
+# USE:       Disassembly of section .text:
+# USE-NEXT:  _start:
+# USE-NEXT:    movl $0x123, %edx
+
+# RUN: not ld.lld -o %t %t.o --defsym=foo2=1 2>&1 | FileCheck %s -check-prefix=ERR1
+# ERR1: error: --defsym: symbol name expected, but got 1
+
+# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR2
+# ERR2: error: -defsym: undefined symbol: und
+
+.globl foo1
+ foo1 = 0x123
+
+.global _start
+_start:
+  movl $foo2, %edx