/src/binutils-gdb/bfd/mach-o-arm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* ARM 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/arm.h" |
27 | | |
28 | | #define bfd_mach_o_object_p bfd_mach_o_arm_object_p |
29 | | #define bfd_mach_o_core_p bfd_mach_o_arm_core_p |
30 | | #define bfd_mach_o_mkobject bfd_mach_o_arm_mkobject |
31 | | |
32 | | #define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_arm_canonicalize_one_reloc |
33 | | #define bfd_mach_o_swap_reloc_out NULL |
34 | | #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm_bfd_reloc_type_lookup |
35 | | #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm_bfd_reloc_name_lookup |
36 | | |
37 | | #define bfd_mach_o_print_thread NULL |
38 | | #define bfd_mach_o_tgt_seg_table NULL |
39 | | #define bfd_mach_o_section_type_valid_for_tgt NULL |
40 | | |
41 | | static bfd_cleanup |
42 | | bfd_mach_o_arm_object_p (bfd *abfd) |
43 | 3.41M | { |
44 | 3.41M | return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM); |
45 | 3.41M | } |
46 | | |
47 | | static bfd_cleanup |
48 | | bfd_mach_o_arm_core_p (bfd *abfd) |
49 | 16.6k | { |
50 | 16.6k | return bfd_mach_o_header_p (abfd, 0, |
51 | 16.6k | BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM); |
52 | 16.6k | } |
53 | | |
54 | | static bool |
55 | | bfd_mach_o_arm_mkobject (bfd *abfd) |
56 | 11 | { |
57 | 11 | bfd_mach_o_data_struct *mdata; |
58 | | |
59 | 11 | if (!bfd_mach_o_mkobject_init (abfd)) |
60 | 0 | return false; |
61 | | |
62 | 11 | mdata = bfd_mach_o_get_data (abfd); |
63 | 11 | mdata->header.magic = BFD_MACH_O_MH_MAGIC; |
64 | 11 | mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM; |
65 | 11 | mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM_ALL; |
66 | 11 | mdata->header.byteorder = BFD_ENDIAN_LITTLE; |
67 | 11 | mdata->header.version = 1; |
68 | | |
69 | 11 | return true; |
70 | 11 | } |
71 | | |
72 | | static reloc_howto_type arm_howto_table[]= |
73 | | { |
74 | | /* 0 */ |
75 | | HOWTO (BFD_RELOC_32, 0, 4, 32, false, 0, |
76 | | complain_overflow_bitfield, |
77 | | NULL, "32", |
78 | | false, 0xffffffff, 0xffffffff, false), |
79 | | HOWTO (BFD_RELOC_16, 0, 2, 16, false, 0, |
80 | | complain_overflow_bitfield, |
81 | | NULL, "16", |
82 | | false, 0xffff, 0xffff, false), |
83 | | HOWTO (BFD_RELOC_8, 0, 1, 8, false, 0, |
84 | | complain_overflow_bitfield, |
85 | | NULL, "8", |
86 | | false, 0xff, 0xff, false), |
87 | | HOWTO (BFD_RELOC_32_PCREL, 0, 4, 32, true, 0, |
88 | | complain_overflow_bitfield, |
89 | | NULL, "DISP32", |
90 | | false, 0xffffffff, 0xffffffff, true), |
91 | | /* 4 */ |
92 | | HOWTO (BFD_RELOC_16_PCREL, 0, 2, 16, true, 0, |
93 | | complain_overflow_bitfield, |
94 | | NULL, "DISP16", |
95 | | false, 0xffff, 0xffff, true), |
96 | | HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 4, 32, false, 0, |
97 | | complain_overflow_bitfield, |
98 | | NULL, "SECTDIFF_32", |
99 | | false, 0xffffffff, 0xffffffff, false), |
100 | | HOWTO (BFD_RELOC_MACH_O_LOCAL_SECTDIFF, 0, 4, 32, false, 0, |
101 | | complain_overflow_bitfield, |
102 | | NULL, "LSECTDIFF_32", |
103 | | false, 0xffffffff, 0xffffffff, false), |
104 | | HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 32, false, 0, |
105 | | complain_overflow_bitfield, |
106 | | NULL, "PAIR_32", |
107 | | false, 0xffffffff, 0xffffffff, false), |
108 | | /* 8 */ |
109 | | HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 2, 16, false, 0, |
110 | | complain_overflow_bitfield, |
111 | | NULL, "SECTDIFF_16", |
112 | | false, 0xffff, 0xffff, false), |
113 | | HOWTO (BFD_RELOC_MACH_O_LOCAL_SECTDIFF, 0, 2, 16, false, 0, |
114 | | complain_overflow_bitfield, |
115 | | NULL, "LSECTDIFF_16", |
116 | | false, 0xffff, 0xffff, false), |
117 | | HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 2, 16, false, 0, |
118 | | complain_overflow_bitfield, |
119 | | NULL, "PAIR_16", |
120 | | false, 0xffff, 0xffff, false), |
121 | | HOWTO (BFD_RELOC_ARM_PCREL_CALL, 2, 4, 24, true, 0, |
122 | | complain_overflow_signed, |
123 | | NULL, "BR24", |
124 | | false, 0x00ffffff, 0x00ffffff, true), |
125 | | /* 12 */ |
126 | | HOWTO (BFD_RELOC_ARM_MOVW, 0, 4, 16, false, 0, |
127 | | complain_overflow_dont, |
128 | | NULL, "MOVW", |
129 | | false, 0x000f0fff, 0x000f0fff, false), |
130 | | HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 16, false, 0, |
131 | | complain_overflow_bitfield, |
132 | | NULL, "PAIR_W", |
133 | | false, 0x000f0fff, 0x000f0fff, false), |
134 | | HOWTO (BFD_RELOC_ARM_MOVT, 0, 4, 16, false, 0, |
135 | | complain_overflow_bitfield, |
136 | | NULL, "MOVT", |
137 | | false, 0x000f0fff, 0x000f0fff, false), |
138 | | HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 16, false, 0, |
139 | | complain_overflow_bitfield, |
140 | | NULL, "PAIR_T", |
141 | | false, 0x000f0fff, 0x000f0fff, false), |
142 | | /* 16 */ |
143 | | HOWTO (BFD_RELOC_THUMB_PCREL_BLX, 2, 4, 24, true, 0, |
144 | | complain_overflow_signed, |
145 | | NULL, "TBR22", |
146 | | false, 0x07ff2fff, 0x07ff2fff, true) |
147 | | }; |
148 | | |
149 | | static bool |
150 | | bfd_mach_o_arm_canonicalize_one_reloc (bfd * abfd, |
151 | | struct mach_o_reloc_info_external * raw, |
152 | | arelent * res, |
153 | | asymbol ** syms, |
154 | | arelent * res_base) |
155 | 6.05M | { |
156 | 6.05M | bfd_mach_o_reloc_info reloc; |
157 | | |
158 | 6.05M | if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms)) |
159 | 18.8k | return false; |
160 | | |
161 | 6.03M | if (reloc.r_scattered) |
162 | 3.73M | { |
163 | 3.73M | switch (reloc.r_type) |
164 | 3.73M | { |
165 | 1.74k | case BFD_MACH_O_ARM_RELOC_PAIR: |
166 | | /* PR 21813: Check for a corrupt PAIR reloc at the start. */ |
167 | 1.74k | if (res == res_base) |
168 | 230 | { |
169 | 230 | _bfd_error_handler (_("malformed mach-o ARM reloc pair: " |
170 | 230 | "reloc is first reloc")); |
171 | 230 | return false; |
172 | 230 | } |
173 | 1.51k | if (reloc.r_length == 2) |
174 | 1.10k | { |
175 | 1.10k | res->howto = &arm_howto_table[7]; |
176 | 1.10k | res->address = res[-1].address; |
177 | 1.10k | return true; |
178 | 1.10k | } |
179 | 408 | else if (reloc.r_length == 1) |
180 | 259 | { |
181 | 259 | res->howto = &arm_howto_table[10]; |
182 | 259 | res->address = res[-1].address; |
183 | 259 | return true; |
184 | 259 | } |
185 | 149 | _bfd_error_handler (_("malformed mach-o ARM reloc pair: " |
186 | 149 | "invalid length: %d"), reloc.r_length); |
187 | 149 | return false; |
188 | | |
189 | 1.07k | case BFD_MACH_O_ARM_RELOC_SECTDIFF: |
190 | 1.07k | if (reloc.r_length == 2) |
191 | 362 | { |
192 | 362 | res->howto = &arm_howto_table[5]; |
193 | 362 | return true; |
194 | 362 | } |
195 | 711 | else if (reloc.r_length == 1) |
196 | 347 | { |
197 | 347 | res->howto = &arm_howto_table[8]; |
198 | 347 | return true; |
199 | 347 | } |
200 | 364 | _bfd_error_handler (_("malformed mach-o ARM sectdiff reloc: " |
201 | 364 | "invalid length: %d"), reloc.r_length); |
202 | 364 | return false; |
203 | | |
204 | 2.92k | case BFD_MACH_O_ARM_RELOC_LOCAL_SECTDIFF: |
205 | 2.92k | if (reloc.r_length == 2) |
206 | 309 | { |
207 | 309 | res->howto = &arm_howto_table[6]; |
208 | 309 | return true; |
209 | 309 | } |
210 | 2.61k | else if (reloc.r_length == 1) |
211 | 2.25k | { |
212 | 2.25k | res->howto = &arm_howto_table[9]; |
213 | 2.25k | return true; |
214 | 2.25k | } |
215 | 361 | _bfd_error_handler (_("malformed mach-o ARM local sectdiff reloc: " |
216 | 361 | "invalid length: %d"), |
217 | 361 | reloc.r_length); |
218 | 361 | return false; |
219 | | |
220 | 3.70M | case BFD_MACH_O_ARM_RELOC_HALF_SECTDIFF: |
221 | 3.70M | switch (reloc.r_length) |
222 | 3.70M | { |
223 | 3.65M | case 2: /* :lower16: for movw arm. */ |
224 | 3.65M | res->howto = &arm_howto_table[12]; |
225 | 3.65M | return true; |
226 | 51.1k | case 3: /* :upper16: for movt arm. */ |
227 | 51.1k | res->howto = &arm_howto_table[14]; |
228 | 51.1k | return true; |
229 | 3.70M | } |
230 | 326 | _bfd_error_handler (_("malformed mach-o ARM half sectdiff reloc: " |
231 | 326 | "invalid length: %d"), |
232 | 326 | reloc.r_length); |
233 | 326 | return false; |
234 | | |
235 | 19.3k | default: |
236 | 19.3k | break; |
237 | 3.73M | } |
238 | 3.73M | } |
239 | 2.29M | else |
240 | 2.29M | { |
241 | 2.29M | switch (reloc.r_type) |
242 | 2.29M | { |
243 | 2.28M | case BFD_MACH_O_ARM_RELOC_VANILLA: |
244 | 2.28M | switch ((reloc.r_length << 1) | reloc.r_pcrel) |
245 | 2.28M | { |
246 | 2.27M | case 0: /* len = 0, pcrel = 0 */ |
247 | 2.27M | res->howto = &arm_howto_table[2]; |
248 | 2.27M | return true; |
249 | 679 | case 2: /* len = 1, pcrel = 0 */ |
250 | 679 | res->howto = &arm_howto_table[1]; |
251 | 679 | return true; |
252 | 2.95k | case 3: /* len = 1, pcrel = 1 */ |
253 | 2.95k | res->howto = &arm_howto_table[4]; |
254 | 2.95k | return true; |
255 | 489 | case 4: /* len = 2, pcrel = 0 */ |
256 | 489 | res->howto = &arm_howto_table[0]; |
257 | 489 | return true; |
258 | 401 | case 5: /* len = 2, pcrel = 1 */ |
259 | 401 | res->howto = &arm_howto_table[3]; |
260 | 401 | return true; |
261 | 2.41k | default: |
262 | 2.41k | _bfd_error_handler (_("malformed mach-o ARM vanilla reloc: " |
263 | 2.41k | "invalid length: %d (pcrel: %d)"), |
264 | 2.41k | reloc.r_length, reloc.r_pcrel); |
265 | 2.41k | return false; |
266 | 2.28M | } |
267 | 0 | break; |
268 | | |
269 | 2.41k | case BFD_MACH_O_ARM_RELOC_BR24: |
270 | 2.41k | if (reloc.r_length == 2 && reloc.r_pcrel == 1) |
271 | 393 | { |
272 | 393 | res->howto = &arm_howto_table[11]; |
273 | 393 | return true; |
274 | 393 | } |
275 | 2.01k | break; |
276 | | |
277 | 2.01k | case BFD_MACH_O_THUMB_RELOC_BR22: |
278 | 1.73k | if (reloc.r_length == 2 && reloc.r_pcrel == 1) |
279 | 753 | { |
280 | 753 | res->howto = &arm_howto_table[16]; |
281 | 753 | return true; |
282 | 753 | } |
283 | 981 | break; |
284 | | |
285 | 1.30k | case BFD_MACH_O_ARM_RELOC_HALF: |
286 | 1.30k | if (reloc.r_pcrel == 0) |
287 | 968 | switch (reloc.r_length) |
288 | 968 | { |
289 | 736 | case 0: /* :lower16: for movw arm. */ |
290 | 736 | res->howto = &arm_howto_table[12]; |
291 | 736 | return true; |
292 | 119 | case 1: /* :upper16: for movt arm. */ |
293 | 119 | res->howto = &arm_howto_table[14]; |
294 | 119 | return true; |
295 | 968 | } |
296 | 454 | break; |
297 | | |
298 | 3.63k | case BFD_MACH_O_ARM_RELOC_PAIR: |
299 | 3.63k | if (res == res_base) |
300 | 1.68k | { |
301 | 1.68k | _bfd_error_handler (_("malformed mach-o ARM reloc pair: " |
302 | 1.68k | "reloc is first reloc")); |
303 | 1.68k | return false; |
304 | 1.68k | } |
305 | 1.94k | if (res[-1].howto == &arm_howto_table[12] |
306 | 1.94k | && reloc.r_length == 0) |
307 | 325 | { |
308 | | /* Pair for :lower16: of movw arm. */ |
309 | 325 | res->howto = &arm_howto_table[13]; |
310 | | /* This reloc contains the other half in its r_address field. */ |
311 | 325 | res[-1].addend += (res->address & 0xffff) << 16; |
312 | 325 | res->address = res[-1].address; |
313 | 325 | return true; |
314 | 325 | } |
315 | 1.62k | else if (res[-1].howto == &arm_howto_table[14] |
316 | 1.62k | && reloc.r_length == 1) |
317 | 87 | { |
318 | | /* Pair for :upper16: of movt arm. */ |
319 | 87 | res->howto = &arm_howto_table[15]; |
320 | | /* This reloc contains the other half in its r_address field. */ |
321 | 87 | res[-1].addend += res->address & 0xffff; |
322 | 87 | res->address = res[-1].address; |
323 | 87 | return true; |
324 | 87 | } |
325 | 1.53k | break; |
326 | | |
327 | 5.34k | default: |
328 | 5.34k | break; |
329 | 2.29M | } |
330 | 2.29M | } |
331 | | |
332 | 29.6k | _bfd_error_handler (_("malformed mach-o ARM reloc: " |
333 | 29.6k | "unknown reloc type: %d"), reloc.r_length); |
334 | 29.6k | return false; |
335 | 6.03M | } |
336 | | |
337 | | static reloc_howto_type * |
338 | | bfd_mach_o_arm_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
339 | | bfd_reloc_code_real_type code) |
340 | 0 | { |
341 | 0 | unsigned int i; |
342 | |
|
343 | 0 | for (i = 0; i < sizeof (arm_howto_table) / sizeof (*arm_howto_table); i++) |
344 | 0 | if (code == arm_howto_table[i].type) |
345 | 0 | return &arm_howto_table[i]; |
346 | 0 | return NULL; |
347 | 0 | } |
348 | | |
349 | | static reloc_howto_type * |
350 | | bfd_mach_o_arm_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
351 | | const char *name ATTRIBUTE_UNUSED) |
352 | 0 | { |
353 | 0 | return NULL; |
354 | 0 | } |
355 | | |
356 | | #define TARGET_NAME arm_mach_o_vec |
357 | | #define TARGET_STRING "mach-o-arm" |
358 | | #define TARGET_ARCHITECTURE bfd_arch_arm |
359 | | #define TARGET_PAGESIZE 4096 |
360 | | #define TARGET_BIG_ENDIAN 0 |
361 | | #define TARGET_ARCHIVE 0 |
362 | | #define TARGET_PRIORITY 0 |
363 | | #include "mach-o-target.c" |