Commit | Line | Data |
---|---|---|
9363c7c3 JY |
1 | // aarch64-reloc-property.cc -- AArch64 relocation properties -*- C++ -*- |
2 | ||
2571583a | 3 | // Copyright (C) 2014-2017 Free Software Foundation, Inc. |
9363c7c3 JY |
4 | // Written by Han Shen <shenhan@google.com> and Jing Yu <jingyu@google.com>. |
5 | ||
6 | // This file is part of gold. | |
7 | ||
8 | // This program is free software; you can redistribute it and/or modify | |
9 | // it under the terms of the GNU General Public License as published by | |
10 | // the Free Software Foundation; either version 3 of the License, or | |
11 | // (at your option) any later version. | |
12 | ||
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | ||
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
21 | // MA 02110-1301, USA. | |
22 | ||
23 | #include "gold.h" | |
24 | ||
25 | #include "aarch64-reloc-property.h" | |
26 | #include "aarch64.h" | |
27 | ||
28 | #include "symtab.h" | |
29 | ||
30 | #include<stdio.h> | |
31 | ||
32 | namespace gold | |
33 | { | |
34 | ||
35 | template<int L, int U> | |
36 | bool | |
37 | rvalue_checkup(int64_t x) | |
38 | { | |
39 | // We save the extra_alignment_requirement bits on [31:16] of U. | |
40 | // "extra_alignment_requirement" could be 0, 1, 3, 7 and 15. | |
41 | unsigned short extra_alignment_requirement = (U & 0xFFFF0000) >> 16; | |
42 | // [15:0] of U indicates the upper bound check. | |
43 | int64_t u = U & 0x0000FFFF; | |
44 | if (u == 0) | |
45 | { | |
46 | // No requirement to check overflow. | |
47 | gold_assert(L == 0); | |
48 | return (x & extra_alignment_requirement) == 0; | |
49 | } | |
50 | ||
51 | // Check both overflow and alignment if needed. | |
52 | int64_t low_bound = -(L == 0 ? 0 : ((int64_t)1 << L)); | |
53 | int64_t up_bound = ((int64_t)1 << u); | |
54 | return ((low_bound <= x && x < up_bound) | |
55 | && ((x & extra_alignment_requirement) == 0)); | |
56 | } | |
57 | ||
58 | template<> | |
59 | bool | |
60 | rvalue_checkup<0, 0>(int64_t) { return true; } | |
61 | ||
8769bc4b HS |
62 | namespace |
63 | { | |
64 | ||
65 | template<int L, int U> | |
66 | class Rvalue_bit_select_impl | |
67 | { | |
68 | public: | |
69 | static uint64_t | |
70 | calc(uint64_t x) | |
71 | { | |
72 | return (x & ((1ULL << (U+1)) - 1)) >> L; | |
73 | } | |
74 | }; | |
75 | ||
76 | template<int L> | |
77 | class Rvalue_bit_select_impl<L, 63> | |
78 | { | |
79 | public: | |
80 | static uint64_t | |
81 | calc(uint64_t x) | |
82 | { | |
83 | return x >> L; | |
84 | } | |
85 | }; | |
86 | ||
87 | // By our convention, L=U=0 means that the whole value should be retrieved. | |
88 | template<> | |
89 | class Rvalue_bit_select_impl<0, 0> | |
90 | { | |
91 | public: | |
92 | static uint64_t | |
93 | calc(uint64_t x) | |
94 | { | |
95 | return x; | |
96 | } | |
97 | }; | |
98 | ||
99 | } // End anonymous namespace. | |
100 | ||
9363c7c3 JY |
101 | template<int L, int U> |
102 | uint64_t | |
103 | rvalue_bit_select(uint64_t x) | |
104 | { | |
8769bc4b | 105 | return Rvalue_bit_select_impl<L, U>::calc(x); |
9363c7c3 JY |
106 | } |
107 | ||
9363c7c3 JY |
108 | AArch64_reloc_property::AArch64_reloc_property( |
109 | unsigned int code, | |
110 | const char* name, | |
111 | Reloc_type rtype, | |
112 | Reloc_class rclass, | |
113 | bool is_implemented, | |
114 | int group_index, | |
115 | int reference_flags, | |
116 | Reloc_inst reloc_inst, | |
117 | rvalue_checkup_func_p rvalue_checkup_func, | |
118 | rvalue_bit_select_func rvalue_bit_select) | |
119 | : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass), | |
120 | group_index_(group_index), | |
121 | is_implemented_(is_implemented), | |
122 | reference_flags_(reference_flags), | |
123 | reloc_inst_(reloc_inst), | |
124 | rvalue_checkup_func_(rvalue_checkup_func), | |
125 | rvalue_bit_select_func_(rvalue_bit_select) | |
126 | {} | |
127 | ||
128 | AArch64_reloc_property_table::AArch64_reloc_property_table() | |
129 | { | |
130 | const bool Y(true), N(false); | |
131 | for (unsigned int i = 0; i < Property_table_size; ++i) | |
132 | table_[i] = NULL; | |
133 | ||
134 | #define RL_CHECK_ALIGN2 (1 << 16) | |
135 | #define RL_CHECK_ALIGN4 (3 << 16) | |
136 | #define RL_CHECK_ALIGN8 (7 << 16) | |
137 | #define RL_CHECK_ALIGN16 (15 << 16) | |
138 | ||
139 | #undef ARD | |
140 | #define ARD(rname, type, class, is_implemented, group_index, LB, UB, BSL, BSH, RFLAGS, inst) \ | |
141 | do \ | |
142 | { \ | |
143 | int tidx = code_to_array_index(elfcpp::R_AARCH64_##rname); \ | |
144 | AArch64_reloc_property * p = new AArch64_reloc_property( \ | |
145 | elfcpp::R_AARCH64_##rname, "R_AARCH64_" #rname, \ | |
146 | AArch64_reloc_property::RT_##type, \ | |
147 | AArch64_reloc_property::RC_##class, \ | |
148 | is_implemented, \ | |
149 | group_index, \ | |
150 | (RFLAGS), \ | |
151 | AArch64_reloc_property::INST_##inst, \ | |
152 | rvalue_checkup<LB,UB>, \ | |
153 | rvalue_bit_select<BSL,BSH>); \ | |
154 | table_[tidx] = p; \ | |
155 | } \ | |
156 | while (0); | |
157 | #include"aarch64-reloc.def" | |
158 | #undef ARD | |
159 | } | |
160 | ||
161 | // Return a string describing a relocation code that fails to get a | |
162 | // relocation property in get_implemented_static_reloc_property(). | |
163 | ||
164 | std::string | |
165 | AArch64_reloc_property_table::reloc_name_in_error_message(unsigned int code) | |
166 | { | |
8e33481e HS |
167 | int tidx = code_to_array_index(code); |
168 | const AArch64_reloc_property* arp = this->table_[tidx]; | |
9363c7c3 JY |
169 | |
170 | if (arp == NULL) | |
171 | { | |
172 | char buffer[100]; | |
173 | sprintf(buffer, _("invalid reloc %u"), code); | |
174 | return std::string(buffer); | |
175 | } | |
176 | ||
177 | // gold only implements static relocation codes. | |
178 | AArch64_reloc_property::Reloc_type reloc_type = arp->reloc_type(); | |
179 | gold_assert(reloc_type == AArch64_reloc_property::RT_STATIC | |
180 | || !arp->is_implemented()); | |
181 | ||
182 | const char* prefix = NULL; | |
183 | switch (reloc_type) | |
184 | { | |
185 | case AArch64_reloc_property::RT_STATIC: | |
186 | prefix = arp->is_implemented() ? _("reloc ") : _("unimplemented reloc "); | |
187 | break; | |
188 | case AArch64_reloc_property::RT_DYNAMIC: | |
189 | prefix = _("dynamic reloc "); | |
190 | break; | |
191 | default: | |
192 | gold_unreachable(); | |
193 | } | |
194 | return std::string(prefix) + arp->name(); | |
195 | } | |
196 | ||
197 | } |