Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -394,8 +394,24 @@ } } +static bool isJustSymbols(const Twine &Path) { + using namespace llvm::sys::fs; + return exists(Path) && !is_directory(Path); +} + static std::string getRpath(opt::InputArgList &Args) { - std::vector V = args::getStrings(Args, OPT_rpath); + std::vector V; + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_R: + if (isJustSymbols(Arg->getValue())) + break; + LLVM_FALLTHROUGH; + case OPT_rpath: + V.push_back(Arg->getValue()); + break; + } + } return llvm::join(V.begin(), V.end(), ":"); } @@ -832,6 +848,24 @@ } error(Twine("cannot find linker script ") + Arg->getValue()); break; + case OPT_R: + if (!isJustSymbols(Arg->getValue())) + break; + LLVM_FALLTHROUGH; + // Handle a rarely-used, --just-symbols option. + // + // This option allows you to link your output against other existing + // program, so that if you load both the other program and your + // output to memory, your output can refer other program's symbols. + // + // What we are doing here is to read defined symbols from given ELF + // files and add them as absolute symbols. + case OPT_just_symbols: { + Optional Buffer = readFile(Arg->getValue()); + if (Buffer.hasValue()) + Files.push_back(createJustSymbolsFile(*Buffer)); + break; + } case OPT_as_needed: Config->AsNeeded = true; break; Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -68,6 +68,7 @@ ArchiveKind, BitcodeKind, BinaryKind, + JustSymbolsKind, }; Kind kind() const { return FileKind; } @@ -123,7 +124,7 @@ ELFFileBase(Kind K, MemoryBufferRef M); static bool classof(const InputFile *F) { Kind K = F->kind(); - return K == ObjKind || K == SharedKind; + return K == ObjKind || K == SharedKind || K == JustSymbolsKind; } llvm::object::ELFFile getObj() const { @@ -328,9 +329,20 @@ template void parse(); }; +template class JustSymbolsFile : public ELFFileBase { +public: + explicit JustSymbolsFile(MemoryBufferRef M) + : ELFFileBase(InputFile::JustSymbolsKind, M) {} + static bool classof(const InputFile *F) { + return F->kind() == InputFile::JustSymbolsKind; + } + void parse(); +}; + InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", uint64_t OffsetInArchive = 0); InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); +InputFile *createJustSymbolsFile(MemoryBufferRef MB); extern std::vector BinaryFiles; extern std::vector BitcodeFiles; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -1007,6 +1007,38 @@ Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } +template void JustSymbolsFile::parse() { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::SymRange Elf_Sym_Range; + + StringRef ObjName = this->getName(); + ELFFile Obj = this->getObj(); + + if (Obj.getHeader()->e_type != ET_EXEC) + error(toString(this) + ": --just-symbols only accepts ET_EXEC files"); + + 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) { + StringRef SymName = CHECK(Sym.getName(StringTable), ObjName); + Symtab->addRegular(SymName, Sym.st_other, Sym.getType(), + Sym.st_value, Sym.st_size, Sym.getBinding(), + nullptr, nullptr); + } + } +} + static bool isBitcode(MemoryBufferRef MB) { using namespace sys::fs; return identify_magic(MB.getBuffer()) == file_magic::bitcode; @@ -1046,6 +1078,21 @@ } } +InputFile *elf::createJustSymbolsFile(MemoryBufferRef MB) { + switch (getELFKind(MB)) { + case ELF32LEKind: + return make>(MB); + case ELF32BEKind: + return make>(MB); + case ELF64LEKind: + return make>(MB); + case ELF64BEKind: + return make>(MB); + default: + llvm_unreachable("getELFKind"); + } +} + MemoryBufferRef LazyObjFile::getBuffer() { if (Seen) return MemoryBufferRef(); @@ -1153,3 +1200,8 @@ template void BinaryFile::parse(); template void BinaryFile::parse(); template void BinaryFile::parse(); + +template class elf::JustSymbolsFile; +template class elf::JustSymbolsFile; +template class elf::JustSymbolsFile; +template class elf::JustSymbolsFile; Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -153,6 +153,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<"">; @@ -245,6 +247,8 @@ def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; +def R: JoinedOrSeparate<["-"], "R">, HelpText<"Alias to --rpath or --just-symbols">; + defm reproduce: Eq<"reproduce">, HelpText<"Dump linker invocation and input files for debugging">; @@ -351,7 +355,6 @@ def alias_pie_pic_executable: F<"pic-executable">, Alias; def alias_print_map_M: Flag<["-"], "M">, Alias; def alias_relocatable_r: Flag<["-"], "r">, Alias; -def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias; def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias