Esempio n. 1
0
/// \brief Parse the input file to lld::File.
error_code ELFFileNode::parse(const LinkingContext &ctx,
                              raw_ostream &diagnostics) {
  ErrorOr<StringRef> filePath = getPath(ctx);
  if (error_code ec = filePath.getError())
    return ec;

  if (error_code ec = getBuffer(*filePath))
    return ec;

  if (ctx.logInputFiles())
    diagnostics << *filePath << "\n";

  if (_isWholeArchive) {
    std::vector<std::unique_ptr<File>> parsedFiles;
    error_code ec = ctx.registry().parseFile(_buffer, parsedFiles);
    if (ec)
      return ec;
    assert(parsedFiles.size() == 1);
    std::unique_ptr<File> f(parsedFiles[0].release());
    if (auto archive = reinterpret_cast<const ArchiveLibraryFile *>(f.get())) {
      // Have this node own the FileArchive object.
      _archiveFile.reset(archive);
      f.release();
      // Add all members to _files vector
      return archive->parseAllMembers(_files);
    } else {
      // if --whole-archive is around non-archive, just use it as normal.
      _files.push_back(std::move(f));
      return error_code::success();
    }
  }
  return ctx.registry().parseFile(_buffer, _files);
}
Esempio n. 2
0
/// \brief Read the file into _buffer.
error_code
FileNode::readFile(const LinkingContext &ctx, raw_ostream &diagnostics,
                   bool &isYaml) {
  ErrorOr<StringRef> filePath = getPath(ctx);
  if (!filePath &&
      error_code(filePath) == llvm::errc::no_such_file_or_directory)
    return make_error_code(llvm::errc::no_such_file_or_directory);

  // Create a memory buffer
  OwningPtr<llvm::MemoryBuffer> opmb;

  if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(*filePath, opmb))
    return ec;

  std::unique_ptr<MemoryBuffer> mb(opmb.take());
  _buffer = std::move(mb);

  if (ctx.logInputFiles())
    diagnostics << _buffer->getBufferIdentifier() << "\n";

  // YAML file is identified by a .objtxt extension
  // FIXME : Identify YAML files by using a magic
  if (filePath->endswith(".objtxt")) {
    if (error_code ec = ctx.getYAMLReader().parseFile(_buffer, _files))
      return ec;
    isYaml = true;
  }
  return error_code::success();
}
Esempio n. 3
0
File: Driver.cpp Progetto: sas/lld
void Driver::parseLLVMOptions(const LinkingContext &ctx) {
  // Honor -mllvm
  if (!ctx.llvmOptions().empty()) {
    unsigned numArgs = ctx.llvmOptions().size();
    auto **args = new const char *[numArgs + 2];
    args[0] = "lld (LLVM option parsing)";
    for (unsigned i = 0; i != numArgs; ++i)
      args[i + 1] = ctx.llvmOptions()[i];
    args[numArgs + 1] = nullptr;
    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
  }
}
Esempio n. 4
0
FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
  ErrorOr<std::unique_ptr<MemoryBuffer>> mb
      = MemoryBuffer::getFileOrSTDIN(path);
  if (std::error_code ec = mb.getError())
    return makeErrorFile(path, ec);
  std::vector<std::unique_ptr<File>> files;
  if (std::error_code ec = ctx.registry().loadFile(std::move(mb.get()), files))
    return makeErrorFile(path, ec);
  if (wholeArchive)
    return parseMemberFiles(files);
  return files;
}
Esempio n. 5
0
/// \brief Parse the input file to lld::File.
std::error_code PECOFFFileNode::parse(const LinkingContext &ctx,
                                      raw_ostream &diagnostics) {
  if (_parsed)
    return std::error_code();
  _parsed = true;
  ErrorOr<StringRef> filePath = getPath(ctx);
  if (std::error_code ec = filePath.getError()) {
    diagnostics << "File not found: " << _path << "\n";
    return ec;
  }

  if (std::error_code ec = getBuffer(*filePath)) {
    diagnostics << "Cannot open file: " << *filePath << "\n";
    return ec;
  }

  if (ctx.logInputFiles())
    diagnostics << *filePath << "\n";

  return ctx.registry().parseFile(_buffer, _files);
}
Esempio n. 6
0
/// \brief Parse the GnuLD Script
error_code GNULdScript::parse(const LinkingContext &ctx,
                              raw_ostream &diagnostics) {
  ErrorOr<StringRef> filePath = getPath(ctx);
  if (error_code ec = filePath.getError())
    return ec;

  if (error_code ec = getBuffer(*filePath))
    return ec;

  if (ctx.logInputFiles())
    diagnostics << *filePath << "\n";

  _lexer.reset(new script::Lexer(std::move(_buffer)));
  _parser.reset(new script::Parser(*_lexer.get()));

  _linkerScript = _parser->parse();

  if (!_linkerScript)
    return LinkerScriptReaderError::parse_error;

  return error_code::success();
}
Esempio n. 7
0
/// This is where the link is actually performed.
bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) {
  // Honor -mllvm
  if (!ctx.llvmOptions().empty()) {
    unsigned numArgs = ctx.llvmOptions().size();
    const char **args = new const char *[numArgs + 2];
    args[0] = "lld (LLVM option parsing)";
    for (unsigned i = 0; i != numArgs; ++i)
      args[i + 1] = ctx.llvmOptions()[i];
    args[numArgs + 1] = 0;
    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
  }
  if (ctx.getNodes().empty())
    return false;

  for (std::unique_ptr<Node> &ie : ctx.getNodes())
    if (FileNode *node = dyn_cast<FileNode>(ie.get()))
      ctx.getTaskGroup().spawn([node] { node->getFile()->parse(); });

  std::vector<std::unique_ptr<File>> internalFiles;
  ctx.createInternalFiles(internalFiles);
  for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
    auto &members = ctx.getNodes();
    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
  }

  // Give target a chance to add files.
  std::vector<std::unique_ptr<File>> implicitFiles;
  ctx.createImplicitFiles(implicitFiles);
  for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
    auto &members = ctx.getNodes();
    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
  }

  // Give target a chance to postprocess input files.
  // Mach-O uses this chance to move all object files before library files.
  // ELF adds specific undefined symbols resolver.
  ctx.finalizeInputFiles();

  // Do core linking.
  ScopedTask resolveTask(getDefaultDomain(), "Resolve");
  Resolver resolver(ctx);
  if (!resolver.resolve()) {
    ctx.getTaskGroup().sync();
    return false;
  }
  std::unique_ptr<SimpleFile> merged = resolver.resultFile();
  resolveTask.end();

  // Run passes on linked atoms.
  ScopedTask passTask(getDefaultDomain(), "Passes");
  PassManager pm;
  ctx.addPasses(pm);
  pm.runOnFile(merged);
  passTask.end();

  // Give linked atoms to Writer to generate output file.
  ScopedTask writeTask(getDefaultDomain(), "Write");
  if (std::error_code ec = ctx.writeFile(*merged)) {
    diagnostics << "Failed to write file '" << ctx.outputPath()
                << "': " << ec.message() << "\n";
    return false;
  }

  return true;
}
Esempio n. 8
0
/// This is where the link is actually performed.
bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) {
  // Honor -mllvm
  if (!context.llvmOptions().empty()) {
    unsigned numArgs = context.llvmOptions().size();
    const char **args = new const char *[numArgs + 2];
    args[0] = "lld (LLVM option parsing)";
    for (unsigned i = 0; i != numArgs; ++i)
      args[i + 1] = context.llvmOptions()[i];
    args[numArgs + 1] = 0;
    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
  }
  InputGraph &inputGraph = context.inputGraph();
  if (!inputGraph.numFiles())
    return false;

  // Read inputs
  ScopedTask readTask(getDefaultDomain(), "Read Args");
  std::vector<std::vector<std::unique_ptr<File> > > files(
      inputGraph.numFiles());
  size_t index = 0;
  std::atomic<bool> fail(false);
  TaskGroup tg;
  std::vector<std::unique_ptr<LinkerInput> > linkerInputs;
  for (auto &ie : inputGraph.inputElements()) {
    if (ie->kind() == InputElement::Kind::File) {
      FileNode *fileNode = (llvm::dyn_cast<FileNode>)(ie.get());
      auto linkerInput = fileNode->createLinkerInput(context);
      if (!linkerInput) {
        llvm::outs() << fileNode->errStr(error_code(linkerInput)) << "\n";
        return false;
      }
      linkerInputs.push_back(std::move(*linkerInput));
    }
    else {
      llvm_unreachable("Not handling other types of InputElements");
    }
  }
  for (const auto &input : linkerInputs) {
    if (context.logInputFiles())
      llvm::outs() << input->getUserPath() << "\n";

    tg.spawn([ &, index]{
      if (error_code ec = context.parseFile(*input, files[index])) {
        diagnostics << "Failed to read file: " << input->getUserPath() << ": "
                    << ec.message() << "\n";
        fail = true;
        return;
      }
    });
    ++index;
  }
  tg.sync();
  readTask.end();

  if (fail)
    return false;

  InputFiles inputs;

  for (auto &f : inputGraph.internalFiles())
    inputs.appendFile(*f.get());

  for (auto &f : files)
    inputs.appendFiles(f);

  // Give target a chance to add files.
  context.addImplicitFiles(inputs);

  // assign an ordinal to each file so sort() can preserve command line order
  inputs.assignFileOrdinals();

  // Do core linking.
  ScopedTask resolveTask(getDefaultDomain(), "Resolve");
  Resolver resolver(context, inputs);
  if (resolver.resolve()) {
    if (!context.allowRemainingUndefines())
      return false;
  }
  MutableFile &merged = resolver.resultFile();
  resolveTask.end();

  // Run passes on linked atoms.
  ScopedTask passTask(getDefaultDomain(), "Passes");
  PassManager pm;
  context.addPasses(pm);
  pm.runOnFile(merged);
  passTask.end();

  // Give linked atoms to Writer to generate output file.
  ScopedTask writeTask(getDefaultDomain(), "Write");
  if (error_code ec = context.writeFile(merged)) {
    diagnostics << "Failed to write file '" << context.outputPath()
                << "': " << ec.message() << "\n";
    return false;
  }

  return true;
}