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 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 22 using namespace llvm; 23 using namespace lld; 24 using namespace lld::elf2; 25 26 namespace { 27 class LinkerScript { 28 public: 29 LinkerScript(SymbolTable *T, StringRef S) : Symtab(T), Tokens(tokenize(S)) {} 30 void run(); 31 32 private: 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 43 SymbolTable *Symtab; 44 std::vector<StringRef> Tokens; 45 size_t Pos = 0; 46 }; 47 } 48 49 void LinkerScript::run() { 50 while (!atEOF()) { 51 StringRef Tok = next(); 52 if (Tok == "GROUP") { 53 readGroup(); 54 } else if (Tok == "OUTPUT_FORMAT") { 55 readOutputFormat(); 56 } else { 57 error("unknown directive: " + Tok); 58 } 59 } 60 } 61 62 // Split S into linker script tokens. 63 std::vector<StringRef> LinkerScript::tokenize(StringRef S) { 64 std::vector<StringRef> Ret; 65 for (;;) { 66 S = skipSpace(S); 67 if (S.empty()) 68 return Ret; 69 70 // Quoted token 71 if (S.startswith("\"")) { 72 size_t E = S.find("\"", 1); 73 if (E == StringRef::npos) 74 error("unclosed quote"); 75 Ret.push_back(S.substr(1, E)); 76 S = S.substr(E + 1); 77 continue; 78 } 79 80 // Unquoted token 81 size_t Pos = S.find_first_not_of( 82 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 83 "0123456789_.$/\\~=+[]*?-:"); 84 // A character that cannot start a word (which is usually a 85 // punctuation) forms a single character token. 86 if (Pos == 0) 87 Pos = 1; 88 Ret.push_back(S.substr(0, Pos)); 89 S = S.substr(Pos); 90 } 91 } 92 93 // Skip leading whitespace characters or /**/-style comments. 94 StringRef LinkerScript::skipSpace(StringRef S) { 95 for (;;) { 96 if (S.startswith("/*")) { 97 size_t E = S.find("*/", 2); 98 if (E == StringRef::npos) 99 error("unclosed comment in a linker script"); 100 S = S.substr(E + 2); 101 continue; 102 } 103 size_t Size = S.size(); 104 S = S.ltrim(); 105 if (S.size() == Size) 106 return S; 107 } 108 } 109 110 StringRef LinkerScript::next() { 111 if (Pos == Tokens.size()) 112 error("unexpected EOF"); 113 return Tokens[Pos++]; 114 } 115 116 void LinkerScript::expect(StringRef Expect) { 117 StringRef Tok = next(); 118 if (Tok != Expect) 119 error(Expect + " expected, but got " + Tok); 120 } 121 122 void LinkerScript::readAsNeeded() { 123 expect("("); 124 for (;;) { 125 StringRef Tok = next(); 126 if (Tok == ")") 127 return; 128 Symtab->addFile(createFile(openFile(Tok))); 129 } 130 } 131 132 void LinkerScript::readGroup() { 133 expect("("); 134 for (;;) { 135 StringRef Tok = next(); 136 if (Tok == ")") 137 return; 138 if (Tok == "AS_NEEDED") { 139 readAsNeeded(); 140 continue; 141 } 142 Symtab->addFile(createFile(openFile(Tok))); 143 } 144 } 145 146 void LinkerScript::readOutputFormat() { 147 // Error checking only for now. 148 expect("("); 149 next(); 150 expect(")"); 151 } 152 153 // Entry point. The other functions or classes are private to this file. 154 void lld::elf2::readLinkerScript(SymbolTable *Symtab, MemoryBufferRef MB) { 155 LinkerScript(Symtab, MB.getBuffer()).run(); 156 } 157