1 1.1 christos /* ARM Mach-O support for BFD. 2 1.1.1.6 christos Copyright (C) 2015-2024 Free Software Foundation, Inc. 3 1.1 christos 4 1.1 christos This file is part of BFD, the Binary File Descriptor library. 5 1.1 christos 6 1.1 christos This program is free software; you can redistribute it and/or modify 7 1.1 christos it under the terms of the GNU General Public License as published by 8 1.1 christos the Free Software Foundation; either version 3 of the License, or 9 1.1 christos (at your option) any later version. 10 1.1 christos 11 1.1 christos This program is distributed in the hope that it will be useful, 12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos GNU General Public License for more details. 15 1.1 christos 16 1.1 christos You should have received a copy of the GNU General Public License 17 1.1 christos along with this program; if not, write to the Free Software 18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 1.1 christos MA 02110-1301, USA. */ 20 1.1 christos 21 1.1 christos #include "sysdep.h" 22 1.1 christos #include "bfd.h" 23 1.1 christos #include "libbfd.h" 24 1.1 christos #include "libiberty.h" 25 1.1.1.3 christos #include "mach-o.h" 26 1.1 christos #include "mach-o/arm.h" 27 1.1 christos 28 1.1 christos #define bfd_mach_o_object_p bfd_mach_o_arm_object_p 29 1.1 christos #define bfd_mach_o_core_p bfd_mach_o_arm_core_p 30 1.1 christos #define bfd_mach_o_mkobject bfd_mach_o_arm_mkobject 31 1.1 christos 32 1.1 christos #define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_arm_canonicalize_one_reloc 33 1.1.1.3 christos #define bfd_mach_o_swap_reloc_out NULL 34 1.1 christos #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm_bfd_reloc_type_lookup 35 1.1 christos #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm_bfd_reloc_name_lookup 36 1.1 christos 37 1.1 christos #define bfd_mach_o_print_thread NULL 38 1.1 christos #define bfd_mach_o_tgt_seg_table NULL 39 1.1 christos #define bfd_mach_o_section_type_valid_for_tgt NULL 40 1.1 christos 41 1.1.1.4 christos static bfd_cleanup 42 1.1 christos bfd_mach_o_arm_object_p (bfd *abfd) 43 1.1 christos { 44 1.1 christos return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM); 45 1.1 christos } 46 1.1 christos 47 1.1.1.4 christos static bfd_cleanup 48 1.1 christos bfd_mach_o_arm_core_p (bfd *abfd) 49 1.1 christos { 50 1.1 christos return bfd_mach_o_header_p (abfd, 0, 51 1.1.1.3 christos BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM); 52 1.1 christos } 53 1.1 christos 54 1.1.1.5 christos static bool 55 1.1 christos bfd_mach_o_arm_mkobject (bfd *abfd) 56 1.1 christos { 57 1.1 christos bfd_mach_o_data_struct *mdata; 58 1.1 christos 59 1.1 christos if (!bfd_mach_o_mkobject_init (abfd)) 60 1.1.1.5 christos return false; 61 1.1 christos 62 1.1 christos mdata = bfd_mach_o_get_data (abfd); 63 1.1 christos mdata->header.magic = BFD_MACH_O_MH_MAGIC; 64 1.1 christos mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM; 65 1.1 christos mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM_ALL; 66 1.1 christos mdata->header.byteorder = BFD_ENDIAN_LITTLE; 67 1.1 christos mdata->header.version = 1; 68 1.1 christos 69 1.1.1.5 christos return true; 70 1.1 christos } 71 1.1 christos 72 1.1 christos static reloc_howto_type arm_howto_table[]= 73 1.1 christos { 74 1.1 christos /* 0 */ 75 1.1.1.5 christos HOWTO (BFD_RELOC_32, 0, 4, 32, false, 0, 76 1.1 christos complain_overflow_bitfield, 77 1.1 christos NULL, "32", 78 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 79 1.1.1.5 christos HOWTO (BFD_RELOC_16, 0, 2, 16, false, 0, 80 1.1 christos complain_overflow_bitfield, 81 1.1 christos NULL, "16", 82 1.1.1.5 christos false, 0xffff, 0xffff, false), 83 1.1.1.5 christos HOWTO (BFD_RELOC_8, 0, 1, 8, false, 0, 84 1.1 christos complain_overflow_bitfield, 85 1.1 christos NULL, "8", 86 1.1.1.5 christos false, 0xff, 0xff, false), 87 1.1.1.5 christos HOWTO (BFD_RELOC_32_PCREL, 0, 4, 32, true, 0, 88 1.1 christos complain_overflow_bitfield, 89 1.1 christos NULL, "DISP32", 90 1.1.1.5 christos false, 0xffffffff, 0xffffffff, true), 91 1.1 christos /* 4 */ 92 1.1.1.5 christos HOWTO (BFD_RELOC_16_PCREL, 0, 2, 16, true, 0, 93 1.1 christos complain_overflow_bitfield, 94 1.1 christos NULL, "DISP16", 95 1.1.1.5 christos false, 0xffff, 0xffff, true), 96 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 4, 32, false, 0, 97 1.1 christos complain_overflow_bitfield, 98 1.1 christos NULL, "SECTDIFF_32", 99 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 100 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_LOCAL_SECTDIFF, 0, 4, 32, false, 0, 101 1.1 christos complain_overflow_bitfield, 102 1.1 christos NULL, "LSECTDIFF_32", 103 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 104 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 32, false, 0, 105 1.1 christos complain_overflow_bitfield, 106 1.1 christos NULL, "PAIR_32", 107 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 108 1.1 christos /* 8 */ 109 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 2, 16, false, 0, 110 1.1 christos complain_overflow_bitfield, 111 1.1 christos NULL, "SECTDIFF_16", 112 1.1.1.5 christos false, 0xffff, 0xffff, false), 113 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_LOCAL_SECTDIFF, 0, 2, 16, false, 0, 114 1.1 christos complain_overflow_bitfield, 115 1.1 christos NULL, "LSECTDIFF_16", 116 1.1.1.5 christos false, 0xffff, 0xffff, false), 117 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 2, 16, false, 0, 118 1.1 christos complain_overflow_bitfield, 119 1.1 christos NULL, "PAIR_16", 120 1.1.1.5 christos false, 0xffff, 0xffff, false), 121 1.1.1.5 christos HOWTO (BFD_RELOC_ARM_PCREL_CALL, 2, 4, 24, true, 0, 122 1.1 christos complain_overflow_signed, 123 1.1 christos NULL, "BR24", 124 1.1.1.5 christos false, 0x00ffffff, 0x00ffffff, true), 125 1.1 christos /* 12 */ 126 1.1.1.5 christos HOWTO (BFD_RELOC_ARM_MOVW, 0, 4, 16, false, 0, 127 1.1 christos complain_overflow_dont, 128 1.1 christos NULL, "MOVW", 129 1.1.1.5 christos false, 0x000f0fff, 0x000f0fff, false), 130 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 16, false, 0, 131 1.1 christos complain_overflow_bitfield, 132 1.1 christos NULL, "PAIR_W", 133 1.1.1.5 christos false, 0x000f0fff, 0x000f0fff, false), 134 1.1.1.5 christos HOWTO (BFD_RELOC_ARM_MOVT, 0, 4, 16, false, 0, 135 1.1 christos complain_overflow_bitfield, 136 1.1 christos NULL, "MOVT", 137 1.1.1.5 christos false, 0x000f0fff, 0x000f0fff, false), 138 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 16, false, 0, 139 1.1 christos complain_overflow_bitfield, 140 1.1 christos NULL, "PAIR_T", 141 1.1.1.5 christos false, 0x000f0fff, 0x000f0fff, false), 142 1.1 christos /* 16 */ 143 1.1.1.5 christos HOWTO (BFD_RELOC_THUMB_PCREL_BLX, 2, 4, 24, true, 0, 144 1.1 christos complain_overflow_signed, 145 1.1 christos NULL, "TBR22", 146 1.1.1.5 christos false, 0x07ff2fff, 0x07ff2fff, true) 147 1.1 christos }; 148 1.1 christos 149 1.1.1.5 christos static bool 150 1.1.1.3 christos bfd_mach_o_arm_canonicalize_one_reloc (bfd * abfd, 151 1.1.1.3 christos struct mach_o_reloc_info_external * raw, 152 1.1.1.3 christos arelent * res, 153 1.1.1.3 christos asymbol ** syms, 154 1.1.1.3 christos arelent * res_base) 155 1.1.1.3 christos { 156 1.1 christos bfd_mach_o_reloc_info reloc; 157 1.1 christos 158 1.1 christos if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms)) 159 1.1.1.5 christos return false; 160 1.1 christos 161 1.1 christos if (reloc.r_scattered) 162 1.1 christos { 163 1.1 christos switch (reloc.r_type) 164 1.1.1.3 christos { 165 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_PAIR: 166 1.1.1.3 christos /* PR 21813: Check for a corrupt PAIR reloc at the start. */ 167 1.1.1.3 christos if (res == res_base) 168 1.1.1.4 christos { 169 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM reloc pair: " 170 1.1.1.5 christos "reloc is first reloc")); 171 1.1.1.5 christos return false; 172 1.1.1.4 christos } 173 1.1.1.3 christos if (reloc.r_length == 2) 174 1.1.1.3 christos { 175 1.1 christos res->howto = &arm_howto_table[7]; 176 1.1 christos res->address = res[-1].address; 177 1.1.1.5 christos return true; 178 1.1.1.3 christos } 179 1.1.1.3 christos else if (reloc.r_length == 1) 180 1.1 christos { 181 1.1 christos res->howto = &arm_howto_table[10]; 182 1.1 christos res->address = res[-1].address; 183 1.1.1.5 christos return true; 184 1.1 christos } 185 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM reloc pair: " 186 1.1.1.5 christos "invalid length: %d"), reloc.r_length); 187 1.1.1.5 christos return false; 188 1.1.1.3 christos 189 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_SECTDIFF: 190 1.1.1.3 christos if (reloc.r_length == 2) 191 1.1.1.3 christos { 192 1.1 christos res->howto = &arm_howto_table[5]; 193 1.1.1.5 christos return true; 194 1.1.1.3 christos } 195 1.1.1.3 christos else if (reloc.r_length == 1) 196 1.1.1.3 christos { 197 1.1 christos res->howto = &arm_howto_table[8]; 198 1.1.1.5 christos return true; 199 1.1.1.3 christos } 200 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM sectdiff reloc: " 201 1.1.1.5 christos "invalid length: %d"), reloc.r_length); 202 1.1.1.5 christos return false; 203 1.1.1.3 christos 204 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_LOCAL_SECTDIFF: 205 1.1.1.3 christos if (reloc.r_length == 2) 206 1.1.1.3 christos { 207 1.1 christos res->howto = &arm_howto_table[6]; 208 1.1.1.5 christos return true; 209 1.1.1.3 christos } 210 1.1.1.3 christos else if (reloc.r_length == 1) 211 1.1.1.3 christos { 212 1.1 christos res->howto = &arm_howto_table[9]; 213 1.1.1.5 christos return true; 214 1.1.1.3 christos } 215 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM local sectdiff reloc: " 216 1.1.1.5 christos "invalid length: %d"), 217 1.1.1.4 christos reloc.r_length); 218 1.1.1.5 christos return false; 219 1.1.1.3 christos 220 1.1 christos case BFD_MACH_O_ARM_RELOC_HALF_SECTDIFF: 221 1.1 christos switch (reloc.r_length) 222 1.1 christos { 223 1.1 christos case 2: /* :lower16: for movw arm. */ 224 1.1 christos res->howto = &arm_howto_table[12]; 225 1.1.1.5 christos return true; 226 1.1 christos case 3: /* :upper16: for movt arm. */ 227 1.1 christos res->howto = &arm_howto_table[14]; 228 1.1.1.5 christos return true; 229 1.1 christos } 230 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM half sectdiff reloc: " 231 1.1.1.5 christos "invalid length: %d"), 232 1.1.1.4 christos reloc.r_length); 233 1.1.1.5 christos return false; 234 1.1.1.3 christos 235 1.1.1.3 christos default: 236 1.1.1.3 christos break; 237 1.1.1.3 christos } 238 1.1 christos } 239 1.1 christos else 240 1.1 christos { 241 1.1 christos switch (reloc.r_type) 242 1.1.1.3 christos { 243 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_VANILLA: 244 1.1.1.3 christos switch ((reloc.r_length << 1) | reloc.r_pcrel) 245 1.1.1.3 christos { 246 1.1.1.3 christos case 0: /* len = 0, pcrel = 0 */ 247 1.1.1.3 christos res->howto = &arm_howto_table[2]; 248 1.1.1.5 christos return true; 249 1.1.1.3 christos case 2: /* len = 1, pcrel = 0 */ 250 1.1.1.3 christos res->howto = &arm_howto_table[1]; 251 1.1.1.5 christos return true; 252 1.1.1.3 christos case 3: /* len = 1, pcrel = 1 */ 253 1.1.1.3 christos res->howto = &arm_howto_table[4]; 254 1.1.1.5 christos return true; 255 1.1.1.3 christos case 4: /* len = 2, pcrel = 0 */ 256 1.1.1.3 christos res->howto = &arm_howto_table[0]; 257 1.1.1.5 christos return true; 258 1.1.1.3 christos case 5: /* len = 2, pcrel = 1 */ 259 1.1.1.3 christos res->howto = &arm_howto_table[3]; 260 1.1.1.5 christos return true; 261 1.1.1.3 christos default: 262 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM vanilla reloc: " 263 1.1.1.5 christos "invalid length: %d (pcrel: %d)"), 264 1.1.1.4 christos reloc.r_length, reloc.r_pcrel); 265 1.1.1.5 christos return false; 266 1.1.1.3 christos } 267 1.1.1.3 christos break; 268 1.1.1.3 christos 269 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_BR24: 270 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 1) 271 1.1 christos { 272 1.1.1.3 christos res->howto = &arm_howto_table[11]; 273 1.1.1.5 christos return true; 274 1.1 christos } 275 1.1 christos break; 276 1.1.1.3 christos 277 1.1.1.3 christos case BFD_MACH_O_THUMB_RELOC_BR22: 278 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 1) 279 1.1 christos { 280 1.1.1.3 christos res->howto = &arm_howto_table[16]; 281 1.1.1.5 christos return true; 282 1.1 christos } 283 1.1 christos break; 284 1.1.1.3 christos 285 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_HALF: 286 1.1 christos if (reloc.r_pcrel == 0) 287 1.1 christos switch (reloc.r_length) 288 1.1 christos { 289 1.1 christos case 0: /* :lower16: for movw arm. */ 290 1.1 christos res->howto = &arm_howto_table[12]; 291 1.1.1.5 christos return true; 292 1.1 christos case 1: /* :upper16: for movt arm. */ 293 1.1 christos res->howto = &arm_howto_table[14]; 294 1.1.1.5 christos return true; 295 1.1 christos } 296 1.1.1.3 christos break; 297 1.1.1.3 christos 298 1.1.1.3 christos case BFD_MACH_O_ARM_RELOC_PAIR: 299 1.1.1.5 christos if (res == res_base) 300 1.1.1.5 christos { 301 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM reloc pair: " 302 1.1.1.5 christos "reloc is first reloc")); 303 1.1.1.5 christos return false; 304 1.1.1.5 christos } 305 1.1 christos if (res[-1].howto == &arm_howto_table[12] 306 1.1 christos && reloc.r_length == 0) 307 1.1 christos { 308 1.1 christos /* Pair for :lower16: of movw arm. */ 309 1.1 christos res->howto = &arm_howto_table[13]; 310 1.1 christos /* This reloc contains the other half in its r_address field. */ 311 1.1 christos res[-1].addend += (res->address & 0xffff) << 16; 312 1.1 christos res->address = res[-1].address; 313 1.1.1.5 christos return true; 314 1.1.1.3 christos } 315 1.1 christos else if (res[-1].howto == &arm_howto_table[14] 316 1.1 christos && reloc.r_length == 1) 317 1.1 christos { 318 1.1 christos /* Pair for :upper16: of movt arm. */ 319 1.1 christos res->howto = &arm_howto_table[15]; 320 1.1 christos /* This reloc contains the other half in its r_address field. */ 321 1.1 christos res[-1].addend += res->address & 0xffff; 322 1.1 christos res->address = res[-1].address; 323 1.1.1.5 christos return true; 324 1.1.1.3 christos } 325 1.1.1.3 christos break; 326 1.1.1.3 christos 327 1.1.1.3 christos default: 328 1.1.1.3 christos break; 329 1.1.1.3 christos } 330 1.1 christos } 331 1.1.1.3 christos 332 1.1.1.5 christos _bfd_error_handler (_("malformed mach-o ARM reloc: " 333 1.1.1.5 christos "unknown reloc type: %d"), reloc.r_length); 334 1.1.1.5 christos return false; 335 1.1 christos } 336 1.1 christos 337 1.1 christos static reloc_howto_type * 338 1.1 christos bfd_mach_o_arm_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 339 1.1 christos bfd_reloc_code_real_type code) 340 1.1 christos { 341 1.1 christos unsigned int i; 342 1.1 christos 343 1.1 christos for (i = 0; i < sizeof (arm_howto_table) / sizeof (*arm_howto_table); i++) 344 1.1 christos if (code == arm_howto_table[i].type) 345 1.1 christos return &arm_howto_table[i]; 346 1.1 christos return NULL; 347 1.1 christos } 348 1.1 christos 349 1.1 christos static reloc_howto_type * 350 1.1 christos bfd_mach_o_arm_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 351 1.1 christos const char *name ATTRIBUTE_UNUSED) 352 1.1 christos { 353 1.1 christos return NULL; 354 1.1 christos } 355 1.1 christos 356 1.1.1.3 christos #define TARGET_NAME arm_mach_o_vec 357 1.1.1.3 christos #define TARGET_STRING "mach-o-arm" 358 1.1 christos #define TARGET_ARCHITECTURE bfd_arch_arm 359 1.1 christos #define TARGET_PAGESIZE 4096 360 1.1.1.3 christos #define TARGET_BIG_ENDIAN 0 361 1.1.1.3 christos #define TARGET_ARCHIVE 0 362 1.1 christos #define TARGET_PRIORITY 0 363 1.1 christos #include "mach-o-target.c" 364