ELFObject.hxx revision 4e4356b34f9751070ac8ccb1bb74bb44e9232661
1a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#ifndef ELF_OBJECT_HXX
2a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#define ELF_OBJECT_HXX
3a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen
4a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include "ELFHeader.h"
5a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include "ELFReloc.h"
6a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include "ELFSection.h"
7a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include "ELFSectionHeaderTable.h"
8a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include "StubLayout.h"
9a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen
10a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include <assert.h>
11a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#include <elf.h>
12a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen
13a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#ifdef __arm__
14a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohentemplate <unsigned Bitwidth>
15a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Coheninline StubLayout *ELFObject<Bitwidth>::getStubLayout() {
16a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  if (!stubs) {
17a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen    stubs.reset(new StubLayout());
18a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  }
19a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  return stubs.get();
20a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen}
21a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen#endif
22a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen
23a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohentemplate <unsigned Bitwidth>
24a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohentemplate <typename Archiver>
25a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Coheninline ELFObject<Bitwidth> *
26a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam CohenELFObject<Bitwidth>::read(Archiver &AR) {
27a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  llvm::OwningPtr<ELFObjectTy> object(new ELFObjectTy());
28a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen
29a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  // Read header
30a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  object->header.reset(ELFHeaderTy::read(AR));
31a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  if (!object->header) {
32a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen    return 0;
33a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  }
34a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen
35a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  // Read section table
360e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen  object->shtab.reset(ELFSectionHeaderTableTy::read(AR, object.get()));
37a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen  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        if (S == 0) {
132          S = (Inst_t)(int64_t)find_sym(context, sym->getName());
133          sym->setAddress((void *)S);
134        }
135        //switch (sym->getType()) {
136        //  default:
137        //    assert(0 && "Wrong type for R_ARM_CALL relocation.");
138        //    break;
139        //  case STT_FUNC:
140        //    {
141        //      S = (uint32_t)sym->getAddress();
142        //    }
143        //    break;
144        //  case STT_NOTYPE:
145        //    {
146        //      if (sym->getAddress() == 0) {
147        //        sym->setAddress(find_sym(context, sym->getName()));
148        //      }
149        //      S = (uint32_t)sym->getAddress();
150        //    }
151        //    break;
152        //}
153        S >>= 2;
154        P >>= 2;
155        uint32_t result = (S+A-P);
156#ifdef __arm__
157        if ((result & 0xFF000000) != 0) {
158          out() << "far stub for: " << sym->getAddress() << " ";
159          void *stub = getStubLayout()->allocateStub((void *)sym->getAddress());
160          if (!stub) {
161            out() << "unable to allocate stub." << "\n";
162            exit(EXIT_FAILURE);
163          }
164          out() << "is at " << stub << "\n";
165          S = ((uint32_t)stub) >> 2;
166          result = (S+A-P);
167        }
168#else
169        // TODO: Stub.
170        assert(((result & 0xFF000000) == 0) && "Too far, need stub.");
171#endif
172        *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000);
173      }
174      break;
175    case 44: // R_ARM_MOVT_ABS
176      S >>= 16;
177    case 43: // R_ARM_MOVW_ABS_NC
178      {
179        // No need sign extend.
180        A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF);
181        uint32_t result = (S+A);
182        *inst = (((result) & 0xF000) << 4) |
183          ((result) & 0xFFF) |
184          (*inst & 0xFFF0F000);
185      }
186      break;
187    }
188    //llvm::errs() << "S:     " << (void *)S << '\n';
189    //llvm::errs() << "A:     " << (void *)A << '\n';
190    //llvm::errs() << "P:     " << (void *)P << '\n';
191    //llvm::errs() << "S+A:   " << (void *)(S+A) << '\n';
192    //llvm::errs() << "S+A-P: " << (void *)(S+A-P) << '\n';
193  }
194}
195
196template <unsigned Bitwidth>
197inline void ELFObject<Bitwidth>::
198relocateX86_64(void *(*find_sym)(void *context, char const *name),
199               void *context) {
200  assert(Bitwidth == 64 && "Only support X86_64.");
201
202  ELFSectionSymTabTy *symtab =
203    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
204
205  char const *name[] = {".text", ".eh_frame"};
206  size_t size = sizeof(name) / sizeof(char const *);
207
208  for (size_t i = 0; i < size; ++i) {
209    ELFSectionRelTableTy *relatab =
210      static_cast<ELFSectionRelTableTy *>(
211          getSectionByName((std::string(".rela") + name[i]).c_str()));
212    ELFSectionProgBitsTy *text =
213      static_cast<ELFSectionProgBitsTy *>(getSectionByName(name[i]));
214
215    for (size_t i = 0; i < relatab->size(); ++i) {
216      // FIXME: Can not implement here, use Fixup!
217      ELFRelocTy *rela = (*relatab)[i];
218      ELFSymbolTy *sym = (*symtab)[rela->getSymTabIndex()];
219
220      //typedef uint64_t Inst_t;
221      typedef int32_t Inst_t;
222      Inst_t *inst = (Inst_t *)&(*text)[rela->getOffset()];
223      Inst_t P = (Inst_t)(int64_t)inst;
224      Inst_t A = (Inst_t)(int64_t)rela->getAddend();
225      Inst_t S = (Inst_t)(int64_t)sym->getAddress();
226
227      if (S == 0) {
228        S = (Inst_t)(int64_t)find_sym(context, sym->getName());
229        sym->setAddress((void *)S);
230      }
231
232      switch (rela->getType()) {
233        default:
234          assert(0 && "Not implemented relocation type.");
235          break;
236
237        case 2: // R_X86_64_PC32
238          *inst = (S+A-P);
239          break;
240
241        case 10: // R_X86_64_32
242        case 11: // R_X86_64_32S
243          *inst = (S+A);
244          break;
245      }
246    }
247  }
248}
249
250template <unsigned Bitwidth>
251inline void ELFObject<Bitwidth>::
252relocateX86_32(void *(*find_sym)(void *context, char const *name),
253               void *context) {
254  assert(Bitwidth == 32 && "Only support X86.");
255
256  ELFSectionSymTabTy *symtab =
257    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
258
259  char const *name[] = {".text"};
260  size_t const size = sizeof(name) / sizeof(char const *);
261
262  for (size_t i = 0; i < size; ++i) {
263    ELFSectionRelTableTy *reltab =
264      static_cast<ELFSectionRelTableTy *>(
265        getSectionByName((std::string(".rel") + name[i]).c_str()));
266
267    ELFSectionProgBitsTy *text =
268      static_cast<ELFSectionProgBitsTy *>(getSectionByName(name[i]));
269
270    for (size_t i = 0; i < reltab->size(); ++i) {
271      // FIXME: Can not implement here, use Fixup!
272      ELFRelocTy *rel = (*reltab)[i];
273      ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
274
275      //typedef uint64_t Inst_t;
276      typedef int32_t Inst_t;
277      Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
278      Inst_t P = (Inst_t)(uintptr_t)inst;
279      Inst_t A = (Inst_t)(uintptr_t)*inst;
280      Inst_t S = (Inst_t)(uintptr_t)sym->getAddress();
281
282      if (S == 0) {
283        S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());
284        sym->setAddress((void *)S);
285      }
286
287      switch (rel->getType()) {
288      default:
289        assert(0 && "Not implemented relocation type.");
290        break;
291
292      case R_386_PC32:
293        *inst = (S+A-P);
294        break;
295
296      case R_386_32:
297        *inst = (S+A);
298        break;
299      }
300    }
301  }
302}
303
304template <unsigned Bitwidth>
305inline void ELFObject<Bitwidth>::
306relocate(void *(*find_sym)(void *context, char const *name), void *context) {
307  switch (getHeader()->getMachine()) {
308    case EM_ARM:    relocateARM(find_sym, context); break;
309    case EM_386:    relocateX86_32(find_sym, context); break;
310    case EM_X86_64: relocateX86_64(find_sym, context); break;
311
312    default:
313      assert(0 && "Only support ARM and X86_64 relocation.");
314      break;
315  }
316
317  for (size_t i = 0; i < stab.size(); ++i) {
318    ELFSectionHeaderTy *sh = (*shtab)[i];
319    if (sh && (sh->getType() == SHT_PROGBITS ||
320               sh->getType() == SHT_NOBITS)) {
321      static_cast<ELFSectionBitsTy *>(stab[i])->memory_protect();
322    }
323  }
324}
325
326template <unsigned Bitwidth>
327inline void ELFObject<Bitwidth>::print() const {
328  header->print();
329  shtab->print();
330
331  for (size_t i = 0; i < stab.size(); ++i) {
332    ELFSectionTy *sec = stab[i];
333    if (sec) {
334      sec->print();
335    }
336  }
337}
338
339#endif // ELF_OBJECT_HXX
340