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