Home | History | Annotate | Download | only in bfd
      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