Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -1062,6 +1062,19 @@ if (errorCount()) return; + // Handle a rarely-used, -just-symbols option. + // + // This option allows you to link your output against other existing + // programs, so that if you load both other program and your output + // to memory, your output can call other program's symbols. + // + // What we are doing here is to read defined symbols from given ELF + // files and add them as absolute symbols. + for (auto *Arg : Args.filtered(OPT_just_symbols)) + if (Optional MB = readFile(Arg->getValue())) + for (std::pair P : readSymbols(*MB)) + Symtab->addAbsoluteOptional(P.first, P.second); + // Handle undefined symbols in DSOs. Symtab->scanShlibUndefined(); Index: lld/ELF/InputFiles.h =================================================================== --- lld/ELF/InputFiles.h +++ lld/ELF/InputFiles.h @@ -59,6 +59,10 @@ // Opens a given file. llvm::Optional readFile(StringRef Path); +// For --just-symbol. +template +std::vector> readSymbols(MemoryBufferRef); + // The root class of input files. class InputFile { public: Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -1049,6 +1049,38 @@ } } +// Reads defined symbols from a given ELF file, and returns their +// names and values. This is used for -just-symbols. +template +std::vector> +elf::readSymbols(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); + + std::vector> Ret; + for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) + if (Sym.st_shndx != SHN_UNDEF) + Ret.emplace_back(check(Sym.getName(StringTable), ObjName), + Sym.st_value); + return Ret; + } + return {}; +} + template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); @@ -1083,3 +1115,12 @@ template void BinaryFile::parse(); template void BinaryFile::parse(); template void BinaryFile::parse(); + +template std::vector> + elf::readSymbols(MemoryBufferRef); +template std::vector> + elf::readSymbols(MemoryBufferRef); +template std::vector> + elf::readSymbols(MemoryBufferRef); +template std::vector> + elf::readSymbols(MemoryBufferRef); Index: lld/ELF/Options.td =================================================================== --- lld/ELF/Options.td +++ lld/ELF/Options.td @@ -147,6 +147,8 @@ defm init: Eq<"init">, HelpText<"Specify an initializer function">, MetaVarName<"">; +defm just_symbols: Eq<"just-symbols">, HelpText<"Just link symbols">; + defm library: Eq<"library">, HelpText<"Root name of library to use">, MetaVarName<"">; Index: lld/ELF/SymbolTable.h =================================================================== --- lld/ELF/SymbolTable.h +++ lld/ELF/SymbolTable.h @@ -48,6 +48,8 @@ uint8_t Visibility = llvm::ELF::STV_HIDDEN, uint8_t Binding = llvm::ELF::STB_GLOBAL); + void addAbsoluteOptional(StringRef Name, uint64_t Value); + template Symbol *addUndefined(StringRef Name); template Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, Index: lld/ELF/SymbolTable.cpp =================================================================== --- lld/ELF/SymbolTable.cpp +++ lld/ELF/SymbolTable.cpp @@ -141,6 +141,14 @@ return cast(Sym->body()); } +void SymbolTable::addAbsoluteOptional(StringRef Name, uint64_t Value) { + outs() << Name << "=" << Value << "\n"; + SymbolBody *B = find(Name); + if (B->isUndefined()) + replaceBody(B->symbol(), nullptr, Name, false, 0, + STT_NOTYPE, Value, 0, nullptr); +} + // Set a flag for --trace-symbol so that we can print out a log message // if a new symbol with the same name is inserted into the symbol table. void SymbolTable::trace(StringRef Name) { Index: lld/test/ELF/Inputs/just-symbols.s =================================================================== --- /dev/null +++ lld/test/ELF/Inputs/just-symbols.s @@ -0,0 +1,3 @@ +.globl foo +foo: + ret Index: lld/test/ELF/just-symbols.s =================================================================== --- /dev/null +++ lld/test/ELF/just-symbols.s @@ -0,0 +1,15 @@ +# 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 -Ttext=0x10000 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 +# RUN: ld.lld %t2 -just-symbols=%t1.exe -o %t2.exe +# RUN: llvm-readelf -symbols %t2.exe | FileCheck %s + +# CHECK: 0000000000010000 0 NOTYPE GLOBAL DEFAULT ABS foo + +.globl _start, foo +_start: + call foo + ret