1 /* AArch-64 Mach-O support for BFD. 2 Copyright (C) 2015-2016 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 "mach-o.h" 23 #include "bfd.h" 24 #include "libbfd.h" 25 #include "libiberty.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 const bfd_target * 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 const bfd_target * 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 bfd_boolean 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, 4, 64, FALSE, 0, 81 complain_overflow_bitfield, 82 NULL, "64", 83 FALSE, MINUS_ONE, MINUS_ONE, FALSE), 84 HOWTO (BFD_RELOC_32, 0, 2, 32, FALSE, 0, 85 complain_overflow_bitfield, 86 NULL, "32", 87 FALSE, 0xffffffff, 0xffffffff, FALSE), 88 HOWTO (BFD_RELOC_16, 0, 1, 16, FALSE, 0, 89 complain_overflow_bitfield, 90 NULL, "16", 91 FALSE, 0xffff, 0xffff, FALSE), 92 HOWTO (BFD_RELOC_8, 0, 0, 8, FALSE, 0, 93 complain_overflow_bitfield, 94 NULL, "8", 95 FALSE, 0xff, 0xff, FALSE), 96 /* 4 */ 97 HOWTO (BFD_RELOC_64_PCREL, 0, 4, 64, TRUE, 0, 98 complain_overflow_bitfield, 99 NULL, "DISP64", 100 FALSE, MINUS_ONE, MINUS_ONE, TRUE), 101 HOWTO (BFD_RELOC_32_PCREL, 0, 2, 32, TRUE, 0, 102 complain_overflow_bitfield, 103 NULL, "DISP32", 104 FALSE, 0xffffffff, 0xffffffff, TRUE), 105 HOWTO (BFD_RELOC_16_PCREL, 0, 1, 16, TRUE, 0, 106 complain_overflow_bitfield, 107 NULL, "DISP16", 108 FALSE, 0xffff, 0xffff, TRUE), 109 HOWTO (BFD_RELOC_AARCH64_CALL26, 0, 2, 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, 2, 21, TRUE, 0, 115 complain_overflow_signed, 116 NULL, "PAGE21", 117 FALSE, 0x1fffff, 0x1fffff, TRUE), 118 HOWTO (BFD_RELOC_AARCH64_LDST16_LO12, 1, 2, 12, TRUE, 0, 119 complain_overflow_signed, 120 NULL, "PGOFF12", 121 FALSE, 0xffe, 0xffe, TRUE), 122 HOWTO (BFD_RELOC_MACH_O_ARM64_ADDEND, 0, 2, 32, FALSE, 0, 123 complain_overflow_signed, 124 NULL, "ADDEND", 125 FALSE, 0xffffffff, 0xffffffff, FALSE), 126 HOWTO (BFD_RELOC_MACH_O_SUBTRACTOR32, 0, 2, 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, 4, 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, 2, 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, 2, 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, 2, 32, TRUE, 0, 144 complain_overflow_bitfield, 145 NULL, "PTR_TO_GOT", 146 FALSE, 0xffffffff, 0xffffffff, TRUE), 147 }; 148 149 static bfd_boolean 150 bfd_mach_o_arm64_canonicalize_one_reloc (bfd *abfd, 151 struct mach_o_reloc_info_external *raw, 152 arelent *res, asymbol **syms) 153 { 154 bfd_mach_o_reloc_info reloc; 155 156 res->address = bfd_get_32 (abfd, raw->r_address); 157 if (res->address & BFD_MACH_O_SR_SCATTERED) 158 { 159 /* Only non-scattered relocations. */ 160 return FALSE; 161 } 162 163 /* The value and info fields have to be extracted dependent on target 164 endian-ness. */ 165 bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum); 166 167 if (reloc.r_type == BFD_MACH_O_ARM64_RELOC_ADDEND) 168 { 169 if (reloc.r_length == 2 && reloc.r_pcrel == 0) 170 { 171 res->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 172 res->addend = reloc.r_value; 173 res->howto = &arm64_howto_table[10]; 174 return TRUE; 175 } 176 return FALSE; 177 } 178 179 if (!bfd_mach_o_canonicalize_non_scattered_reloc (abfd, &reloc, res, syms)) 180 return FALSE; 181 182 switch (reloc.r_type) 183 { 184 case BFD_MACH_O_ARM64_RELOC_UNSIGNED: 185 switch ((reloc.r_length << 1) | reloc.r_pcrel) 186 { 187 case 0: /* len = 0, pcrel = 0 */ 188 res->howto = &arm64_howto_table[3]; 189 return TRUE; 190 case 2: /* len = 1, pcrel = 0 */ 191 res->howto = &arm64_howto_table[2]; 192 return TRUE; 193 case 3: /* len = 1, pcrel = 1 */ 194 res->howto = &arm64_howto_table[6]; 195 return TRUE; 196 case 4: /* len = 2, pcrel = 0 */ 197 res->howto = &arm64_howto_table[1]; 198 return TRUE; 199 case 5: /* len = 2, pcrel = 1 */ 200 res->howto = &arm64_howto_table[5]; 201 return TRUE; 202 case 6: /* len = 3, pcrel = 0 */ 203 res->howto = &arm64_howto_table[0]; 204 return TRUE; 205 case 7: /* len = 3, pcrel = 1 */ 206 res->howto = &arm64_howto_table[4]; 207 return TRUE; 208 default: 209 return FALSE; 210 } 211 break; 212 case BFD_MACH_O_ARM64_RELOC_SUBTRACTOR: 213 if (reloc.r_pcrel) 214 return FALSE; 215 switch (reloc.r_length) 216 { 217 case 2: 218 res->howto = &arm64_howto_table[11]; 219 return TRUE; 220 case 3: 221 res->howto = &arm64_howto_table[12]; 222 return TRUE; 223 default: 224 return FALSE; 225 } 226 break; 227 case BFD_MACH_O_ARM64_RELOC_BRANCH26: 228 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 229 { 230 res->howto = &arm64_howto_table[7]; 231 return TRUE; 232 } 233 break; 234 case BFD_MACH_O_ARM64_RELOC_PAGE21: 235 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 236 { 237 res->howto = &arm64_howto_table[8]; 238 return TRUE; 239 } 240 break; 241 case BFD_MACH_O_ARM64_RELOC_PAGEOFF12: 242 if (reloc.r_length == 2 && reloc.r_pcrel == 0) 243 { 244 res->howto = &arm64_howto_table[9]; 245 return TRUE; 246 } 247 break; 248 case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGE21: 249 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 250 { 251 res->howto = &arm64_howto_table[13]; 252 return TRUE; 253 } 254 break; 255 case BFD_MACH_O_ARM64_RELOC_GOT_LOAD_PAGEOFF12: 256 if (reloc.r_length == 2 && reloc.r_pcrel == 0) 257 { 258 res->howto = &arm64_howto_table[14]; 259 return TRUE; 260 } 261 break; 262 case BFD_MACH_O_ARM64_RELOC_POINTER_TO_GOT: 263 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 264 { 265 res->howto = &arm64_howto_table[15]; 266 return TRUE; 267 } 268 break; 269 default: 270 break; 271 } 272 return FALSE; 273 } 274 275 static reloc_howto_type * 276 bfd_mach_o_arm64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 277 bfd_reloc_code_real_type code) 278 { 279 unsigned int i; 280 281 for (i = 0; 282 i < sizeof (arm64_howto_table) / sizeof (*arm64_howto_table); 283 i++) 284 if (code == arm64_howto_table[i].type) 285 return &arm64_howto_table[i]; 286 return NULL; 287 } 288 289 static reloc_howto_type * 290 bfd_mach_o_arm64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 291 const char *name ATTRIBUTE_UNUSED) 292 { 293 return NULL; 294 } 295 296 #define TARGET_NAME aarch64_mach_o_vec 297 #define TARGET_STRING "mach-o-arm64" 298 #define TARGET_ARCHITECTURE bfd_arch_aarch64 299 #define TARGET_PAGESIZE 4096 300 #define TARGET_BIG_ENDIAN 0 301 #define TARGET_ARCHIVE 0 302 #define TARGET_PRIORITY 0 303 #include "mach-o-target.c" 304 305 #undef TARGET_NAME 306 #undef TARGET_STRING 307 #undef TARGET_ARCHIVE 308 #undef TARGET_PRIORITY 309