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