ELFObject.hxx revision ee6cdb95525abc8c7766798148302306a100b774
1/*
2 * Copyright 2011, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ELF_OBJECT_HXX
18#define ELF_OBJECT_HXX
19
20#include "ELFHeader.h"
21#include "ELFReloc.h"
22#include "ELFSection.h"
23#include "ELFSectionHeaderTable.h"
24#include "StubLayout.h"
25
26#include <llvm/ADT/SmallVector.h>
27
28#include "utils/rsl_assert.h"
29#include <elf.h>
30
31template <unsigned Bitwidth>
32template <typename Archiver>
33inline ELFObject<Bitwidth> *
34ELFObject<Bitwidth>::read(Archiver &AR) {
35  llvm::OwningPtr<ELFObjectTy> object(new ELFObjectTy());
36
37  // Read header
38  object->header.reset(ELFHeaderTy::read(AR));
39  if (!object->header) {
40    return 0;
41  }
42
43  // Read section table
44  object->shtab.reset(ELFSectionHeaderTableTy::read(AR, object.get()));
45  if (!object->shtab) {
46    return 0;
47  }
48
49  // Read each section
50  llvm::SmallVector<size_t, 4> progbits_ndx;
51  for (size_t i = 0; i < object->header->getSectionHeaderNum(); ++i) {
52    if ((*object->shtab)[i]->getType() == SHT_PROGBITS) {
53      object->stab.push_back(NULL);
54      progbits_ndx.push_back(i);
55    } else {
56      llvm::OwningPtr<ELFSectionTy> sec(
57        ELFSectionTy::read(AR, object.get(), (*object->shtab)[i]));
58      object->stab.push_back(sec.take());
59    }
60  }
61
62  for (size_t i = 0; i < progbits_ndx.size(); ++i) {
63    size_t index = progbits_ndx[i];
64
65    llvm::OwningPtr<ELFSectionTy> sec(
66      ELFSectionTy::read(AR, object.get(), (*object->shtab)[index]));
67    object->stab[index] = sec.take();
68  }
69
70  return object.take();
71}
72
73template <unsigned Bitwidth>
74inline char const *ELFObject<Bitwidth>::getSectionName(size_t i) const {
75  ELFSectionTy const *sec = stab[header->getStringSectionIndex()];
76
77  if (sec) {
78    ELFSectionStrTabTy const &st =
79      static_cast<ELFSectionStrTabTy const &>(*sec);
80    return st[i];
81  }
82
83  return NULL;
84}
85
86template <unsigned Bitwidth>
87inline ELFSection<Bitwidth> const *
88ELFObject<Bitwidth>::getSectionByIndex(size_t i) const {
89  return stab[i];
90}
91
92template <unsigned Bitwidth>
93inline ELFSection<Bitwidth> *
94ELFObject<Bitwidth>::getSectionByIndex(size_t i) {
95  return stab[i];
96}
97
98template <unsigned Bitwidth>
99inline ELFSection<Bitwidth> const *
100ELFObject<Bitwidth>::getSectionByName(std::string const &str) const {
101  size_t idx = getSectionHeaderTable()->getByName(str)->getIndex();
102  return stab[idx];
103}
104
105template <unsigned Bitwidth>
106inline ELFSection<Bitwidth> *
107ELFObject<Bitwidth>::getSectionByName(std::string const &str) {
108  ELFObjectTy const *const_this = this;
109  ELFSectionTy const *sptr = const_this->getSectionByName(str);
110  // Const cast for the same API's const and non-const versions.
111  return const_cast<ELFSectionTy *>(sptr);
112}
113
114
115template <unsigned Bitwidth>
116inline void ELFObject<Bitwidth>::
117relocateARM(void *(*find_sym)(void *context, char const *name),
118            void *context,
119            ELFSectionRelTableTy *reltab,
120            ELFSectionProgBitsTy *text) {
121  // FIXME: Should be implement in independent files.
122  rsl_assert(Bitwidth == 32 && "ARM only have 32 bits.");
123
124  ELFSectionSymTabTy *symtab =
125    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
126
127  for (size_t i = 0; i < reltab->size(); ++i) {
128    // FIXME: Can not implement here, use Fixup!
129    ELFRelocTy *rel = (*reltab)[i];
130    ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
131
132    // FIXME: May be not uint32_t *.
133    typedef int32_t Inst_t;
134    Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
135    Inst_t P = (Inst_t)(int64_t)inst;
136    Inst_t A = 0;
137    Inst_t S = (Inst_t)(int64_t)sym->getAddress();
138
139    switch (rel->getType()) {
140    default:
141      rsl_assert(0 && "Not implemented relocation type.");
142      break;
143
144    case 2: // R_ARM_ABS32
145      {
146        A = *inst;
147        *inst = (S+A);
148      }
149      break;
150
151      // FIXME: Predefine relocation codes.
152    case 28: // R_ARM_CALL
153      {
154#define SIGN_EXTEND(x, l) (((x)^(1<<((l)-1)))-(1<<(l-1)))
155        A = (Inst_t)(int64_t)SIGN_EXTEND(*inst & 0xFFFFFF, 24);
156#undef SIGN_EXTEND
157
158        switch (sym->getType()) {
159        default:
160          rsl_assert(0 && "Wrong type for R_ARM_CALL relocation.");
161          abort();
162          break;
163
164        case STT_FUNC:
165          if (S == 0) {
166            rsl_assert(0 && "We should get function address at previous "
167                   "sym->getAddress() function call.");
168            abort();
169          }
170          break;
171
172        case STT_NOTYPE:
173          if (S == 0) {
174            void *ext_func = find_sym(context, sym->getName());
175            S = (Inst_t)(uintptr_t)ext_func;
176            sym->setAddress(ext_func);
177
178            uint32_t result = (S >> 2) - (P >> 2) + A;
179            if (result > 0x007fffff && result < 0xff800000) {
180#ifndef __arm__
181              // We have not implement function stub in this runtime env
182              rsl_assert(0 && "Target address is far from call instruction");
183              abort();
184#else
185              void *stub = getStubLayout()->allocateStub(ext_func);
186              if (!stub) {
187                llvm::errs() << "unable to allocate stub." << "\n";
188                exit(EXIT_FAILURE);
189              }
190
191              //out() << "stub: for " << ext_func << " at " << stub << "\n";
192              sym->setAddress(stub);
193              S = (uint32_t)stub;
194#endif
195            }
196          }
197          break;
198        }
199
200        uint32_t result = (S >> 2) - (P >> 2) + A;
201
202        if (result > 0x007fffff && result < 0xff800000) {
203          rsl_assert(0 && "Stub is still too far");
204          abort();
205        }
206
207        *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000);
208      }
209      break;
210    case 44: // R_ARM_MOVT_ABS
211      S >>= 16;
212    case 43: // R_ARM_MOVW_ABS_NC
213      {
214        // No need sign extend.
215        A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF);
216        uint32_t result = (S+A);
217        *inst = (((result) & 0xF000) << 4) |
218          ((result) & 0xFFF) |
219          (*inst & 0xFFF0F000);
220      }
221      break;
222    }
223    //llvm::errs() << "S:     " << (void *)S << '\n';
224    //llvm::errs() << "A:     " << (void *)A << '\n';
225    //llvm::errs() << "P:     " << (void *)P << '\n';
226    //llvm::errs() << "S+A:   " << (void *)(S+A) << '\n';
227    //llvm::errs() << "S+A-P: " << (void *)(S+A-P) << '\n';
228  }
229}
230
231template <unsigned Bitwidth>
232inline void ELFObject<Bitwidth>::
233relocateX86_64(void *(*find_sym)(void *context, char const *name),
234               void *context,
235               ELFSectionRelTableTy *reltab,
236               ELFSectionProgBitsTy *text) {
237  rsl_assert(Bitwidth == 64 && "Only support X86_64.");
238
239  ELFSectionSymTabTy *symtab =
240    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
241
242  for (size_t i = 0; i < reltab->size(); ++i) {
243    // FIXME: Can not implement here, use Fixup!
244    ELFRelocTy *rel = (*reltab)[i];
245    ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
246
247    //typedef uint64_t Inst_t;
248    typedef int32_t Inst_t;
249    Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
250    Inst_t P = (Inst_t)(int64_t)inst;
251    Inst_t A = (Inst_t)(int64_t)rel->getAddend();
252    Inst_t S = (Inst_t)(int64_t)sym->getAddress();
253
254    if (S == 0) {
255      S = (Inst_t)(int64_t)find_sym(context, sym->getName());
256      sym->setAddress((void *)S);
257    }
258
259    switch (rel->getType()) {
260      default:
261        rsl_assert(0 && "Not implemented relocation type.");
262        break;
263
264      // FIXME: XXX: R_X86_64_64 is 64 bit, there is a big problem here.
265      case 1: // R_X86_64_64
266        *inst = (S+A);
267        break;
268
269      case 2: // R_X86_64_PC32
270        *inst = (S+A-P);
271        break;
272
273      case 10: // R_X86_64_32
274      case 11: // R_X86_64_32S
275        *inst = (S+A);
276        break;
277    }
278  }
279}
280
281template <unsigned Bitwidth>
282inline void ELFObject<Bitwidth>::
283relocateX86_32(void *(*find_sym)(void *context, char const *name),
284               void *context,
285               ELFSectionRelTableTy *reltab,
286               ELFSectionProgBitsTy *text) {
287  rsl_assert(Bitwidth == 32 && "Only support X86.");
288
289  ELFSectionSymTabTy *symtab =
290    static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
291
292  for (size_t i = 0; i < reltab->size(); ++i) {
293    // FIXME: Can not implement here, use Fixup!
294    ELFRelocTy *rel = (*reltab)[i];
295    ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
296
297    //typedef uint64_t Inst_t;
298    typedef int32_t Inst_t;
299    Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
300    Inst_t P = (Inst_t)(uintptr_t)inst;
301    Inst_t A = (Inst_t)(uintptr_t)*inst;
302    Inst_t S = (Inst_t)(uintptr_t)sym->getAddress();
303
304    if (S == 0) {
305      S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());
306      sym->setAddress((void *)S);
307    }
308
309    switch (rel->getType()) {
310    default:
311      rsl_assert(0 && "Not implemented relocation type.");
312      break;
313
314    case R_386_PC32:
315      *inst = (S+A-P);
316      break;
317
318    case R_386_32:
319      *inst = (S+A);
320      break;
321    }
322  }
323}
324
325template <unsigned Bitwidth>
326inline void ELFObject<Bitwidth>::
327relocate(void *(*find_sym)(void *context, char const *name), void *context) {
328
329  for (size_t i = 0; i < stab.size(); ++i) {
330    ELFSectionHeaderTy *sh = (*shtab)[i];
331    if (sh->getType() != SHT_REL && sh->getType() != SHT_RELA) {
332      continue;
333    }
334    ELFSectionRelTableTy *reltab =
335      static_cast<ELFSectionRelTableTy *>(stab[i]);
336    rsl_assert(reltab && "Relocation section can't be NULL.");
337
338    const char *reltab_name = sh->getName();
339    const char *need_rel_name;
340    if (sh->getType() == SHT_REL) {
341      need_rel_name = reltab_name + 4;
342      // ".rel.xxxx"
343      //      ^ start from here.
344    } else {
345      need_rel_name = reltab_name + 5;
346    }
347
348    ELFSectionProgBitsTy *need_rel =
349      static_cast<ELFSectionProgBitsTy *>(getSectionByName(need_rel_name));
350    rsl_assert(need_rel && "Need be relocated section can't be NULL.");
351
352    switch (getHeader()->getMachine()) {
353      case EM_ARM:
354        relocateARM(find_sym, context, reltab, need_rel);
355        break;
356      case EM_386:
357        relocateX86_32(find_sym, context, reltab, need_rel);
358        break;
359      case EM_X86_64:
360        relocateX86_64(find_sym, context, reltab, need_rel);
361        break;
362
363      default:
364        rsl_assert(0 && "Only support ARM, X86, and X86_64 relocation.");
365        break;
366    }
367  }
368
369  for (size_t i = 0; i < stab.size(); ++i) {
370    ELFSectionHeaderTy *sh = (*shtab)[i];
371    if (sh->getType() == SHT_PROGBITS || sh->getType() == SHT_NOBITS) {
372      if (stab[i]) {
373        static_cast<ELFSectionBitsTy *>(stab[i])->protect();
374      }
375    }
376  }
377}
378
379template <unsigned Bitwidth>
380inline void ELFObject<Bitwidth>::print() const {
381  header->print();
382  shtab->print();
383
384  for (size_t i = 0; i < stab.size(); ++i) {
385    ELFSectionTy *sec = stab[i];
386    if (sec) {
387      sec->print();
388    }
389  }
390}
391
392#endif // ELF_OBJECT_HXX
393