/src/binutils-gdb/bfd/mach-o-aarch64.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* AArch-64 Mach-O support for BFD. |
2 | | Copyright (C) 2015-2025 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of BFD, the Binary File Descriptor library. |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
19 | | MA 02110-1301, USA. */ |
20 | | |
21 | | #include "sysdep.h" |
22 | | #include "bfd.h" |
23 | | #include "libbfd.h" |
24 | | #include "libiberty.h" |
25 | | #include "mach-o.h" |
26 | | #include "mach-o/arm64.h" |
27 | | |
28 | | #define bfd_mach_o_object_p bfd_mach_o_arm64_object_p |
29 | | #define bfd_mach_o_core_p bfd_mach_o_arm64_core_p |
30 | | #define bfd_mach_o_mkobject bfd_mach_o_arm64_mkobject |
31 | | |
32 | | #define bfd_mach_o_canonicalize_one_reloc \ |
33 | | bfd_mach_o_arm64_canonicalize_one_reloc |
34 | | #define bfd_mach_o_swap_reloc_out NULL |
35 | | |
36 | | #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm64_bfd_reloc_type_lookup |
37 | | #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm64_bfd_reloc_name_lookup |
38 | | |
39 | | #define bfd_mach_o_print_thread NULL |
40 | | #define bfd_mach_o_tgt_seg_table NULL |
41 | | #define bfd_mach_o_section_type_valid_for_tgt NULL |
42 | | |
43 | | static bfd_cleanup |
44 | | bfd_mach_o_arm64_object_p (bfd *abfd) |
45 | 3.41M | { |
46 | 3.41M | return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM64); |
47 | 3.41M | } |
48 | | |
49 | | static bfd_cleanup |
50 | | bfd_mach_o_arm64_core_p (bfd *abfd) |
51 | 16.6k | { |
52 | 16.6k | return bfd_mach_o_header_p (abfd, 0, |
53 | 16.6k | BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM64); |
54 | 16.6k | } |
55 | | |
56 | | static bool |
57 | | bfd_mach_o_arm64_mkobject (bfd *abfd) |
58 | 2 | { |
59 | 2 | bfd_mach_o_data_struct *mdata; |
60 | | |
61 | 2 | if (!bfd_mach_o_mkobject_init (abfd)) |
62 | 0 | return false; |
63 | | |
64 | 2 | mdata = bfd_mach_o_get_data (abfd); |
65 | 2 | mdata->header.magic = BFD_MACH_O_MH_MAGIC; |
66 | 2 | mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM64; |
67 | 2 | mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM64_ALL; |
68 | 2 | mdata->header.byteorder = BFD_ENDIAN_LITTLE; |
69 | 2 | mdata->header.version = 1; |
70 | | |
71 | 2 | return true; |
72 | 2 | } |
73 | | |
74 | | /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ |
75 | | #define MINUS_ONE (~ (bfd_vma) 0) |
76 | | |
77 | | static reloc_howto_type arm64_howto_table[]= |
78 | | { |
79 | | /* 0 */ |
80 | | HOWTO (BFD_RELOC_64, 0, 8, 64, false, 0, |
81 | | complain_overflow_bitfield, |
82 | | NULL, "64", |
83 | | false, MINUS_ONE, MINUS_ONE, false), |
84 | | HOWTO (BFD_RELOC_32, 0, 4, 32, false, 0, |
85 | | complain_overflow_bitfield, |
86 | | NULL, "32", |
87 | | false, 0xffffffff, 0xffffffff, false), |
88 | | HOWTO (BFD_RELOC_16, 0, 2, 16, false, 0, |
89 | | complain_overflow_bitfield, |
90 | | NULL, "16", |
91 | | false, 0xffff, 0xffff, false), |
92 | | HOWTO (BFD_RELOC_8, 0, 1, 8, false, 0, |
93 | | complain_overflow_bitfield, |
94 | | NULL, "8", |
95 | | false, 0xff, 0xff, false), |
96 | | /* 4 */ |
97 | | HOWTO (BFD_RELOC_64_PCREL, 0, 8, 64, true, 0, |
98 | | complain_overflow_bitfield, |
99 | | NULL, "DISP64", |
100 | | false, MINUS_ONE, MINUS_ONE, true), |
101 | | HOWTO (BFD_RELOC_32_PCREL, 0, 4, 32, true, 0, |
102 | | complain_overflow_bitfield, |
103 | | NULL, "DISP32", |
104 | | false, 0xffffffff, 0xffffffff, true), |
105 | | HOWTO (BFD_RELOC_16_PCREL, 0, 2, 16, true, 0, |
106 | | complain_overflow_bitfield, |
107 | | NULL, "DISP16", |
108 | | false, 0xffff, 0xffff, true), |
109 | | HOWTO (BFD_RELOC_AARCH64_CALL26, 0, 4, 26, true, 0, |
110 | | complain_overflow_bitfield, |
111 | | NULL, "BRANCH26", |
112 | | false, 0x03ffffff, 0x03ffffff, true), |
113 | | /* 8 */ |
114 | | HOWTO (BFD_RELOC_AARCH64_ADR_HI21_PCREL, 12, 4, 21, true, 0, |
115 | | complain_overflow_signed, |
116 | | NULL, "PAGE21", |
117 | | false, 0x1fffff, 0x1fffff, true), |
118 | | HOWTO (BFD_RELOC_AARCH64_LDST16_LO12, 1, 4, 12, true, 0, |
119 | | complain_overflow_signed, |
120 | | NULL, "PGOFF12", |
121 | | false, 0xffe, 0xffe, true), |
122 | | HOWTO (BFD_RELOC_MACH_O_ARM64_ADDEND, 0, 4, 32, false, 0, |
123 | | complain_overflow_signed, |
124 | | NULL, "ADDEND", |
125 | | false, 0xffffffff, 0xffffffff, false), |
126 | | HOWTO (BFD_RELOC_MACH_O_SUBTRACTOR32, 0, 4, 32, false, 0, |
127 | | complain_overflow_bitfield, |
128 | | NULL, "SUBTRACTOR32", |
129 | | false, 0xffffffff, 0xffffffff, false), |
130 | | /* 12 */ |
131 | | HOWTO (BFD_RELOC_MACH_O_SUBTRACTOR64, 0, 8, 64, false, 0, |
132 | | complain_overflow_bitfield, |
133 | | NULL, "SUBTRACTOR64", |
134 | | false, MINUS_ONE, MINUS_ONE, false), |
135 | | HOWTO (BFD_RELOC_MACH_O_ARM64_GOT_LOAD_PAGE21, 12, 4, 21, true, 0, |
136 | | complain_overflow_signed, |
137 | | NULL, "GOT_LD_PG21", |
138 | | false, 0x1fffff, 0x1fffff, true), |
139 | | HOWTO (BFD_RELOC_MACH_O_ARM64_GOT_LOAD_PAGEOFF12, 1, 4, 12, true, 0, |
140 | | complain_overflow_signed, |
141 | | NULL, "GOT_LD_PGOFF12", |
142 | | false, 0xffe, 0xffe, true), |
143 | | HOWTO (BFD_RELOC_MACH_O_ARM64_POINTER_TO_GOT, 0, 4, 32, true, 0, |
144 | | complain_overflow_bitfield, |
145 | | NULL, "PTR_TO_GOT", |
146 | | false, 0xffffffff, 0xffffffff, true), |
147 | | }; |
148 | | |
149 | | static bool |
150 | | bfd_mach_o_arm64_canonicalize_one_reloc (bfd * abfd, |
151 | | struct mach_o_reloc_info_external * raw, |
152 | | arelent * res, |
153 | | asymbol ** syms, |
154 | | arelent * res_base ATTRIBUTE_UNUSED) |
155 | 9.98M | { |
156 | 9.98M | bfd_mach_o_reloc_info reloc; |
157 | | |
158 | 9.98M | res->address = bfd_get_32 (abfd, raw->r_address); |
159 | 9.98M | if (res->address & BFD_MACH_O_SR_SCATTERED) |
160 | 12.4k | { |
161 | | /* Only non-scattered relocations. */ |
162 | 12.4k | return false; |
163 | 12.4k | } |
164 | | |
165 | | /* The value and info fields have to be extracted dependent on target |
166 | | endian-ness. */ |
167 | 9.97M | bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum); |
168 | | |
169 | 9.97M | if (reloc.r_type == BFD_MACH_O_ARM64_RELOC_ADDEND) |
170 | 576 | { |
171 | 576 | if (reloc.r_length == 2 && reloc.r_pcrel == 0) |
172 | 175 | { |
173 | 175 | res->sym_ptr_ptr = &bfd_abs_section_ptr->symbol; |
174 | 175 | res->addend = reloc.r_value; |
175 | 175 | res->howto = &arm64_howto_table[10]; |
176 | 175 | return true; |
177 | 175 | } |
178 | 401 | return false; |
179 | 576 | } |
180 | | |
181 | 9.97M | if (!bfd_mach_o_canonicalize_non_scattered_reloc (abfd, &reloc, res, syms)) |
182 | 13.0k | return false; |
183 | | |
184 | 9.96M | switch (reloc.r_type) |
185 | 9.96M | { |
186 | 9.19M | case BFD_MACH_O_ARM64_RELOC_UNSIGNED: |
187 | 9.19M | switch ((reloc.r_length << 1) | reloc.r_pcrel) |
188 | 9.19M | { |
189 | 4.86M | case 0: /* len = 0, pcrel = 0 */ |
190 | 4.86M | res->howto = &arm64_howto_table[3]; |
191 | 4.86M | return true; |
192 | 218 | case 2: /* len = 1, pcrel = 0 */ |
193 | 218 | res->howto = &arm64_howto_table[2]; |
194 | 218 | return true; |
195 | 4.32M | case 3: /* len = 1, pcrel = 1 */ |
196 | 4.32M | res->howto = &arm64_howto_table[6]; |
197 | 4.32M | return true; |
198 | 136 | case 4: /* len = 2, pcrel = 0 */ |
199 | 136 | res->howto = &arm64_howto_table[1]; |
200 | 136 | return true; |
201 | 52 | case 5: /* len = 2, pcrel = 1 */ |
202 | 52 | res->howto = &arm64_howto_table[5]; |
203 | 52 | return true; |
204 | 284 | case 6: /* len = 3, pcrel = 0 */ |
205 | 284 | res->howto = &arm64_howto_table[0]; |
206 | 284 | return true; |
207 | 589 | case 7: /* len = 3, pcrel = 1 */ |
208 | 589 | res->howto = &arm64_howto_table[4]; |
209 | 589 | return true; |
210 | 728 | default: |
211 | 728 | return false; |
212 | 9.19M | } |
213 | 0 | break; |
214 | 67.0k | case BFD_MACH_O_ARM64_RELOC_SUBTRACTOR: |
215 | 67.0k | if (reloc.r_pcrel) |
216 | 982 | return false; |
217 | 66.0k | switch (reloc.r_length) |
218 | 66.0k | { |
219 | 64.6k | case 2: |
220 | 64.6k | res->howto = &arm64_howto_table[11]; |
221 | 64.6k | return true; |
222 | 535 | case 3: |
223 | 535 | res->howto = &arm64_howto_table[12]; |
224 | 535 | return true; |
225 | 853 | default: |
226 | 853 | return false; |
227 | 66.0k | } |
228 | 0 | break; |
229 | 3.14k | case BFD_MACH_O_ARM64_RELOC_BRANCH26: |
230 | 3.14k | if (reloc.r_length == 2 && reloc.r_pcrel == 1) |
231 | 2.39k | { |
232 | 2.39k | res->howto = &arm64_howto_table[7]; |
233 | 2.39k | return true; |
234 | 2.39k | } |
235 | 752 | break; |
236 | 136k | case BFD_MACH_O_ARM64_RELOC_PAGE21: |
237 | 136k | if (reloc.r_length == 2 && reloc.r_pcrel == 1) |
238 | 136k | { |
239 | 136k | res->howto = &arm64_howto_table[8]; |
240 | 136k | return true; |
241 | 136k | } |
242 | 381 | break; |
243 | 3.55k | case BFD_MACH_O_ARM64_RELOC_PAGEOFF12: |
244 | 3.55k | if (reloc.r_length == 2 && reloc.r_pcrel == 0) |
245 | 2.97k | { |
246 | 2.97k | res->howto = &arm64_howto_table[9]; |
247 | 2.97k | return true; |
248 | 2.97k | } |
249 | 579 | break; |
250 | 2.01k | case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGE21: |
251 | 2.01k | if (reloc.r_length == 2 && reloc.r_pcrel == 1) |
252 | 375 | { |
253 | 375 | res->howto = &arm64_howto_table[13]; |
254 | 375 | return true; |
255 | 375 | } |
256 | 1.63k | break; |
257 | 1.71k | case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGEOFF12: |
258 | 1.71k | if (reloc.r_length == 2 && reloc.r_pcrel == 0) |
259 | 565 | { |
260 | 565 | res->howto = &arm64_howto_table[14]; |
261 | 565 | return true; |
262 | 565 | } |
263 | 1.15k | break; |
264 | 551k | case BFD_MACH_O_ARM64_RELOC_POINTER_TO_GOT: |
265 | 551k | if (reloc.r_length == 2 && reloc.r_pcrel == 1) |
266 | 550k | { |
267 | 550k | res->howto = &arm64_howto_table[15]; |
268 | 550k | return true; |
269 | 550k | } |
270 | 782 | break; |
271 | 2.36k | default: |
272 | 2.36k | break; |
273 | 9.96M | } |
274 | 7.64k | return false; |
275 | 9.96M | } |
276 | | |
277 | | static reloc_howto_type * |
278 | | bfd_mach_o_arm64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
279 | | bfd_reloc_code_real_type code) |
280 | 0 | { |
281 | 0 | unsigned int i; |
282 | |
|
283 | 0 | for (i = 0; |
284 | 0 | i < sizeof (arm64_howto_table) / sizeof (*arm64_howto_table); |
285 | 0 | i++) |
286 | 0 | if (code == arm64_howto_table[i].type) |
287 | 0 | return &arm64_howto_table[i]; |
288 | 0 | return NULL; |
289 | 0 | } |
290 | | |
291 | | static reloc_howto_type * |
292 | | bfd_mach_o_arm64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
293 | | const char *name ATTRIBUTE_UNUSED) |
294 | 0 | { |
295 | 0 | return NULL; |
296 | 0 | } |
297 | | |
298 | | #define TARGET_NAME aarch64_mach_o_vec |
299 | | #define TARGET_STRING "mach-o-arm64" |
300 | | #define TARGET_ARCHITECTURE bfd_arch_aarch64 |
301 | | #define TARGET_PAGESIZE 4096 |
302 | | #define TARGET_BIG_ENDIAN 0 |
303 | | #define TARGET_ARCHIVE 0 |
304 | | #define TARGET_PRIORITY 0 |
305 | | #include "mach-o-target.c" |
306 | | |
307 | | #undef TARGET_NAME |
308 | | #undef TARGET_STRING |
309 | | #undef TARGET_ARCHIVE |
310 | | #undef TARGET_PRIORITY |