1 //===- 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 Driver 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 #include "llvm/Support/Path.h" 22 #include "llvm/Support/StringSaver.h" 23 24 using namespace llvm; 25 using namespace lld; 26 using namespace lld::elf2; 27 28 namespace { 29 class LinkerScript { 30 public: 31 LinkerScript(BumpPtrAllocator *A, StringRef S) 32 : Saver(*A), Tokens(tokenize(S)) {} 33 void run(); 34 35 private: 36 static std::vector<StringRef> tokenize(StringRef S); 37 static StringRef skipSpace(StringRef S); 38 StringRef next(); 39 bool atEOF() { return Tokens.size() == Pos; } 40 void expect(StringRef Expect); 41 42 void addFile(StringRef Path); 43 44 void readAsNeeded(); 45 void readEntry(); 46 void readGroup(); 47 void readInclude(); 48 void readOutput(); 49 void readOutputArch(); 50 void readOutputFormat(); 51 void readSearchDir(); 52 53 StringSaver Saver; 54 std::vector<StringRef> Tokens; 55 size_t Pos = 0; 56 }; 57 } 58 59 void LinkerScript::run() { 60 while (!atEOF()) { 61 StringRef Tok = next(); 62 if (Tok == ";") 63 continue; 64 if (Tok == "ENTRY") { 65 readEntry(); 66 } else if (Tok == "GROUP" || Tok == "INPUT") { 67 readGroup(); 68 } else if (Tok == "INCLUDE") { 69 readInclude(); 70 } else if (Tok == "OUTPUT") { 71 readOutput(); 72 } else if (Tok == "OUTPUT_ARCH") { 73 readOutputArch(); 74 } else if (Tok == "OUTPUT_FORMAT") { 75 readOutputFormat(); 76 } else if (Tok == "SEARCH_DIR") { 77 readSearchDir(); 78 } else { 79 error("unknown directive: " + Tok); 80 } 81 } 82 } 83 84 // Split S into linker script tokens. 85 std::vector<StringRef> LinkerScript::tokenize(StringRef S) { 86 std::vector<StringRef> Ret; 87 for (;;) { 88 S = skipSpace(S); 89 if (S.empty()) 90 return Ret; 91 92 // Quoted token 93 if (S.startswith("\"")) { 94 size_t E = S.find("\"", 1); 95 if (E == StringRef::npos) 96 error("unclosed quote"); 97 Ret.push_back(S.substr(1, E)); 98 S = S.substr(E + 1); 99 continue; 100 } 101 102 // Unquoted token 103 size_t Pos = S.find_first_not_of( 104 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 105 "0123456789_.$/\\~=+[]*?-:"); 106 // A character that cannot start a word (which is usually a 107 // punctuation) forms a single character token. 108 if (Pos == 0) 109 Pos = 1; 110 Ret.push_back(S.substr(0, Pos)); 111 S = S.substr(Pos); 112 } 113 } 114 115 // Skip leading whitespace characters or /**/-style comments. 116 StringRef LinkerScript::skipSpace(StringRef S) { 117 for (;;) { 118 if (S.startswith("/*")) { 119 size_t E = S.find("*/", 2); 120 if (E == StringRef::npos) 121 error("unclosed comment in a linker script"); 122 S = S.substr(E + 2); 123 continue; 124 } 125 size_t Size = S.size(); 126 S = S.ltrim(); 127 if (S.size() == Size) 128 return S; 129 } 130 } 131 132 StringRef LinkerScript::next() { 133 if (Pos == Tokens.size()) 134 error("unexpected EOF"); 135 return Tokens[Pos++]; 136 } 137 138 void LinkerScript::expect(StringRef Expect) { 139 StringRef Tok = next(); 140 if (Tok != Expect) 141 error(Expect + " expected, but got " + Tok); 142 } 143 144 void LinkerScript::addFile(StringRef S) { 145 if (sys::path::is_absolute(S)) { 146 Driver->addFile(S); 147 } else if (S.startswith("=")) { 148 if (Config->Sysroot.empty()) 149 Driver->addFile(S.substr(1)); 150 else 151 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1))); 152 } else if (S.startswith("-l")) { 153 Driver->addFile(searchLibrary(S.substr(2))); 154 } else { 155 std::string Path = findFromSearchPaths(S); 156 if (Path.empty()) 157 error("Unable to find " + S); 158 Driver->addFile(Saver.save(Path)); 159 } 160 } 161 162 void LinkerScript::readAsNeeded() { 163 expect("("); 164 bool Orig = Config->AsNeeded; 165 Config->AsNeeded = true; 166 for (;;) { 167 StringRef Tok = next(); 168 if (Tok == ")") 169 break; 170 addFile(Tok); 171 } 172 Config->AsNeeded = Orig; 173 } 174 175 void LinkerScript::readEntry() { 176 // -e <symbol> takes predecence over ENTRY(<symbol>). 177 expect("("); 178 StringRef Tok = next(); 179 if (Config->Entry.empty()) 180 Config->Entry = Tok; 181 expect(")"); 182 } 183 184 void LinkerScript::readGroup() { 185 expect("("); 186 for (;;) { 187 StringRef Tok = next(); 188 if (Tok == ")") 189 return; 190 if (Tok == "AS_NEEDED") { 191 readAsNeeded(); 192 continue; 193 } 194 addFile(Tok); 195 } 196 } 197 198 void LinkerScript::readInclude() { 199 StringRef Tok = next(); 200 auto MBOrErr = MemoryBuffer::getFile(Tok); 201 error(MBOrErr, "cannot open " + Tok); 202 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; 203 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); 204 std::vector<StringRef> V = tokenize(S); 205 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); 206 } 207 208 void LinkerScript::readOutput() { 209 // -o <file> takes predecence over OUTPUT(<file>). 210 expect("("); 211 StringRef Tok = next(); 212 if (Config->OutputFile.empty()) 213 Config->OutputFile = Tok; 214 expect(")"); 215 } 216 217 void LinkerScript::readOutputArch() { 218 // Error checking only for now. 219 expect("("); 220 next(); 221 expect(")"); 222 } 223 224 void LinkerScript::readOutputFormat() { 225 // Error checking only for now. 226 expect("("); 227 next(); 228 StringRef Tok = next(); 229 if (Tok == ")") 230 return; 231 if (Tok != ",") 232 error("unexpected token: " + Tok); 233 next(); 234 expect(","); 235 next(); 236 expect(")"); 237 } 238 239 void LinkerScript::readSearchDir() { 240 expect("("); 241 Config->SearchPaths.push_back(next()); 242 expect(")"); 243 } 244 245 // Entry point. The other functions or classes are private to this file. 246 void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) { 247 LinkerScript(A, MB.getBuffer()).run(); 248 } 249