1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CRAZY_LINKER_ELF_RELOCATIONS_H
6#define CRAZY_LINKER_ELF_RELOCATIONS_H
7
8#include <string.h>
9#include <unistd.h>
10
11#include "elf_traits.h"
12
13namespace crazy {
14
15class ElfSymbols;
16class ElfView;
17class Error;
18
19// An ElfRelocations instance holds information about relocations in a mapped
20// ELF binary.
21class ElfRelocations {
22 public:
23  ElfRelocations() { ::memset(this, 0, sizeof(*this)); }
24  ~ElfRelocations() {}
25
26  bool Init(const ElfView* view, Error* error);
27
28  // Abstract class used to resolve symbol names into addresses.
29  // Callers of ::ApplyAll() should pass the address of a derived class
30  // that properly implements the Lookup() method.
31  class SymbolResolver {
32   public:
33    SymbolResolver() {}
34    ~SymbolResolver() {}
35    virtual void* Lookup(const char* symbol_name) = 0;
36  };
37
38  // Apply all relocations to the target mapped ELF binary. Must be called
39  // after Init().
40  // |symbols| maps to the symbol entries for the target library only.
41  // |resolver| can resolve symbols out of the current library.
42  // On error, return false and set |error| message.
43  bool ApplyAll(const ElfSymbols* symbols,
44                SymbolResolver* resolver,
45                Error* error);
46
47#if defined(__arm__) || defined(__aarch64__)
48  // Register packed relocations to apply.
49  // |packed_relocs| is a pointer to packed relocations data.
50  void RegisterPackedRelocations(uint8_t* packed_relocations);
51#endif
52
53  // This function is used to adjust relocated addresses in a copy of an
54  // existing section of an ELF binary. I.e. |src_addr|...|src_addr + size|
55  // must be inside the mapped ELF binary, this function will first copy its
56  // content into |dst_addr|...|dst_addr + size|, then adjust all relocated
57  // addresses inside the destination section as if it was loaded/mapped
58  // at |map_addr|...|map_addr + size|. Only relative relocations are processed,
59  // symbolic ones are ignored.
60  void CopyAndRelocate(size_t src_addr,
61                       size_t dst_addr,
62                       size_t map_addr,
63                       size_t size);
64
65 private:
66  bool ResolveSymbol(unsigned rel_type,
67                     unsigned rel_symbol,
68                     const ElfSymbols* symbols,
69                     SymbolResolver* resolver,
70                     ELF::Addr reloc,
71                     ELF::Addr* sym_addr,
72                     Error* error);
73  bool ApplyRelaReloc(const ELF::Rela* rela,
74                      ELF::Addr sym_addr,
75                      bool resolved,
76                      Error* error);
77  bool ApplyRelReloc(const ELF::Rel* rel,
78                     ELF::Addr sym_addr,
79                     bool resolved,
80                     Error* error);
81  bool ApplyRelaRelocs(const ELF::Rela* relocs,
82                       size_t relocs_count,
83                       const ElfSymbols* symbols,
84                       SymbolResolver* resolver,
85                       Error* error);
86  bool ApplyRelRelocs(const ELF::Rel* relocs,
87                      size_t relocs_count,
88                      const ElfSymbols* symbols,
89                      SymbolResolver* resolver,
90                      Error* error);
91  void AdjustRelocation(ELF::Word rel_type,
92                        ELF::Addr src_reloc,
93                        size_t dst_delta,
94                        size_t map_delta);
95  void RelocateRela(size_t src_addr,
96                    size_t dst_addr,
97                    size_t map_addr,
98                    size_t size);
99  void RelocateRel(size_t src_addr,
100                   size_t dst_addr,
101                   size_t map_addr,
102                   size_t size);
103
104#if defined(__arm__) || defined(__aarch64__)
105  // Apply packed rel or rela relocations.  On error, return false.
106  bool ApplyPackedRel(const uint8_t* packed_relocations, Error* error);
107  bool ApplyPackedRela(const uint8_t* packed_relocations, Error* error);
108
109  // Apply packed relocations.
110  // On error, return false and set |error| message.  No-op if no packed
111  // relocations were registered.
112  bool ApplyPackedRelocations(Error* error);
113#endif
114
115#if defined(__mips__)
116  bool RelocateMipsGot(const ElfSymbols* symbols,
117                       SymbolResolver* resolver,
118                       Error* error);
119#endif
120
121  const ELF::Phdr* phdr_;
122  size_t phdr_count_;
123  size_t load_bias_;
124
125  ELF::Addr relocations_type_;
126  ELF::Addr plt_relocations_;
127  size_t plt_relocations_size_;
128  ELF::Addr* plt_got_;
129
130  ELF::Addr relocations_;
131  size_t relocations_size_;
132
133#if defined(__mips__)
134  // MIPS-specific relocation fields.
135  ELF::Word mips_symtab_count_;
136  ELF::Word mips_local_got_count_;
137  ELF::Word mips_gotsym_;
138#endif
139
140#if defined(__arm__) || defined(__aarch64__)
141  uint8_t* packed_relocations_;
142#endif
143
144  bool has_text_relocations_;
145  bool has_symbolic_;
146};
147
148}  // namespace crazy
149
150#endif  // CRAZY_LINKER_ELF_RELOCATIONS_H
151