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