RuntimeDyldELF.cpp revision 234285
1//===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-===//
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// Implementation of ELF support for the MC-JIT runtime dynamic linker.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "dyld"
15#include "llvm/ADT/OwningPtr.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/IntervalMap.h"
19#include "RuntimeDyldELF.h"
20#include "llvm/Object/ObjectFile.h"
21#include "llvm/Support/ELF.h"
22#include "llvm/ADT/Triple.h"
23using namespace llvm;
24using namespace llvm::object;
25
26namespace llvm {
27
28
29void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress,
30                                             uint64_t FinalAddress,
31                                             uint64_t Value,
32                                             uint32_t Type,
33                                             int64_t Addend) {
34  switch (Type) {
35  default:
36    llvm_unreachable("Relocation type not implemented yet!");
37  break;
38  case ELF::R_X86_64_64: {
39    uint64_t *Target = (uint64_t*)(LocalAddress);
40    *Target = Value + Addend;
41    break;
42  }
43  case ELF::R_X86_64_32:
44  case ELF::R_X86_64_32S: {
45    Value += Addend;
46    // FIXME: Handle the possibility of this assertion failing
47    assert((Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) ||
48           (Type == ELF::R_X86_64_32S &&
49            (Value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL));
50    uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
51    uint32_t *Target = reinterpret_cast<uint32_t*>(LocalAddress);
52    *Target = TruncatedAddr;
53    break;
54  }
55  case ELF::R_X86_64_PC32: {
56    uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress);
57    int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
58    assert(RealOffset <= 214783647 && RealOffset >= -214783648);
59    int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
60    *Placeholder = TruncOffset;
61    break;
62  }
63  }
64}
65
66void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress,
67                                          uint32_t FinalAddress,
68                                          uint32_t Value,
69                                          uint32_t Type,
70                                          int32_t Addend) {
71  switch (Type) {
72  case ELF::R_386_32: {
73    uint32_t *Target = (uint32_t*)(LocalAddress);
74    uint32_t Placeholder = *Target;
75    *Target = Placeholder + Value + Addend;
76    break;
77  }
78  case ELF::R_386_PC32: {
79    uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress);
80    uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
81    *Placeholder = RealOffset;
82    break;
83    }
84    default:
85      // There are other relocation types, but it appears these are the
86      //  only ones currently used by the LLVM ELF object writer
87      llvm_unreachable("Relocation type not implemented yet!");
88      break;
89  }
90}
91
92void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress,
93                                          uint32_t FinalAddress,
94                                          uint32_t Value,
95                                          uint32_t Type,
96                                          int32_t Addend) {
97  // TODO: Add Thumb relocations.
98  uint32_t* TargetPtr = (uint32_t*)LocalAddress;
99  Value += Addend;
100
101  DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " << LocalAddress
102               << " FinalAddress: " << format("%p",FinalAddress)
103               << " Value: " << format("%x",Value)
104               << " Type: " << format("%x",Type)
105               << " Addend: " << format("%x",Addend)
106               << "\n");
107
108  switch(Type) {
109  default:
110    llvm_unreachable("Not implemented relocation type!");
111
112  // Just write 32bit value to relocation address
113  case ELF::R_ARM_ABS32 :
114    *TargetPtr = Value;
115    break;
116
117  // Write first 16 bit of 32 bit value to the mov instruction.
118  // Last 4 bit should be shifted.
119  case ELF::R_ARM_MOVW_ABS_NC :
120    Value = Value & 0xFFFF;
121    *TargetPtr |= Value & 0xFFF;
122    *TargetPtr |= ((Value >> 12) & 0xF) << 16;
123    break;
124
125  // Write last 16 bit of 32 bit value to the mov instruction.
126  // Last 4 bit should be shifted.
127  case ELF::R_ARM_MOVT_ABS :
128    Value = (Value >> 16) & 0xFFFF;
129    *TargetPtr |= Value & 0xFFF;
130    *TargetPtr |= ((Value >> 12) & 0xF) << 16;
131    break;
132
133  // Write 24 bit relative value to the branch instruction.
134  case ELF::R_ARM_PC24 :    // Fall through.
135  case ELF::R_ARM_CALL :    // Fall through.
136  case ELF::R_ARM_JUMP24 :
137    int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8);
138    RelValue = (RelValue & 0x03FFFFFC) >> 2;
139    *TargetPtr &= 0xFF000000;
140    *TargetPtr |= RelValue;
141    break;
142  }
143}
144
145void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
146                                       uint64_t FinalAddress,
147                                       uint64_t Value,
148                                       uint32_t Type,
149                                       int64_t Addend) {
150  switch (Arch) {
151  case Triple::x86_64:
152    resolveX86_64Relocation(LocalAddress, FinalAddress, Value, Type, Addend);
153    break;
154  case Triple::x86:
155    resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL),
156                         (uint32_t)(Value & 0xffffffffL), Type,
157                         (uint32_t)(Addend & 0xffffffffL));
158    break;
159  case Triple::arm:    // Fall through.
160  case Triple::thumb:
161    resolveARMRelocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL),
162                         (uint32_t)(Value & 0xffffffffL), Type,
163                         (uint32_t)(Addend & 0xffffffffL));
164    break;
165  default: llvm_unreachable("Unsupported CPU type!");
166  }
167}
168
169void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
170                                          const ObjectFile &Obj,
171                                          ObjSectionToIDMap &ObjSectionToID,
172                                          LocalSymbolMap &Symbols,
173                                          StubMap &Stubs) {
174
175  uint32_t RelType = (uint32_t)(Rel.Type & 0xffffffffL);
176  intptr_t Addend = (intptr_t)Rel.AdditionalInfo;
177  RelocationValueRef Value;
178  StringRef TargetName;
179  const SymbolRef &Symbol = Rel.Symbol;
180  Symbol.getName(TargetName);
181  DEBUG(dbgs() << "\t\tRelType: " << RelType
182               << " Addend: " << Addend
183               << " TargetName: " << TargetName
184               << "\n");
185  // First look the symbol in object file symbols.
186  LocalSymbolMap::iterator lsi = Symbols.find(TargetName.data());
187  if (lsi != Symbols.end()) {
188    Value.SectionID = lsi->second.first;
189    Value.Addend = lsi->second.second;
190  } else {
191    // Second look the symbol in global symbol table.
192    StringMap<SymbolLoc>::iterator gsi = SymbolTable.find(TargetName.data());
193    if (gsi != SymbolTable.end()) {
194      Value.SectionID = gsi->second.first;
195      Value.Addend = gsi->second.second;
196    } else {
197      SymbolRef::Type SymType;
198      Symbol.getType(SymType);
199      switch (SymType) {
200        case SymbolRef::ST_Debug: {
201          // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously
202          // and can be changed by another developers. Maybe best way is add
203          // a new symbol type ST_Section to SymbolRef and use it.
204          section_iterator si = Obj.end_sections();
205          Symbol.getSection(si);
206          if (si == Obj.end_sections())
207            llvm_unreachable("Symbol section not found, bad object file format!");
208          DEBUG(dbgs() << "\t\tThis is section symbol\n");
209          Value.SectionID = findOrEmitSection((*si), true, ObjSectionToID);
210          Value.Addend = Addend;
211          break;
212        }
213        case SymbolRef::ST_Unknown: {
214          Value.SymbolName = TargetName.data();
215          Value.Addend = Addend;
216          break;
217        }
218        default:
219          llvm_unreachable("Unresolved symbol type!");
220          break;
221      }
222    }
223  }
224  DEBUG(dbgs() << "\t\tRel.SectionID: " << Rel.SectionID
225               << " Rel.Offset: " << Rel.Offset
226               << "\n");
227  if (Arch == Triple::arm &&
228      (RelType == ELF::R_ARM_PC24 ||
229       RelType == ELF::R_ARM_CALL ||
230       RelType == ELF::R_ARM_JUMP24)) {
231    // This is an ARM branch relocation, need to use a stub function.
232    DEBUG(dbgs() << "\t\tThis is an ARM branch relocation.");
233    SectionEntry &Section = Sections[Rel.SectionID];
234    uint8_t *Target = Section.Address + Rel.Offset;
235
236    //  Look up for existing stub.
237    StubMap::const_iterator i = Stubs.find(Value);
238    if (i != Stubs.end()) {
239      resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address +
240                        i->second, RelType, 0);
241      DEBUG(dbgs() << " Stub function found\n");
242    } else {
243      // Create a new stub function.
244      DEBUG(dbgs() << " Create a new stub function\n");
245      Stubs[Value] = Section.StubOffset;
246      uint8_t *StubTargetAddr = createStubFunction(Section.Address +
247                                                   Section.StubOffset);
248      AddRelocation(Value, Rel.SectionID,
249                    StubTargetAddr - Section.Address, ELF::R_ARM_ABS32);
250      resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address +
251                        Section.StubOffset, RelType, 0);
252      Section.StubOffset += getMaxStubSize();
253    }
254  } else
255    AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType);
256}
257
258bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const {
259  StringRef Magic = InputBuffer->getBuffer().slice(0, ELF::EI_NIDENT);
260  return (memcmp(Magic.data(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0;
261}
262} // namespace llvm
263