summaryrefslogtreecommitdiffstats
path: root/lld/lib/Driver/GnuLdInputGraph.cpp
blob: cd3eb8787f207a284d70c317a262b7d20d35d054 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//===- lib/Driver/GnuLdInputGraph.cpp -------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Driver/GnuLdInputGraph.h"
#include "lld/ReaderWriter/LinkerScript.h"

using namespace lld;

/// \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);
}

/// \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();
}

/// \brief Handle GnuLD script for ELF.
error_code ELFGNULdScript::parse(const LinkingContext &ctx,
                                 raw_ostream &diagnostics) {
  int64_t index = 0;
  if (error_code ec = GNULdScript::parse(ctx, diagnostics))
    return ec;
  for (const auto &c : _linkerScript->_commands) {
    if (auto group = dyn_cast<script::Group>(c)) {
      std::unique_ptr<Group> groupStart(new Group(index++));
      for (auto &path : group->getPaths()) {
        // TODO : Propagate Set WholeArchive/dashlPrefix
        auto inputNode = new ELFFileNode(
            _elfLinkingContext, _elfLinkingContext.allocateString(path._path),
            index++, false, path._asNeeded, false);
        std::unique_ptr<InputElement> inputFile(inputNode);
        cast<Group>(groupStart.get())->addFile(
            std::move(inputFile));
      }
      _expandElements.push_back(std::move(groupStart));
    }
  }
  return error_code::success();
}
OpenPOWER on IntegriCloud