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