ELFObject.hxx revision ddd3e1ce7bddc792b89cd23cbe0150c57c97e70a
1#ifndef ELF_OBJECT_HXX
2#define ELF_OBJECT_HXX
3
4#include "ELFHeader.h"
5#include "ELFReloc.h"
6#include "ELFSection.h"
7#include "ELFSectionHeaderTable.h"
8#include "StubLayout.h"
9
10#include <assert.h>
11#include <elf.h>
12
13#ifdef __arm__
14template <unsigned Bitwidth>
15inline StubLayout *ELFObject<Bitwidth>::getStubLayout() {
16  if (!stubs) {
17    stubs.reset(new StubLayout());
18  }
19  return stubs.get();
20}
21#endif
22
23template <unsigned Bitwidth>
24template <typename Archiver>
25inline ELFObject<Bitwidth> *
26ELFObject<Bitwidth>::read(Archiver &AR) {
27  llvm::OwningPtr<ELFObjectTy> object(new ELFObjectTy());
28
29  // Read header
30  object->header.reset(ELFHeaderTy::read(AR));
31  if (!object->header) {
32    return 0;
33  }
34
35  // Read section table
36  object->shtab.reset(ELFSectionHeaderTableTy::read(AR, object.get()));
37  if (!object->shtab) {
38    return 0;
39  }
40
41  // Read each section
42  for (size_t i = 0; i < object->header->getSectionHeaderNum(); ++i) {
43    llvm::OwningPtr<ELFSectionTy> sec(
44      ELFSectionTy::read(AR, object.get(), (*object->shtab)[i]));
45    object->stab.push_back(sec.take());
46  }
47
48  return object.take();
49}
50
51template <unsigned Bitwidth>
52inline char const *ELFObject<Bitwidth>::getSectionName(size_t i) const {
53  ELFSectionTy const *sec = stab[header->getStringSectionIndex()];
54
55  if (sec) {
56    ELFSectionStrTabTy const &st =
57      static_cast<ELFSectionStrTabTy const &>(*sec);
58    return st[i];
59  }
60
61  return NULL;
62}
63
64template <unsigned Bitwidth>
65inline ELFSection<Bitwidth> const *
66ELFObject<Bitwidth>::getSectionByIndex(size_t i) const {
67  return stab[i];
68}
69
70template <unsigned Bitwidth>
71inline ELFSection<Bitwidth> *
72ELFObject<Bitwidth>::getSectionByIndex(size_t i) {
73  return stab[i];
74}
75
76template <unsigned Bitwidth>
77inline ELFSection<Bitwidth> const *
78ELFObject<Bitwidth>::getSectionByName(std::string const &str) const {
79  size_t idx = getSectionHeaderTable()->getByName(str)->getIndex();
80  return stab[idx];
81}
82
83template <unsigned Bitwidth>
84inline ELFSection<Bitwidth> *
85ELFObject<Bitwidth>::getSectionByName(std::string const &str) {
86  ELFObjectTy const *const_this = this;
87  ELFSectionTy const *sptr = const_this->getSectionByName(str);
88  // Const cast for the same API's const and non-const versions.
89  return const_cast<ELFSectionTy *>(sptr);
90}
91
92
93template <unsigned Bitwidth>
94inline void ELFObject<Bitwidth>::
95relocateARM(void *(*find_sym)(void *context, char const *name),
96            void *context) {
97  // FIXME: Should be implement in independent files.
98  assert(Bitwidth == 32 && "ARM only have 32 bits.");
99
100  // FIXME: Can not only relocate .rel.text!
101  ELFSectionRelTableTy *reltab =
102    static_cast<ELFSectionRelTableTy *>(getSectionByName(".rel.text"));
103  ELFSectionProgBitsTy *text =
104    static_cast<ELFSectionProgBitsTy *>(getSectionByName(".text"));
105  ELFSectionSymTabTy *symtab =
106    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
107
108  for (size_t i = 0; i < reltab->size(); ++i) {
109    // FIXME: Can not implement here, use Fixup!
110    ELFRelocTy *rel = (*reltab)[i];
111    ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
112
113    // FIXME: May be not uint32_t *.
114    typedef int32_t Inst_t;
115    Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
116    Inst_t P = (Inst_t)(int64_t)inst;
117    Inst_t A = 0;
118    Inst_t S = (Inst_t)(int64_t)sym->getAddress();
119
120    switch (rel->getType()) {
121    default:
122      assert(0 && "Not implemented relocation type.");
123      break;
124
125      // FIXME: Predefine relocation codes.
126    case 28: // R_ARM_CALL
127      {
128#define SIGN_EXTEND(x, l) (((x)^(1<<((l)-1)))-(1<<(l-1)))
129        A = (Inst_t)(int64_t)SIGN_EXTEND(*inst & 0xFFFFFF, 24);
130#undef SIGN_EXTEND
131        if (S == 0) {
132          S = (Inst_t)(int64_t)find_sym(context, sym->getName());
133          sym->setAddress((void *)S);
134        }
135        //switch (sym->getType()) {
136        //  default:
137        //    assert(0 && "Wrong type for R_ARM_CALL relocation.");
138        //    break;
139        //  case STT_FUNC:
140        //    {
141        //      S = (uint32_t)sym->getAddress();
142        //    }
143        //    break;
144        //  case STT_NOTYPE:
145        //    {
146        //      if (sym->getAddress() == 0) {
147        //        sym->setAddress(find_sym(context, sym->getName()));
148        //      }
149        //      S = (uint32_t)sym->getAddress();
150        //    }
151        //    break;
152        //}
153        S >>= 2;
154        P >>= 2;
155        uint32_t result = (S+A-P);
156
157        if (result > 0x007fffff && result < 0xff800000) {
158#ifndef __arm__
159          assert(0 && "Target address is far from call instruction");
160          abort();
161#else
162          void *stub = getStubLayout()->allocateStub((void *)sym->getAddress());
163          if (!stub) {
164            out() << "unable to allocate stub." << "\n";
165            exit(EXIT_FAILURE);
166          }
167          out() << "far stub for: " << sym->getAddress() << " ";
168          out() << "is at " << stub << "\n";
169          sym->setAddress(stub);
170          S = ((uint32_t)stub) >> 2;
171          result = (S+A-P);
172
173          if (result > 0x007fffff && result < 0xff800000) {
174            assert(0 && "Stub is still too far");
175            abort();
176          }
177#endif
178        }
179
180        *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000);
181      }
182      break;
183    case 44: // R_ARM_MOVT_ABS
184      S >>= 16;
185    case 43: // R_ARM_MOVW_ABS_NC
186      {
187        // No need sign extend.
188        A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF);
189        uint32_t result = (S+A);
190        *inst = (((result) & 0xF000) << 4) |
191          ((result) & 0xFFF) |
192          (*inst & 0xFFF0F000);
193      }
194      break;
195    }
196    //llvm::errs() << "S:     " << (void *)S << '\n';
197    //llvm::errs() << "A:     " << (void *)A << '\n';
198    //llvm::errs() << "P:     " << (void *)P << '\n';
199    //llvm::errs() << "S+A:   " << (void *)(S+A) << '\n';
200    //llvm::errs() << "S+A-P: " << (void *)(S+A-P) << '\n';
201  }
202}
203
204template <unsigned Bitwidth>
205inline void ELFObject<Bitwidth>::
206relocateX86_64(void *(*find_sym)(void *context, char const *name),
207               void *context) {
208  assert(Bitwidth == 64 && "Only support X86_64.");
209
210  ELFSectionSymTabTy *symtab =
211    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
212
213  char const *name[] = {".text", ".eh_frame"};
214  size_t size = sizeof(name) / sizeof(char const *);
215
216  for (size_t i = 0; i < size; ++i) {
217    ELFSectionRelTableTy *relatab =
218      static_cast<ELFSectionRelTableTy *>(
219          getSectionByName((std::string(".rela") + name[i]).c_str()));
220    ELFSectionProgBitsTy *text =
221      static_cast<ELFSectionProgBitsTy *>(getSectionByName(name[i]));
222
223    for (size_t i = 0; i < relatab->size(); ++i) {
224      // FIXME: Can not implement here, use Fixup!
225      ELFRelocTy *rela = (*relatab)[i];
226      ELFSymbolTy *sym = (*symtab)[rela->getSymTabIndex()];
227
228      //typedef uint64_t Inst_t;
229      typedef int32_t Inst_t;
230      Inst_t *inst = (Inst_t *)&(*text)[rela->getOffset()];
231      Inst_t P = (Inst_t)(int64_t)inst;
232      Inst_t A = (Inst_t)(int64_t)rela->getAddend();
233      Inst_t S = (Inst_t)(int64_t)sym->getAddress();
234
235      if (S == 0) {
236        S = (Inst_t)(int64_t)find_sym(context, sym->getName());
237        sym->setAddress((void *)S);
238      }
239
240      switch (rela->getType()) {
241        default:
242          assert(0 && "Not implemented relocation type.");
243          break;
244
245        case 2: // R_X86_64_PC32
246          *inst = (S+A-P);
247          break;
248
249        case 10: // R_X86_64_32
250        case 11: // R_X86_64_32S
251          *inst = (S+A);
252          break;
253      }
254    }
255  }
256}
257
258template <unsigned Bitwidth>
259inline void ELFObject<Bitwidth>::
260relocateX86_32(void *(*find_sym)(void *context, char const *name),
261               void *context) {
262  assert(Bitwidth == 32 && "Only support X86.");
263
264  ELFSectionSymTabTy *symtab =
265    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
266
267  char const *name[] = {".text"};
268  size_t const size = sizeof(name) / sizeof(char const *);
269
270  for (size_t i = 0; i < size; ++i) {
271    ELFSectionRelTableTy *reltab =
272      static_cast<ELFSectionRelTableTy *>(
273        getSectionByName((std::string(".rel") + name[i]).c_str()));
274
275    ELFSectionProgBitsTy *text =
276      static_cast<ELFSectionProgBitsTy *>(getSectionByName(name[i]));
277
278    for (size_t i = 0; i < reltab->size(); ++i) {
279      // FIXME: Can not implement here, use Fixup!
280      ELFRelocTy *rel = (*reltab)[i];
281      ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
282
283      //typedef uint64_t Inst_t;
284      typedef int32_t Inst_t;
285      Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
286      Inst_t P = (Inst_t)(uintptr_t)inst;
287      Inst_t A = (Inst_t)(uintptr_t)*inst;
288      Inst_t S = (Inst_t)(uintptr_t)sym->getAddress();
289
290      if (S == 0) {
291        S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());
292        sym->setAddress((void *)S);
293      }
294
295      switch (rel->getType()) {
296      default:
297        assert(0 && "Not implemented relocation type.");
298        break;
299
300      case R_386_PC32:
301        *inst = (S+A-P);
302        break;
303
304      case R_386_32:
305        *inst = (S+A);
306        break;
307      }
308    }
309  }
310}
311
312template <unsigned Bitwidth>
313inline void ELFObject<Bitwidth>::
314relocate(void *(*find_sym)(void *context, char const *name), void *context) {
315  switch (getHeader()->getMachine()) {
316    case EM_ARM:    relocateARM(find_sym, context); break;
317    case EM_386:    relocateX86_32(find_sym, context); break;
318    case EM_X86_64: relocateX86_64(find_sym, context); break;
319
320    default:
321      assert(0 && "Only support ARM and X86_64 relocation.");
322      break;
323  }
324
325  for (size_t i = 0; i < stab.size(); ++i) {
326    ELFSectionHeaderTy *sh = (*shtab)[i];
327    if (sh && (sh->getType() == SHT_PROGBITS ||
328               sh->getType() == SHT_NOBITS)) {
329      static_cast<ELFSectionBitsTy *>(stab[i])->memory_protect();
330    }
331  }
332}
333
334template <unsigned Bitwidth>
335inline void ELFObject<Bitwidth>::print() const {
336  header->print();
337  shtab->print();
338
339  for (size_t i = 0; i < stab.size(); ++i) {
340    ELFSectionTy *sec = stab[i];
341    if (sec) {
342      sec->print();
343    }
344  }
345}
346
347#endif // ELF_OBJECT_HXX
348