Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 1 | //===- InputFiles.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 | #include "InputFiles.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 11 | #include "Config.h" |
Sam Clegg | 5fa274b | 2018-01-10 01:13:34 +0000 | [diff] [blame] | 12 | #include "InputChunks.h" |
Sam Clegg | 9310297 | 2018-02-23 05:08:53 +0000 | [diff] [blame] | 13 | #include "InputGlobal.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 14 | #include "SymbolTable.h" |
| 15 | #include "lld/Common/ErrorHandler.h" |
Rui Ueyama | 2017d52 | 2017-11-28 20:39:17 +0000 | [diff] [blame] | 16 | #include "lld/Common/Memory.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 17 | #include "llvm/Object/Binary.h" |
| 18 | #include "llvm/Object/Wasm.h" |
| 19 | #include "llvm/Support/raw_ostream.h" |
| 20 | |
| 21 | #define DEBUG_TYPE "lld" |
| 22 | |
| 23 | using namespace lld; |
| 24 | using namespace lld::wasm; |
| 25 | |
| 26 | using namespace llvm; |
| 27 | using namespace llvm::object; |
| 28 | using namespace llvm::wasm; |
| 29 | |
| 30 | Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) { |
| 31 | log("Loading: " + Path); |
| 32 | |
| 33 | auto MBOrErr = MemoryBuffer::getFile(Path); |
| 34 | if (auto EC = MBOrErr.getError()) { |
| 35 | error("cannot open " + Path + ": " + EC.message()); |
| 36 | return None; |
| 37 | } |
| 38 | std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; |
| 39 | MemoryBufferRef MBRef = MB->getMemBufferRef(); |
| 40 | make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership |
| 41 | |
| 42 | return MBRef; |
| 43 | } |
| 44 | |
| 45 | void ObjFile::dumpInfo() const { |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 46 | log("info for: " + getName() + |
| 47 | "\n Symbols : " + Twine(Symbols.size()) + |
| 48 | "\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) + |
| 49 | "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals())); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 50 | } |
| 51 | |
Sam Clegg | d96d935 | 2018-01-10 19:22:42 +0000 | [diff] [blame] | 52 | // Relocations contain an index into the function, global or table index |
| 53 | // space of the input file. This function takes a relocation and returns the |
| 54 | // relocated index (i.e. translates from the input index space to the output |
| 55 | // index space). |
| 56 | uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const { |
Rui Ueyama | d1063bb | 2018-02-28 00:26:26 +0000 | [diff] [blame] | 57 | if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { |
| 58 | assert(TypeIsUsed[Reloc.Index]); |
| 59 | return TypeMap[Reloc.Index]; |
| 60 | } |
| 61 | return Symbols[Reloc.Index]->getOutputSymbolIndex(); |
Sam Clegg | d96d935 | 2018-01-10 19:22:42 +0000 | [diff] [blame] | 62 | } |
| 63 | |
Sam Clegg | ab604a9 | 2018-01-23 01:25:56 +0000 | [diff] [blame] | 64 | // Translate from the relocation's index into the final linked output value. |
| 65 | uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const { |
| 66 | switch (Reloc.Type) { |
| 67 | case R_WEBASSEMBLY_TABLE_INDEX_I32: |
Nicholas Wilson | 2e55ee7 | 2018-03-09 17:06:38 +0000 | [diff] [blame^] | 68 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: |
| 69 | return getFunctionSymbol(Reloc.Index)->getTableIndex(); |
Sam Clegg | ab604a9 | 2018-01-23 01:25:56 +0000 | [diff] [blame] | 70 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: |
| 71 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: |
| 72 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: |
Rui Ueyama | d1063bb | 2018-02-28 00:26:26 +0000 | [diff] [blame] | 73 | if (auto *Sym = dyn_cast<DefinedData>(getDataSymbol(Reloc.Index))) |
| 74 | return Sym->getVirtualAddress() + Reloc.Addend; |
| 75 | return Reloc.Addend; |
Sam Clegg | ab604a9 | 2018-01-23 01:25:56 +0000 | [diff] [blame] | 76 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: |
Rui Ueyama | d1063bb | 2018-02-28 00:26:26 +0000 | [diff] [blame] | 77 | return TypeMap[Reloc.Index]; |
Sam Clegg | ab604a9 | 2018-01-23 01:25:56 +0000 | [diff] [blame] | 78 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: |
Rui Ueyama | d1063bb | 2018-02-28 00:26:26 +0000 | [diff] [blame] | 79 | return getFunctionSymbol(Reloc.Index)->getOutputIndex(); |
Sam Clegg | ab604a9 | 2018-01-23 01:25:56 +0000 | [diff] [blame] | 80 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: |
Rui Ueyama | d1063bb | 2018-02-28 00:26:26 +0000 | [diff] [blame] | 81 | return getGlobalSymbol(Reloc.Index)->getOutputIndex(); |
Sam Clegg | ab604a9 | 2018-01-23 01:25:56 +0000 | [diff] [blame] | 82 | default: |
| 83 | llvm_unreachable("unknown relocation type"); |
| 84 | } |
| 85 | } |
| 86 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 87 | void ObjFile::parse() { |
| 88 | // Parse a memory buffer as a wasm file. |
| 89 | DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); |
Rui Ueyama | bdc5150 | 2017-12-06 22:08:17 +0000 | [diff] [blame] | 90 | std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this)); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 91 | |
| 92 | auto *Obj = dyn_cast<WasmObjectFile>(Bin.get()); |
| 93 | if (!Obj) |
| 94 | fatal(toString(this) + ": not a wasm file"); |
| 95 | if (!Obj->isRelocatableObject()) |
| 96 | fatal(toString(this) + ": not a relocatable wasm file"); |
| 97 | |
| 98 | Bin.release(); |
| 99 | WasmObj.reset(Obj); |
| 100 | |
| 101 | // Find the code and data sections. Wasm objects can have at most one code |
| 102 | // and one data section. |
| 103 | for (const SectionRef &Sec : WasmObj->sections()) { |
| 104 | const WasmSection &Section = WasmObj->getWasmSection(Sec); |
| 105 | if (Section.Type == WASM_SEC_CODE) |
| 106 | CodeSection = &Section; |
| 107 | else if (Section.Type == WASM_SEC_DATA) |
| 108 | DataSection = &Section; |
| 109 | } |
| 110 | |
Sam Clegg | 8f6d2de | 2018-01-31 23:48:14 +0000 | [diff] [blame] | 111 | TypeMap.resize(getWasmObj()->types().size()); |
| 112 | TypeIsUsed.resize(getWasmObj()->types().size(), false); |
| 113 | |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 114 | // Populate `Segments`. |
| 115 | for (const WasmSegment &S : WasmObj->dataSegments()) { |
| 116 | InputSegment *Seg = make<InputSegment>(S, this); |
| 117 | Seg->copyRelocations(*DataSection); |
| 118 | Segments.emplace_back(Seg); |
| 119 | } |
Sam Clegg | 8d146bb | 2018-01-09 23:56:44 +0000 | [diff] [blame] | 120 | |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 121 | // Populate `Functions`. |
| 122 | ArrayRef<WasmFunction> Funcs = WasmObj->functions(); |
| 123 | ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes(); |
| 124 | ArrayRef<WasmSignature> Types = WasmObj->types(); |
| 125 | Functions.reserve(Funcs.size()); |
Sam Clegg | 8d146bb | 2018-01-09 23:56:44 +0000 | [diff] [blame] | 126 | |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 127 | for (size_t I = 0, E = Funcs.size(); I != E; ++I) { |
| 128 | InputFunction *F = |
| 129 | make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this); |
| 130 | F->copyRelocations(*CodeSection); |
| 131 | Functions.emplace_back(F); |
| 132 | } |
| 133 | |
| 134 | // Populate `Globals`. |
| 135 | for (const WasmGlobal &G : WasmObj->globals()) |
| 136 | Globals.emplace_back(make<InputGlobal>(G)); |
| 137 | |
| 138 | // Populate `Symbols` based on the WasmSymbols in the object. |
| 139 | Symbols.reserve(WasmObj->getNumberOfSymbols()); |
| 140 | for (const SymbolRef &Sym : WasmObj->symbols()) { |
| 141 | const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl()); |
| 142 | if (Symbol *Sym = createDefined(WasmSym)) |
| 143 | Symbols.push_back(Sym); |
| 144 | else |
| 145 | Symbols.push_back(createUndefined(WasmSym)); |
| 146 | } |
Sam Clegg | 9310297 | 2018-02-23 05:08:53 +0000 | [diff] [blame] | 147 | } |
| 148 | |
Sam Clegg | e0f6fcd | 2018-01-12 22:25:17 +0000 | [diff] [blame] | 149 | bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const { |
Rui Ueyama | dcf6234 | 2018-03-01 23:29:05 +0000 | [diff] [blame] | 150 | StringRef S = Chunk->getComdat(); |
| 151 | if (S.empty()) |
| 152 | return false; |
| 153 | return !Symtab->addComdat(S, this); |
Sam Clegg | e0f6fcd | 2018-01-12 22:25:17 +0000 | [diff] [blame] | 154 | } |
| 155 | |
Sam Clegg | 9310297 | 2018-02-23 05:08:53 +0000 | [diff] [blame] | 156 | FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const { |
| 157 | return cast<FunctionSymbol>(Symbols[Index]); |
| 158 | } |
| 159 | |
| 160 | GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const { |
| 161 | return cast<GlobalSymbol>(Symbols[Index]); |
| 162 | } |
| 163 | |
| 164 | DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const { |
| 165 | return cast<DataSymbol>(Symbols[Index]); |
| 166 | } |
| 167 | |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 168 | Symbol *ObjFile::createDefined(const WasmSymbol &Sym) { |
| 169 | if (!Sym.isDefined()) |
| 170 | return nullptr; |
| 171 | |
Rui Ueyama | e89b0ef | 2018-03-02 21:19:55 +0000 | [diff] [blame] | 172 | StringRef Name = Sym.Info.Name; |
| 173 | uint32_t Flags = Sym.Info.Flags; |
| 174 | |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 175 | switch (Sym.Info.Kind) { |
| 176 | case WASM_SYMBOL_TYPE_FUNCTION: { |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 177 | InputFunction *Func = |
| 178 | Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()]; |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 179 | if (isExcludedByComdat(Func)) { |
| 180 | Func->Live = false; |
| 181 | return nullptr; |
| 182 | } |
| 183 | |
| 184 | if (Sym.isBindingLocal()) |
Rui Ueyama | e89b0ef | 2018-03-02 21:19:55 +0000 | [diff] [blame] | 185 | return make<DefinedFunction>(Name, Flags, this, Func); |
| 186 | return Symtab->addDefinedFunction(Name, Flags, this, Func); |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 187 | } |
| 188 | case WASM_SYMBOL_TYPE_DATA: { |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 189 | InputSegment *Seg = Segments[Sym.Info.DataRef.Segment]; |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 190 | if (isExcludedByComdat(Seg)) { |
| 191 | Seg->Live = false; |
| 192 | return nullptr; |
| 193 | } |
| 194 | |
| 195 | uint32_t Offset = Sym.Info.DataRef.Offset; |
| 196 | uint32_t Size = Sym.Info.DataRef.Size; |
| 197 | |
| 198 | if (Sym.isBindingLocal()) |
Rui Ueyama | e89b0ef | 2018-03-02 21:19:55 +0000 | [diff] [blame] | 199 | return make<DefinedData>(Name, Flags, this, Seg, Offset, Size); |
| 200 | return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size); |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 201 | } |
| 202 | case WASM_SYMBOL_TYPE_GLOBAL: |
Rui Ueyama | 0a9583c | 2018-02-28 02:57:37 +0000 | [diff] [blame] | 203 | InputGlobal *Global = |
| 204 | Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()]; |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 205 | if (Sym.isBindingLocal()) |
Rui Ueyama | e89b0ef | 2018-03-02 21:19:55 +0000 | [diff] [blame] | 206 | return make<DefinedGlobal>(Name, Flags, this, Global); |
| 207 | return Symtab->addDefinedGlobal(Name, Flags, this, Global); |
Rui Ueyama | 4b56adc | 2018-02-28 00:50:54 +0000 | [diff] [blame] | 208 | } |
| 209 | llvm_unreachable("unkown symbol kind"); |
| 210 | } |
| 211 | |
Sam Clegg | 9310297 | 2018-02-23 05:08:53 +0000 | [diff] [blame] | 212 | Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { |
Rui Ueyama | e3498ec | 2018-02-28 00:09:22 +0000 | [diff] [blame] | 213 | StringRef Name = Sym.Info.Name; |
| 214 | uint32_t Flags = Sym.Info.Flags; |
| 215 | |
| 216 | switch (Sym.Info.Kind) { |
| 217 | case WASM_SYMBOL_TYPE_FUNCTION: |
| 218 | return Symtab->addUndefinedFunction(Name, Flags, this, Sym.FunctionType); |
| 219 | case WASM_SYMBOL_TYPE_DATA: |
| 220 | return Symtab->addUndefinedData(Name, Flags, this); |
| 221 | case WASM_SYMBOL_TYPE_GLOBAL: |
| 222 | return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType); |
| 223 | } |
| 224 | llvm_unreachable("unkown symbol kind"); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 225 | } |
| 226 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 227 | void ArchiveFile::parse() { |
| 228 | // Parse a MemoryBufferRef as an archive file. |
| 229 | DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n"); |
Rui Ueyama | bdc5150 | 2017-12-06 22:08:17 +0000 | [diff] [blame] | 230 | File = CHECK(Archive::create(MB), toString(this)); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 231 | |
| 232 | // Read the symbol table to construct Lazy symbols. |
| 233 | int Count = 0; |
| 234 | for (const Archive::Symbol &Sym : File->symbols()) { |
| 235 | Symtab->addLazy(this, &Sym); |
| 236 | ++Count; |
| 237 | } |
| 238 | DEBUG(dbgs() << "Read " << Count << " symbols\n"); |
| 239 | } |
| 240 | |
| 241 | void ArchiveFile::addMember(const Archive::Symbol *Sym) { |
| 242 | const Archive::Child &C = |
Rui Ueyama | bdc5150 | 2017-12-06 22:08:17 +0000 | [diff] [blame] | 243 | CHECK(Sym->getMember(), |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 244 | "could not get the member for symbol " + Sym->getName()); |
| 245 | |
| 246 | // Don't try to load the same member twice (this can happen when members |
| 247 | // mutually reference each other). |
| 248 | if (!Seen.insert(C.getChildOffset()).second) |
| 249 | return; |
| 250 | |
Sam Clegg | a681a11 | 2017-12-06 03:10:39 +0000 | [diff] [blame] | 251 | DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n"); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 252 | DEBUG(dbgs() << "from archive: " << toString(this) << "\n"); |
| 253 | |
| 254 | MemoryBufferRef MB = |
Rui Ueyama | bdc5150 | 2017-12-06 22:08:17 +0000 | [diff] [blame] | 255 | CHECK(C.getMemoryBufferRef(), |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 256 | "could not get the buffer for the member defining symbol " + |
| 257 | Sym->getName()); |
| 258 | |
| 259 | if (identify_magic(MB.getBuffer()) != file_magic::wasm_object) { |
| 260 | error("unknown file type: " + MB.getBufferIdentifier()); |
| 261 | return; |
| 262 | } |
| 263 | |
| 264 | InputFile *Obj = make<ObjFile>(MB); |
| 265 | Obj->ParentName = ParentName; |
| 266 | Symtab->addFile(Obj); |
| 267 | } |
| 268 | |
| 269 | // Returns a string in the format of "foo.o" or "foo.a(bar.o)". |
Sam Clegg | 7e75663 | 2017-12-05 16:50:46 +0000 | [diff] [blame] | 270 | std::string lld::toString(const wasm::InputFile *File) { |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 +0000 | [diff] [blame] | 271 | if (!File) |
| 272 | return "<internal>"; |
| 273 | |
| 274 | if (File->ParentName.empty()) |
| 275 | return File->getName(); |
| 276 | |
| 277 | return (File->ParentName + "(" + File->getName() + ")").str(); |
| 278 | } |