1 /* AArch-64 Mach-O support for BFD. 2 Copyright (C) 2015-2024 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 { 46 return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM64); 47 } 48 49 static bfd_cleanup 50 bfd_mach_o_arm64_core_p (bfd *abfd) 51 { 52 return bfd_mach_o_header_p (abfd, 0, 53 BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM64); 54 } 55 56 static bool 57 bfd_mach_o_arm64_mkobject (bfd *abfd) 58 { 59 bfd_mach_o_data_struct *mdata; 60 61 if (!bfd_mach_o_mkobject_init (abfd)) 62 return false; 63 64 mdata = bfd_mach_o_get_data (abfd); 65 mdata->header.magic = BFD_MACH_O_MH_MAGIC; 66 mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM64; 67 mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM64_ALL; 68 mdata->header.byteorder = BFD_ENDIAN_LITTLE; 69 mdata->header.version = 1; 70 71 return true; 72 } 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 { 156 bfd_mach_o_reloc_info reloc; 157 158 res->address = bfd_get_32 (abfd, raw->r_address); 159 if (res->address & BFD_MACH_O_SR_SCATTERED) 160 { 161 /* Only non-scattered relocations. */ 162 return false; 163 } 164 165 /* The value and info fields have to be extracted dependent on target 166 endian-ness. */ 167 bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum); 168 169 if (reloc.r_type == BFD_MACH_O_ARM64_RELOC_ADDEND) 170 { 171 if (reloc.r_length == 2 && reloc.r_pcrel == 0) 172 { 173 res->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 174 res->addend = reloc.r_value; 175 res->howto = &arm64_howto_table[10]; 176 return true; 177 } 178 return false; 179 } 180 181 if (!bfd_mach_o_canonicalize_non_scattered_reloc (abfd, &reloc, res, syms)) 182 return false; 183 184 switch (reloc.r_type) 185 { 186 case BFD_MACH_O_ARM64_RELOC_UNSIGNED: 187 switch ((reloc.r_length << 1) | reloc.r_pcrel) 188 { 189 case 0: /* len = 0, pcrel = 0 */ 190 res->howto = &arm64_howto_table[3]; 191 return true; 192 case 2: /* len = 1, pcrel = 0 */ 193 res->howto = &arm64_howto_table[2]; 194 return true; 195 case 3: /* len = 1, pcrel = 1 */ 196 res->howto = &arm64_howto_table[6]; 197 return true; 198 case 4: /* len = 2, pcrel = 0 */ 199 res->howto = &arm64_howto_table[1]; 200 return true; 201 case 5: /* len = 2, pcrel = 1 */ 202 res->howto = &arm64_howto_table[5]; 203 return true; 204 case 6: /* len = 3, pcrel = 0 */ 205 res->howto = &arm64_howto_table[0]; 206 return true; 207 case 7: /* len = 3, pcrel = 1 */ 208 res->howto = &arm64_howto_table[4]; 209 return true; 210 default: 211 return false; 212 } 213 break; 214 case BFD_MACH_O_ARM64_RELOC_SUBTRACTOR: 215 if (reloc.r_pcrel) 216 return false; 217 switch (reloc.r_length) 218 { 219 case 2: 220 res->howto = &arm64_howto_table[11]; 221 return true; 222 case 3: 223 res->howto = &arm64_howto_table[12]; 224 return true; 225 default: 226 return false; 227 } 228 break; 229 case BFD_MACH_O_ARM64_RELOC_BRANCH26: 230 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 231 { 232 res->howto = &arm64_howto_table[7]; 233 return true; 234 } 235 break; 236 case BFD_MACH_O_ARM64_RELOC_PAGE21: 237 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 238 { 239 res->howto = &arm64_howto_table[8]; 240 return true; 241 } 242 break; 243 case BFD_MACH_O_ARM64_RELOC_PAGEOFF12: 244 if (reloc.r_length == 2 && reloc.r_pcrel == 0) 245 { 246 res->howto = &arm64_howto_table[9]; 247 return true; 248 } 249 break; 250 case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGE21: 251 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 252 { 253 res->howto = &arm64_howto_table[13]; 254 return true; 255 } 256 break; 257 case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGEOFF12: 258 if (reloc.r_length == 2 && reloc.r_pcrel == 0) 259 { 260 res->howto = &arm64_howto_table[14]; 261 return true; 262 } 263 break; 264 case BFD_MACH_O_ARM64_RELOC_POINTER_TO_GOT: 265 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 266 { 267 res->howto = &arm64_howto_table[15]; 268 return true; 269 } 270 break; 271 default: 272 break; 273 } 274 return false; 275 } 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 { 281 unsigned int i; 282 283 for (i = 0; 284 i < sizeof (arm64_howto_table) / sizeof (*arm64_howto_table); 285 i++) 286 if (code == arm64_howto_table[i].type) 287 return &arm64_howto_table[i]; 288 return NULL; 289 } 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 { 295 return NULL; 296 } 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 311