1/* ARM Mach-O support for BFD. 2 Copyright (C) 2015-2017 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/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 41static const bfd_target * 42bfd_mach_o_arm_object_p (bfd *abfd) 43{ 44 return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM); 45} 46 47static const bfd_target * 48bfd_mach_o_arm_core_p (bfd *abfd) 49{ 50 return bfd_mach_o_header_p (abfd, 0, 51 BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM); 52} 53 54static bfd_boolean 55bfd_mach_o_arm_mkobject (bfd *abfd) 56{ 57 bfd_mach_o_data_struct *mdata; 58 59 if (!bfd_mach_o_mkobject_init (abfd)) 60 return FALSE; 61 62 mdata = bfd_mach_o_get_data (abfd); 63 mdata->header.magic = BFD_MACH_O_MH_MAGIC; 64 mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM; 65 mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM_ALL; 66 mdata->header.byteorder = BFD_ENDIAN_LITTLE; 67 mdata->header.version = 1; 68 69 return TRUE; 70} 71 72static reloc_howto_type arm_howto_table[]= 73{ 74 /* 0 */ 75 HOWTO (BFD_RELOC_32, 0, 2, 32, FALSE, 0, 76 complain_overflow_bitfield, 77 NULL, "32", 78 FALSE, 0xffffffff, 0xffffffff, FALSE), 79 HOWTO (BFD_RELOC_16, 0, 1, 16, FALSE, 0, 80 complain_overflow_bitfield, 81 NULL, "16", 82 FALSE, 0xffff, 0xffff, FALSE), 83 HOWTO (BFD_RELOC_8, 0, 0, 8, FALSE, 0, 84 complain_overflow_bitfield, 85 NULL, "8", 86 FALSE, 0xff, 0xff, FALSE), 87 HOWTO (BFD_RELOC_32_PCREL, 0, 2, 32, TRUE, 0, 88 complain_overflow_bitfield, 89 NULL, "DISP32", 90 FALSE, 0xffffffff, 0xffffffff, TRUE), 91 /* 4 */ 92 HOWTO (BFD_RELOC_16_PCREL, 0, 1, 16, TRUE, 0, 93 complain_overflow_bitfield, 94 NULL, "DISP16", 95 FALSE, 0xffff, 0xffff, TRUE), 96 HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 2, 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, 2, 32, FALSE, 0, 101 complain_overflow_bitfield, 102 NULL, "LSECTDIFF_32", 103 FALSE, 0xffffffff, 0xffffffff, FALSE), 104 HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 2, 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, 1, 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, 1, 16, FALSE, 0, 114 complain_overflow_bitfield, 115 NULL, "LSECTDIFF_16", 116 FALSE, 0xffff, 0xffff, FALSE), 117 HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 1, 16, FALSE, 0, 118 complain_overflow_bitfield, 119 NULL, "PAIR_16", 120 FALSE, 0xffff, 0xffff, FALSE), 121 HOWTO (BFD_RELOC_ARM_PCREL_CALL, 2, 2, 24, TRUE, 0, 122 complain_overflow_signed, 123 NULL, "BR24", 124 FALSE, 0x00ffffff, 0x00ffffff, TRUE), 125 /* 12 */ 126 HOWTO (BFD_RELOC_ARM_MOVW, 0, 2, 16, FALSE, 0, 127 complain_overflow_dont, 128 NULL, "MOVW", 129 FALSE, 0x000f0fff, 0x000f0fff, FALSE), 130 HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 2, 16, FALSE, 0, 131 complain_overflow_bitfield, 132 NULL, "PAIR_W", 133 FALSE, 0x000f0fff, 0x000f0fff, FALSE), 134 HOWTO (BFD_RELOC_ARM_MOVT, 0, 2, 16, FALSE, 0, 135 complain_overflow_bitfield, 136 NULL, "MOVT", 137 FALSE, 0x000f0fff, 0x000f0fff, FALSE), 138 HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 2, 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, 2, 24, TRUE, 0, 144 complain_overflow_signed, 145 NULL, "TBR22", 146 FALSE, 0x07ff2fff, 0x07ff2fff, TRUE) 147}; 148 149static bfd_boolean 150bfd_mach_o_arm_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 if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms)) 157 return FALSE; 158 159 if (reloc.r_scattered) 160 { 161 switch (reloc.r_type) 162 { 163 case BFD_MACH_O_ARM_RELOC_PAIR: 164 if (reloc.r_length == 2) 165 { 166 res->howto = &arm_howto_table[7]; 167 res->address = res[-1].address; 168 return TRUE; 169 } 170 else if (reloc.r_length == 1) 171 { 172 res->howto = &arm_howto_table[10]; 173 res->address = res[-1].address; 174 return TRUE; 175 } 176 return FALSE; 177 case BFD_MACH_O_ARM_RELOC_SECTDIFF: 178 if (reloc.r_length == 2) 179 { 180 res->howto = &arm_howto_table[5]; 181 return TRUE; 182 } 183 else if (reloc.r_length == 1) 184 { 185 res->howto = &arm_howto_table[8]; 186 return TRUE; 187 } 188 return FALSE; 189 case BFD_MACH_O_ARM_RELOC_LOCAL_SECTDIFF: 190 if (reloc.r_length == 2) 191 { 192 res->howto = &arm_howto_table[6]; 193 return TRUE; 194 } 195 else if (reloc.r_length == 1) 196 { 197 res->howto = &arm_howto_table[9]; 198 return TRUE; 199 } 200 return FALSE; 201 case BFD_MACH_O_ARM_RELOC_HALF_SECTDIFF: 202 switch (reloc.r_length) 203 { 204 case 2: /* :lower16: for movw arm. */ 205 res->howto = &arm_howto_table[12]; 206 return TRUE; 207 case 3: /* :upper16: for movt arm. */ 208 res->howto = &arm_howto_table[14]; 209 return TRUE; 210 } 211 return FALSE; 212 default: 213 return FALSE; 214 } 215 } 216 else 217 { 218 switch (reloc.r_type) 219 { 220 case BFD_MACH_O_ARM_RELOC_VANILLA: 221 switch ((reloc.r_length << 1) | reloc.r_pcrel) 222 { 223 case 0: /* len = 0, pcrel = 0 */ 224 res->howto = &arm_howto_table[2]; 225 return TRUE; 226 case 2: /* len = 1, pcrel = 0 */ 227 res->howto = &arm_howto_table[1]; 228 return TRUE; 229 case 3: /* len = 1, pcrel = 1 */ 230 res->howto = &arm_howto_table[4]; 231 return TRUE; 232 case 4: /* len = 2, pcrel = 0 */ 233 res->howto = &arm_howto_table[0]; 234 return TRUE; 235 case 5: /* len = 2, pcrel = 1 */ 236 res->howto = &arm_howto_table[3]; 237 return TRUE; 238 default: 239 return FALSE; 240 } 241 break; 242 case BFD_MACH_O_ARM_RELOC_BR24: 243 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 244 { 245 res->howto = &arm_howto_table[11]; 246 return TRUE; 247 } 248 else 249 return FALSE; 250 break; 251 case BFD_MACH_O_THUMB_RELOC_BR22: 252 if (reloc.r_length == 2 && reloc.r_pcrel == 1) 253 { 254 res->howto = &arm_howto_table[16]; 255 return TRUE; 256 } 257 else 258 return FALSE; 259 break; 260 case BFD_MACH_O_ARM_RELOC_HALF: 261 if (reloc.r_pcrel == 0) 262 switch (reloc.r_length) 263 { 264 case 0: /* :lower16: for movw arm. */ 265 res->howto = &arm_howto_table[12]; 266 return TRUE; 267 case 1: /* :upper16: for movt arm. */ 268 res->howto = &arm_howto_table[14]; 269 return TRUE; 270 } 271 return FALSE; 272 case BFD_MACH_O_ARM_RELOC_PAIR: 273 if (res[-1].howto == &arm_howto_table[12] 274 && reloc.r_length == 0) 275 { 276 /* Pair for :lower16: of movw arm. */ 277 res->howto = &arm_howto_table[13]; 278 /* This reloc contains the other half in its r_address field. */ 279 res[-1].addend += (res->address & 0xffff) << 16; 280 res->address = res[-1].address; 281 return TRUE; 282 } 283 else if (res[-1].howto == &arm_howto_table[14] 284 && reloc.r_length == 1) 285 { 286 /* Pair for :upper16: of movt arm. */ 287 res->howto = &arm_howto_table[15]; 288 /* This reloc contains the other half in its r_address field. */ 289 res[-1].addend += res->address & 0xffff; 290 res->address = res[-1].address; 291 return TRUE; 292 } 293 return FALSE; 294 default: 295 return FALSE; 296 } 297 } 298} 299 300static reloc_howto_type * 301bfd_mach_o_arm_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 302 bfd_reloc_code_real_type code) 303{ 304 unsigned int i; 305 306 for (i = 0; i < sizeof (arm_howto_table) / sizeof (*arm_howto_table); i++) 307 if (code == arm_howto_table[i].type) 308 return &arm_howto_table[i]; 309 return NULL; 310} 311 312static reloc_howto_type * 313bfd_mach_o_arm_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 314 const char *name ATTRIBUTE_UNUSED) 315{ 316 return NULL; 317} 318 319#define TARGET_NAME arm_mach_o_vec 320#define TARGET_STRING "mach-o-arm" 321#define TARGET_ARCHITECTURE bfd_arch_arm 322#define TARGET_PAGESIZE 4096 323#define TARGET_BIG_ENDIAN 0 324#define TARGET_ARCHIVE 0 325#define TARGET_PRIORITY 0 326#include "mach-o-target.c" 327