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