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