blob: 57fefee5dedc470522faaa982dd1724872f9b17d [file] [log] [blame]
Jim Grosbache0934be2012-01-16 23:50:58 +00001//===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-===//
Eli Benderskya66a1852012-01-16 08:56:09 +00002//
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"
Eli Bendersky76463fd2012-01-22 07:05:02 +000019#include "RuntimeDyldELF.h"
Eli Benderskya66a1852012-01-16 08:56:09 +000020#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
Eli Benderskya66a1852012-01-16 08:56:09 +000028
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000029void 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;
Eli Benderskya66a1852012-01-16 08:56:09 +000038 case ELF::R_X86_64_64: {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000039 uint64_t *Target = (uint64_t*)(LocalAddress);
40 *Target = Value + Addend;
Eli Benderskya66a1852012-01-16 08:56:09 +000041 break;
42 }
43 case ELF::R_X86_64_32:
44 case ELF::R_X86_64_32S: {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000045 Value += Addend;
Eli Benderskya66a1852012-01-16 08:56:09 +000046 // FIXME: Handle the possibility of this assertion failing
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000047 assert((Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) ||
48 (Type == ELF::R_X86_64_32S &&
Eli Bendersky92238222012-01-16 09:31:10 +000049 (Value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL));
Eli Benderskya66a1852012-01-16 08:56:09 +000050 uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000051 uint32_t *Target = reinterpret_cast<uint32_t*>(LocalAddress);
Eli Benderskya66a1852012-01-16 08:56:09 +000052 *Target = TruncatedAddr;
53 break;
54 }
55 case ELF::R_X86_64_PC32: {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000056 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);
Eli Benderskya66a1852012-01-16 08:56:09 +000060 *Placeholder = TruncOffset;
61 break;
62 }
63 }
64}
65
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000066void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress,
67 uint32_t FinalAddress,
68 uint32_t Value,
69 uint32_t Type,
70 int32_t Addend) {
71 switch (Type) {
Eli Benderskya66a1852012-01-16 08:56:09 +000072 case ELF::R_386_32: {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000073 uint32_t *Target = (uint32_t*)(LocalAddress);
Preston Gurdc68dda82012-04-12 20:13:57 +000074 uint32_t Placeholder = *Target;
75 *Target = Placeholder + Value + Addend;
Eli Benderskya66a1852012-01-16 08:56:09 +000076 break;
77 }
78 case ELF::R_386_PC32: {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000079 uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress);
80 uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
Eli Benderskya66a1852012-01-16 08:56:09 +000081 *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
Craig Topper85814382012-02-07 05:05:23 +000087 llvm_unreachable("Relocation type not implemented yet!");
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000088 break;
Eli Benderskya66a1852012-01-16 08:56:09 +000089 }
90}
91
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000092void 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 }
Eli Benderskya66a1852012-01-16 08:56:09 +0000143}
144
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000145void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
146 uint64_t FinalAddress,
147 uint64_t Value,
148 uint32_t Type,
149 int64_t Addend) {
Eli Benderskya66a1852012-01-16 08:56:09 +0000150 switch (Arch) {
151 case Triple::x86_64:
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000152 resolveX86_64Relocation(LocalAddress, FinalAddress, Value, Type, Addend);
Eli Benderskya66a1852012-01-16 08:56:09 +0000153 break;
154 case Triple::x86:
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000155 resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL),
156 (uint32_t)(Value & 0xffffffffL), Type,
157 (uint32_t)(Addend & 0xffffffffL));
Eli Benderskya66a1852012-01-16 08:56:09 +0000158 break;
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000159 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));
Eli Benderskya66a1852012-01-16 08:56:09 +0000164 break;
Craig Topper85814382012-02-07 05:05:23 +0000165 default: llvm_unreachable("Unsupported CPU type!");
Eli Benderskya66a1852012-01-16 08:56:09 +0000166 }
167}
168
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000169void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
170 const ObjectFile &Obj,
171 ObjSectionToIDMap &ObjSectionToID,
172 LocalSymbolMap &Symbols,
173 StubMap &Stubs) {
Eli Benderskya66a1852012-01-16 08:56:09 +0000174
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000175 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 }
Eli Benderskya66a1852012-01-16 08:56:09 +0000223 }
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000224 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;
Eli Benderskya66a1852012-01-16 08:56:09 +0000235
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000236 // 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);
Jim Grosbach61425c02012-01-16 22:26:39 +0000256}
257
Eli Benderskya66a1852012-01-16 08:56:09 +0000258bool 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