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