ELFObject.hxx revision 2061b057e0922ac33b9314c1ccaa50eb7286b847
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 <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  // FIXME: Should be implement in independent files.
104  assert(Bitwidth == 32 && "ARM only have 32 bits.");
105
106  // FIXME: Can not only relocate .rel.text!
107  ELFSectionRelTableTy *reltab =
108    static_cast<ELFSectionRelTableTy *>(getSectionByName(".rel.text"));
109  ELFSectionProgBitsTy *text =
110    static_cast<ELFSectionProgBitsTy *>(getSectionByName(".text"));
111  ELFSectionSymTabTy *symtab =
112    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
113
114  for (size_t i = 0; i < reltab->size(); ++i) {
115    // FIXME: Can not implement here, use Fixup!
116    ELFRelocTy *rel = (*reltab)[i];
117    ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
118
119    // FIXME: May be not uint32_t *.
120    typedef int32_t Inst_t;
121    Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
122    Inst_t P = (Inst_t)(int64_t)inst;
123    Inst_t A = 0;
124    Inst_t S = (Inst_t)(int64_t)sym->getAddress();
125
126    switch (rel->getType()) {
127    default:
128      assert(0 && "Not implemented relocation type.");
129      break;
130
131      // FIXME: Predefine relocation codes.
132    case 28: // R_ARM_CALL
133      {
134#define SIGN_EXTEND(x, l) (((x)^(1<<((l)-1)))-(1<<(l-1)))
135        A = (Inst_t)(int64_t)SIGN_EXTEND(*inst & 0xFFFFFF, 24);
136#undef SIGN_EXTEND
137
138        switch (sym->getType()) {
139        default:
140          assert(0 && "Wrong type for R_ARM_CALL relocation.");
141          abort();
142          break;
143
144        case STT_FUNC:
145          if (S == 0) {
146            assert(0 && "We should get function address at previous "
147                   "sym->getAddress() function call.");
148            abort();
149          }
150          break;
151
152        case STT_NOTYPE:
153          if (S == 0) {
154            void *ext_func = find_sym(context, sym->getName());
155            S = (Inst_t)(uintptr_t)ext_func;
156            sym->setAddress(ext_func);
157
158            uint32_t result = (S >> 2) - (P >> 2) + A;
159            if (result > 0x007fffff && result < 0xff800000) {
160#ifndef __arm__
161              // We have not implement function stub in this runtime env
162              assert(0 && "Target address is far from call instruction");
163              abort();
164#else
165              void *stub = getStubLayout()->allocateStub(ext_func);
166              if (!stub) {
167                llvm::errs() << "unable to allocate stub." << "\n";
168                exit(EXIT_FAILURE);
169              }
170
171              //out() << "stub: for " << ext_func << " at " << stub << "\n";
172              sym->setAddress(stub);
173              S = (uint32_t)stub;
174#endif
175            }
176          }
177          break;
178        }
179
180        uint32_t result = (S >> 2) - (P >> 2) + A;
181
182        if (result > 0x007fffff && result < 0xff800000) {
183          assert(0 && "Stub is still too far");
184          abort();
185        }
186
187        *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000);
188      }
189      break;
190    case 44: // R_ARM_MOVT_ABS
191      S >>= 16;
192    case 43: // R_ARM_MOVW_ABS_NC
193      {
194        // No need sign extend.
195        A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF);
196        uint32_t result = (S+A);
197        *inst = (((result) & 0xF000) << 4) |
198          ((result) & 0xFFF) |
199          (*inst & 0xFFF0F000);
200      }
201      break;
202    }
203    //llvm::errs() << "S:     " << (void *)S << '\n';
204    //llvm::errs() << "A:     " << (void *)A << '\n';
205    //llvm::errs() << "P:     " << (void *)P << '\n';
206    //llvm::errs() << "S+A:   " << (void *)(S+A) << '\n';
207    //llvm::errs() << "S+A-P: " << (void *)(S+A-P) << '\n';
208  }
209}
210
211template <unsigned Bitwidth>
212inline void ELFObject<Bitwidth>::
213relocateX86_64(void *(*find_sym)(void *context, char const *name),
214               void *context) {
215  assert(Bitwidth == 64 && "Only support X86_64.");
216
217  ELFSectionSymTabTy *symtab =
218    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
219
220  char const *name[] = {".text", ".eh_frame"};
221  size_t size = sizeof(name) / sizeof(char const *);
222
223  for (size_t i = 0; i < size; ++i) {
224    ELFSectionRelTableTy *relatab =
225      static_cast<ELFSectionRelTableTy *>(
226          getSectionByName((std::string(".rela") + name[i]).c_str()));
227    ELFSectionProgBitsTy *text =
228      static_cast<ELFSectionProgBitsTy *>(getSectionByName(name[i]));
229
230    for (size_t i = 0; i < relatab->size(); ++i) {
231      // FIXME: Can not implement here, use Fixup!
232      ELFRelocTy *rela = (*relatab)[i];
233      ELFSymbolTy *sym = (*symtab)[rela->getSymTabIndex()];
234
235      //typedef uint64_t Inst_t;
236      typedef int32_t Inst_t;
237      Inst_t *inst = (Inst_t *)&(*text)[rela->getOffset()];
238      Inst_t P = (Inst_t)(int64_t)inst;
239      Inst_t A = (Inst_t)(int64_t)rela->getAddend();
240      Inst_t S = (Inst_t)(int64_t)sym->getAddress();
241
242      if (S == 0) {
243        S = (Inst_t)(int64_t)find_sym(context, sym->getName());
244        sym->setAddress((void *)S);
245      }
246
247      switch (rela->getType()) {
248        default:
249          assert(0 && "Not implemented relocation type.");
250          break;
251
252        case 2: // R_X86_64_PC32
253          *inst = (S+A-P);
254          break;
255
256        case 10: // R_X86_64_32
257        case 11: // R_X86_64_32S
258          *inst = (S+A);
259          break;
260      }
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  assert(Bitwidth == 32 && "Only support X86.");
270
271  ELFSectionSymTabTy *symtab =
272    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
273
274  char const *name[] = {".text"};
275  size_t const size = sizeof(name) / sizeof(char const *);
276
277  for (size_t i = 0; i < size; ++i) {
278    ELFSectionRelTableTy *reltab =
279      static_cast<ELFSectionRelTableTy *>(
280        getSectionByName((std::string(".rel") + name[i]).c_str()));
281
282    ELFSectionProgBitsTy *text =
283      static_cast<ELFSectionProgBitsTy *>(getSectionByName(name[i]));
284
285    for (size_t i = 0; i < reltab->size(); ++i) {
286      // FIXME: Can not implement here, use Fixup!
287      ELFRelocTy *rel = (*reltab)[i];
288      ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
289
290      //typedef uint64_t Inst_t;
291      typedef int32_t Inst_t;
292      Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
293      Inst_t P = (Inst_t)(uintptr_t)inst;
294      Inst_t A = (Inst_t)(uintptr_t)*inst;
295      Inst_t S = (Inst_t)(uintptr_t)sym->getAddress();
296
297      if (S == 0) {
298        S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());
299        sym->setAddress((void *)S);
300      }
301
302      switch (rel->getType()) {
303      default:
304        assert(0 && "Not implemented relocation type.");
305        break;
306
307      case R_386_PC32:
308        *inst = (S+A-P);
309        break;
310
311      case R_386_32:
312        *inst = (S+A);
313        break;
314      }
315    }
316  }
317}
318
319template <unsigned Bitwidth>
320inline void ELFObject<Bitwidth>::
321relocate(void *(*find_sym)(void *context, char const *name), void *context) {
322  switch (getHeader()->getMachine()) {
323    case EM_ARM:    relocateARM(find_sym, context); break;
324    case EM_386:    relocateX86_32(find_sym, context); break;
325    case EM_X86_64: relocateX86_64(find_sym, context); break;
326
327    default:
328      assert(0 && "Only support ARM and X86_64 relocation.");
329      break;
330  }
331
332  for (size_t i = 0; i < stab.size(); ++i) {
333    ELFSectionHeaderTy *sh = (*shtab)[i];
334    if (sh->getType() == SHT_PROGBITS || sh->getType() == SHT_NOBITS) {
335      if (stab[i]) {
336        static_cast<ELFSectionBitsTy *>(stab[i])->protect();
337      }
338    }
339  }
340}
341
342template <unsigned Bitwidth>
343inline void ELFObject<Bitwidth>::print() const {
344  header->print();
345  shtab->print();
346
347  for (size_t i = 0; i < stab.size(); ++i) {
348    ELFSectionTy *sec = stab[i];
349    if (sec) {
350      sec->print();
351    }
352  }
353}
354
355#endif // ELF_OBJECT_HXX
356