1 1.1 christos /* AArch-64 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/arm64.h" 27 1.1 christos 28 1.1 christos #define bfd_mach_o_object_p bfd_mach_o_arm64_object_p 29 1.1 christos #define bfd_mach_o_core_p bfd_mach_o_arm64_core_p 30 1.1 christos #define bfd_mach_o_mkobject bfd_mach_o_arm64_mkobject 31 1.1 christos 32 1.1 christos #define bfd_mach_o_canonicalize_one_reloc \ 33 1.1 christos bfd_mach_o_arm64_canonicalize_one_reloc 34 1.1 christos #define bfd_mach_o_swap_reloc_out NULL 35 1.1 christos 36 1.1 christos #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm64_bfd_reloc_type_lookup 37 1.1 christos #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm64_bfd_reloc_name_lookup 38 1.1 christos 39 1.1 christos #define bfd_mach_o_print_thread NULL 40 1.1 christos #define bfd_mach_o_tgt_seg_table NULL 41 1.1 christos #define bfd_mach_o_section_type_valid_for_tgt NULL 42 1.1 christos 43 1.1.1.4 christos static bfd_cleanup 44 1.1 christos bfd_mach_o_arm64_object_p (bfd *abfd) 45 1.1 christos { 46 1.1 christos return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM64); 47 1.1 christos } 48 1.1 christos 49 1.1.1.4 christos static bfd_cleanup 50 1.1 christos bfd_mach_o_arm64_core_p (bfd *abfd) 51 1.1 christos { 52 1.1 christos return bfd_mach_o_header_p (abfd, 0, 53 1.1.1.3 christos BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM64); 54 1.1 christos } 55 1.1 christos 56 1.1.1.5 christos static bool 57 1.1 christos bfd_mach_o_arm64_mkobject (bfd *abfd) 58 1.1 christos { 59 1.1 christos bfd_mach_o_data_struct *mdata; 60 1.1 christos 61 1.1 christos if (!bfd_mach_o_mkobject_init (abfd)) 62 1.1.1.5 christos return false; 63 1.1 christos 64 1.1 christos mdata = bfd_mach_o_get_data (abfd); 65 1.1 christos mdata->header.magic = BFD_MACH_O_MH_MAGIC; 66 1.1 christos mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM64; 67 1.1 christos mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM64_ALL; 68 1.1 christos mdata->header.byteorder = BFD_ENDIAN_LITTLE; 69 1.1 christos mdata->header.version = 1; 70 1.1 christos 71 1.1.1.5 christos return true; 72 1.1 christos } 73 1.1 christos 74 1.1 christos /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ 75 1.1 christos #define MINUS_ONE (~ (bfd_vma) 0) 76 1.1 christos 77 1.1 christos static reloc_howto_type arm64_howto_table[]= 78 1.1 christos { 79 1.1 christos /* 0 */ 80 1.1.1.5 christos HOWTO (BFD_RELOC_64, 0, 8, 64, false, 0, 81 1.1 christos complain_overflow_bitfield, 82 1.1 christos NULL, "64", 83 1.1.1.5 christos false, MINUS_ONE, MINUS_ONE, false), 84 1.1.1.5 christos HOWTO (BFD_RELOC_32, 0, 4, 32, false, 0, 85 1.1 christos complain_overflow_bitfield, 86 1.1 christos NULL, "32", 87 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 88 1.1.1.5 christos HOWTO (BFD_RELOC_16, 0, 2, 16, false, 0, 89 1.1 christos complain_overflow_bitfield, 90 1.1 christos NULL, "16", 91 1.1.1.5 christos false, 0xffff, 0xffff, false), 92 1.1.1.5 christos HOWTO (BFD_RELOC_8, 0, 1, 8, false, 0, 93 1.1 christos complain_overflow_bitfield, 94 1.1 christos NULL, "8", 95 1.1.1.5 christos false, 0xff, 0xff, false), 96 1.1 christos /* 4 */ 97 1.1.1.5 christos HOWTO (BFD_RELOC_64_PCREL, 0, 8, 64, true, 0, 98 1.1 christos complain_overflow_bitfield, 99 1.1 christos NULL, "DISP64", 100 1.1.1.5 christos false, MINUS_ONE, MINUS_ONE, true), 101 1.1.1.5 christos HOWTO (BFD_RELOC_32_PCREL, 0, 4, 32, true, 0, 102 1.1 christos complain_overflow_bitfield, 103 1.1 christos NULL, "DISP32", 104 1.1.1.5 christos false, 0xffffffff, 0xffffffff, true), 105 1.1.1.5 christos HOWTO (BFD_RELOC_16_PCREL, 0, 2, 16, true, 0, 106 1.1 christos complain_overflow_bitfield, 107 1.1 christos NULL, "DISP16", 108 1.1.1.5 christos false, 0xffff, 0xffff, true), 109 1.1.1.5 christos HOWTO (BFD_RELOC_AARCH64_CALL26, 0, 4, 26, true, 0, 110 1.1 christos complain_overflow_bitfield, 111 1.1 christos NULL, "BRANCH26", 112 1.1.1.5 christos false, 0x03ffffff, 0x03ffffff, true), 113 1.1 christos /* 8 */ 114 1.1.1.5 christos HOWTO (BFD_RELOC_AARCH64_ADR_HI21_PCREL, 12, 4, 21, true, 0, 115 1.1 christos complain_overflow_signed, 116 1.1 christos NULL, "PAGE21", 117 1.1.1.5 christos false, 0x1fffff, 0x1fffff, true), 118 1.1.1.5 christos HOWTO (BFD_RELOC_AARCH64_LDST16_LO12, 1, 4, 12, true, 0, 119 1.1 christos complain_overflow_signed, 120 1.1 christos NULL, "PGOFF12", 121 1.1.1.5 christos false, 0xffe, 0xffe, true), 122 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_ARM64_ADDEND, 0, 4, 32, false, 0, 123 1.1 christos complain_overflow_signed, 124 1.1 christos NULL, "ADDEND", 125 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 126 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_SUBTRACTOR32, 0, 4, 32, false, 0, 127 1.1 christos complain_overflow_bitfield, 128 1.1 christos NULL, "SUBTRACTOR32", 129 1.1.1.5 christos false, 0xffffffff, 0xffffffff, false), 130 1.1 christos /* 12 */ 131 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_SUBTRACTOR64, 0, 8, 64, false, 0, 132 1.1 christos complain_overflow_bitfield, 133 1.1 christos NULL, "SUBTRACTOR64", 134 1.1.1.5 christos false, MINUS_ONE, MINUS_ONE, false), 135 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_ARM64_GOT_LOAD_PAGE21, 12, 4, 21, true, 0, 136 1.1 christos complain_overflow_signed, 137 1.1 christos NULL, "GOT_LD_PG21", 138 1.1.1.5 christos false, 0x1fffff, 0x1fffff, true), 139 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_ARM64_GOT_LOAD_PAGEOFF12, 1, 4, 12, true, 0, 140 1.1 christos complain_overflow_signed, 141 1.1 christos NULL, "GOT_LD_PGOFF12", 142 1.1.1.5 christos false, 0xffe, 0xffe, true), 143 1.1.1.5 christos HOWTO (BFD_RELOC_MACH_O_ARM64_POINTER_TO_GOT, 0, 4, 32, true, 0, 144 1.1 christos complain_overflow_bitfield, 145 1.1 christos NULL, "PTR_TO_GOT", 146 1.1.1.5 christos false, 0xffffffff, 0xffffffff, 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_arm64_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 ATTRIBUTE_UNUSED) 155 1.1 christos { 156 1.1 christos bfd_mach_o_reloc_info reloc; 157 1.1 christos 158 1.1 christos res->address = bfd_get_32 (abfd, raw->r_address); 159 1.1 christos if (res->address & BFD_MACH_O_SR_SCATTERED) 160 1.1 christos { 161 1.1 christos /* Only non-scattered relocations. */ 162 1.1.1.5 christos return false; 163 1.1 christos } 164 1.1 christos 165 1.1 christos /* The value and info fields have to be extracted dependent on target 166 1.1 christos endian-ness. */ 167 1.1 christos bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum); 168 1.1 christos 169 1.1 christos if (reloc.r_type == BFD_MACH_O_ARM64_RELOC_ADDEND) 170 1.1 christos { 171 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 0) 172 1.1 christos { 173 1.1.1.7 christos res->sym_ptr_ptr = &bfd_abs_section_ptr->symbol; 174 1.1 christos res->addend = reloc.r_value; 175 1.1 christos res->howto = &arm64_howto_table[10]; 176 1.1.1.5 christos return true; 177 1.1 christos } 178 1.1.1.5 christos return false; 179 1.1 christos } 180 1.1 christos 181 1.1 christos if (!bfd_mach_o_canonicalize_non_scattered_reloc (abfd, &reloc, res, syms)) 182 1.1.1.5 christos return false; 183 1.1 christos 184 1.1 christos switch (reloc.r_type) 185 1.1 christos { 186 1.1 christos case BFD_MACH_O_ARM64_RELOC_UNSIGNED: 187 1.1 christos switch ((reloc.r_length << 1) | reloc.r_pcrel) 188 1.1 christos { 189 1.1 christos case 0: /* len = 0, pcrel = 0 */ 190 1.1 christos res->howto = &arm64_howto_table[3]; 191 1.1.1.5 christos return true; 192 1.1 christos case 2: /* len = 1, pcrel = 0 */ 193 1.1 christos res->howto = &arm64_howto_table[2]; 194 1.1.1.5 christos return true; 195 1.1 christos case 3: /* len = 1, pcrel = 1 */ 196 1.1 christos res->howto = &arm64_howto_table[6]; 197 1.1.1.5 christos return true; 198 1.1 christos case 4: /* len = 2, pcrel = 0 */ 199 1.1 christos res->howto = &arm64_howto_table[1]; 200 1.1.1.5 christos return true; 201 1.1 christos case 5: /* len = 2, pcrel = 1 */ 202 1.1 christos res->howto = &arm64_howto_table[5]; 203 1.1.1.5 christos return true; 204 1.1 christos case 6: /* len = 3, pcrel = 0 */ 205 1.1 christos res->howto = &arm64_howto_table[0]; 206 1.1.1.5 christos return true; 207 1.1 christos case 7: /* len = 3, pcrel = 1 */ 208 1.1 christos res->howto = &arm64_howto_table[4]; 209 1.1.1.5 christos return true; 210 1.1 christos default: 211 1.1.1.5 christos return false; 212 1.1 christos } 213 1.1 christos break; 214 1.1 christos case BFD_MACH_O_ARM64_RELOC_SUBTRACTOR: 215 1.1 christos if (reloc.r_pcrel) 216 1.1.1.5 christos return false; 217 1.1 christos switch (reloc.r_length) 218 1.1.1.3 christos { 219 1.1.1.3 christos case 2: 220 1.1.1.3 christos res->howto = &arm64_howto_table[11]; 221 1.1.1.5 christos return true; 222 1.1.1.3 christos case 3: 223 1.1.1.3 christos res->howto = &arm64_howto_table[12]; 224 1.1.1.5 christos return true; 225 1.1.1.3 christos default: 226 1.1.1.5 christos return false; 227 1.1.1.3 christos } 228 1.1 christos break; 229 1.1 christos case BFD_MACH_O_ARM64_RELOC_BRANCH26: 230 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 1) 231 1.1 christos { 232 1.1 christos res->howto = &arm64_howto_table[7]; 233 1.1.1.5 christos return true; 234 1.1 christos } 235 1.1 christos break; 236 1.1 christos case BFD_MACH_O_ARM64_RELOC_PAGE21: 237 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 1) 238 1.1 christos { 239 1.1 christos res->howto = &arm64_howto_table[8]; 240 1.1.1.5 christos return true; 241 1.1 christos } 242 1.1 christos break; 243 1.1 christos case BFD_MACH_O_ARM64_RELOC_PAGEOFF12: 244 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 0) 245 1.1 christos { 246 1.1 christos res->howto = &arm64_howto_table[9]; 247 1.1.1.5 christos return true; 248 1.1 christos } 249 1.1 christos break; 250 1.1 christos case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGE21: 251 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 1) 252 1.1 christos { 253 1.1 christos res->howto = &arm64_howto_table[13]; 254 1.1.1.5 christos return true; 255 1.1 christos } 256 1.1 christos break; 257 1.1 christos case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGEOFF12: 258 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 0) 259 1.1 christos { 260 1.1 christos res->howto = &arm64_howto_table[14]; 261 1.1.1.5 christos return true; 262 1.1 christos } 263 1.1 christos break; 264 1.1 christos case BFD_MACH_O_ARM64_RELOC_POINTER_TO_GOT: 265 1.1 christos if (reloc.r_length == 2 && reloc.r_pcrel == 1) 266 1.1 christos { 267 1.1 christos res->howto = &arm64_howto_table[15]; 268 1.1.1.5 christos return true; 269 1.1 christos } 270 1.1 christos break; 271 1.1 christos default: 272 1.1 christos break; 273 1.1 christos } 274 1.1.1.5 christos return false; 275 1.1 christos } 276 1.1 christos 277 1.1 christos static reloc_howto_type * 278 1.1 christos bfd_mach_o_arm64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 279 1.1 christos bfd_reloc_code_real_type code) 280 1.1 christos { 281 1.1 christos unsigned int i; 282 1.1 christos 283 1.1 christos for (i = 0; 284 1.1 christos i < sizeof (arm64_howto_table) / sizeof (*arm64_howto_table); 285 1.1 christos i++) 286 1.1 christos if (code == arm64_howto_table[i].type) 287 1.1 christos return &arm64_howto_table[i]; 288 1.1 christos return NULL; 289 1.1 christos } 290 1.1 christos 291 1.1 christos static reloc_howto_type * 292 1.1 christos bfd_mach_o_arm64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 293 1.1 christos const char *name ATTRIBUTE_UNUSED) 294 1.1 christos { 295 1.1 christos return NULL; 296 1.1 christos } 297 1.1 christos 298 1.1.1.3 christos #define TARGET_NAME aarch64_mach_o_vec 299 1.1.1.3 christos #define TARGET_STRING "mach-o-arm64" 300 1.1 christos #define TARGET_ARCHITECTURE bfd_arch_aarch64 301 1.1 christos #define TARGET_PAGESIZE 4096 302 1.1.1.3 christos #define TARGET_BIG_ENDIAN 0 303 1.1.1.3 christos #define TARGET_ARCHIVE 0 304 1.1 christos #define TARGET_PRIORITY 0 305 1.1 christos #include "mach-o-target.c" 306 1.1 christos 307 1.1 christos #undef TARGET_NAME 308 1.1 christos #undef TARGET_STRING 309 1.1 christos #undef TARGET_ARCHIVE 310 1.1 christos #undef TARGET_PRIORITY 311