1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #pragma once
30
31 #include <string.h>
32
33 #include "linker.h"
34 #include "linker_sleb128.h"
35
36 const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1;
37 const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
38 const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
39 const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
40
41 #if defined(USE_RELA)
42 typedef ElfW(Rela) rel_t;
43 #else
44 typedef ElfW(Rel) rel_t;
45 #endif
46
47 template <typename F>
for_all_packed_relocs(sleb128_decoder decoder,F && callback)48 inline bool for_all_packed_relocs(sleb128_decoder decoder, F&& callback) {
49 const size_t num_relocs = decoder.pop_front();
50
51 rel_t reloc = {
52 .r_offset = decoder.pop_front(),
53 };
54
55 for (size_t idx = 0; idx < num_relocs; ) {
56 const size_t group_size = decoder.pop_front();
57 const size_t group_flags = decoder.pop_front();
58
59 size_t group_r_offset_delta = 0;
60
61 if (group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) {
62 group_r_offset_delta = decoder.pop_front();
63 }
64 if (group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) {
65 reloc.r_info = decoder.pop_front();
66 }
67
68 #if defined(USE_RELA)
69 const size_t group_flags_reloc = group_flags & (RELOCATION_GROUP_HAS_ADDEND_FLAG |
70 RELOCATION_GROUPED_BY_ADDEND_FLAG);
71 if (group_flags_reloc == RELOCATION_GROUP_HAS_ADDEND_FLAG) {
72 // Each relocation has an addend. This is the default situation with lld's current encoder.
73 } else if (group_flags_reloc == (RELOCATION_GROUP_HAS_ADDEND_FLAG |
74 RELOCATION_GROUPED_BY_ADDEND_FLAG)) {
75 reloc.r_addend += decoder.pop_front();
76 } else {
77 reloc.r_addend = 0;
78 }
79 #else
80 if (__predict_false(group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG)) {
81 // This platform does not support rela, and yet we have it encoded in android_rel section.
82 async_safe_fatal("unexpected r_addend in android.rel section");
83 }
84 #endif
85
86 for (size_t i = 0; i < group_size; ++i) {
87 if (group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) {
88 reloc.r_offset += group_r_offset_delta;
89 } else {
90 reloc.r_offset += decoder.pop_front();
91 }
92 if ((group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) == 0) {
93 reloc.r_info = decoder.pop_front();
94 }
95 #if defined(USE_RELA)
96 if (group_flags_reloc == RELOCATION_GROUP_HAS_ADDEND_FLAG) {
97 reloc.r_addend += decoder.pop_front();
98 }
99 #endif
100 if (!callback(reloc)) {
101 return false;
102 }
103 }
104
105 idx += group_size;
106 }
107
108 return true;
109 }
110