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:
X86_64ELFRelocationInfo(MCContext & Ctx)26   X86_64ELFRelocationInfo(MCContext &Ctx) : MCRelocationInfo(Ctx) {}
27 
createExprForRelocation(RelocationRef Rel)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())
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.
createX86_64ELFRelocationInfo(MCContext & Ctx)132 MCRelocationInfo *llvm::createX86_64ELFRelocationInfo(MCContext &Ctx) {
133   // We only handle x86-64 for now.
134   return new X86_64ELFRelocationInfo(Ctx);
135 }
136