mgorny created this revision.
mgorny added reviewers: ruiu, krytarowski.
Herald added subscribers: llvm-commits, jfb, arichardson, emaste.
Herald added a reviewer: espindola.

This is my proof-of-concept on making `--copy-dt-needed-entries` work. 
Apparently, i've been able to hack on it hard enough to make it actually emit 
DT_NEEDED for all symbols, recursively:

  $ clang -fuse-ld=lld  -Wl,--copy-dt-needed-entries test.c  -lgit2
  $ readelf -d a.out 
  
  Dynamic section at offset 0x3010 contains 40 entries:
    Tag        Type                         Name/Value
   0x0000000000000001 (NEEDED)             Shared library: [libgit2.so.27]
   0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
   0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
   0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
   0x0000000000000001 (NEEDED)             Shared library: 
[ld-linux-x86-64.so.2]
   0x0000000000000001 (NEEDED)             Shared library: [libcurl.so.4]
   0x0000000000000001 (NEEDED)             Shared library: [libcares.so.2]
   0x0000000000000001 (NEEDED)             Shared library: [libnghttp2.so.14]
   0x0000000000000001 (NEEDED)             Shared library: [libidn2.so.4]
   0x0000000000000001 (NEEDED)             Shared library: [libunistring.so.2]
   0x0000000000000001 (NEEDED)             Shared library: [libssl.so.1.1]
   0x0000000000000001 (NEEDED)             Shared library: [libcrypto.so.1.1]
   0x0000000000000001 (NEEDED)             Shared library: [libz.so.1]
   0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
   0x0000000000000001 (NEEDED)             Shared library: 
[libhttp_parser.so.2.9]
   0x0000000000000001 (NEEDED)             Shared library: [libssh2.so.1]
   0x0000000000000015 (DEBUG)              0x0
   0x0000000000000007 (RELA)               0x200620
   0x0000000000000008 (RELASZ)             48 (bytes)
   0x0000000000000009 (RELAENT)            24 (bytes)
   0x0000000000000017 (JMPREL)             0x200650
   0x0000000000000002 (PLTRELSZ)           72 (bytes)
   0x0000000000000003 (PLTGOT)             0x202010
   0x0000000000000014 (PLTREL)             RELA
   0x0000000000000006 (SYMTAB)             0x2002b0
   0x000000000000000b (SYMENT)             24 (bytes)
   0x0000000000000005 (STRTAB)             0x200488
   0x000000000000000a (STRSZ)              404 (bytes)
   0x000000006ffffef5 (GNU_HASH)           0x200400
   0x0000000000000004 (HASH)               0x200428
   0x0000000000000019 (INIT_ARRAY)         0x203008
   0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
   0x000000000000001a (FINI_ARRAY)         0x203000
   0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
   0x000000000000000c (INIT)               0x201200
   0x000000000000000d (FINI)               0x201218
   0x000000006ffffff0 (VERSYM)             0x2003b8
   0x000000006ffffffe (VERNEED)            0x2003d0
   0x000000006fffffff (VERNEEDNUM)         1
   0x0000000000000000 (NULL)               0x0

Can't say the code is nice but before I try to make it cleanly, I'd appreciate 
some tips on whether I'm even starting in the right direction.

FWICS, GNU ld's `--copy-dt-needed-entries` adds lot less libraries — it seems 
as if it implicitly forced `--as-needed`, and `--no-as-needed` doesn't seem to 
make a difference.


Repository:
  rLLD LLVM Linker

https://reviews.llvm.org/D56647

Files:
  ELF/Config.h
  ELF/Driver.cpp
  ELF/InputFiles.cpp
  ELF/InputFiles.h
  ELF/Options.td
  ELF/SymbolTable.cpp

Index: ELF/SymbolTable.cpp
===================================================================
--- ELF/SymbolTable.cpp
+++ ELF/SymbolTable.cpp
@@ -16,6 +16,7 @@
 
 #include "SymbolTable.h"
 #include "Config.h"
+#include "Driver.h"
 #include "LinkerScript.h"
 #include "Symbols.h"
 #include "SyntheticSections.h"
@@ -109,6 +110,17 @@
       return;
 
     SharedFiles.push_back(F);
+    if (F->CopyDtNeeded) {
+      for (std::string& DtNeeded : F->parseDtNeeded()) {
+        if (Optional<std::string> Path = searchLibrary(":" + DtNeeded)) {
+          // TODO: how does memory management work here?
+          if (Optional<MemoryBufferRef> Buffer = readFile(*Path))
+            addFile<ELFT>(make<SharedFile<ELFT>>(*Buffer, DtNeeded));
+        } else {
+          // TODO: error out?
+        }
+      }
+    }
     F->parseRest();
     return;
   }
Index: ELF/Options.td
===================================================================
--- ELF/Options.td
+++ ELF/Options.td
@@ -88,6 +88,10 @@
   HelpText<"Use colors in diagnostics">,
   MetaVarName<"[auto,always,never]">;
 
+defm copy_dt_needed_entries: B<"copy-dt-needed-entries",
+    "Recursively include all dependencies (DT_NEEDED) of linked libraries in the executable",
+    "Include only DT_NEEDED entries for libraries explicity listed (default)">;
+
 defm cref: B<"cref",
     "Output cross reference table",
     "Do not output cross reference table">;
@@ -495,7 +499,6 @@
 def: F<"long-plt">;
 def: F<"no-add-needed">;
 def: F<"no-allow-shlib-undefined">;
-def: F<"no-copy-dt-needed-entries">;
 def: F<"no-ctors-in-init-array">;
 def: F<"no-keep-memory">;
 def: F<"no-mmap-output-file">;
Index: ELF/InputFiles.h
===================================================================
--- ELF/InputFiles.h
+++ ELF/InputFiles.h
@@ -337,6 +337,7 @@
   uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym);
   std::vector<const Elf_Verdef *> parseVerdefs();
   std::vector<uint32_t> parseVersyms();
+  std::vector<std::string> parseDtNeeded();
 
   struct NeededVer {
     // The string table offset of the version name in the output file.
@@ -352,6 +353,9 @@
 
   // Used for --as-needed
   bool IsNeeded;
+
+  // Used for --copy-dt-needed-entries
+  bool CopyDtNeeded;
 };
 
 class BinaryFile : public InputFile {
Index: ELF/InputFiles.cpp
===================================================================
--- ELF/InputFiles.cpp
+++ ELF/InputFiles.cpp
@@ -863,7 +863,8 @@
 template <class ELFT>
 SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
     : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName),
-      IsNeeded(!Config->AsNeeded) {}
+      IsNeeded(!Config->AsNeeded), CopyDtNeeded(Config->CopyDtNeededEntries)
+{}
 
 // Partially parse the shared object file so that we can call
 // getSoName on this object.
@@ -962,6 +963,33 @@
   return Verdefs;
 }
 
+// Parse the shared object file for list of DT_NEEDED libraries.
+template <class ELFT>
+std::vector<std::string> SharedFile<ELFT>::parseDtNeeded() {
+  const ELFFile<ELFT> Obj = this->getObj();
+  ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this);
+  std::vector<std::string> DtNeeded;
+
+  for (const typename ELFT::Shdr &Sec : Sections) {
+    if (Sec.sh_type != SHT_DYNAMIC)
+      continue;
+
+    ArrayRef<Elf_Dyn> Arr =
+        CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(&Sec), this);
+    for (const Elf_Dyn &Dyn : Arr) {
+      if (Dyn.d_tag == DT_NEEDED) {
+        uint64_t Val = Dyn.getVal();
+        if (Val >= this->StringTable.size())
+          fatal(toString(this) + ": invalid DT_NEEDED entry");
+        DtNeeded.push_back(this->StringTable.data() + Val);
+      }
+    }
+
+    break;
+  }
+  return DtNeeded;
+}
+
 // We do not usually care about alignments of data in shared object
 // files because the loader takes care of it. However, if we promote a
 // DSO symbol to point to .bss due to copy relocation, we need to keep
Index: ELF/Driver.cpp
===================================================================
--- ELF/Driver.cpp
+++ ELF/Driver.cpp
@@ -1089,7 +1089,7 @@
 
 void LinkerDriver::createFiles(opt::InputArgList &Args) {
   // For --{push,pop}-state.
-  std::vector<std::tuple<bool, bool, bool>> Stack;
+  std::vector<std::tuple<bool, bool, bool, bool>> Stack;
 
   // Iterate over argv to process input files and positional arguments.
   for (auto *Arg : Args) {
@@ -1121,12 +1121,18 @@
     case OPT_as_needed:
       Config->AsNeeded = true;
       break;
+    case OPT_copy_dt_needed_entries:
+      Config->CopyDtNeededEntries = true;
+      break;
     case OPT_format:
       Config->FormatBinary = isFormatBinary(Arg->getValue());
       break;
     case OPT_no_as_needed:
       Config->AsNeeded = false;
       break;
+    case OPT_no_copy_dt_needed_entries:
+      Config->CopyDtNeededEntries = false;
+      break;
     case OPT_Bstatic:
       Config->Static = true;
       break;
@@ -1172,14 +1178,16 @@
       ++InputFile::NextGroupId;
       break;
     case OPT_push_state:
-      Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive);
+      Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive,
+                         Config->CopyDtNeededEntries);
       break;
     case OPT_pop_state:
       if (Stack.empty()) {
         error("unbalanced --push-state/--pop-state");
         break;
       }
-      std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back();
+      std::tie(Config->AsNeeded, Config->Static, InWholeArchive,
+               Config->CopyDtNeededEntries) = Stack.back();
       Stack.pop_back();
       break;
     }
Index: ELF/Config.h
===================================================================
--- ELF/Config.h
+++ ELF/Config.h
@@ -130,6 +130,7 @@
   bool BsymbolicFunctions;
   bool CallGraphProfileSort;
   bool CheckSections;
+  bool CopyDtNeededEntries = false;
   bool CompressDebugSections;
   bool Cref;
   bool DefineCommon;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D56647: [WIP] [... Michał Górny via Phabricator via cfe-commits

Reply via email to