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::
169 processRelocationRef(const ObjRelocationInfo &Rel, const ObjectFile &Obj,
170                      ObjSectionToIDMap &ObjSectionToID,
171                      LocalSymbolMap &Symbols, StubMap &Stubs) {
172
173   uint32_t RelType = (uint32_t)(Rel.Type & 0xffffffffL);
174   intptr_t Addend = (intptr_t)Rel.AdditionalInfo;
175   RelocationValueRef Value;
176   StringRef TargetName;
177   const SymbolRef &Symbol = Rel.Symbol;
178   Symbol.getName(TargetName);
179   DEBUG(dbgs() << "\t\tRelType: " << RelType
180                << " Addend: " << Addend
181                << " TargetName: " << TargetName
182                << "\n");
183   // First look the symbol in object file symbols.
184   LocalSymbolMap::iterator it = Symbols.find(TargetName.data());
185   if (it != Symbols.end()) {
186     Value.SectionID = it->second.first;
187     Value.Addend = it->second.second;
188   } else {
189     // Second look the symbol in global symbol table.
190     StringMap<SymbolLoc>::iterator itS = SymbolTable.find(TargetName.data());
191     if (itS != SymbolTable.end()) {
192       Value.SectionID = itS->second.first;
193       Value.Addend = itS->second.second;
194     } else {
195       SymbolRef::Type SymType;
196       Symbol.getType(SymType);
197       switch (SymType) {
198         case SymbolRef::ST_Debug: {
199           // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously
200           // and can be changed by another developers. Maybe best way is add
201           // a new symbol type ST_Section to SymbolRef and use it.
202           section_iterator sIt = Obj.end_sections();
203           Symbol.getSection(sIt);
204           if (sIt == Obj.end_sections())
205             llvm_unreachable("Symbol section not found, bad object file format!");
206           DEBUG(dbgs() << "\t\tThis is section symbol\n");
207           Value.SectionID = findOrEmitSection((*sIt), true, ObjSectionToID);
208           Value.Addend = Addend;
209           break;
210         }
211         case SymbolRef::ST_Unknown: {
212           Value.SymbolName = TargetName.data();
213           Value.Addend = Addend;
214           break;
215         }
216         default:
217           llvm_unreachable("Unresolved symbol type!");
218           break;
219       }
220     }
221   }
222   DEBUG(dbgs() << "\t\tRel.SectionID: " << Rel.SectionID
223                << " Rel.Offset: " << Rel.Offset
224                << "\n");
225   if (Arch == Triple::arm &&
226       (RelType == ELF::R_ARM_PC24 ||
227        RelType == ELF::R_ARM_CALL ||
228        RelType == ELF::R_ARM_JUMP24)) {
229     // This is an ARM branch relocation, need to use a stub function.
230     DEBUG(dbgs() << "\t\tThis is an ARM branch relocation.");
231     SectionEntry &Section = Sections[Rel.SectionID];
232     uint8_t *Target = Section.Address + Rel.Offset;
233
234     //  Look up for existing stub.
235     StubMap::const_iterator stubIt = Stubs.find(Value);
236     if (stubIt != Stubs.end()) {
237       resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address +
238                         stubIt->second, RelType, 0);
239       DEBUG(dbgs() << " Stub function found\n");
240     } else {
241       // Create a new stub function.
242       DEBUG(dbgs() << " Create a new stub function\n");
243       Stubs[Value] = Section.StubOffset;
244       uint8_t *StubTargetAddr = createStubFunction(Section.Address +
245                                                    Section.StubOffset);
246       AddRelocation(Value, Rel.SectionID,
247                     StubTargetAddr - Section.Address, ELF::R_ARM_ABS32);
248       resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address +
249                         Section.StubOffset, RelType, 0);
250       Section.StubOffset += getMaxStubSize();
251     }
252   } else
253     AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType);
254 }
255
256 bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const {
257   StringRef Magic = InputBuffer->getBuffer().slice(0, ELF::EI_NIDENT);
258   return (memcmp(Magic.data(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0;
259 }
260 } // namespace llvm