Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -27,7 +27,7 @@ class LinkerDriver { public: void main(ArrayRef Args); - void addFile(StringRef Path, bool WithLOption); + void addFile(StringRef Path, bool WithLOption, bool JustSymbols); void addLibrary(StringRef Name); private: Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -173,7 +173,7 @@ } // Opens a file and create a file object. Path has to be resolved already. -void LinkerDriver::addFile(StringRef Path, bool WithLOption) { +void LinkerDriver::addFile(StringRef Path, bool WithLOption, bool JustSymbols) { using namespace sys::fs; Optional Buffer = readFile(Path); @@ -187,6 +187,15 @@ } switch (identify_magic(MBRef.getBuffer())) { + case file_magic::elf_executable: { + // We allow executable files as --just-symbols inputs. + Files.push_back(createObjectFile(MBRef, /*ArchiveName=*/"", + /*OffsetInArchive=*/0, + /*JustSymbols*/ true)); + if (!JustSymbols) + error(Path + ": is an executable ELF file"); + return; + } case file_magic::unknown: readLinkerScript(MBRef); return; @@ -249,7 +258,7 @@ // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef Name) { if (Optional Path = searchLibrary(Name)) - addFile(*Path, /*WithLOption=*/true); + addFile(*Path, /*WithLOption=*/true, /*JustSymbols=*/false); else error("unable to find library -l" + Name); } @@ -870,11 +879,14 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getUnaliasedOption().getID()) { + case OPT_just_symbols: + addFile(Arg->getValue(), /*WithLOption=*/false, /*JustSymbols=*/true); + break; case OPT_library: addLibrary(Arg->getValue()); break; case OPT_INPUT: - addFile(Arg->getValue(), /*WithLOption=*/false); + addFile(Arg->getValue(), /*WithLOption=*/false, /*JustSymbols=*/false); break; case OPT_defsym: { StringRef From; @@ -1074,11 +1086,6 @@ for (StringRef S : Config->Undefined) Symtab->fetchIfLazy(S); - // Handle the --just-symbols option. This may add absolute symbols - // to the symbol table. - for (auto *Arg : Args.filtered(OPT_just_symbols)) - if (Optional MB = readFile(Arg->getValue())) - readJustSymbolsFile(*MB); // If an entry symbol is in a static archive, pull out that file now // to complete the symbol table. After this, no new names except a Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -161,12 +161,14 @@ const Elf_Shdr &Sec); ArrayRef getShtGroupEntries(const Elf_Shdr &Sec); + void readJustSymbols(); + public: static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } ArrayRef getLocalSymbols(); - ObjFile(MemoryBufferRef M, StringRef ArchiveName); + ObjFile(MemoryBufferRef M, StringRef ArchiveName, bool JustSymbols); void parse(llvm::DenseSet &ComdatGroups); Symbol &getSymbol(uint32_t SymbolIndex) const { @@ -218,6 +220,9 @@ std::unique_ptr DwarfLine; llvm::DenseMap> VariableLoc; llvm::once_flag InitDwarfLine; + + // True if it is a -just-symbols file. + bool JustSymbols; }; // LazyObjFile is analogous to ArchiveFile in the sense that @@ -327,12 +332,10 @@ }; InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", - uint64_t OffsetInArchive = 0); + uint64_t OffsetInArchive = 0, + bool JustSymbols = false); InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); -// For --just-symbols -template void readJustSymbolsFile(MemoryBufferRef MB); - extern std::vector BinaryFiles; extern std::vector BitcodeFiles; extern std::vector ObjectFiles; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -269,8 +269,9 @@ } template -ObjFile::ObjFile(MemoryBufferRef M, StringRef ArchiveName) - : ELFFileBase(Base::ObjKind, M) { +ObjFile::ObjFile(MemoryBufferRef M, StringRef ArchiveName, + bool JustSymbols) + : ELFFileBase(Base::ObjKind, M), JustSymbols(JustSymbols) { this->ArchiveName = ArchiveName; } @@ -280,11 +281,45 @@ return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); } +// This is for --just-symbols. +// +// This option allows you to link your output against other existing +// program, so that if you load both your program and the other program +// into memory, your output can use program's symbols. +// +// What we are doing here is reading defined symbols from the object. +template void ObjFile::readJustSymbols() { + ArrayRef Sections = + CHECK(this->getObj().sections(), toString(this)); + + for (const Elf_Shdr &Sec : Sections) { + if (Sec.sh_type != SHT_SYMTAB) + continue; + + Elf_Sym_Range Syms = CHECK(this->getObj().symbols(&Sec), toString(this)); + this->FirstNonLocal = Sec.sh_info; + StringRef StringTable = CHECK( + this->getObj().getStringTableForSymtab(Sec, Sections), toString(this)); + + for (const Elf_Sym &Sym : Syms.slice(this->FirstNonLocal)) + if (Sym.st_shndx != SHN_UNDEF) + this->Symbols.push_back( + Symtab->addRegular(CHECK(Sym.getName(StringTable), toString(this)), + Sym.st_other, Sym.getType(), Sym.st_value, + Sym.st_size, Sym.getBinding(), nullptr, this)); + return; + } +} + template void ObjFile::parse(DenseSet &ComdatGroups) { - // Read section and symbol tables. - initializeSections(ComdatGroups); - initializeSymbols(); + if (JustSymbols) { + readJustSymbols(); + } else { + // Read section and symbol tables. + initializeSections(ComdatGroups); + initializeSymbols(); + } } // Sections with SHT_GROUP and comdat bits define comdat section groups. @@ -1077,19 +1112,19 @@ } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, - uint64_t OffsetInArchive) { + uint64_t OffsetInArchive, bool JustSymbols) { if (isBitcode(MB)) return make(MB, ArchiveName, OffsetInArchive); switch (getELFKind(MB)) { case ELF32LEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName, JustSymbols); case ELF32BEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName, JustSymbols); case ELF64LEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName, JustSymbols); case ELF64BEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName, JustSymbols); default: llvm_unreachable("getELFKind"); } @@ -1174,41 +1209,6 @@ } } -// This is for --just-symbols. -// -// This option allows you to link your output against other existing -// program, so that if you load both your program and the other program -// into memory, your output can use program's symbols. -// -// What we are doing here is to read defined symbols from a given ELF -// file and add them as absolute symbols. -template void elf::readJustSymbolsFile(MemoryBufferRef MB) { - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Sym Elf_Sym; - typedef typename ELFT::SymRange Elf_Sym_Range; - - StringRef ObjName = MB.getBufferIdentifier(); - ELFFile Obj = check(ELFFile::create(MB.getBuffer())); - ArrayRef Sections = CHECK(Obj.sections(), ObjName); - - for (const Elf_Shdr &Sec : Sections) { - if (Sec.sh_type != SHT_SYMTAB) - continue; - - Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), ObjName); - uint32_t FirstNonLocal = Sec.sh_info; - StringRef StringTable = - CHECK(Obj.getStringTableForSymtab(Sec, Sections), ObjName); - - for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) - if (Sym.st_shndx != SHN_UNDEF) - Symtab->addRegular(CHECK(Sym.getName(StringTable), ObjName), - Sym.st_other, Sym.getType(), Sym.st_value, - Sym.st_size, Sym.getBinding(), nullptr, nullptr); - return; - } -} - template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); @@ -1238,8 +1238,3 @@ template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; - -template void elf::readJustSymbolsFile(MemoryBufferRef); -template void elf::readJustSymbolsFile(MemoryBufferRef); -template void elf::readJustSymbolsFile(MemoryBufferRef); -template void elf::readJustSymbolsFile(MemoryBufferRef); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -277,26 +277,29 @@ SmallString<128> PathData; StringRef Path = (Config->Sysroot + S).toStringRef(PathData); if (sys::fs::exists(Path)) { - Driver->addFile(Saver.save(Path), /*WithLOption=*/false); + Driver->addFile(Saver.save(Path), /*WithLOption=*/false, + /*JustSymbols=*/false); return; } } if (S.startswith("/")) { - Driver->addFile(S, /*WithLOption=*/false); + Driver->addFile(S, /*WithLOption=*/false, /*JustSymbols=*/false); } else if (S.startswith("=")) { if (Config->Sysroot.empty()) - Driver->addFile(S.substr(1), /*WithLOption=*/false); + Driver->addFile(S.substr(1), /*WithLOption=*/false, + /*JustSymbols=*/false); else Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)), - /*WithLOption=*/false); + /*WithLOption=*/false, /*JustSymbols=*/false); } else if (S.startswith("-l")) { Driver->addLibrary(S.substr(2)); } else if (sys::fs::exists(S)) { - Driver->addFile(S, /*WithLOption=*/false); + Driver->addFile(S, /*WithLOption=*/false, /*JustSymbols=*/false); } else { if (Optional Path = findFromSearchPaths(S)) - Driver->addFile(Saver.save(*Path), /*WithLOption=*/true); + Driver->addFile(Saver.save(*Path), /*WithLOption=*/true, + /*JustSymbols=*/false); else setError("unable to find " + S); } Index: test/ELF/invalid/executable.s =================================================================== --- test/ELF/invalid/executable.s +++ test/ELF/invalid/executable.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld -o %t1.exe %t.o # RUN: not ld.lld -o %t2.exe %t1.exe 2>&1 | FileCheck %s -# CHECK: unknown file type +# CHECK: {{.*}}1.exe: is an executable ELF file .global _start _start: Index: test/ELF/just-symbols-cref.s =================================================================== --- test/ELF/just-symbols-cref.s +++ test/ELF/just-symbols-cref.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/just-symbols.s -o %t1 +# RUN: ld.lld %t1 -o %t1.exe + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 +# RUN: ld.lld %t2 -just-symbols=%t1.exe -o /dev/null -cref | FileCheck -strict-whitespace %s + +# CHECK: Symbol File +# CHECK-NEXT: _start {{.*}}2 +# CHECK-NEXT: bar {{.*}}1.exe +# CHECK-NEXT: {{.*}}2 +# CHECK-NEXT: foo {{.*}}1.exe +# CHECK-NEXT: {{.*}}2 + +.globl _start +_start: + call foo + call bar + ret Index: test/ELF/just-symbols-input.s =================================================================== --- test/ELF/just-symbols-input.s +++ test/ELF/just-symbols-input.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t1.exe +# RUN: ld.lld -just-symbols=%t1.exe -o %t2.exe + +## Check we are able to produce the output when the only input is a -just-symbols file. +# RUN: llvm-readelf -symbols %t2.exe | FileCheck %s +# CHECK: Num: Value Size Type Bind Vis Ndx Name +# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +# CHECK-NEXT: 1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT ABS foo + +.globl foo +foo: + ret