1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_relocations.h"
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <errno.h>
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_debug.h"
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_symbols.h"
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_view.h"
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_error.h"
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "crazy_linker_leb128.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "crazy_linker_system.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_util.h"
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "linker_phdr.h"
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define DEBUG_RELOCATIONS 0
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__)
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__)
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef DF_SYMBOLIC
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define DF_SYMBOLIC 2
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef DF_TEXTREL
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define DF_TEXTREL 4
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef DT_FLAGS
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define DT_FLAGS 30
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Processor-specific relocation types supported by the linker.
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __arm__
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* arm32 relocations */
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_ARM_ABS32 2
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_ARM_REL32 3
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_ARM_GLOB_DAT 21
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_ARM_JUMP_SLOT 22
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_ARM_COPY 20
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_ARM_RELATIVE 23
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define RELATIVE_RELOCATION_CODE R_ARM_RELATIVE
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __arm__
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __aarch64__
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* arm64 relocations */
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_AARCH64_ABS64 257
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_AARCH64_COPY 1024
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_AARCH64_GLOB_DAT 1025
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_AARCH64_JUMP_SLOT 1026
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_AARCH64_RELATIVE 1027
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define RELATIVE_RELOCATION_CODE R_AARCH64_RELATIVE
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __aarch64__
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __i386__
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* i386 relocations */
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_386_32 1
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_386_PC32 2
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_386_GLOB_DAT 6
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_386_JMP_SLOT 7
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define R_386_RELATIVE 8
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __i386__
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#ifdef __x86_64__
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/* x86_64 relocations */
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#define R_X86_64_64 1
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#define R_X86_64_PC32 2
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#define R_X86_64_GLOB_DAT 6
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#define R_X86_64_JMP_SLOT 7
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#define R_X86_64_RELATIVE 8
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif  // __x86_64__
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace crazy {
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// List of known relocation types the relocator knows about.
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)enum RelocationType {
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RELOCATION_TYPE_UNKNOWN = 0,
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RELOCATION_TYPE_ABSOLUTE = 1,
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RELOCATION_TYPE_RELATIVE = 2,
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RELOCATION_TYPE_PC_RELATIVE = 3,
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RELOCATION_TYPE_COPY = 4,
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Convert an ELF relocation type info a RelocationType value.
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)RelocationType GetRelocationType(ELF::Word r_type) {
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (r_type) {
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __arm__
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_JUMP_SLOT:
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_GLOB_DAT:
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_ABS32:
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_ABSOLUTE;
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_REL32:
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_RELATIVE:
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_RELATIVE;
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_COPY:
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_COPY;
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __aarch64__
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_JUMP_SLOT:
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_GLOB_DAT:
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_ABS64:
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_ABSOLUTE;
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_RELATIVE:
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_RELATIVE;
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_COPY:
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_COPY;
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __i386__
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_JMP_SLOT:
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_GLOB_DAT:
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_32:
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_ABSOLUTE;
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_RELATIVE:
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_RELATIVE;
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_PC32:
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_PC_RELATIVE;
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#ifdef __x86_64__
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_JMP_SLOT:
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_GLOB_DAT:
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_64:
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return RELOCATION_TYPE_ABSOLUTE;
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_RELATIVE:
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return RELOCATION_TYPE_RELATIVE;
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_PC32:
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return RELOCATION_TYPE_PC_RELATIVE;
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __mips__
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_MIPS_REL32:
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_RELATIVE;
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RELOCATION_TYPE_UNKNOWN;
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::Init(const ElfView* view, Error* error) {
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Save these for later.
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  phdr_ = view->phdr();
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  phdr_count_ = view->phdr_count();
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  load_bias_ = view->load_bias();
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // then we require DT_PLTREL to agree.
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool has_rela_relocations = false;
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool has_rel_relocations = false;
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Parse the dynamic table.
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ElfView::DynamicIterator dyn(view);
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (; dyn.HasNext(); dyn.GetNext()) {
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr dyn_value = dyn.GetValue();
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    uintptr_t dyn_addr = dyn.GetAddress(view->load_bias());
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Addr tag = dyn.GetTag();
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    switch (tag) {
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_PLTREL:
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_PLTREL value=%d\n", dyn_value);
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (dyn_value != DT_REL && dyn_value != DT_RELA) {
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          *error = "Invalid DT_PLTREL value in dynamic section";
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          return false;
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        }
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        relocations_type_ = dyn_value;
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_JMPREL:
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_JMPREL addr=%p\n", dyn_addr);
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        plt_relocations_ = dyn_addr;
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_PLTRELSZ:
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        plt_relocations_size_ = dyn_value;
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_PLTRELSZ size=%d\n", dyn_value);
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_RELA:
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_REL:
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  %s addr=%p\n",
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             (tag == DT_RELA) ? "DT_RELA" : "DT_REL",
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             dyn_addr);
206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (relocations_) {
207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          *error = "Unsupported DT_RELA/DT_REL combination in dynamic section";
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          return false;
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        }
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        relocations_ = dyn_addr;
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (tag == DT_RELA)
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          has_rela_relocations = true;
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        else
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          has_rel_relocations = true;
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_RELASZ:
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_RELSZ:
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  %s size=%d\n",
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             (tag == DT_RELASZ) ? "DT_RELASZ" : "DT_RELSZ",
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             dyn_addr);
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (relocations_size_) {
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section";
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          return false;
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        }
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        relocations_size_ = dyn_value;
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (tag == DT_RELASZ)
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          has_rela_relocations = true;
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        else
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          has_rel_relocations = true;
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_PLTGOT:
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // Only used on MIPS currently. Could also be used on other platforms
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // when lazy binding (i.e. RTLD_LAZY) is implemented.
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_PLTGOT addr=%p\n", dyn_addr);
235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr);
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_TEXTREL:
238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_TEXTREL\n");
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        has_text_relocations_ = true;
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_SYMBOLIC:
242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_SYMBOLIC\n");
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        has_symbolic_ = true;
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_FLAGS:
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (dyn_value & DF_TEXTREL)
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          has_text_relocations_ = true;
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (dyn_value & DF_SYMBOLIC)
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          has_symbolic_ = true;
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n",
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             has_text_relocations_ ? "true" : "false",
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             has_symbolic_ ? "true" : "false");
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(__mips__)
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_MIPS_SYMTABNO:
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_MIPS_SYMTABNO value=%d\n", dyn_value);
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        mips_symtab_count_ = dyn_value;
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_MIPS_LOCAL_GOTNO:
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value);
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        mips_local_got_count_ = dyn_value;
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      case DT_MIPS_GOTSYM:
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        RLOG("  DT_MIPS_GOTSYM value=%d\n", dyn_value);
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        mips_gotsym_ = dyn_value;
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      default:
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        ;
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (has_rel_relocations && has_rela_relocations) {
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *error = "Combining DT_REL and DT_RELA is not currently supported";
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If DT_PLTREL did not explicitly assign relocations_type_, set it
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // here based on the type of relocations found.
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) {
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (has_rel_relocations)
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      relocations_type_ = DT_REL;
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else if (has_rela_relocations)
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      relocations_type_ = DT_RELA;
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (relocations_type_ == DT_REL && has_rela_relocations) {
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL";
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (relocations_type_ == DT_RELA && has_rel_relocations) {
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA";
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::ApplyAll(const ElfSymbols* symbols,
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                              SymbolResolver* resolver,
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                              Error* error) {
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  LOG("%s: Enter\n", __FUNCTION__);
305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (has_text_relocations_) {
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) {
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error->Format("Can't unprotect loadable segments: %s", strerror(errno));
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (relocations_type_ == DT_REL) {
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_),
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        plt_relocations_size_ / sizeof(ELF::Rel),
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        symbols,
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        resolver,
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        error))
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_),
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        relocations_size_ / sizeof(ELF::Rel),
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        symbols,
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        resolver,
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        error))
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (relocations_type_ == DT_RELA) {
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_),
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         plt_relocations_size_ / sizeof(ELF::Rela),
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         symbols,
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         resolver,
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         error))
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_),
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         relocations_size_ / sizeof(ELF::Rela),
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         symbols,
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         resolver,
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         error))
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
34303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if defined(__arm__) || defined(__aarch64__)
34403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!ApplyPackedRelocations(error))
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __mips__
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!RelocateMipsGot(symbols, resolver, error))
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (has_text_relocations_) {
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) {
355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error->Format("Can't reprotect loadable segments: %s", strerror(errno));
356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  LOG("%s: Done\n", __FUNCTION__);
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
36403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if defined(__arm__) || defined(__aarch64__)
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
36603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void ElfRelocations::RegisterPackedRelocations(uint8_t* packed_relocations) {
36703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  packed_relocations_ = packed_relocations;
368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
37003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool ElfRelocations::ApplyPackedRel(const uint8_t* packed_relocations,
37103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                    Error* error) {
37203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Leb128Decoder decoder(packed_relocations);
373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Find the count of pairs and the start address.
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t pairs = decoder.Dequeue();
37603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const ELF::Addr start_address = decoder.Dequeue();
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
37803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Emit initial relative relocation.
37903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ELF::Rel relocation;
38003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  relocation.r_offset = start_address;
38103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE);
382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const ELF::Addr sym_addr = 0;
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const bool resolved = false;
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ApplyRelReloc(&relocation, sym_addr, resolved, error))
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
386116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t unpacked_count = 1;
388116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
389116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Emit relocations for each count-delta pair.
390116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (pairs) {
391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    size_t count = decoder.Dequeue();
392116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const size_t delta = decoder.Dequeue();
393116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
39403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Emit count relative relocations with delta offset.
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    while (count) {
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      relocation.r_offset += delta;
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!ApplyRelReloc(&relocation, sym_addr, resolved, error))
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return false;
399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      unpacked_count++;
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      count--;
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pairs--;
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count);
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
40803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
40903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool ElfRelocations::ApplyPackedRela(const uint8_t* packed_relocations,
41003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                     Error* error) {
41103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Sleb128Decoder decoder(packed_relocations);
41203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Find the count of pairs.
41403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t pairs = decoder.Dequeue();
41503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ELF::Addr offset = 0;
41703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ELF::Sxword addend = 0;
41803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const ELF::Addr sym_addr = 0;
42003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const bool resolved = false;
42103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
42203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t unpacked_count = 0;
42303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
42403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Emit relocations for each deltas pair.
42503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (pairs) {
42603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    offset += decoder.Dequeue();
42703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    addend += decoder.Dequeue();
42803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
42903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ELF::Rela relocation;
43003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    relocation.r_offset = offset;
43103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE);
43203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    relocation.r_addend = addend;
43303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!ApplyRelaReloc(&relocation, sym_addr, resolved, error))
43403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return false;
43503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    unpacked_count++;
43603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    pairs--;
43703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
43803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
43903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count);
44003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
44103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
44203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
44303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool ElfRelocations::ApplyPackedRelocations(Error* error) {
44403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!packed_relocations_)
44503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return true;
44603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
44703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Check for an initial APR1 header, packed relocations.
44803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (packed_relocations_[0] == 'A' &&
44903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      packed_relocations_[1] == 'P' &&
45003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      packed_relocations_[2] == 'R' &&
45103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      packed_relocations_[3] == '1') {
45203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return ApplyPackedRel(packed_relocations_ + 4, error);
45303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
45403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
45503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Check for an initial APA1 header, packed relocations with addend.
45603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (packed_relocations_[0] == 'A' &&
45703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      packed_relocations_[1] == 'P' &&
45803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      packed_relocations_[2] == 'A' &&
45903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      packed_relocations_[3] == '1') {
46003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return ApplyPackedRela(packed_relocations_ + 4, error);
46103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
46203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
46303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  error->Format("Bad packed relocations ident, expected APR1 or APA1");
46403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return false;
46503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
46603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#endif  // __arm__ || __aarch64__
467116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
468f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela,
469f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    ELF::Addr sym_addr,
470f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    bool resolved CRAZY_UNUSED,
471f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    Error* error) {
472f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Word rela_type = ELF_R_TYPE(rela->r_info);
473f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info);
474f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Sword CRAZY_UNUSED addend = rela->r_addend;
475f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
476f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
477f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
478f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RLOG("  rela reloc=%p offset=%p type=%d addend=%p\n",
479f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       reloc,
480f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       rela->r_offset,
481f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       rela_type,
482f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       addend);
483f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
484f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Apply the relocation.
485f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc);
486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (rela_type) {
487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __aarch64__
488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_JUMP_SLOT:
489f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_AARCH64_JUMP_SLOT target=%p addr=%p\n",
490f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           sym_addr + addend);
492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = sym_addr + addend;
493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
494f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
495f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_GLOB_DAT:
496f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_AARCH64_GLOB_DAT target=%p addr=%p\n",
497f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
498f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           sym_addr + addend);
499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = sym_addr + addend;
500f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
501f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
502f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_ABS64:
503f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_AARCH64_ABS64 target=%p (%p) addr=%p\n",
504f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           *target,
506f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           sym_addr + addend);
507f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += sym_addr + addend;
508f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
509f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
510f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_RELATIVE:
511f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_AARCH64_RELATIVE target=%p (%p) bias=%p\n",
512f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
513f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           *target,
514f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           load_bias_ + addend);
515f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (__builtin_expect(rela_symbol, 0)) {
516f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        *error = "Invalid relative relocation with symbol";
517f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return false;
518f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
519f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = load_bias_ + addend;
520f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
521f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
522f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_COPY:
523f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // NOTE: These relocations are forbidden in shared libraries.
524f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_AARCH64_COPY\n");
525f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *error = "Invalid R_AARCH64_COPY relocation in shared library";
526f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
527f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __aarch64__
528f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#ifdef __x86_64__
5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_JMP_SLOT:
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *target = sym_addr + addend;
5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_GLOB_DAT:
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *target = sym_addr + addend;
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_RELATIVE:
5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (rela_symbol) {
5405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        *error = "Invalid relative relocation with symbol";
5415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return false;
5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *target = load_bias_ + addend;
5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_64:
5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *target = sym_addr + addend;
5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_PC32:
5515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *target = sym_addr + (addend - reloc);
5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
5535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif  // __x86_64__
5545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
555f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
556f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error->Format("Invalid relocation type (%d)", rela_type);
557f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
558f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
559f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
560f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
561f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
562f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
563f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel,
564f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   ELF::Addr sym_addr,
565f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   bool resolved CRAZY_UNUSED,
566f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   Error* error) {
567f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
568f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info);
569f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
570f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
571f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
572f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RLOG("  rel reloc=%p offset=%p type=%d\n", reloc, rel->r_offset, rel_type);
573f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
574f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Apply the relocation.
575f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc);
576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (rel_type) {
577f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __arm__
578f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_JUMP_SLOT:
579f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_ARM_JUMP_SLOT target=%p addr=%p\n", target, sym_addr);
580f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = sym_addr;
581f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
582f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
583f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_GLOB_DAT:
584f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_ARM_GLOB_DAT target=%p addr=%p\n", target, sym_addr);
585f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = sym_addr;
586f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
587f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
588f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_ABS32:
589f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_ARM_ABS32 target=%p (%p) addr=%p\n",
590f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
591f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           *target,
592f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           sym_addr);
593f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += sym_addr;
594f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
595f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
596f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_REL32:
597f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_ARM_REL32 target=%p (%p) addr=%p offset=%p\n",
598f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
599f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           *target,
600f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           sym_addr,
601f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           rel->r_offset);
602f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += sym_addr - rel->r_offset;
603f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
604f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
605f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_RELATIVE:
606f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_ARM_RELATIVE target=%p (%p) bias=%p\n",
607f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           target,
608f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           *target,
609f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           load_bias_);
610f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (__builtin_expect(rel_symbol, 0)) {
611f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        *error = "Invalid relative relocation with symbol";
612f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return false;
613f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
614f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += load_bias_;
615f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
616f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
617f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_COPY:
618f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // NOTE: These relocations are forbidden in shared libraries.
619f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // The Android linker has special code to deal with this, which
620f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // is not needed here.
621f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      RLOG("  R_ARM_COPY\n");
622f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *error = "Invalid R_ARM_COPY relocation in shared library";
623f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
624f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __arm__
625f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
626f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __i386__
627f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_JMP_SLOT:
628f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = sym_addr;
629f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
630f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
631f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_GLOB_DAT:
632f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target = sym_addr;
633f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
634f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
635f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_RELATIVE:
636f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (rel_symbol) {
637f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        *error = "Invalid relative relocation with symbol";
638f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return false;
639f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
640f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += load_bias_;
641f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
642f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
643f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_32:
644f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += sym_addr;
645f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
646f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
647f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_PC32:
648f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *target += (sym_addr - reloc);
649f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
650f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __i386__
651f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
652f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __mips__
653f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_MIPS_REL32:
654f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (resolved)
655f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        *target += sym_addr;
656f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      else
657f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        *target += load_bias_;
658f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
659f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __mips__
660f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
661f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
662f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error->Format("Invalid relocation type (%d)", rel_type);
663f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
664f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
665f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
666f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
667f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
668f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
669f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::ResolveSymbol(ELF::Word rel_type,
670f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   ELF::Word rel_symbol,
671f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   const ElfSymbols* symbols,
672f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   SymbolResolver* resolver,
673f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   ELF::Addr reloc,
674f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   ELF::Addr* sym_addr,
675f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   Error* error) {
676f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char* sym_name = symbols->LookupNameById(rel_symbol);
677f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RLOG("    symbol name='%s'\n", sym_name);
678f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void* address = resolver->Lookup(sym_name);
679f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
680f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (address) {
681f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // The symbol was found, so compute its address.
682f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    RLOG("%s: symbol %s resolved to %p\n", __FUNCTION__, sym_name, address);
683f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    *sym_addr = reinterpret_cast<ELF::Addr>(address);
684f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
685f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
686f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
687f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The symbol was not found. Normally this is an error except
688f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // if this is a weak reference.
689f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!symbols->IsWeakById(rel_symbol)) {
690f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Could not find symbol '%s'", sym_name);
691f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
692f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
693f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
694f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RLOG("%s: weak reference to unresolved symbol %s\n", __FUNCTION__, sym_name);
695f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
696f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // IHI0044C AAELF 4.5.1.1:
697f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Libraries are not searched to resolve weak references.
698f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // It is not an error for a weak reference to remain
699f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // unsatisfied.
700f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //
701f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // During linking, the value of an undefined weak reference is:
702f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // - Zero if the relocation type is absolute
703f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // - The address of the place if the relocation is pc-relative
704f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // - The address of nominal base address if the relocation
705f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //   type is base-relative.
706f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RelocationType r = GetRelocationType(rel_type);
707f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE) {
708f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    *sym_addr = 0;
709f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
710f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
711f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
712f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (r == RELOCATION_TYPE_PC_RELATIVE) {
713f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    *sym_addr = reloc;
714f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
715f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
716f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
717f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  error->Format(
718f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "Invalid weak relocation type (%d) for unknown symbol '%s'",
719f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      r,
720f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      sym_name);
721f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return false;
722f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
723f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
724f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel,
725f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    size_t rel_count,
726f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    const ElfSymbols* symbols,
727f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    SymbolResolver* resolver,
728f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    Error* error) {
729f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count);
730f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
731f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!rel)
732f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
733f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
734f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) {
735f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
736f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
737f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
738f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr sym_addr = 0;
739f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
740f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
741f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_n + 1,
742f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_count,
743f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         reloc,
744f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel->r_offset,
745f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_type,
746f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_symbol);
747f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
748f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (rel_type == 0)
749f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
750f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
751f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool resolved = false;
752f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
753f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // If this is a symbolic relocation, compute the symbol's address.
754f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (__builtin_expect(rel_symbol != 0, 0)) {
755116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!ResolveSymbol(rel_type,
756116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         rel_symbol,
757116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         symbols,
758116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         resolver,
759116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         reloc,
760116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         &sym_addr,
761116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         error)) {
762116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return false;
763116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
764116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      resolved = true;
765f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
766f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
767f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ApplyRelReloc(rel, sym_addr, resolved, error))
768f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
769f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
770f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
771f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
772f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
773f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
774f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela,
775f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     size_t rela_count,
776f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     const ElfSymbols* symbols,
777f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     SymbolResolver* resolver,
778f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     Error* error) {
779f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RLOG("%s: rela=%p rela_count=%d\n", __FUNCTION__, rela, rela_count);
780f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
781f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!rela)
782f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
783f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
784f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) {
785f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_type = ELF_R_TYPE(rela->r_info);
786f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info);
787f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
788f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr sym_addr = 0;
789f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
790f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
791f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_n + 1,
792f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rela_count,
793f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         reloc,
794f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rela->r_offset,
795f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_type,
796f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         rel_symbol);
797f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
798f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (rel_type == 0)
799f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
800f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
801f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool resolved = false;
802f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
803f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // If this is a symbolic relocation, compute the symbol's address.
804f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (__builtin_expect(rel_symbol != 0, 0)) {
805116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!ResolveSymbol(rel_type,
806116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         rel_symbol,
807116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         symbols,
808116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         resolver,
809116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         reloc,
810116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         &sym_addr,
811116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         error)) {
812116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return false;
813116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
814116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      resolved = true;
815f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
816f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
817f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ApplyRelaReloc(rela, sym_addr, resolved, error))
818f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return false;
819f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
820f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
821f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
822f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
823f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
824f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __mips__
825f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols,
826f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     SymbolResolver* resolver,
827f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     Error* error) {
828f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!plt_got_)
829f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
830f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
831f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Handle the local GOT entries.
832f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // This mimics what the system linker does.
833f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Note from the system linker:
834f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // got[0]: lazy resolver function address.
835f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // got[1]: may be used for a GNU extension.
836f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Set it to a recognizable address in case someone calls it
837f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // (should be _rtld_bind_start).
838f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ELF::Addr* got = plt_got_;
839f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  got[0] = 0xdeadbeef;
840f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (got[1] & 0x80000000)
841f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    got[1] = 0xdeadbeef;
842f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
843f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (ELF::Addr n = 2; n < mips_local_got_count_; ++n)
844f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    got[n] += load_bias_;
845f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
846f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Handle the global GOT entries.
847f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  got += mips_local_got_count_;
848f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t idx = mips_gotsym_; idx < mips_symtab_count_; idx++, got++) {
849f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const char* sym_name = symbols->LookupNameById(idx);
850f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    void* sym_addr = resolver->Lookup(sym_name);
851f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (sym_addr) {
852f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Found symbol, update GOT entry.
853f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *got = reinterpret_cast<ELF::Addr>(sym_addr);
854f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
855f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
856f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
857f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (symbols->IsWeakById(idx)) {
858f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Undefined symbols are only ok if this is a weak reference.
859f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Update GOT entry to 0 though.
860f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *got = 0;
861f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
862f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
863f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
864f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Cannot locate symbol %s", sym_name);
865f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
866f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
867f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
868f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
869f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
870f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __mips__
871f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
872f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ElfRelocations::AdjustRelocation(ELF::Word rel_type,
873f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                      ELF::Addr src_reloc,
874f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                      size_t dst_delta,
875f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                      size_t map_delta) {
876f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(src_reloc + dst_delta);
877f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
878f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (rel_type) {
879f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __arm__
880f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_ARM_RELATIVE:
881f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *dst_ptr += map_delta;
882f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
883f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __arm__
884f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
885f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __aarch64__
886f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_AARCH64_RELATIVE:
887f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *dst_ptr += map_delta;
888f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
889f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // __aarch64__
890f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
891f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __i386__
892f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_386_RELATIVE:
893f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *dst_ptr += map_delta;
894f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
895f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
896f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
8975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#ifdef __x86_64__
8985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case R_X86_64_RELATIVE:
8995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *dst_ptr += map_delta;
9005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
9015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
9025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
903f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __mips__
904f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case R_MIPS_REL32:
905f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *dst_ptr += map_delta;
906f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
907f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
908f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
909f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ;
910f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
911f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
912f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
913f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ElfRelocations::RelocateRela(size_t src_addr,
914f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  size_t dst_addr,
915f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  size_t map_addr,
916f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  size_t size) {
917f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Add this value to each source address to get the corresponding
918f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // destination address.
919f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t dst_delta = dst_addr - src_addr;
920f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t map_delta = map_addr - src_addr;
921f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
922f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Ignore PLT relocations, which all target symbols (ignored here).
923f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Rela* rel = reinterpret_cast<ELF::Rela*>(relocations_);
924f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t relocations_count = relocations_size_ / sizeof(ELF::Rela);
925f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Rela* rel_limit = rel + relocations_count;
926f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
927f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (; rel < rel_limit; ++rel) {
928f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
929f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
930f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
931f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
932f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (rel_type == 0 || rel_symbol != 0) {
933f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Ignore empty and symbolic relocations
934f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
935f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
936f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
937f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (src_reloc < src_addr || src_reloc >= src_addr + size) {
938f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Ignore entries that don't relocate addresses inside the source section.
939f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
940f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
941f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
942f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta);
943f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
944f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
945f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
946f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ElfRelocations::RelocateRel(size_t src_addr,
947f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 size_t dst_addr,
948f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 size_t map_addr,
949f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 size_t size) {
950f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Add this value to each source address to get the corresponding
951f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // destination address.
952f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t dst_delta = dst_addr - src_addr;
953f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t map_delta = map_addr - src_addr;
954f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
955f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Ignore PLT relocations, which all target symbols (ignored here).
956f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Rel* rel = reinterpret_cast<ELF::Rel*>(relocations_);
957f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t relocations_count = relocations_size_ / sizeof(ELF::Rel);
958f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ELF::Rel* rel_limit = rel + relocations_count;
959f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
960f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (; rel < rel_limit; ++rel) {
961f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
962f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
963f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
964f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
965f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (rel_type == 0 || rel_symbol != 0) {
966f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Ignore empty and symbolic relocations
967f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
968f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
969f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
970f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (src_reloc < src_addr || src_reloc >= src_addr + size) {
971f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Ignore entries that don't relocate addresses inside the source section.
972f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
973f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
974f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
975f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta);
976f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
977f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
978f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
979f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ElfRelocations::CopyAndRelocate(size_t src_addr,
980f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     size_t dst_addr,
981f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     size_t map_addr,
982f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     size_t size) {
983f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // First, a straight copy.
984f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ::memcpy(reinterpret_cast<void*>(dst_addr),
985f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           reinterpret_cast<void*>(src_addr),
986f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           size);
987f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
988f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Relocate relocations.
989f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (relocations_type_ == DT_REL)
990f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    RelocateRel(src_addr, dst_addr, map_addr, size);
991f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
992116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (relocations_type_ == DT_RELA)
993f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    RelocateRela(src_addr, dst_addr, map_addr, size);
994f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
995f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __mips__
996f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Add this value to each source address to get the corresponding
997f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // destination address.
998f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t dst_delta = dst_addr - src_addr;
999f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const size_t map_delta = map_addr - src_addr;
1000f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1001f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Only relocate local GOT entries.
1002f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ELF::Addr* got = plt_got_;
1003f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (got) {
1004f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (ELF::Addr n = 2; n < mips_local_got_count_; ++n) {
1005f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      size_t got_addr = reinterpret_cast<size_t>(&got[n]);
1006f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (got_addr < src_addr || got_addr >= src_addr + size)
1007f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        continue;
1008f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta);
1009f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      *dst_ptr += map_delta;
1010f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
1011f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
1012f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
1013f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
1014f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1015f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace crazy
1016