1*5ffd83dbSDimitry Andric //===- X86_64.cpp ---------------------------------------------------------===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric 9*5ffd83dbSDimitry Andric #include "InputFiles.h" 10*5ffd83dbSDimitry Andric #include "Symbols.h" 11*5ffd83dbSDimitry Andric #include "SyntheticSections.h" 12*5ffd83dbSDimitry Andric #include "Target.h" 13*5ffd83dbSDimitry Andric 14*5ffd83dbSDimitry Andric #include "lld/Common/ErrorHandler.h" 15*5ffd83dbSDimitry Andric #include "llvm/BinaryFormat/MachO.h" 16*5ffd83dbSDimitry Andric #include "llvm/Support/Endian.h" 17*5ffd83dbSDimitry Andric 18*5ffd83dbSDimitry Andric using namespace llvm::MachO; 19*5ffd83dbSDimitry Andric using namespace llvm::support::endian; 20*5ffd83dbSDimitry Andric using namespace lld; 21*5ffd83dbSDimitry Andric using namespace lld::macho; 22*5ffd83dbSDimitry Andric 23*5ffd83dbSDimitry Andric namespace { 24*5ffd83dbSDimitry Andric 25*5ffd83dbSDimitry Andric struct X86_64 : TargetInfo { 26*5ffd83dbSDimitry Andric X86_64(); 27*5ffd83dbSDimitry Andric 28*5ffd83dbSDimitry Andric uint64_t getImplicitAddend(MemoryBufferRef, const section_64 &, 29*5ffd83dbSDimitry Andric const relocation_info &) const override; 30*5ffd83dbSDimitry Andric void relocateOne(uint8_t *loc, const Reloc &, uint64_t val) const override; 31*5ffd83dbSDimitry Andric 32*5ffd83dbSDimitry Andric void writeStub(uint8_t *buf, const DylibSymbol &) const override; 33*5ffd83dbSDimitry Andric void writeStubHelperHeader(uint8_t *buf) const override; 34*5ffd83dbSDimitry Andric void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &, 35*5ffd83dbSDimitry Andric uint64_t entryAddr) const override; 36*5ffd83dbSDimitry Andric 37*5ffd83dbSDimitry Andric void prepareSymbolRelocation(lld::macho::Symbol &, const InputSection *, 38*5ffd83dbSDimitry Andric const Reloc &) override; 39*5ffd83dbSDimitry Andric uint64_t getSymbolVA(const lld::macho::Symbol &, uint8_t type) const override; 40*5ffd83dbSDimitry Andric }; 41*5ffd83dbSDimitry Andric 42*5ffd83dbSDimitry Andric } // namespace 43*5ffd83dbSDimitry Andric 44*5ffd83dbSDimitry Andric static std::string getErrorLocation(MemoryBufferRef mb, const section_64 &sec, 45*5ffd83dbSDimitry Andric const relocation_info &rel) { 46*5ffd83dbSDimitry Andric return ("invalid relocation at offset " + std::to_string(rel.r_address) + 47*5ffd83dbSDimitry Andric " of " + sec.segname + "," + sec.sectname + " in " + 48*5ffd83dbSDimitry Andric mb.getBufferIdentifier()) 49*5ffd83dbSDimitry Andric .str(); 50*5ffd83dbSDimitry Andric } 51*5ffd83dbSDimitry Andric 52*5ffd83dbSDimitry Andric static void validateLength(MemoryBufferRef mb, const section_64 &sec, 53*5ffd83dbSDimitry Andric const relocation_info &rel, 54*5ffd83dbSDimitry Andric const std::vector<uint8_t> &validLengths) { 55*5ffd83dbSDimitry Andric if (std::find(validLengths.begin(), validLengths.end(), rel.r_length) != 56*5ffd83dbSDimitry Andric validLengths.end()) 57*5ffd83dbSDimitry Andric return; 58*5ffd83dbSDimitry Andric 59*5ffd83dbSDimitry Andric std::string msg = getErrorLocation(mb, sec, rel) + ": relocations of type " + 60*5ffd83dbSDimitry Andric std::to_string(rel.r_type) + " must have r_length of "; 61*5ffd83dbSDimitry Andric bool first = true; 62*5ffd83dbSDimitry Andric for (uint8_t length : validLengths) { 63*5ffd83dbSDimitry Andric if (!first) 64*5ffd83dbSDimitry Andric msg += " or "; 65*5ffd83dbSDimitry Andric first = false; 66*5ffd83dbSDimitry Andric msg += std::to_string(length); 67*5ffd83dbSDimitry Andric } 68*5ffd83dbSDimitry Andric fatal(msg); 69*5ffd83dbSDimitry Andric } 70*5ffd83dbSDimitry Andric 71*5ffd83dbSDimitry Andric uint64_t X86_64::getImplicitAddend(MemoryBufferRef mb, const section_64 &sec, 72*5ffd83dbSDimitry Andric const relocation_info &rel) const { 73*5ffd83dbSDimitry Andric auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart()); 74*5ffd83dbSDimitry Andric const uint8_t *loc = buf + sec.offset + rel.r_address; 75*5ffd83dbSDimitry Andric switch (rel.r_type) { 76*5ffd83dbSDimitry Andric case X86_64_RELOC_BRANCH: 77*5ffd83dbSDimitry Andric // XXX: ld64 also supports r_length = 0 here but I'm not sure when such a 78*5ffd83dbSDimitry Andric // relocation will actually be generated. 79*5ffd83dbSDimitry Andric validateLength(mb, sec, rel, {2}); 80*5ffd83dbSDimitry Andric break; 81*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED: 82*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_1: 83*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_2: 84*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_4: 85*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT_LOAD: 86*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT: 87*5ffd83dbSDimitry Andric if (!rel.r_pcrel) 88*5ffd83dbSDimitry Andric fatal(getErrorLocation(mb, sec, rel) + ": relocations of type " + 89*5ffd83dbSDimitry Andric std::to_string(rel.r_type) + " must be pcrel"); 90*5ffd83dbSDimitry Andric validateLength(mb, sec, rel, {2}); 91*5ffd83dbSDimitry Andric break; 92*5ffd83dbSDimitry Andric case X86_64_RELOC_UNSIGNED: 93*5ffd83dbSDimitry Andric if (rel.r_pcrel) 94*5ffd83dbSDimitry Andric fatal(getErrorLocation(mb, sec, rel) + ": relocations of type " + 95*5ffd83dbSDimitry Andric std::to_string(rel.r_type) + " must not be pcrel"); 96*5ffd83dbSDimitry Andric validateLength(mb, sec, rel, {2, 3}); 97*5ffd83dbSDimitry Andric break; 98*5ffd83dbSDimitry Andric default: 99*5ffd83dbSDimitry Andric error("TODO: Unhandled relocation type " + std::to_string(rel.r_type)); 100*5ffd83dbSDimitry Andric return 0; 101*5ffd83dbSDimitry Andric } 102*5ffd83dbSDimitry Andric 103*5ffd83dbSDimitry Andric switch (rel.r_length) { 104*5ffd83dbSDimitry Andric case 0: 105*5ffd83dbSDimitry Andric return *loc; 106*5ffd83dbSDimitry Andric case 1: 107*5ffd83dbSDimitry Andric return read16le(loc); 108*5ffd83dbSDimitry Andric case 2: 109*5ffd83dbSDimitry Andric return read32le(loc); 110*5ffd83dbSDimitry Andric case 3: 111*5ffd83dbSDimitry Andric return read64le(loc); 112*5ffd83dbSDimitry Andric default: 113*5ffd83dbSDimitry Andric llvm_unreachable("invalid r_length"); 114*5ffd83dbSDimitry Andric } 115*5ffd83dbSDimitry Andric } 116*5ffd83dbSDimitry Andric 117*5ffd83dbSDimitry Andric void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t val) const { 118*5ffd83dbSDimitry Andric switch (r.type) { 119*5ffd83dbSDimitry Andric case X86_64_RELOC_BRANCH: 120*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED: 121*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_1: 122*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_2: 123*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_4: 124*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT_LOAD: 125*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT: 126*5ffd83dbSDimitry Andric // These types are only used for pc-relative relocations, so offset by 4 127*5ffd83dbSDimitry Andric // since the RIP has advanced by 4 at this point. This is only valid when 128*5ffd83dbSDimitry Andric // r_length = 2, which is enforced by validateLength(). 129*5ffd83dbSDimitry Andric val -= 4; 130*5ffd83dbSDimitry Andric break; 131*5ffd83dbSDimitry Andric case X86_64_RELOC_UNSIGNED: 132*5ffd83dbSDimitry Andric break; 133*5ffd83dbSDimitry Andric default: 134*5ffd83dbSDimitry Andric llvm_unreachable( 135*5ffd83dbSDimitry Andric "getImplicitAddend should have flagged all unhandled relocation types"); 136*5ffd83dbSDimitry Andric } 137*5ffd83dbSDimitry Andric 138*5ffd83dbSDimitry Andric switch (r.length) { 139*5ffd83dbSDimitry Andric case 0: 140*5ffd83dbSDimitry Andric *loc = val; 141*5ffd83dbSDimitry Andric break; 142*5ffd83dbSDimitry Andric case 1: 143*5ffd83dbSDimitry Andric write16le(loc, val); 144*5ffd83dbSDimitry Andric break; 145*5ffd83dbSDimitry Andric case 2: 146*5ffd83dbSDimitry Andric write32le(loc, val); 147*5ffd83dbSDimitry Andric break; 148*5ffd83dbSDimitry Andric case 3: 149*5ffd83dbSDimitry Andric write64le(loc, val); 150*5ffd83dbSDimitry Andric break; 151*5ffd83dbSDimitry Andric default: 152*5ffd83dbSDimitry Andric llvm_unreachable("invalid r_length"); 153*5ffd83dbSDimitry Andric } 154*5ffd83dbSDimitry Andric } 155*5ffd83dbSDimitry Andric 156*5ffd83dbSDimitry Andric // The following methods emit a number of assembly sequences with RIP-relative 157*5ffd83dbSDimitry Andric // addressing. Note that RIP-relative addressing on X86-64 has the RIP pointing 158*5ffd83dbSDimitry Andric // to the next instruction, not the current instruction, so we always have to 159*5ffd83dbSDimitry Andric // account for the current instruction's size when calculating offsets. 160*5ffd83dbSDimitry Andric // writeRipRelative helps with that. 161*5ffd83dbSDimitry Andric // 162*5ffd83dbSDimitry Andric // bufAddr: The virtual address corresponding to buf[0]. 163*5ffd83dbSDimitry Andric // bufOff: The offset within buf of the next instruction. 164*5ffd83dbSDimitry Andric // destAddr: The destination address that the current instruction references. 165*5ffd83dbSDimitry Andric static void writeRipRelative(uint8_t *buf, uint64_t bufAddr, uint64_t bufOff, 166*5ffd83dbSDimitry Andric uint64_t destAddr) { 167*5ffd83dbSDimitry Andric uint64_t rip = bufAddr + bufOff; 168*5ffd83dbSDimitry Andric // For the instructions we care about, the RIP-relative address is always 169*5ffd83dbSDimitry Andric // stored in the last 4 bytes of the instruction. 170*5ffd83dbSDimitry Andric write32le(buf + bufOff - 4, destAddr - rip); 171*5ffd83dbSDimitry Andric } 172*5ffd83dbSDimitry Andric 173*5ffd83dbSDimitry Andric static constexpr uint8_t stub[] = { 174*5ffd83dbSDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmpq *__la_symbol_ptr(%rip) 175*5ffd83dbSDimitry Andric }; 176*5ffd83dbSDimitry Andric 177*5ffd83dbSDimitry Andric void X86_64::writeStub(uint8_t *buf, const DylibSymbol &sym) const { 178*5ffd83dbSDimitry Andric memcpy(buf, stub, 2); // just copy the two nonzero bytes 179*5ffd83dbSDimitry Andric uint64_t stubAddr = in.stubs->addr + sym.stubsIndex * sizeof(stub); 180*5ffd83dbSDimitry Andric writeRipRelative(buf, stubAddr, sizeof(stub), 181*5ffd83dbSDimitry Andric in.lazyPointers->addr + sym.stubsIndex * WordSize); 182*5ffd83dbSDimitry Andric } 183*5ffd83dbSDimitry Andric 184*5ffd83dbSDimitry Andric static constexpr uint8_t stubHelperHeader[] = { 185*5ffd83dbSDimitry Andric 0x4c, 0x8d, 0x1d, 0, 0, 0, 0, // 0x0: leaq ImageLoaderCache(%rip), %r11 186*5ffd83dbSDimitry Andric 0x41, 0x53, // 0x7: pushq %r11 187*5ffd83dbSDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // 0x9: jmpq *dyld_stub_binder@GOT(%rip) 188*5ffd83dbSDimitry Andric 0x90, // 0xf: nop 189*5ffd83dbSDimitry Andric }; 190*5ffd83dbSDimitry Andric 191*5ffd83dbSDimitry Andric static constexpr uint8_t stubHelperEntry[] = { 192*5ffd83dbSDimitry Andric 0x68, 0, 0, 0, 0, // 0x0: pushq <bind offset> 193*5ffd83dbSDimitry Andric 0xe9, 0, 0, 0, 0, // 0x5: jmp <__stub_helper> 194*5ffd83dbSDimitry Andric }; 195*5ffd83dbSDimitry Andric 196*5ffd83dbSDimitry Andric void X86_64::writeStubHelperHeader(uint8_t *buf) const { 197*5ffd83dbSDimitry Andric memcpy(buf, stubHelperHeader, sizeof(stubHelperHeader)); 198*5ffd83dbSDimitry Andric writeRipRelative(buf, in.stubHelper->addr, 7, in.imageLoaderCache->getVA()); 199*5ffd83dbSDimitry Andric writeRipRelative(buf, in.stubHelper->addr, 0xf, 200*5ffd83dbSDimitry Andric in.got->addr + 201*5ffd83dbSDimitry Andric in.stubHelper->stubBinder->gotIndex * WordSize); 202*5ffd83dbSDimitry Andric } 203*5ffd83dbSDimitry Andric 204*5ffd83dbSDimitry Andric void X86_64::writeStubHelperEntry(uint8_t *buf, const DylibSymbol &sym, 205*5ffd83dbSDimitry Andric uint64_t entryAddr) const { 206*5ffd83dbSDimitry Andric memcpy(buf, stubHelperEntry, sizeof(stubHelperEntry)); 207*5ffd83dbSDimitry Andric write32le(buf + 1, sym.lazyBindOffset); 208*5ffd83dbSDimitry Andric writeRipRelative(buf, entryAddr, sizeof(stubHelperEntry), 209*5ffd83dbSDimitry Andric in.stubHelper->addr); 210*5ffd83dbSDimitry Andric } 211*5ffd83dbSDimitry Andric 212*5ffd83dbSDimitry Andric void X86_64::prepareSymbolRelocation(lld::macho::Symbol &sym, 213*5ffd83dbSDimitry Andric const InputSection *isec, const Reloc &r) { 214*5ffd83dbSDimitry Andric switch (r.type) { 215*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT_LOAD: 216*5ffd83dbSDimitry Andric // TODO: implement mov -> lea relaxation for non-dynamic symbols 217*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT: 218*5ffd83dbSDimitry Andric in.got->addEntry(sym); 219*5ffd83dbSDimitry Andric break; 220*5ffd83dbSDimitry Andric case X86_64_RELOC_BRANCH: { 221*5ffd83dbSDimitry Andric if (auto *dysym = dyn_cast<DylibSymbol>(&sym)) 222*5ffd83dbSDimitry Andric in.stubs->addEntry(*dysym); 223*5ffd83dbSDimitry Andric break; 224*5ffd83dbSDimitry Andric } 225*5ffd83dbSDimitry Andric case X86_64_RELOC_UNSIGNED: { 226*5ffd83dbSDimitry Andric if (auto *dysym = dyn_cast<DylibSymbol>(&sym)) { 227*5ffd83dbSDimitry Andric if (r.length != 3) { 228*5ffd83dbSDimitry Andric error("X86_64_RELOC_UNSIGNED referencing the dynamic symbol " + 229*5ffd83dbSDimitry Andric dysym->getName() + " must have r_length = 3"); 230*5ffd83dbSDimitry Andric return; 231*5ffd83dbSDimitry Andric } 232*5ffd83dbSDimitry Andric in.binding->addEntry(dysym, isec, r.offset, r.addend); 233*5ffd83dbSDimitry Andric } 234*5ffd83dbSDimitry Andric break; 235*5ffd83dbSDimitry Andric } 236*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED: 237*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_1: 238*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_2: 239*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_4: 240*5ffd83dbSDimitry Andric break; 241*5ffd83dbSDimitry Andric case X86_64_RELOC_SUBTRACTOR: 242*5ffd83dbSDimitry Andric case X86_64_RELOC_TLV: 243*5ffd83dbSDimitry Andric fatal("TODO: handle relocation type " + std::to_string(r.type)); 244*5ffd83dbSDimitry Andric break; 245*5ffd83dbSDimitry Andric default: 246*5ffd83dbSDimitry Andric llvm_unreachable("unexpected relocation type"); 247*5ffd83dbSDimitry Andric } 248*5ffd83dbSDimitry Andric } 249*5ffd83dbSDimitry Andric 250*5ffd83dbSDimitry Andric uint64_t X86_64::getSymbolVA(const lld::macho::Symbol &sym, 251*5ffd83dbSDimitry Andric uint8_t type) const { 252*5ffd83dbSDimitry Andric switch (type) { 253*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT_LOAD: 254*5ffd83dbSDimitry Andric case X86_64_RELOC_GOT: 255*5ffd83dbSDimitry Andric return in.got->addr + sym.gotIndex * WordSize; 256*5ffd83dbSDimitry Andric case X86_64_RELOC_BRANCH: 257*5ffd83dbSDimitry Andric if (auto *dysym = dyn_cast<DylibSymbol>(&sym)) 258*5ffd83dbSDimitry Andric return in.stubs->addr + dysym->stubsIndex * sizeof(stub); 259*5ffd83dbSDimitry Andric return sym.getVA(); 260*5ffd83dbSDimitry Andric case X86_64_RELOC_UNSIGNED: 261*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED: 262*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_1: 263*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_2: 264*5ffd83dbSDimitry Andric case X86_64_RELOC_SIGNED_4: 265*5ffd83dbSDimitry Andric return sym.getVA(); 266*5ffd83dbSDimitry Andric case X86_64_RELOC_SUBTRACTOR: 267*5ffd83dbSDimitry Andric case X86_64_RELOC_TLV: 268*5ffd83dbSDimitry Andric fatal("TODO: handle relocation type " + std::to_string(type)); 269*5ffd83dbSDimitry Andric default: 270*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected relocation type"); 271*5ffd83dbSDimitry Andric } 272*5ffd83dbSDimitry Andric } 273*5ffd83dbSDimitry Andric 274*5ffd83dbSDimitry Andric X86_64::X86_64() { 275*5ffd83dbSDimitry Andric cpuType = CPU_TYPE_X86_64; 276*5ffd83dbSDimitry Andric cpuSubtype = CPU_SUBTYPE_X86_64_ALL; 277*5ffd83dbSDimitry Andric 278*5ffd83dbSDimitry Andric stubSize = sizeof(stub); 279*5ffd83dbSDimitry Andric stubHelperHeaderSize = sizeof(stubHelperHeader); 280*5ffd83dbSDimitry Andric stubHelperEntrySize = sizeof(stubHelperEntry); 281*5ffd83dbSDimitry Andric } 282*5ffd83dbSDimitry Andric 283*5ffd83dbSDimitry Andric TargetInfo *macho::createX86_64TargetInfo() { 284*5ffd83dbSDimitry Andric static X86_64 t; 285*5ffd83dbSDimitry Andric return &t; 286*5ffd83dbSDimitry Andric } 287