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; 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> Stack; + std::vector> 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/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -337,6 +337,7 @@ uint32_t getAlignment(ArrayRef Sections, const Elf_Sym &Sym); std::vector parseVerdefs(); std::vector parseVersyms(); + std::vector 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 SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(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 +std::vector SharedFile::parseDtNeeded() { + const ELFFile Obj = this->getObj(); + ArrayRef Sections = CHECK(Obj.sections(), this); + std::vector DtNeeded; + + for (const typename ELFT::Shdr &Sec : Sections) { + if (Sec.sh_type != SHT_DYNAMIC) + continue; + + ArrayRef Arr = + CHECK(Obj.template getSectionContentsAsArray(&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/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/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 Path = searchLibrary(":" + DtNeeded)) { + // TODO: how does memory management work here? + if (Optional Buffer = readFile(*Path)) + addFile(make>(*Buffer, DtNeeded)); + } else { + // TODO: error out? + } + } + } F->parseRest(); return; }