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