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