1//===-- X86ELFRelocationInfo.cpp ----------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
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 "MCTargetDesc/X86MCTargetDesc.h"
11#include "llvm/MC/MCContext.h"
12#include "llvm/MC/MCExpr.h"
13#include "llvm/MC/MCInst.h"
14#include "llvm/MC/MCRelocationInfo.h"
15#include "llvm/MC/MCSymbol.h"
16#include "llvm/Object/ELFObjectFile.h"
17#include "llvm/Support/ELF.h"
18
19using namespace llvm;
20using namespace object;
21using namespace ELF;
22
23namespace {
24class X86_64ELFRelocationInfo : public MCRelocationInfo {
25public:
26  X86_64ELFRelocationInfo(MCContext &Ctx) : MCRelocationInfo(Ctx) {}
27
28  const MCExpr *createExprForRelocation(RelocationRef Rel) override {
29    uint64_t RelType; Rel.getType(RelType);
30    symbol_iterator SymI = Rel.getSymbol();
31
32    StringRef SymName; SymI->getName(SymName);
33    uint64_t  SymAddr; SymI->getAddress(SymAddr);
34    uint64_t  SymSize; SymI->getSize(SymSize);
35    int64_t  Addend;  getELFRelocationAddend(Rel, Addend);
36
37    MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName);
38    // FIXME: check that the value is actually the same.
39    if (Sym->isVariable() == false)
40      Sym->setVariableValue(MCConstantExpr::Create(SymAddr, Ctx));
41
42    const MCExpr *Expr = nullptr;
43    // If hasAddend is true, then we need to add Addend (r_addend) to Expr.
44    bool hasAddend = false;
45
46    // The AMD64 SysV ABI says:
47    // A: the addend used to compute the value of the relocatable field.
48    // B: the base address at which a shared object has been loaded into memory
49    //    during execution. Generally, a shared object is built with a 0 base
50    //    virtual address, but the execution address will be different.
51    // G: the offset into the global offset table at which the relocation
52    //    entry's symbol will reside during execution.
53    // GOT: the address of the global offset table.
54    // L: the place (section offset or address) of the Procedure Linkage Table
55    //    entry for a symbol.
56    // P: the place (section offset or address) of the storage unit being
57    //    relocated (computed using r_offset).
58    // S: the value of the symbol whose index resides in the relocation entry.
59    // Z: the size of the symbol whose index resides in the relocation entry.
60
61    switch(RelType) {
62    case R_X86_64_NONE:
63    case R_X86_64_COPY:
64      // none
65      break;
66    case R_X86_64_64:
67    case R_X86_64_16:
68    case R_X86_64_8:
69      // S + A
70    case R_X86_64_32:
71    case R_X86_64_32S:
72      // S + A (We don't care about the result not fitting in 32 bits.)
73    case R_X86_64_PC32:
74    case R_X86_64_PC16:
75    case R_X86_64_PC8:
76    case R_X86_64_PC64:
77      // S + A - P (P/pcrel is implicit)
78      hasAddend = true;
79      Expr = MCSymbolRefExpr::Create(Sym, Ctx);
80      break;
81    case R_X86_64_GOT32:
82    case R_X86_64_GOT64:
83    case R_X86_64_GOTPC32:
84    case R_X86_64_GOTPC64:
85    case R_X86_64_GOTPLT64:
86      // G + A
87      hasAddend = true;
88      Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOT, Ctx);
89      break;
90    case R_X86_64_PLT32:
91      // L + A - P -> S@PLT + A
92      hasAddend = true;
93      Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_PLT, Ctx);
94      break;
95    case R_X86_64_GLOB_DAT:
96    case R_X86_64_JUMP_SLOT:
97      // S
98      Expr = MCSymbolRefExpr::Create(Sym, Ctx);
99      break;
100    case R_X86_64_GOTPCREL:
101    case R_X86_64_GOTPCREL64:
102      // G + GOT + A - P -> S@GOTPCREL + A
103      hasAddend = true;
104      Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, Ctx);
105      break;
106    case R_X86_64_GOTOFF64:
107      // S + A - GOT
108      Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTOFF, Ctx);
109      break;
110    case R_X86_64_PLTOFF64:
111      // L + A - GOT
112      break;
113    case R_X86_64_SIZE32:
114    case R_X86_64_SIZE64:
115      // Z + A
116      Expr = MCConstantExpr::Create(SymSize, Ctx);
117      break;
118    default:
119      Expr = MCSymbolRefExpr::Create(Sym, Ctx);
120      break;
121    }
122    if (Expr && hasAddend && Addend != 0)
123      Expr = MCBinaryExpr::CreateAdd(Expr,
124                                     MCConstantExpr::Create(Addend, Ctx),
125                                     Ctx);
126    return Expr;
127  }
128};
129} // End unnamed namespace
130
131/// createX86ELFRelocationInfo - Construct an X86 Mach-O RelocationInfo.
132MCRelocationInfo *llvm::createX86_64ELFRelocationInfo(MCContext &Ctx) {
133  // We only handle x86-64 for now.
134  return new X86_64ELFRelocationInfo(Ctx);
135}
136