1 //===- Chunks.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 "Chunks.h" 11 #include "Error.h" 12 #include "InputFiles.h" 13 #include "Symbols.h" 14 #include "llvm/Object/COFF.h" 15 #include "llvm/Support/COFF.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/Endian.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include <algorithm> 20 21 using namespace llvm; 22 using namespace llvm::object; 23 using namespace llvm::support::endian; 24 using namespace llvm::COFF; 25 using llvm::support::ulittle32_t; 26 27 namespace lld { 28 namespace coff { 29 30 SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H) 31 : Chunk(SectionKind), Repl(this), File(F), Header(H), 32 Relocs(File->getCOFFObj()->getRelocations(Header)), 33 NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { 34 // Initialize SectionName. 35 File->getCOFFObj()->getSectionName(Header, SectionName); 36 37 Align = Header->getAlignment(); 38 39 // Only COMDAT sections are subject of dead-stripping. 40 Live = !isCOMDAT(); 41 } 42 43 static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } 44 static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } 45 static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } 46 static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } 47 48 void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, 49 uint64_t P) const { 50 uint64_t S = Sym->getRVA(); 51 switch (Type) { 52 case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; 53 case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; 54 case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; 55 case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; 56 case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; 57 case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; 58 case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; 59 case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; 60 case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; 61 case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; 62 case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break; 63 default: 64 error("Unsupported relocation type"); 65 } 66 } 67 68 void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, 69 uint64_t P) const { 70 uint64_t S = Sym->getRVA(); 71 switch (Type) { 72 case IMAGE_REL_I386_ABSOLUTE: break; 73 case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; 74 case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; 75 case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; 76 case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; 77 case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break; 78 default: 79 error("Unsupported relocation type"); 80 } 81 } 82 83 static void applyMOV(uint8_t *Off, uint16_t V) { 84 or16(Off, ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); 85 or16(Off + 2, ((V & 0x700) << 4) | (V & 0xff)); 86 } 87 88 static void applyMOV32T(uint8_t *Off, uint32_t V) { 89 applyMOV(Off, V); // set MOVW operand 90 applyMOV(Off + 4, V >> 16); // set MOVT operand 91 } 92 93 static void applyBranch20T(uint8_t *Off, int32_t V) { 94 uint32_t S = V < 0 ? 1 : 0; 95 uint32_t J1 = (V >> 19) & 1; 96 uint32_t J2 = (V >> 18) & 1; 97 or16(Off, (S << 10) | ((V >> 12) & 0x3f)); 98 or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); 99 } 100 101 static void applyBranch24T(uint8_t *Off, int32_t V) { 102 uint32_t S = V < 0 ? 1 : 0; 103 uint32_t J1 = ((~V >> 23) & 1) ^ S; 104 uint32_t J2 = ((~V >> 22) & 1) ^ S; 105 or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); 106 or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); 107 } 108 109 void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, 110 uint64_t P) const { 111 uint64_t S = Sym->getRVA(); 112 // Pointer to thumb code must have the LSB set. 113 if (Sym->isExecutable()) 114 S |= 1; 115 switch (Type) { 116 case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break; 117 case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break; 118 case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break; 119 case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; 120 case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; 121 case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; 122 default: 123 error("Unsupported relocation type"); 124 } 125 } 126 127 void SectionChunk::writeTo(uint8_t *Buf) const { 128 if (!hasData()) 129 return; 130 // Copy section contents from source object file to output file. 131 ArrayRef<uint8_t> A = getContents(); 132 memcpy(Buf + OutputSectionOff, A.data(), A.size()); 133 134 // Apply relocations. 135 for (const coff_relocation &Rel : Relocs) { 136 uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; 137 SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); 138 Defined *Sym = cast<Defined>(Body); 139 uint64_t P = RVA + Rel.VirtualAddress; 140 switch (Config->Machine) { 141 case AMD64: 142 applyRelX64(Off, Rel.Type, Sym, P); 143 break; 144 case I386: 145 applyRelX86(Off, Rel.Type, Sym, P); 146 break; 147 case ARMNT: 148 applyRelARM(Off, Rel.Type, Sym, P); 149 break; 150 default: 151 llvm_unreachable("unknown machine type"); 152 } 153 } 154 } 155 156 void SectionChunk::addAssociative(SectionChunk *Child) { 157 AssocChildren.push_back(Child); 158 } 159 160 static uint8_t getBaserelType(const coff_relocation &Rel) { 161 switch (Config->Machine) { 162 case AMD64: 163 if (Rel.Type == IMAGE_REL_AMD64_ADDR64) 164 return IMAGE_REL_BASED_DIR64; 165 return IMAGE_REL_BASED_ABSOLUTE; 166 case I386: 167 if (Rel.Type == IMAGE_REL_I386_DIR32) 168 return IMAGE_REL_BASED_HIGHLOW; 169 return IMAGE_REL_BASED_ABSOLUTE; 170 case ARMNT: 171 if (Rel.Type == IMAGE_REL_ARM_ADDR32) 172 return IMAGE_REL_BASED_HIGHLOW; 173 if (Rel.Type == IMAGE_REL_ARM_MOV32T) 174 return IMAGE_REL_BASED_ARM_MOV32T; 175 return IMAGE_REL_BASED_ABSOLUTE; 176 default: 177 llvm_unreachable("unknown machine type"); 178 } 179 } 180 181 // Windows-specific. 182 // Collect all locations that contain absolute addresses, which need to be 183 // fixed by the loader if load-time relocation is needed. 184 // Only called when base relocation is enabled. 185 void SectionChunk::getBaserels(std::vector<Baserel> *Res) { 186 for (const coff_relocation &Rel : Relocs) { 187 uint8_t Ty = getBaserelType(Rel); 188 if (Ty == IMAGE_REL_BASED_ABSOLUTE) 189 continue; 190 SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); 191 if (isa<DefinedAbsolute>(Body)) 192 continue; 193 Res->emplace_back(RVA + Rel.VirtualAddress, Ty); 194 } 195 } 196 197 bool SectionChunk::hasData() const { 198 return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); 199 } 200 201 uint32_t SectionChunk::getPermissions() const { 202 return Header->Characteristics & PermMask; 203 } 204 205 bool SectionChunk::isCOMDAT() const { 206 return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; 207 } 208 209 void SectionChunk::printDiscardedMessage() const { 210 // Removed by dead-stripping. If it's removed by ICF, ICF already 211 // printed out the name, so don't repeat that here. 212 if (Sym && this == Repl) 213 llvm::outs() << "Discarded " << Sym->getName() << "\n"; 214 } 215 216 StringRef SectionChunk::getDebugName() { 217 if (Sym) 218 return Sym->getName(); 219 return ""; 220 } 221 222 ArrayRef<uint8_t> SectionChunk::getContents() const { 223 ArrayRef<uint8_t> A; 224 File->getCOFFObj()->getSectionContents(Header, A); 225 return A; 226 } 227 228 void SectionChunk::replace(SectionChunk *Other) { 229 Other->Repl = Repl; 230 Other->Live = false; 231 } 232 233 CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { 234 // Common symbols are aligned on natural boundaries up to 32 bytes. 235 // This is what MSVC link.exe does. 236 Align = std::min(uint64_t(32), NextPowerOf2(Sym.getValue())); 237 } 238 239 uint32_t CommonChunk::getPermissions() const { 240 return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | 241 IMAGE_SCN_MEM_WRITE; 242 } 243 244 void StringChunk::writeTo(uint8_t *Buf) const { 245 memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); 246 } 247 248 ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { 249 // Intel Optimization Manual says that all branch targets 250 // should be 16-byte aligned. MSVC linker does this too. 251 Align = 16; 252 } 253 254 void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { 255 memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); 256 // The first two bytes is a JMP instruction. Fill its operand. 257 write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); 258 } 259 260 void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) { 261 Res->emplace_back(getRVA() + 2); 262 } 263 264 void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { 265 memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); 266 // The first two bytes is a JMP instruction. Fill its operand. 267 write32le(Buf + OutputSectionOff + 2, 268 ImpSymbol->getRVA() + Config->ImageBase); 269 } 270 271 void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) { 272 Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); 273 } 274 275 void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { 276 memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); 277 // Fix mov.w and mov.t operands. 278 applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); 279 } 280 281 void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) { 282 Res->emplace_back(getRVA()); 283 } 284 285 size_t LocalImportChunk::getSize() const { 286 return Config->is64() ? 8 : 4; 287 } 288 289 void LocalImportChunk::writeTo(uint8_t *Buf) const { 290 if (Config->is64()) { 291 write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); 292 } else { 293 write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); 294 } 295 } 296 297 void SEHTableChunk::writeTo(uint8_t *Buf) const { 298 ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff); 299 size_t Cnt = 0; 300 for (Defined *D : Syms) 301 Begin[Cnt++] = D->getRVA(); 302 std::sort(Begin, Begin + Cnt); 303 } 304 305 // Windows-specific. 306 // This class represents a block in .reloc section. 307 BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { 308 // Block header consists of 4 byte page RVA and 4 byte block size. 309 // Each entry is 2 byte. Last entry may be padding. 310 Data.resize(alignTo((End - Begin) * 2 + 8, 4)); 311 uint8_t *P = Data.data(); 312 write32le(P, Page); 313 write32le(P + 4, Data.size()); 314 P += 8; 315 for (Baserel *I = Begin; I != End; ++I) { 316 write16le(P, (I->Type << 12) | (I->RVA - Page)); 317 P += 2; 318 } 319 } 320 321 void BaserelChunk::writeTo(uint8_t *Buf) const { 322 memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); 323 } 324 325 uint8_t Baserel::getDefaultType() { 326 switch (Config->Machine) { 327 case AMD64: 328 return IMAGE_REL_BASED_DIR64; 329 case I386: 330 return IMAGE_REL_BASED_HIGHLOW; 331 default: 332 llvm_unreachable("unknown machine type"); 333 } 334 } 335 336 } // namespace coff 337 } // namespace lld 338