Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -103,6 +103,7 @@ std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; + std::vector JustSymbols; bool AllowMultipleDefinition; bool AndroidPackDynRelocs = false; bool AsNeeded = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -852,9 +852,29 @@ return false; } +// Used for --just-symbol. Adds file from Path. +static void addJustSymbolsFile(StringRef Path) { + Optional Buffer = readFile(Path); + if (!Buffer) + return; + + file_magic Type = identify_magic(Buffer->getBuffer()); + if (Type != file_magic::elf_relocatable && + Type != file_magic::elf_executable) { + error("--just-symbols: unknown format of file " + Path + + " (supported formats: ELF executable, ELF relocatable)"); + return; + } + + Config->JustSymbols.push_back(createObjectFile(*Buffer)); +} + void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getUnaliasedOption().getID()) { + case OPT_just_symbols: + addJustSymbolsFile(Arg->getValue()); + break; case OPT_library: addLibrary(Arg->getValue()); break; @@ -1041,6 +1061,8 @@ // symbols that we need to the symbol table. for (InputFile *F : Files) Symtab->addFile(F); + for (InputFile *F : Config->JustSymbols) + cast>(F)->parseJustSymbols(); // Process -defsym option. for (auto *Arg : Args.filtered(OPT_defsym)) { Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -167,6 +167,9 @@ ObjFile(MemoryBufferRef M, StringRef ArchiveName); void parse(llvm::DenseSet &ComdatGroups); + // For --just-symbols implementation. + void parseJustSymbols(); + InputSectionBase *getSection(uint32_t Index) const; Symbol &getSymbol(uint32_t SymbolIndex) const { Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -242,6 +242,43 @@ initializeSymbols(); } +// Used for --just-symbol=filename implementation, here we scan +// and add symbols from object file. +template void ObjFile::parseJustSymbols() { + ArrayRef ObjSections = + check(this->getObj().sections(), toString(this)); + + // Initialize symbol and string tables. + for (const Elf_Shdr &Hdr : ObjSections) { + if (Hdr.sh_type != SHT_SYMTAB) + continue; + this->initSymtab(ObjSections, &Hdr); + break; + } + + // Scan over all symbols. + for (const Elf_Sym &Sym : this->ELFSyms) { + // Skip all local symbols. + if (Sym.getBinding() == STB_LOCAL) + continue; + + StringRef Name = check(Sym.getName(this->StringTable), toString(this)); + // We do not want to automatically resolve undefined symbols here, so + // leaving them as is, assuming they must be defined somewhere else. + if (Sym.st_shndx == SHN_UNDEF) { + this->Symbols.push_back(Symtab->addUndefined( + Name, Sym.getBinding(), Sym.st_other, Sym.getType(), + /*CanOmitFromDynSym=*/false, this)); + continue; + } + + // All other symbols are added as absolute ones. + this->Symbols.push_back(Symtab->addRegular( + Name, Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, + Sym.getBinding(), nullptr /*Sec*/, this)); + } +} + // Sections with SHT_GROUP and comdat bits define comdat section groups. // They are identified and deduplicated by group name. This function // returns a group name. Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -147,6 +147,8 @@ defm init: Eq<"init">, HelpText<"Specify an initializer function">, MetaVarName<"">; +defm just_symbols: Eq<"just-symbols">, HelpText<"Add symbols from file">; + defm library: Eq<"library">, HelpText<"Root name of library to use">, MetaVarName<"">; Index: test/ELF/just-symbols.s =================================================================== --- test/ELF/just-symbols.s +++ test/ELF/just-symbols.s @@ -0,0 +1,84 @@ +# REQUIRES: x86 + +# RUN: echo "_start:" > %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tsymbols.o +# RUN: ld.lld -o %t.exe %t.o --just-symbols=%tsymbols.o +# RUN: llvm-readobj -symbols %t.exe | FileCheck %s + +# CHECK: Symbol { +# CHECK: Name: hiddenFoo +# CHECK-NEXT: Value: 0x5 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: absoluteFoo +# CHECK-NEXT: Value: 0x123 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: commonFoo +# CHECK-NEXT: Value: 0x4 +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: undefFoo +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: weakFoo +# CHECK-NEXT: Value: 0x5 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } + +.section .foo, "a" +.global foo +foo: + callq undefFoo@PLT + +.global absoluteFoo +absoluteFoo = 0x123 + +.weak weakFoo +weakFoo: + +.local localFoo +localFoo: + +.globl hiddenFoo +.hidden hiddenFoo +hiddenFoo: + +.comm commonFoo,4,4