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" 11 12 #include "Config.h" 13 #include "InputSegment.h" 14 #include "SymbolTable.h" 15 #include "lld/Common/ErrorHandler.h" 16 #include "lld/Common/Memory.h" 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 { 46 log("reloc info for: " + getName() + "\n" + 47 " FunctionIndexOffset : " + Twine(FunctionIndexOffset) + "\n" + 48 " NumFunctionImports : " + Twine(NumFunctionImports()) + "\n" + 49 " NumGlobalImports : " + Twine(NumGlobalImports()) + "\n"); 50 } 51 52 bool ObjFile::isImportedFunction(uint32_t Index) const { 53 return Index < NumFunctionImports(); 54 } 55 56 Symbol *ObjFile::getFunctionSymbol(uint32_t Index) const { 57 return FunctionSymbols[Index]; 58 } 59 60 Symbol *ObjFile::getTableSymbol(uint32_t Index) const { 61 return TableSymbols[Index]; 62 } 63 64 Symbol *ObjFile::getGlobalSymbol(uint32_t Index) const { 65 return GlobalSymbols[Index]; 66 } 67 68 uint32_t ObjFile::getRelocatedAddress(uint32_t Index) const { 69 return getGlobalSymbol(Index)->getVirtualAddress(); 70 } 71 72 uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const { 73 Symbol *Sym = getFunctionSymbol(Original); 74 uint32_t Index = Sym->getOutputIndex(); 75 DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": " 76 << Original << " -> " << Index << "\n"); 77 return Index; 78 } 79 80 uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const { 81 return TypeMap[Original]; 82 } 83 84 uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { 85 Symbol *Sym = getTableSymbol(Original); 86 uint32_t Index = Sym->getTableIndex(); 87 DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original 88 << " -> " << Index << "\n"); 89 return Index; 90 } 91 92 uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const { 93 Symbol *Sym = getGlobalSymbol(Original); 94 uint32_t Index = Sym->getOutputIndex(); 95 DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original 96 << " -> " << Index << "\n"); 97 return Index; 98 } 99 100 void ObjFile::parse() { 101 // Parse a memory buffer as a wasm file. 102 DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); 103 std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this)); 104 105 auto *Obj = dyn_cast<WasmObjectFile>(Bin.get()); 106 if (!Obj) 107 fatal(toString(this) + ": not a wasm file"); 108 if (!Obj->isRelocatableObject()) 109 fatal(toString(this) + ": not a relocatable wasm file"); 110 111 Bin.release(); 112 WasmObj.reset(Obj); 113 114 // Find the code and data sections. Wasm objects can have at most one code 115 // and one data section. 116 for (const SectionRef &Sec : WasmObj->sections()) { 117 const WasmSection &Section = WasmObj->getWasmSection(Sec); 118 if (Section.Type == WASM_SEC_CODE) 119 CodeSection = &Section; 120 else if (Section.Type == WASM_SEC_DATA) 121 DataSection = &Section; 122 } 123 124 initializeSymbols(); 125 } 126 127 // Return the InputSegment in which a given symbol is defined. 128 InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) { 129 uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym); 130 for (InputSegment *Segment : Segments) { 131 if (Address >= Segment->startVA() && Address < Segment->endVA()) { 132 DEBUG(dbgs() << "Found symbol in segment: " << WasmSym.Name << " -> " 133 << Segment->getName() << "\n"); 134 135 return Segment; 136 } 137 } 138 error("symbol not found in any segment: " + WasmSym.Name); 139 return nullptr; 140 } 141 142 static void copyRelocationsRange(std::vector<WasmRelocation> &To, 143 ArrayRef<WasmRelocation> From, size_t Start, 144 size_t End) { 145 for (const WasmRelocation &R : From) 146 if (R.Offset >= Start && R.Offset < End) 147 To.push_back(R); 148 } 149 150 void ObjFile::initializeSymbols() { 151 Symbols.reserve(WasmObj->getNumberOfSymbols()); 152 153 for (const WasmImport &Import : WasmObj->imports()) { 154 switch (Import.Kind) { 155 case WASM_EXTERNAL_FUNCTION: 156 ++FunctionImports; 157 break; 158 case WASM_EXTERNAL_GLOBAL: 159 ++GlobalImports; 160 break; 161 } 162 } 163 164 FunctionSymbols.resize(FunctionImports + WasmObj->functions().size()); 165 GlobalSymbols.resize(GlobalImports + WasmObj->globals().size()); 166 167 for (const WasmSegment &S : WasmObj->dataSegments()) { 168 InputSegment *Seg = make<InputSegment>(&S, this); 169 copyRelocationsRange(Seg->Relocations, DataSection->Relocations, 170 Seg->getInputSectionOffset(), 171 Seg->getInputSectionOffset() + Seg->getSize()); 172 Segments.emplace_back(Seg); 173 } 174 175 // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols 176 // in the object 177 for (const SymbolRef &Sym : WasmObj->symbols()) { 178 const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl()); 179 Symbol *S; 180 switch (WasmSym.Type) { 181 case WasmSymbol::SymbolType::FUNCTION_IMPORT: 182 case WasmSymbol::SymbolType::GLOBAL_IMPORT: 183 S = createUndefined(WasmSym); 184 break; 185 case WasmSymbol::SymbolType::GLOBAL_EXPORT: 186 S = createDefined(WasmSym, getSegment(WasmSym)); 187 break; 188 case WasmSymbol::SymbolType::FUNCTION_EXPORT: 189 S = createDefined(WasmSym); 190 break; 191 case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: 192 // These are for debugging only, no need to create linker symbols for them 193 continue; 194 } 195 196 Symbols.push_back(S); 197 if (WasmSym.isFunction()) { 198 DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> " 199 << toString(*S) << "\n"); 200 FunctionSymbols[WasmSym.ElementIndex] = S; 201 if (WasmSym.HasAltIndex) 202 FunctionSymbols[WasmSym.AltIndex] = S; 203 } else { 204 DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> " 205 << toString(*S) << "\n"); 206 GlobalSymbols[WasmSym.ElementIndex] = S; 207 if (WasmSym.HasAltIndex) 208 GlobalSymbols[WasmSym.AltIndex] = S; 209 } 210 } 211 212 DEBUG(for (size_t I = 0; I < FunctionSymbols.size(); ++I) 213 assert(FunctionSymbols[I] != nullptr); 214 for (size_t I = 0; I < GlobalSymbols.size(); ++I) 215 assert(GlobalSymbols[I] != nullptr);); 216 217 // Populate `TableSymbols` with all symbols that are called indirectly 218 uint32_t SegmentCount = WasmObj->elements().size(); 219 if (SegmentCount) { 220 if (SegmentCount > 1) 221 fatal(getName() + ": contains more than one element segment"); 222 const WasmElemSegment &Segment = WasmObj->elements()[0]; 223 if (Segment.Offset.Opcode != WASM_OPCODE_I32_CONST) 224 fatal(getName() + ": unsupported element segment"); 225 if (Segment.TableIndex != 0) 226 fatal(getName() + ": unsupported table index in elem segment"); 227 if (Segment.Offset.Value.Int32 != 0) 228 fatal(getName() + ": unsupported element segment offset"); 229 TableSymbols.reserve(Segment.Functions.size()); 230 for (uint64_t FunctionIndex : Segment.Functions) 231 TableSymbols.push_back(getFunctionSymbol(FunctionIndex)); 232 } 233 234 DEBUG(dbgs() << "TableSymbols: " << TableSymbols.size() << "\n"); 235 DEBUG(dbgs() << "Functions : " << FunctionSymbols.size() << "\n"); 236 DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n"); 237 } 238 239 Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { 240 return Symtab->addUndefined(this, &Sym); 241 } 242 243 Symbol *ObjFile::createDefined(const WasmSymbol &Sym, 244 const InputSegment *Segment) { 245 Symbol *S; 246 if (Sym.isLocal()) { 247 S = make<Symbol>(Sym.Name, true); 248 Symbol::Kind Kind; 249 if (Sym.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT) 250 Kind = Symbol::Kind::DefinedFunctionKind; 251 else if (Sym.Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) 252 Kind = Symbol::Kind::DefinedGlobalKind; 253 else 254 llvm_unreachable("invalid local symbol type"); 255 S->update(Kind, this, &Sym, Segment); 256 return S; 257 } 258 return Symtab->addDefined(this, &Sym, Segment); 259 } 260 261 void ArchiveFile::parse() { 262 // Parse a MemoryBufferRef as an archive file. 263 DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n"); 264 File = CHECK(Archive::create(MB), toString(this)); 265 266 // Read the symbol table to construct Lazy symbols. 267 int Count = 0; 268 for (const Archive::Symbol &Sym : File->symbols()) { 269 Symtab->addLazy(this, &Sym); 270 ++Count; 271 } 272 DEBUG(dbgs() << "Read " << Count << " symbols\n"); 273 } 274 275 void ArchiveFile::addMember(const Archive::Symbol *Sym) { 276 const Archive::Child &C = 277 CHECK(Sym->getMember(), 278 "could not get the member for symbol " + Sym->getName()); 279 280 // Don't try to load the same member twice (this can happen when members 281 // mutually reference each other). 282 if (!Seen.insert(C.getChildOffset()).second) 283 return; 284 285 DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n"); 286 DEBUG(dbgs() << "from archive: " << toString(this) << "\n"); 287 288 MemoryBufferRef MB = 289 CHECK(C.getMemoryBufferRef(), 290 "could not get the buffer for the member defining symbol " + 291 Sym->getName()); 292 293 if (identify_magic(MB.getBuffer()) != file_magic::wasm_object) { 294 error("unknown file type: " + MB.getBufferIdentifier()); 295 return; 296 } 297 298 InputFile *Obj = make<ObjFile>(MB); 299 Obj->ParentName = ParentName; 300 Symtab->addFile(Obj); 301 } 302 303 // Returns a string in the format of "foo.o" or "foo.a(bar.o)". 304 std::string lld::toString(const wasm::InputFile *File) { 305 if (!File) 306 return "<internal>"; 307 308 if (File->ParentName.empty()) 309 return File->getName(); 310 311 return (File->ParentName + "(" + File->getName() + ")").str(); 312 } 313