1 //===- InputChunks.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 "InputChunks.h" 11 #include "Config.h" 12 #include "OutputSegment.h" 13 #include "WriterUtils.h" 14 #include "lld/Common/ErrorHandler.h" 15 #include "lld/Common/LLVM.h" 16 #include "llvm/Support/LEB128.h" 17 18 #define DEBUG_TYPE "lld" 19 20 using namespace llvm; 21 using namespace llvm::wasm; 22 using namespace llvm::support::endian; 23 using namespace lld; 24 using namespace lld::wasm; 25 26 StringRef ReloctTypeToString(uint8_t RelocType) { 27 switch (RelocType) { 28 #define WASM_RELOC(NAME, REL) case REL: return #NAME; 29 #include "llvm/BinaryFormat/WasmRelocs.def" 30 #undef WASM_RELOC 31 } 32 llvm_unreachable("unknown reloc type"); 33 } 34 35 std::string lld::toString(const InputChunk *C) { 36 return (toString(C->File) + ":(" + C->getName() + ")").str(); 37 } 38 39 StringRef InputChunk::getComdatName() const { 40 uint32_t Index = getComdat(); 41 if (Index == UINT32_MAX) 42 return StringRef(); 43 return File->getWasmObj()->linkingData().Comdats[Index]; 44 } 45 46 void InputChunk::copyRelocations(const WasmSection &Section) { 47 if (Section.Relocations.empty()) 48 return; 49 size_t Start = getInputSectionOffset(); 50 size_t Size = getSize(); 51 for (const WasmRelocation &R : Section.Relocations) 52 if (R.Offset >= Start && R.Offset < Start + Size) 53 Relocations.push_back(R); 54 } 55 56 void InputChunk::verifyRelocTargets() const { 57 for (const WasmRelocation &Rel : Relocations) { 58 uint32_t ExistingValue; 59 unsigned BytesRead = 0; 60 uint32_t Offset = Rel.Offset - getInputSectionOffset(); 61 const uint8_t *Loc = data().data() + Offset; 62 switch (Rel.Type) { 63 case R_WEBASSEMBLY_TYPE_INDEX_LEB: 64 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 65 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: 66 case R_WEBASSEMBLY_MEMORY_ADDR_LEB: 67 ExistingValue = decodeULEB128(Loc, &BytesRead); 68 break; 69 case R_WEBASSEMBLY_TABLE_INDEX_SLEB: 70 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 71 ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead)); 72 break; 73 case R_WEBASSEMBLY_TABLE_INDEX_I32: 74 case R_WEBASSEMBLY_MEMORY_ADDR_I32: 75 case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: 76 case R_WEBASSEMBLY_SECTION_OFFSET_I32: 77 ExistingValue = static_cast<uint32_t>(read32le(Loc)); 78 break; 79 default: 80 llvm_unreachable("unknown relocation type"); 81 } 82 83 if (BytesRead && BytesRead != 5) 84 warn("expected LEB at relocation site be 5-byte padded"); 85 uint32_t ExpectedValue = File->calcExpectedValue(Rel); 86 if (ExpectedValue != ExistingValue) 87 warn("unexpected existing value for " + ReloctTypeToString(Rel.Type) + 88 ": existing=" + Twine(ExistingValue) + 89 " expected=" + Twine(ExpectedValue)); 90 } 91 } 92 93 // Copy this input chunk to an mmap'ed output file and apply relocations. 94 void InputChunk::writeTo(uint8_t *Buf) const { 95 // Copy contents 96 memcpy(Buf + OutputOffset, data().data(), data().size()); 97 98 // Apply relocations 99 if (Relocations.empty()) 100 return; 101 102 #ifndef NDEBUG 103 verifyRelocTargets(); 104 #endif 105 106 DEBUG(dbgs() << "applying relocations: " << getName() 107 << " count=" << Relocations.size() << "\n"); 108 int32_t Off = OutputOffset - getInputSectionOffset(); 109 110 for (const WasmRelocation &Rel : Relocations) { 111 uint8_t *Loc = Buf + Rel.Offset + Off; 112 uint32_t Value = File->calcNewValue(Rel); 113 DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type) 114 << " addend=" << Rel.Addend << " index=" << Rel.Index 115 << " value=" << Value << " offset=" << Rel.Offset << "\n"); 116 117 switch (Rel.Type) { 118 case R_WEBASSEMBLY_TYPE_INDEX_LEB: 119 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 120 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: 121 case R_WEBASSEMBLY_MEMORY_ADDR_LEB: 122 encodeULEB128(Value, Loc, 5); 123 break; 124 case R_WEBASSEMBLY_TABLE_INDEX_SLEB: 125 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 126 encodeSLEB128(static_cast<int32_t>(Value), Loc, 5); 127 break; 128 case R_WEBASSEMBLY_TABLE_INDEX_I32: 129 case R_WEBASSEMBLY_MEMORY_ADDR_I32: 130 case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: 131 case R_WEBASSEMBLY_SECTION_OFFSET_I32: 132 write32le(Loc, Value); 133 break; 134 default: 135 llvm_unreachable("unknown relocation type"); 136 } 137 } 138 } 139 140 // Copy relocation entries to a given output stream. 141 // This function is used only when a user passes "-r". For a regular link, 142 // we consume relocations instead of copying them to an output file. 143 void InputChunk::writeRelocations(raw_ostream &OS) const { 144 if (Relocations.empty()) 145 return; 146 147 int32_t Off = OutputOffset - getInputSectionOffset(); 148 DEBUG(dbgs() << "writeRelocations: " << File->getName() 149 << " offset=" << Twine(Off) << "\n"); 150 151 for (const WasmRelocation &Rel : Relocations) { 152 writeUleb128(OS, Rel.Type, "reloc type"); 153 writeUleb128(OS, Rel.Offset + Off, "reloc offset"); 154 writeUleb128(OS, File->calcNewIndex(Rel), "reloc index"); 155 156 switch (Rel.Type) { 157 case R_WEBASSEMBLY_MEMORY_ADDR_LEB: 158 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 159 case R_WEBASSEMBLY_MEMORY_ADDR_I32: 160 case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: 161 case R_WEBASSEMBLY_SECTION_OFFSET_I32: 162 writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend"); 163 break; 164 } 165 } 166 } 167 168 void InputFunction::setFunctionIndex(uint32_t Index) { 169 DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName() << " -> " 170 << Index << "\n"); 171 assert(!hasFunctionIndex()); 172 FunctionIndex = Index; 173 } 174 175 void InputFunction::setTableIndex(uint32_t Index) { 176 DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> " 177 << Index << "\n"); 178 assert(!hasTableIndex()); 179 TableIndex = Index; 180 } 181