57fefee5dedc470522faaa982dd1724872f9b17d
[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     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
92 void 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
145 void 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
169 void 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
258 bool 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