/// claim_file_hook - called by gold to see whether this file is one that /// our plugin can handle. We'll try to open it and register all the symbols /// with add_symbol if possible. static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { LTOModule *M; const void *view; std::unique_ptr<MemoryBuffer> buffer; if (get_view) { if (get_view(file->handle, &view) != LDPS_OK) { (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name); return LDPS_ERR; } } else { int64_t offset = 0; // Gold has found what might be IR part-way inside of a file, such as // an .a archive. if (file->offset) { offset = file->offset; } if (std::error_code ec = MemoryBuffer::getOpenFileSlice( file->fd, file->name, buffer, file->filesize, offset)) { (*message)(LDPL_ERROR, ec.message().c_str()); return LDPS_ERR; } view = buffer->getBufferStart(); } if (!LTOModule::isBitcodeFile(view, file->filesize)) return LDPS_OK; std::string Error; M = LTOModule::makeLTOModule(view, file->filesize, TargetOpts, Error); if (!M) { (*message)(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s", Error.c_str()); return LDPS_OK; } *claimed = 1; Modules.resize(Modules.size() + 1); claimed_file &cf = Modules.back(); if (!options::triple.empty()) M->setTargetTriple(options::triple.c_str()); cf.handle = file->handle; unsigned sym_count = M->getSymbolCount(); cf.syms.reserve(sym_count); for (unsigned i = 0; i != sym_count; ++i) { lto_symbol_attributes attrs = M->getSymbolAttributes(i); if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) continue; cf.syms.push_back(ld_plugin_symbol()); ld_plugin_symbol &sym = cf.syms.back(); sym.name = strdup(M->getSymbolName(i)); sym.version = NULL; int scope = attrs & LTO_SYMBOL_SCOPE_MASK; bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; if (!CanBeHidden) CannotBeHidden.insert(sym.name); switch (scope) { case LTO_SYMBOL_SCOPE_HIDDEN: sym.visibility = LDPV_HIDDEN; break; case LTO_SYMBOL_SCOPE_PROTECTED: sym.visibility = LDPV_PROTECTED; break; case 0: // extern case LTO_SYMBOL_SCOPE_DEFAULT: case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: sym.visibility = LDPV_DEFAULT; break; default: (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope); return LDPS_ERR; } int definition = attrs & LTO_SYMBOL_DEFINITION_MASK; sym.comdat_key = NULL; switch (definition) { case LTO_SYMBOL_DEFINITION_REGULAR: sym.def = LDPK_DEF; break; case LTO_SYMBOL_DEFINITION_UNDEFINED: sym.def = LDPK_UNDEF; break; case LTO_SYMBOL_DEFINITION_TENTATIVE: sym.def = LDPK_COMMON; break; case LTO_SYMBOL_DEFINITION_WEAK: sym.comdat_key = sym.name; sym.def = LDPK_WEAKDEF; break; case LTO_SYMBOL_DEFINITION_WEAKUNDEF: sym.def = LDPK_WEAKUNDEF; break; default: (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition); return LDPS_ERR; } sym.size = 0; sym.resolution = LDPR_UNKNOWN; } cf.syms.reserve(cf.syms.size()); if (!cf.syms.empty()) { if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) { (*message)(LDPL_ERROR, "Unable to add symbols!"); return LDPS_ERR; } } if (CodeGen) { std::string Error; if (!CodeGen->addModule(M, Error)) { (*message)(LDPL_ERROR, "Error linking module: %s", Error.c_str()); return LDPS_ERR; } } delete M; return LDPS_OK; }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n"); if (OptLevel < '0' || OptLevel > '3') { errs() << argv[0] << ": optimization level must be between 0 and 3\n"; return 1; } // Initialize the configured targets. InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); // set up the TargetOptions for the machine TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); if (ListSymbolsOnly) return listSymbols(argv[0], Options); unsigned BaseArg = 0; LTOCodeGenerator CodeGen; if (UseDiagnosticHandler) CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr); switch (RelocModel) { case Reloc::Static: CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_STATIC); break; case Reloc::PIC_: CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC); break; case Reloc::DynamicNoPIC: CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC); break; default: CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DEFAULT); } CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); CodeGen.setTargetOptions(Options); llvm::StringSet<llvm::MallocAllocator> DSOSymbolsSet; for (unsigned i = 0; i < DSOSymbols.size(); ++i) DSOSymbolsSet.insert(DSOSymbols[i]); std::vector<std::string> KeptDSOSyms; for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { std::string error; std::unique_ptr<LTOModule> Module( LTOModule::createFromFile(InputFilenames[i].c_str(), Options, error)); if (!error.empty()) { errs() << argv[0] << ": error loading file '" << InputFilenames[i] << "': " << error << "\n"; return 1; } LTOModule *LTOMod = Module.get(); // We use the first input module as the destination module when // SetMergedModule is true. if (SetMergedModule && i == BaseArg) { // Transfer ownership to the code generator. CodeGen.setModule(Module.release()); } else if (!CodeGen.addModule(Module.get())) { // Print a message here so that we know addModule() did not abort. errs() << argv[0] << ": error adding file '" << InputFilenames[i] << "'\n"; return 1; } unsigned NumSyms = LTOMod->getSymbolCount(); for (unsigned I = 0; I < NumSyms; ++I) { StringRef Name = LTOMod->getSymbolName(I); if (!DSOSymbolsSet.count(Name)) continue; lto_symbol_attributes Attrs = LTOMod->getSymbolAttributes(I); unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK; if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN) KeptDSOSyms.push_back(Name); } } // Add all the exported symbols to the table of symbols to preserve. for (unsigned i = 0; i < ExportedSymbols.size(); ++i) CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str()); // Add all the dso symbols to the table of symbols to expose. for (unsigned i = 0; i < KeptDSOSyms.size(); ++i) CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str()); // Set cpu and attrs strings for the default target/subtarget. CodeGen.setCpu(MCPU.c_str()); CodeGen.setOptLevel(OptLevel - '0'); std::string attrs; for (unsigned i = 0; i < MAttrs.size(); ++i) { if (i > 0) attrs.append(","); attrs.append(MAttrs[i]); } if (!attrs.empty()) CodeGen.setAttr(attrs.c_str()); if (!OutputFilename.empty()) { std::string ErrorInfo; std::unique_ptr<MemoryBuffer> Code = CodeGen.compile( DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo); if (!Code) { errs() << argv[0] << ": error compiling the code: " << ErrorInfo << "\n"; return 1; } std::error_code EC; raw_fd_ostream FileStream(OutputFilename, EC, sys::fs::F_None); if (EC) { errs() << argv[0] << ": error opening the file '" << OutputFilename << "': " << EC.message() << "\n"; return 1; } FileStream.write(Code->getBufferStart(), Code->getBufferSize()); } else { std::string ErrorInfo; const char *OutputName = nullptr; if (!CodeGen.compile_to_file(&OutputName, DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo)) { errs() << argv[0] << ": error compiling the code: " << ErrorInfo << "\n"; return 1; } outs() << "Wrote native object file '" << OutputName << "'\n"; } return 0; }