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, bool B) 32 : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {} 33 void run(); 34 35 private: 36 void setError(const Twine &Msg); 37 static std::vector<StringRef> tokenize(StringRef S); 38 static StringRef skipSpace(StringRef S); 39 bool atEOF(); 40 StringRef next(); 41 bool skip(StringRef Tok); 42 void expect(StringRef Expect); 43 44 void addFile(StringRef Path); 45 46 void readAsNeeded(); 47 void readEntry(); 48 void readExtern(); 49 void readGroup(); 50 void readInclude(); 51 void readOutput(); 52 void readOutputArch(); 53 void readOutputFormat(); 54 void readSearchDir(); 55 void readSections(); 56 57 void readOutputSectionDescription(); 58 59 StringSaver Saver; 60 std::vector<StringRef> Tokens; 61 bool Error = false; 62 size_t Pos = 0; 63 bool IsUnderSysroot; 64 }; 65 } 66 67 void LinkerScript::run() { 68 while (!atEOF()) { 69 StringRef Tok = next(); 70 if (Tok == ";") 71 continue; 72 if (Tok == "ENTRY") { 73 readEntry(); 74 } else if (Tok == "EXTERN") { 75 readExtern(); 76 } else if (Tok == "GROUP" || Tok == "INPUT") { 77 readGroup(); 78 } else if (Tok == "INCLUDE") { 79 readInclude(); 80 } else if (Tok == "OUTPUT") { 81 readOutput(); 82 } else if (Tok == "OUTPUT_ARCH") { 83 readOutputArch(); 84 } else if (Tok == "OUTPUT_FORMAT") { 85 readOutputFormat(); 86 } else if (Tok == "SEARCH_DIR") { 87 readSearchDir(); 88 } else if (Tok == "SECTIONS") { 89 readSections(); 90 } else { 91 setError("unknown directive: " + Tok); 92 return; 93 } 94 } 95 } 96 97 // We don't want to record cascading errors. Keep only the first one. 98 void LinkerScript::setError(const Twine &Msg) { 99 if (Error) 100 return; 101 error(Msg); 102 Error = true; 103 } 104 105 // Split S into linker script tokens. 106 std::vector<StringRef> LinkerScript::tokenize(StringRef S) { 107 std::vector<StringRef> Ret; 108 for (;;) { 109 S = skipSpace(S); 110 if (S.empty()) 111 return Ret; 112 113 // Quoted token 114 if (S.startswith("\"")) { 115 size_t E = S.find("\"", 1); 116 if (E == StringRef::npos) { 117 error("unclosed quote"); 118 return {}; 119 } 120 Ret.push_back(S.substr(1, E - 1)); 121 S = S.substr(E + 1); 122 continue; 123 } 124 125 // Unquoted token 126 size_t Pos = S.find_first_not_of( 127 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 128 "0123456789_.$/\\~=+[]*?-:"); 129 // A character that cannot start a word (which is usually a 130 // punctuation) forms a single character token. 131 if (Pos == 0) 132 Pos = 1; 133 Ret.push_back(S.substr(0, Pos)); 134 S = S.substr(Pos); 135 } 136 } 137 138 // Skip leading whitespace characters or /**/-style comments. 139 StringRef LinkerScript::skipSpace(StringRef S) { 140 for (;;) { 141 if (S.startswith("/*")) { 142 size_t E = S.find("*/", 2); 143 if (E == StringRef::npos) { 144 error("unclosed comment in a linker script"); 145 return ""; 146 } 147 S = S.substr(E + 2); 148 continue; 149 } 150 size_t Size = S.size(); 151 S = S.ltrim(); 152 if (S.size() == Size) 153 return S; 154 } 155 } 156 157 // An errneous token is handled as if it were the last token before EOF. 158 bool LinkerScript::atEOF() { return Error || Tokens.size() == Pos; } 159 160 StringRef LinkerScript::next() { 161 if (Error) 162 return ""; 163 if (atEOF()) { 164 setError("unexpected EOF"); 165 return ""; 166 } 167 return Tokens[Pos++]; 168 } 169 170 bool LinkerScript::skip(StringRef Tok) { 171 if (Error) 172 return false; 173 if (atEOF()) { 174 setError("unexpected EOF"); 175 return false; 176 } 177 if (Tok != Tokens[Pos]) 178 return false; 179 ++Pos; 180 return true; 181 } 182 183 void LinkerScript::expect(StringRef Expect) { 184 if (Error) 185 return; 186 StringRef Tok = next(); 187 if (Tok != Expect) 188 setError(Expect + " expected, but got " + Tok); 189 } 190 191 void LinkerScript::addFile(StringRef S) { 192 if (IsUnderSysroot && S.startswith("/")) { 193 SmallString<128> Path; 194 (Config->Sysroot + S).toStringRef(Path); 195 if (sys::fs::exists(Path)) { 196 Driver->addFile(Saver.save(Path.str())); 197 return; 198 } 199 } 200 201 if (sys::path::is_absolute(S)) { 202 Driver->addFile(S); 203 } else if (S.startswith("=")) { 204 if (Config->Sysroot.empty()) 205 Driver->addFile(S.substr(1)); 206 else 207 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1))); 208 } else if (S.startswith("-l")) { 209 Driver->addLibrary(S.substr(2)); 210 } else if (sys::fs::exists(S)) { 211 Driver->addFile(S); 212 } else { 213 std::string Path = findFromSearchPaths(S); 214 if (Path.empty()) 215 setError("Unable to find " + S); 216 else 217 Driver->addFile(Saver.save(Path)); 218 } 219 } 220 221 void LinkerScript::readAsNeeded() { 222 expect("("); 223 bool Orig = Config->AsNeeded; 224 Config->AsNeeded = true; 225 while (!Error) { 226 StringRef Tok = next(); 227 if (Tok == ")") 228 break; 229 addFile(Tok); 230 } 231 Config->AsNeeded = Orig; 232 } 233 234 void LinkerScript::readEntry() { 235 // -e <symbol> takes predecence over ENTRY(<symbol>). 236 expect("("); 237 StringRef Tok = next(); 238 if (Config->Entry.empty()) 239 Config->Entry = Tok; 240 expect(")"); 241 } 242 243 void LinkerScript::readExtern() { 244 expect("("); 245 while (!Error) { 246 StringRef Tok = next(); 247 if (Tok == ")") 248 return; 249 Config->Undefined.push_back(Tok); 250 } 251 } 252 253 void LinkerScript::readGroup() { 254 expect("("); 255 while (!Error) { 256 StringRef Tok = next(); 257 if (Tok == ")") 258 return; 259 if (Tok == "AS_NEEDED") { 260 readAsNeeded(); 261 continue; 262 } 263 addFile(Tok); 264 } 265 } 266 267 void LinkerScript::readInclude() { 268 StringRef Tok = next(); 269 auto MBOrErr = MemoryBuffer::getFile(Tok); 270 if (!MBOrErr) { 271 setError("cannot open " + Tok); 272 return; 273 } 274 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; 275 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); 276 std::vector<StringRef> V = tokenize(S); 277 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); 278 } 279 280 void LinkerScript::readOutput() { 281 // -o <file> takes predecence over OUTPUT(<file>). 282 expect("("); 283 StringRef Tok = next(); 284 if (Config->OutputFile.empty()) 285 Config->OutputFile = Tok; 286 expect(")"); 287 } 288 289 void LinkerScript::readOutputArch() { 290 // Error checking only for now. 291 expect("("); 292 next(); 293 expect(")"); 294 } 295 296 void LinkerScript::readOutputFormat() { 297 // Error checking only for now. 298 expect("("); 299 next(); 300 StringRef Tok = next(); 301 if (Tok == ")") 302 return; 303 if (Tok != ",") { 304 setError("unexpected token: " + Tok); 305 return; 306 } 307 next(); 308 expect(","); 309 next(); 310 expect(")"); 311 } 312 313 void LinkerScript::readSearchDir() { 314 expect("("); 315 Config->SearchPaths.push_back(next()); 316 expect(")"); 317 } 318 319 void LinkerScript::readSections() { 320 expect("{"); 321 while (!Error && !skip("}")) 322 readOutputSectionDescription(); 323 } 324 325 void LinkerScript::readOutputSectionDescription() { 326 StringRef Name = next(); 327 std::vector<StringRef> &InputSections = Config->OutputSections[Name]; 328 329 expect(":"); 330 expect("{"); 331 while (!Error && !skip("}")) { 332 next(); // Skip input file name. 333 expect("("); 334 while (!Error && !skip(")")) 335 InputSections.push_back(next()); 336 } 337 } 338 339 static bool isUnderSysroot(StringRef Path) { 340 if (Config->Sysroot == "") 341 return false; 342 for (; !Path.empty(); Path = sys::path::parent_path(Path)) 343 if (sys::fs::equivalent(Config->Sysroot, Path)) 344 return true; 345 return false; 346 } 347 348 // Entry point. The other functions or classes are private to this file. 349 void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) { 350 StringRef Path = MB.getBufferIdentifier(); 351 LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run(); 352 } 353