brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.0 KiB · 33c3e6f Raw
529 lines · cpp
1//===- llvm-link.cpp - Low-level LLVM linker ------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This utility may be invoked in the following manner:10//  llvm-link a.bc b.bc c.bc -o x.bc11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ADT/STLExtras.h"15#include "llvm/BinaryFormat/Magic.h"16#include "llvm/Bitcode/BitcodeReader.h"17#include "llvm/Bitcode/BitcodeWriter.h"18#include "llvm/IR/AutoUpgrade.h"19#include "llvm/IR/DiagnosticInfo.h"20#include "llvm/IR/DiagnosticPrinter.h"21#include "llvm/IR/LLVMContext.h"22#include "llvm/IR/Module.h"23#include "llvm/IR/ModuleSummaryIndex.h"24#include "llvm/IR/Verifier.h"25#include "llvm/IRReader/IRReader.h"26#include "llvm/Linker/Linker.h"27#include "llvm/Object/Archive.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/FileSystem.h"30#include "llvm/Support/InitLLVM.h"31#include "llvm/Support/Path.h"32#include "llvm/Support/SourceMgr.h"33#include "llvm/Support/SystemUtils.h"34#include "llvm/Support/ToolOutputFile.h"35#include "llvm/Support/WithColor.h"36#include "llvm/Transforms/IPO/FunctionImport.h"37#include "llvm/Transforms/IPO/Internalize.h"38#include "llvm/Transforms/Utils/FunctionImportUtils.h"39 40#include <memory>41#include <utility>42using namespace llvm;43 44static cl::OptionCategory LinkCategory("Link Options");45 46static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,47                                            cl::desc("<input bitcode files>"),48                                            cl::cat(LinkCategory));49 50static cl::list<std::string> OverridingInputs(51    "override", cl::value_desc("filename"),52    cl::desc(53        "input bitcode file which can override previously defined symbol(s)"),54    cl::cat(LinkCategory));55 56// Option to simulate function importing for testing. This enables using57// llvm-link to simulate ThinLTO backend processes.58static cl::list<std::string> Imports(59    "import", cl::value_desc("function:filename"),60    cl::desc("Pair of function name and filename, where function should be "61             "imported from bitcode in filename"),62    cl::cat(LinkCategory));63 64// Option to support testing of function importing. The module summary65// must be specified in the case were we request imports via the -import66// option, as well as when compiling any module with functions that may be67// exported (imported by a different llvm-link -import invocation), to ensure68// consistent promotion and renaming of locals.69static cl::opt<std::string>70    SummaryIndex("summary-index", cl::desc("Module summary index filename"),71                 cl::init(""), cl::value_desc("filename"),72                 cl::cat(LinkCategory));73 74static cl::opt<std::string>75    OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),76                   cl::value_desc("filename"), cl::cat(LinkCategory));77 78static cl::opt<bool> Internalize("internalize",79                                 cl::desc("Internalize linked symbols"),80                                 cl::cat(LinkCategory));81 82static cl::opt<bool>83    DisableDITypeMap("disable-debug-info-type-map",84                     cl::desc("Don't use a uniquing type map for debug info"),85                     cl::cat(LinkCategory));86 87static cl::opt<bool> OnlyNeeded("only-needed",88                                cl::desc("Link only needed symbols"),89                                cl::cat(LinkCategory));90 91static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"),92                           cl::cat(LinkCategory));93 94static cl::opt<bool> DisableLazyLoad("disable-lazy-loading",95                                     cl::desc("Disable lazy module loading"),96                                     cl::cat(LinkCategory));97 98static cl::opt<bool> OutputAssembly("S",99                                    cl::desc("Write output as LLVM assembly"),100                                    cl::Hidden, cl::cat(LinkCategory));101 102static cl::opt<bool> Verbose("v",103                             cl::desc("Print information about actions taken"),104                             cl::cat(LinkCategory));105 106static cl::opt<bool> DumpAsm("d", cl::desc("Print assembly as linked"),107                             cl::Hidden, cl::cat(LinkCategory));108 109static cl::opt<bool> SuppressWarnings("suppress-warnings",110                                      cl::desc("Suppress all linking warnings"),111                                      cl::init(false), cl::cat(LinkCategory));112 113static cl::opt<bool> NoVerify("disable-verify",114                              cl::desc("Do not run the verifier"), cl::Hidden,115                              cl::cat(LinkCategory));116 117static cl::opt<bool> IgnoreNonBitcode(118    "ignore-non-bitcode",119    cl::desc("Do not report an error for non-bitcode files in archives"),120    cl::Hidden);121 122static ExitOnError ExitOnErr;123 124// Read the specified bitcode file in and return it. This routine searches the125// link path for the specified file to try to find it...126//127static std::unique_ptr<Module> loadFile(const char *argv0,128                                        std::unique_ptr<MemoryBuffer> Buffer,129                                        LLVMContext &Context,130                                        bool MaterializeMetadata = true) {131  SMDiagnostic Err;132  if (Verbose)133    errs() << "Loading '" << Buffer->getBufferIdentifier() << "'\n";134  std::unique_ptr<Module> Result;135  if (DisableLazyLoad)136    Result = parseIR(*Buffer, Err, Context);137  else138    Result =139        getLazyIRModule(std::move(Buffer), Err, Context, !MaterializeMetadata);140 141  if (!Result) {142    Err.print(argv0, errs());143    return nullptr;144  }145 146  if (MaterializeMetadata) {147    ExitOnErr(Result->materializeMetadata());148    UpgradeDebugInfo(*Result);149  }150 151  return Result;152}153 154static std::unique_ptr<Module> loadArFile(const char *Argv0,155                                          std::unique_ptr<MemoryBuffer> Buffer,156                                          LLVMContext &Context) {157  std::unique_ptr<Module> Result(new Module("ArchiveModule", Context));158  StringRef ArchiveName = Buffer->getBufferIdentifier();159  if (Verbose)160    errs() << "Reading library archive file '" << ArchiveName161           << "' to memory\n";162  Expected<std::unique_ptr<object::Archive>> ArchiveOrError =163      object::Archive::create(Buffer->getMemBufferRef());164  if (!ArchiveOrError)165    ExitOnErr(ArchiveOrError.takeError());166 167  std::unique_ptr<object::Archive> Archive = std::move(ArchiveOrError.get());168 169  Linker L(*Result);170  Error Err = Error::success();171  for (const object::Archive::Child &C : Archive->children(Err)) {172    Expected<StringRef> Ename = C.getName();173    if (Error E = Ename.takeError()) {174      errs() << Argv0 << ": ";175      WithColor::error() << " failed to read name of archive member"176                         << ArchiveName << "'\n";177      return nullptr;178    }179    std::string ChildName = Ename.get().str();180    if (Verbose)181      errs() << "Parsing member '" << ChildName182             << "' of archive library to module.\n";183    SMDiagnostic ParseErr;184    Expected<MemoryBufferRef> MemBuf = C.getMemoryBufferRef();185    if (Error E = MemBuf.takeError()) {186      errs() << Argv0 << ": ";187      WithColor::error() << " loading memory for member '" << ChildName188                         << "' of archive library failed'" << ArchiveName189                         << "'\n";190      return nullptr;191    };192 193    if (!isBitcode(reinterpret_cast<const unsigned char *>(194                       MemBuf.get().getBufferStart()),195                   reinterpret_cast<const unsigned char *>(196                       MemBuf.get().getBufferEnd()))) {197      if (IgnoreNonBitcode)198        continue;199      errs() << Argv0 << ": ";200      WithColor::error() << "  member of archive is not a bitcode file: '"201                         << ChildName << "'\n";202      return nullptr;203    }204 205    std::unique_ptr<Module> M;206    if (DisableLazyLoad)207      M = parseIR(MemBuf.get(), ParseErr, Context);208    else209      M = getLazyIRModule(MemoryBuffer::getMemBuffer(MemBuf.get(), false),210                          ParseErr, Context);211 212    if (!M) {213      errs() << Argv0 << ": ";214      WithColor::error() << " parsing member '" << ChildName215                         << "' of archive library failed'" << ArchiveName216                         << "'\n";217      return nullptr;218    }219    if (Verbose)220      errs() << "Linking member '" << ChildName << "' of archive library.\n";221    if (L.linkInModule(std::move(M)))222      return nullptr;223  } // end for each child224  ExitOnErr(std::move(Err));225  return Result;226}227 228namespace {229 230/// Helper to load on demand a Module from file and cache it for subsequent231/// queries during function importing.232class ModuleLazyLoaderCache {233  /// Cache of lazily loaded module for import.234  StringMap<std::unique_ptr<Module>> ModuleMap;235 236  /// Retrieve a Module from the cache or lazily load it on demand.237  std::function<std::unique_ptr<Module>(const char *argv0,238                                        const std::string &FileName)>239      createLazyModule;240 241public:242  /// Create the loader, Module will be initialized in \p Context.243  ModuleLazyLoaderCache(std::function<std::unique_ptr<Module>(244                            const char *argv0, const std::string &FileName)>245                            createLazyModule)246      : createLazyModule(std::move(createLazyModule)) {}247 248  /// Retrieve a Module from the cache or lazily load it on demand.249  Module &operator()(const char *argv0, const std::string &FileName);250 251  std::unique_ptr<Module> takeModule(const std::string &FileName) {252    auto I = ModuleMap.find(FileName);253    assert(I != ModuleMap.end());254    std::unique_ptr<Module> Ret = std::move(I->second);255    ModuleMap.erase(I);256    return Ret;257  }258};259 260// Get a Module for \p FileName from the cache, or load it lazily.261Module &ModuleLazyLoaderCache::operator()(const char *argv0,262                                          const std::string &Identifier) {263  auto &Module = ModuleMap[Identifier];264  if (!Module) {265    Module = createLazyModule(argv0, Identifier);266    assert(Module && "Failed to create lazy module!");267  }268  return *Module;269}270} // anonymous namespace271 272namespace {273struct LLVMLinkDiagnosticHandler : public DiagnosticHandler {274  bool handleDiagnostics(const DiagnosticInfo &DI) override {275    unsigned Severity = DI.getSeverity();276    switch (Severity) {277    case DS_Error:278      WithColor::error();279      break;280    case DS_Warning:281      if (SuppressWarnings)282        return true;283      WithColor::warning();284      break;285    case DS_Remark:286    case DS_Note:287      llvm_unreachable("Only expecting warnings and errors");288    }289 290    DiagnosticPrinterRawOStream DP(errs());291    DI.print(DP);292    errs() << '\n';293    return true;294  }295};296} // namespace297 298/// Import any functions requested via the -import option.299static bool importFunctions(const char *argv0, Module &DestModule) {300  if (SummaryIndex.empty())301    return true;302  std::unique_ptr<ModuleSummaryIndex> Index =303      ExitOnErr(llvm::getModuleSummaryIndexForFile(SummaryIndex));304 305  // Map of Module -> List of globals to import from the Module306  FunctionImporter::ImportIDTable ImportIDs;307  FunctionImporter::ImportMapTy ImportList(ImportIDs);308 309  auto ModuleLoader = [&DestModule](const char *argv0,310                                    const std::string &Identifier) {311    std::unique_ptr<MemoryBuffer> Buffer = ExitOnErr(errorOrToExpected(312        MemoryBuffer::getFileOrSTDIN(Identifier, /*IsText=*/true)));313    return loadFile(argv0, std::move(Buffer), DestModule.getContext(), false);314  };315 316  ModuleLazyLoaderCache ModuleLoaderCache(ModuleLoader);317  // Owns the filename strings used to key into the ImportList. Normally this is318  // constructed from the index and the strings are owned by the index, however,319  // since we are synthesizing this data structure from options we need a cache320  // to own those strings.321  StringSet<> FileNameStringCache;322  for (const auto &Import : Imports) {323    // Identify the requested function and its bitcode source file.324    size_t Idx = Import.find(':');325    if (Idx == std::string::npos) {326      errs() << "Import parameter bad format: " << Import << "\n";327      return false;328    }329    std::string FunctionName = Import.substr(0, Idx);330    std::string FileName = Import.substr(Idx + 1, std::string::npos);331 332    // Load the specified source module.333    auto &SrcModule = ModuleLoaderCache(argv0, FileName);334 335    if (!NoVerify && verifyModule(SrcModule, &errs())) {336      errs() << argv0 << ": " << FileName;337      WithColor::error() << "input module is broken!\n";338      return false;339    }340 341    Function *F = SrcModule.getFunction(FunctionName);342    if (!F) {343      errs() << "Ignoring import request for non-existent function "344             << FunctionName << " from " << FileName << "\n";345      continue;346    }347    // We cannot import weak_any functions without possibly affecting the348    // order they are seen and selected by the linker, changing program349    // semantics.350    if (F->hasWeakAnyLinkage()) {351      errs() << "Ignoring import request for weak-any function " << FunctionName352             << " from " << FileName << "\n";353      continue;354    }355 356    if (Verbose)357      errs() << "Importing " << FunctionName << " from " << FileName << "\n";358 359    // `-import` specifies the `<filename,function-name>` pairs to import as360    // definition, so make the import type definition directly.361    // FIXME: A follow-up patch should add test coverage for import declaration362    // in `llvm-link` CLI (e.g., by introducing a new command line option).363    ImportList.addDefinition(364        FileNameStringCache.insert(FileName).first->getKey(), F->getGUID());365  }366  auto CachedModuleLoader = [&](StringRef Identifier) {367    return ModuleLoaderCache.takeModule(std::string(Identifier));368  };369  FunctionImporter Importer(*Index, CachedModuleLoader,370                            /*ClearDSOLocalOnDeclarations=*/false);371  ExitOnErr(Importer.importFunctions(DestModule, ImportList));372 373  return true;374}375 376static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,377                      const cl::list<std::string> &Files, unsigned Flags) {378  // Filter out flags that don't apply to the first file we load.379  unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc;380  // Similar to some flags, internalization doesn't apply to the first file.381  bool InternalizeLinkedSymbols = false;382  for (const auto &File : Files) {383    auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/true);384 385    // When we encounter a missing file, make sure we expose its name.386    if (auto EC = BufferOrErr.getError())387      if (EC == std::errc::no_such_file_or_directory)388        ExitOnErr(createStringError(EC, "No such file or directory: '%s'",389                                    File.c_str()));390 391    std::unique_ptr<MemoryBuffer> Buffer =392        ExitOnErr(errorOrToExpected(std::move(BufferOrErr)));393 394    std::unique_ptr<Module> M =395        identify_magic(Buffer->getBuffer()) == file_magic::archive396            ? loadArFile(argv0, std::move(Buffer), Context)397            : loadFile(argv0, std::move(Buffer), Context);398    if (!M) {399      errs() << argv0 << ": ";400      WithColor::error() << " loading file '" << File << "'\n";401      return false;402    }403 404    // Note that when ODR merging types cannot verify input files in here When405    // doing that debug metadata in the src module might already be pointing to406    // the destination.407    if (DisableDITypeMap && !NoVerify && verifyModule(*M, &errs())) {408      errs() << argv0 << ": " << File << ": ";409      WithColor::error() << "input module is broken!\n";410      return false;411    }412 413    // If a module summary index is supplied, load it so linkInModule can treat414    // local functions/variables as exported and promote if necessary.415    if (!SummaryIndex.empty()) {416      std::unique_ptr<ModuleSummaryIndex> Index =417          ExitOnErr(llvm::getModuleSummaryIndexForFile(SummaryIndex));418 419      // Conservatively mark all internal values as promoted, since this tool420      // does not do the ThinLink that would normally determine what values to421      // promote.422      for (auto &I : *Index) {423        for (auto &S : I.second.getSummaryList()) {424          if (GlobalValue::isLocalLinkage(S->linkage()))425            S->setLinkage(GlobalValue::ExternalLinkage);426        }427      }428 429      // Promotion430      renameModuleForThinLTO(*M, *Index,431                             /*ClearDSOLocalOnDeclarations=*/false);432    }433 434    if (Verbose)435      errs() << "Linking in '" << File << "'\n";436 437    bool Err = false;438    if (InternalizeLinkedSymbols) {439      Err = L.linkInModule(440          std::move(M), ApplicableFlags, [](Module &M, const StringSet<> &GVS) {441            internalizeModule(M, [&GVS](const GlobalValue &GV) {442              return !GV.hasName() || (GVS.count(GV.getName()) == 0);443            });444          });445    } else {446      Err = L.linkInModule(std::move(M), ApplicableFlags);447    }448 449    if (Err)450      return false;451 452    // Internalization applies to linking of subsequent files.453    InternalizeLinkedSymbols = Internalize;454 455    // All linker flags apply to linking of subsequent files.456    ApplicableFlags = Flags;457  }458 459  return true;460}461 462int main(int argc, char **argv) {463  InitLLVM X(argc, argv);464  ExitOnErr.setBanner(std::string(argv[0]) + ": ");465 466  cl::HideUnrelatedOptions({&LinkCategory, &getColorCategory()});467  cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");468 469  LLVMContext Context;470  Context.setDiagnosticHandler(std::make_unique<LLVMLinkDiagnosticHandler>(),471                               true);472 473  if (!DisableDITypeMap)474    Context.enableDebugTypeODRUniquing();475 476  auto Composite = std::make_unique<Module>("llvm-link", Context);477  Linker L(*Composite);478 479  unsigned Flags = Linker::Flags::None;480  if (OnlyNeeded)481    Flags |= Linker::Flags::LinkOnlyNeeded;482 483  // First add all the regular input files484  if (!linkFiles(argv[0], Context, L, InputFilenames, Flags))485    return 1;486 487  // Next the -override ones.488  if (!linkFiles(argv[0], Context, L, OverridingInputs,489                 Flags | Linker::Flags::OverrideFromSrc))490    return 1;491 492  // Import any functions requested via -import493  if (!importFunctions(argv[0], *Composite))494    return 1;495 496  if (DumpAsm)497    errs() << "Here's the assembly:\n" << *Composite;498 499  std::error_code EC;500  ToolOutputFile Out(OutputFilename, EC,501                     OutputAssembly ? sys::fs::OF_TextWithCRLF502                                    : sys::fs::OF_None);503  if (EC) {504    WithColor::error() << EC.message() << '\n';505    return 1;506  }507 508  if (!NoVerify && verifyModule(*Composite, &errs())) {509    errs() << argv[0] << ": ";510    WithColor::error() << "linked module is broken!\n";511    return 1;512  }513 514  if (Verbose)515    errs() << "Writing bitcode...\n";516  Composite->removeDebugIntrinsicDeclarations();517  if (OutputAssembly) {518    Composite->print(Out.os(), nullptr, /* ShouldPreserveUseListOrder */ false);519  } else if (Force || !CheckBitcodeOutputToConsole(Out.os())) {520    WriteBitcodeToFile(*Composite, Out.os(),521                       /* ShouldPreserveUseListOrder */ true);522  }523 524  // Declare success.525  Out.keep();526 527  return 0;528}529