blob: 44c045ad17ccc10a78ed0b5ff04e49b90e2f169e [file] [log] [blame]
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +00001//===- LinkerScript.cpp ---------------------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the parser/evaluator of the linker script.
11// It does not construct an AST but consume linker script directives directly.
12// Results are written to Symtab or Config object.
13//
14//===----------------------------------------------------------------------===//
15
16#include "Config.h"
17#include "Driver.h"
18#include "SymbolTable.h"
19#include "llvm/Support/FileSystem.h"
20#include "llvm/Support/MemoryBuffer.h"
21
22using namespace llvm;
23using namespace lld;
24using namespace lld::elf2;
25
26namespace {
27class LinkerScript {
28public:
Rui Ueyama983ed2b2015-10-01 15:23:09 +000029 LinkerScript(StringRef S) : Tokens(tokenize(S)) {}
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000030 void run();
31
32private:
33 static std::vector<StringRef> tokenize(StringRef S);
34 static StringRef skipSpace(StringRef S);
35 StringRef next();
36 bool atEOF() { return Tokens.size() == Pos; }
37 void expect(StringRef Expect);
38
39 void readAsNeeded();
40 void readGroup();
41 void readOutputFormat();
42
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000043 std::vector<StringRef> Tokens;
44 size_t Pos = 0;
45};
46}
47
48void LinkerScript::run() {
49 while (!atEOF()) {
50 StringRef Tok = next();
51 if (Tok == "GROUP") {
52 readGroup();
53 } else if (Tok == "OUTPUT_FORMAT") {
54 readOutputFormat();
55 } else {
56 error("unknown directive: " + Tok);
57 }
58 }
59}
60
61// Split S into linker script tokens.
62std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
63 std::vector<StringRef> Ret;
64 for (;;) {
65 S = skipSpace(S);
66 if (S.empty())
67 return Ret;
68
69 // Quoted token
70 if (S.startswith("\"")) {
71 size_t E = S.find("\"", 1);
72 if (E == StringRef::npos)
73 error("unclosed quote");
74 Ret.push_back(S.substr(1, E));
75 S = S.substr(E + 1);
76 continue;
77 }
78
79 // Unquoted token
80 size_t Pos = S.find_first_not_of(
81 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
82 "0123456789_.$/\\~=+[]*?-:");
83 // A character that cannot start a word (which is usually a
84 // punctuation) forms a single character token.
85 if (Pos == 0)
86 Pos = 1;
87 Ret.push_back(S.substr(0, Pos));
88 S = S.substr(Pos);
89 }
90}
91
92// Skip leading whitespace characters or /**/-style comments.
93StringRef LinkerScript::skipSpace(StringRef S) {
94 for (;;) {
95 if (S.startswith("/*")) {
96 size_t E = S.find("*/", 2);
97 if (E == StringRef::npos)
98 error("unclosed comment in a linker script");
99 S = S.substr(E + 2);
100 continue;
101 }
102 size_t Size = S.size();
103 S = S.ltrim();
104 if (S.size() == Size)
105 return S;
106 }
107}
108
109StringRef LinkerScript::next() {
110 if (Pos == Tokens.size())
111 error("unexpected EOF");
112 return Tokens[Pos++];
113}
114
115void LinkerScript::expect(StringRef Expect) {
116 StringRef Tok = next();
117 if (Tok != Expect)
118 error(Expect + " expected, but got " + Tok);
119}
120
121void LinkerScript::readAsNeeded() {
122 expect("(");
123 for (;;) {
124 StringRef Tok = next();
125 if (Tok == ")")
126 return;
Rui Ueyama983ed2b2015-10-01 15:23:09 +0000127 Driver->addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000128 }
129}
130
131void LinkerScript::readGroup() {
132 expect("(");
133 for (;;) {
134 StringRef Tok = next();
135 if (Tok == ")")
136 return;
137 if (Tok == "AS_NEEDED") {
138 readAsNeeded();
139 continue;
140 }
Rui Ueyama983ed2b2015-10-01 15:23:09 +0000141 Driver->addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000142 }
143}
144
145void LinkerScript::readOutputFormat() {
146 // Error checking only for now.
147 expect("(");
148 next();
149 expect(")");
150}
151
152// Entry point. The other functions or classes are private to this file.
Rui Ueyama983ed2b2015-10-01 15:23:09 +0000153void lld::elf2::readLinkerScript(MemoryBufferRef MB) {
154 LinkerScript(MB.getBuffer()).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000155}