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