//===-- X86ELFRelocationInfo.cpp ----------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/X86MCTargetDesc.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCRelocationInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/ELF.h" using namespace llvm; using namespace object; using namespace ELF; namespace { class X86_64ELFRelocationInfo : public MCRelocationInfo { public: X86_64ELFRelocationInfo(MCContext &Ctx) : MCRelocationInfo(Ctx) {} const MCExpr *createExprForRelocation(RelocationRef Rel) override { uint64_t RelType; Rel.getType(RelType); symbol_iterator SymI = Rel.getSymbol(); StringRef SymName; SymI->getName(SymName); uint64_t SymAddr; SymI->getAddress(SymAddr); uint64_t SymSize; SymI->getSize(SymSize); int64_t Addend; getELFRelocationAddend(Rel, Addend); MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName); // FIXME: check that the value is actually the same. if (!Sym->isVariable()) Sym->setVariableValue(MCConstantExpr::Create(SymAddr, Ctx)); const MCExpr *Expr = nullptr; // If hasAddend is true, then we need to add Addend (r_addend) to Expr. bool hasAddend = false; // The AMD64 SysV ABI says: // A: the addend used to compute the value of the relocatable field. // B: the base address at which a shared object has been loaded into memory // during execution. Generally, a shared object is built with a 0 base // virtual address, but the execution address will be different. // G: the offset into the global offset table at which the relocation // entry's symbol will reside during execution. // GOT: the address of the global offset table. // L: the place (section offset or address) of the Procedure Linkage Table // entry for a symbol. // P: the place (section offset or address) of the storage unit being // relocated (computed using r_offset). // S: the value of the symbol whose index resides in the relocation entry. // Z: the size of the symbol whose index resides in the relocation entry. switch(RelType) { case R_X86_64_NONE: case R_X86_64_COPY: // none break; case R_X86_64_64: case R_X86_64_16: case R_X86_64_8: // S + A case R_X86_64_32: case R_X86_64_32S: // S + A (We don't care about the result not fitting in 32 bits.) case R_X86_64_PC32: case R_X86_64_PC16: case R_X86_64_PC8: case R_X86_64_PC64: // S + A - P (P/pcrel is implicit) hasAddend = true; Expr = MCSymbolRefExpr::Create(Sym, Ctx); break; case R_X86_64_GOT32: case R_X86_64_GOT64: case R_X86_64_GOTPC32: case R_X86_64_GOTPC64: case R_X86_64_GOTPLT64: // G + A hasAddend = true; Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOT, Ctx); break; case R_X86_64_PLT32: // L + A - P -> S@PLT + A hasAddend = true; Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_PLT, Ctx); break; case R_X86_64_GLOB_DAT: case R_X86_64_JUMP_SLOT: // S Expr = MCSymbolRefExpr::Create(Sym, Ctx); break; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCREL64: // G + GOT + A - P -> S@GOTPCREL + A hasAddend = true; Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, Ctx); break; case R_X86_64_GOTOFF64: // S + A - GOT Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTOFF, Ctx); break; case R_X86_64_PLTOFF64: // L + A - GOT break; case R_X86_64_SIZE32: case R_X86_64_SIZE64: // Z + A Expr = MCConstantExpr::Create(SymSize, Ctx); break; default: Expr = MCSymbolRefExpr::Create(Sym, Ctx); break; } if (Expr && hasAddend && Addend != 0) Expr = MCBinaryExpr::CreateAdd(Expr, MCConstantExpr::Create(Addend, Ctx), Ctx); return Expr; } }; } // End unnamed namespace /// createX86ELFRelocationInfo - Construct an X86 Mach-O RelocationInfo. MCRelocationInfo *llvm::createX86_64ELFRelocationInfo(MCContext &Ctx) { // We only handle x86-64 for now. return new X86_64ELFRelocationInfo(Ctx); }