1259698Sdim//===-- X86MachORelocationInfo.cpp ----------------------------------------===//
2259698Sdim//
3259698Sdim//                     The LLVM Compiler Infrastructure
4259698Sdim//
5259698Sdim// This file is distributed under the University of Illinois Open Source
6259698Sdim// License. See LICENSE.TXT for details.
7259698Sdim//
8259698Sdim//===----------------------------------------------------------------------===//
9259698Sdim
10259698Sdim#include "MCTargetDesc/X86MCTargetDesc.h"
11259698Sdim#include "llvm/MC/MCContext.h"
12259698Sdim#include "llvm/MC/MCExpr.h"
13259698Sdim#include "llvm/MC/MCInst.h"
14259698Sdim#include "llvm/MC/MCSymbol.h"
15259698Sdim#include "llvm/MC/MCRelocationInfo.h"
16259698Sdim#include "llvm/Object/MachO.h"
17259698Sdim
18259698Sdimusing namespace llvm;
19259698Sdimusing namespace object;
20259698Sdimusing namespace MachO;
21259698Sdim
22259698Sdimnamespace {
23259698Sdimclass X86_64MachORelocationInfo : public MCRelocationInfo {
24259698Sdimpublic:
25259698Sdim  X86_64MachORelocationInfo(MCContext &Ctx) : MCRelocationInfo(Ctx) {}
26259698Sdim
27259698Sdim  const MCExpr *createExprForRelocation(RelocationRef Rel) {
28259698Sdim    const MachOObjectFile *Obj = cast<MachOObjectFile>(Rel.getObjectFile());
29259698Sdim
30259698Sdim    uint64_t RelType; Rel.getType(RelType);
31259698Sdim    symbol_iterator SymI = Rel.getSymbol();
32259698Sdim
33259698Sdim    StringRef SymName; SymI->getName(SymName);
34259698Sdim    uint64_t  SymAddr; SymI->getAddress(SymAddr);
35259698Sdim
36259698Sdim    any_relocation_info RE = Obj->getRelocation(Rel.getRawDataRefImpl());
37259698Sdim    bool isPCRel = Obj->getAnyRelocationPCRel(RE);
38259698Sdim
39259698Sdim    MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName);
40259698Sdim    // FIXME: check that the value is actually the same.
41259698Sdim    if (Sym->isVariable() == false)
42259698Sdim      Sym->setVariableValue(MCConstantExpr::Create(SymAddr, Ctx));
43259698Sdim    const MCExpr *Expr = 0;
44259698Sdim
45259698Sdim    switch(RelType) {
46259698Sdim    case X86_64_RELOC_TLV:
47259698Sdim      Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_TLVP, Ctx);
48259698Sdim      break;
49259698Sdim    case X86_64_RELOC_SIGNED_4:
50259698Sdim      Expr = MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(Sym, Ctx),
51259698Sdim                                     MCConstantExpr::Create(4, Ctx),
52259698Sdim                                     Ctx);
53259698Sdim      break;
54259698Sdim    case X86_64_RELOC_SIGNED_2:
55259698Sdim      Expr = MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(Sym, Ctx),
56259698Sdim                                     MCConstantExpr::Create(2, Ctx),
57259698Sdim                                     Ctx);
58259698Sdim      break;
59259698Sdim    case X86_64_RELOC_SIGNED_1:
60259698Sdim      Expr = MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(Sym, Ctx),
61259698Sdim                                     MCConstantExpr::Create(1, Ctx),
62259698Sdim                                     Ctx);
63259698Sdim      break;
64259698Sdim    case X86_64_RELOC_GOT_LOAD:
65259698Sdim      Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, Ctx);
66259698Sdim      break;
67259698Sdim    case X86_64_RELOC_GOT:
68259698Sdim      Expr = MCSymbolRefExpr::Create(Sym, isPCRel ?
69259698Sdim                                     MCSymbolRefExpr::VK_GOTPCREL :
70259698Sdim                                     MCSymbolRefExpr::VK_GOT,
71259698Sdim                                     Ctx);
72259698Sdim      break;
73259698Sdim    case X86_64_RELOC_SUBTRACTOR:
74259698Sdim      {
75259698Sdim        RelocationRef RelNext;
76259698Sdim        Obj->getRelocationNext(Rel.getRawDataRefImpl(), RelNext);
77259698Sdim        any_relocation_info RENext = Obj->getRelocation(RelNext.getRawDataRefImpl());
78259698Sdim
79259698Sdim        // X86_64_SUBTRACTOR must be followed by a relocation of type
80259698Sdim        // X86_64_RELOC_UNSIGNED.
81259698Sdim        // NOTE: Scattered relocations don't exist on x86_64.
82259698Sdim        unsigned RType = Obj->getAnyRelocationType(RENext);
83259698Sdim        if (RType != X86_64_RELOC_UNSIGNED)
84259698Sdim          report_fatal_error("Expected X86_64_RELOC_UNSIGNED after "
85259698Sdim                             "X86_64_RELOC_SUBTRACTOR.");
86259698Sdim
87259698Sdim        const MCExpr *LHS = MCSymbolRefExpr::Create(Sym, Ctx);
88259698Sdim
89259698Sdim        symbol_iterator RSymI = RelNext.getSymbol();
90259698Sdim        uint64_t RSymAddr;
91259698Sdim        RSymI->getAddress(RSymAddr);
92259698Sdim        StringRef RSymName;
93259698Sdim        RSymI->getName(RSymName);
94259698Sdim
95259698Sdim        MCSymbol *RSym = Ctx.GetOrCreateSymbol(RSymName);
96259698Sdim        if (RSym->isVariable() == false)
97259698Sdim          RSym->setVariableValue(MCConstantExpr::Create(RSymAddr, Ctx));
98259698Sdim
99259698Sdim        const MCExpr *RHS = MCSymbolRefExpr::Create(RSym, Ctx);
100259698Sdim
101259698Sdim        Expr = MCBinaryExpr::CreateSub(LHS, RHS, Ctx);
102259698Sdim        break;
103259698Sdim      }
104259698Sdim    default:
105259698Sdim      Expr = MCSymbolRefExpr::Create(Sym, Ctx);
106259698Sdim      break;
107259698Sdim    }
108259698Sdim    return Expr;
109259698Sdim  }
110259698Sdim};
111259698Sdim} // End unnamed namespace
112259698Sdim
113259698Sdim/// createX86_64MachORelocationInfo - Construct an X86-64 Mach-O RelocationInfo.
114259698SdimMCRelocationInfo *llvm::createX86_64MachORelocationInfo(MCContext &Ctx) {
115259698Sdim  return new X86_64MachORelocationInfo(Ctx);
116259698Sdim}
117