Home | History | Annotate | Line # | Download | only in bfd
      1      1.1  christos /* ARM 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/arm.h"
     27      1.1  christos 
     28      1.1  christos #define bfd_mach_o_object_p bfd_mach_o_arm_object_p
     29      1.1  christos #define bfd_mach_o_core_p bfd_mach_o_arm_core_p
     30      1.1  christos #define bfd_mach_o_mkobject bfd_mach_o_arm_mkobject
     31      1.1  christos 
     32      1.1  christos #define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_arm_canonicalize_one_reloc
     33  1.1.1.3  christos #define bfd_mach_o_swap_reloc_out  NULL
     34      1.1  christos #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm_bfd_reloc_type_lookup
     35      1.1  christos #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm_bfd_reloc_name_lookup
     36      1.1  christos 
     37      1.1  christos #define bfd_mach_o_print_thread NULL
     38      1.1  christos #define bfd_mach_o_tgt_seg_table NULL
     39      1.1  christos #define bfd_mach_o_section_type_valid_for_tgt NULL
     40      1.1  christos 
     41  1.1.1.4  christos static bfd_cleanup
     42      1.1  christos bfd_mach_o_arm_object_p (bfd *abfd)
     43      1.1  christos {
     44      1.1  christos   return bfd_mach_o_header_p (abfd, 0, 0, BFD_MACH_O_CPU_TYPE_ARM);
     45      1.1  christos }
     46      1.1  christos 
     47  1.1.1.4  christos static bfd_cleanup
     48      1.1  christos bfd_mach_o_arm_core_p (bfd *abfd)
     49      1.1  christos {
     50      1.1  christos   return bfd_mach_o_header_p (abfd, 0,
     51  1.1.1.3  christos 			      BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_ARM);
     52      1.1  christos }
     53      1.1  christos 
     54  1.1.1.5  christos static bool
     55      1.1  christos bfd_mach_o_arm_mkobject (bfd *abfd)
     56      1.1  christos {
     57      1.1  christos   bfd_mach_o_data_struct *mdata;
     58      1.1  christos 
     59      1.1  christos   if (!bfd_mach_o_mkobject_init (abfd))
     60  1.1.1.5  christos     return false;
     61      1.1  christos 
     62      1.1  christos   mdata = bfd_mach_o_get_data (abfd);
     63      1.1  christos   mdata->header.magic = BFD_MACH_O_MH_MAGIC;
     64      1.1  christos   mdata->header.cputype = BFD_MACH_O_CPU_TYPE_ARM;
     65      1.1  christos   mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_ARM_ALL;
     66      1.1  christos   mdata->header.byteorder = BFD_ENDIAN_LITTLE;
     67      1.1  christos   mdata->header.version = 1;
     68      1.1  christos 
     69  1.1.1.5  christos   return true;
     70      1.1  christos }
     71      1.1  christos 
     72      1.1  christos static reloc_howto_type arm_howto_table[]=
     73      1.1  christos {
     74      1.1  christos   /* 0 */
     75  1.1.1.5  christos   HOWTO (BFD_RELOC_32, 0, 4, 32, false, 0,
     76      1.1  christos 	 complain_overflow_bitfield,
     77      1.1  christos 	 NULL, "32",
     78  1.1.1.5  christos 	 false, 0xffffffff, 0xffffffff, false),
     79  1.1.1.5  christos   HOWTO (BFD_RELOC_16, 0, 2, 16, false, 0,
     80      1.1  christos 	 complain_overflow_bitfield,
     81      1.1  christos 	 NULL, "16",
     82  1.1.1.5  christos 	 false, 0xffff, 0xffff, false),
     83  1.1.1.5  christos   HOWTO (BFD_RELOC_8, 0, 1, 8, false, 0,
     84      1.1  christos 	 complain_overflow_bitfield,
     85      1.1  christos 	 NULL, "8",
     86  1.1.1.5  christos 	 false, 0xff, 0xff, false),
     87  1.1.1.5  christos   HOWTO (BFD_RELOC_32_PCREL, 0, 4, 32, true, 0,
     88      1.1  christos 	 complain_overflow_bitfield,
     89      1.1  christos 	 NULL, "DISP32",
     90  1.1.1.5  christos 	 false, 0xffffffff, 0xffffffff, true),
     91      1.1  christos   /* 4 */
     92  1.1.1.5  christos   HOWTO (BFD_RELOC_16_PCREL, 0, 2, 16, true, 0,
     93      1.1  christos 	 complain_overflow_bitfield,
     94      1.1  christos 	 NULL, "DISP16",
     95  1.1.1.5  christos 	 false, 0xffff, 0xffff, true),
     96  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 4, 32, false, 0,
     97      1.1  christos 	 complain_overflow_bitfield,
     98      1.1  christos 	 NULL, "SECTDIFF_32",
     99  1.1.1.5  christos 	 false, 0xffffffff, 0xffffffff, false),
    100  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_LOCAL_SECTDIFF, 0, 4, 32, false, 0,
    101      1.1  christos 	 complain_overflow_bitfield,
    102      1.1  christos 	 NULL, "LSECTDIFF_32",
    103  1.1.1.5  christos 	 false, 0xffffffff, 0xffffffff, false),
    104  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 32, false, 0,
    105      1.1  christos 	 complain_overflow_bitfield,
    106      1.1  christos 	 NULL, "PAIR_32",
    107  1.1.1.5  christos 	 false, 0xffffffff, 0xffffffff, false),
    108      1.1  christos   /* 8 */
    109  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_SECTDIFF, 0, 2, 16, false, 0,
    110      1.1  christos 	 complain_overflow_bitfield,
    111      1.1  christos 	 NULL, "SECTDIFF_16",
    112  1.1.1.5  christos 	 false, 0xffff, 0xffff, false),
    113  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_LOCAL_SECTDIFF, 0, 2, 16, false, 0,
    114      1.1  christos 	 complain_overflow_bitfield,
    115      1.1  christos 	 NULL, "LSECTDIFF_16",
    116  1.1.1.5  christos 	 false, 0xffff, 0xffff, false),
    117  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 2, 16, false, 0,
    118      1.1  christos 	 complain_overflow_bitfield,
    119      1.1  christos 	 NULL, "PAIR_16",
    120  1.1.1.5  christos 	 false, 0xffff, 0xffff, false),
    121  1.1.1.5  christos   HOWTO (BFD_RELOC_ARM_PCREL_CALL, 2, 4, 24, true, 0,
    122      1.1  christos 	 complain_overflow_signed,
    123      1.1  christos 	 NULL, "BR24",
    124  1.1.1.5  christos 	 false, 0x00ffffff, 0x00ffffff, true),
    125      1.1  christos   /* 12 */
    126  1.1.1.5  christos   HOWTO (BFD_RELOC_ARM_MOVW, 0,	4, 16, false, 0,
    127      1.1  christos 	 complain_overflow_dont,
    128      1.1  christos 	 NULL, "MOVW",
    129  1.1.1.5  christos 	 false, 0x000f0fff, 0x000f0fff, false),
    130  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 16, false, 0,
    131      1.1  christos 	 complain_overflow_bitfield,
    132      1.1  christos 	 NULL, "PAIR_W",
    133  1.1.1.5  christos 	 false, 0x000f0fff, 0x000f0fff, false),
    134  1.1.1.5  christos   HOWTO (BFD_RELOC_ARM_MOVT, 0, 4, 16, false, 0,
    135      1.1  christos 	 complain_overflow_bitfield,
    136      1.1  christos 	 NULL, "MOVT",
    137  1.1.1.5  christos 	 false, 0x000f0fff, 0x000f0fff, false),
    138  1.1.1.5  christos   HOWTO (BFD_RELOC_MACH_O_PAIR, 0, 4, 16, false, 0,
    139      1.1  christos 	 complain_overflow_bitfield,
    140      1.1  christos 	 NULL, "PAIR_T",
    141  1.1.1.5  christos 	 false, 0x000f0fff, 0x000f0fff, false),
    142      1.1  christos   /* 16 */
    143  1.1.1.5  christos   HOWTO (BFD_RELOC_THUMB_PCREL_BLX, 2, 4, 24, true, 0,
    144      1.1  christos 	 complain_overflow_signed,
    145      1.1  christos 	 NULL, "TBR22",
    146  1.1.1.5  christos 	 false, 0x07ff2fff, 0x07ff2fff, 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_arm_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)
    155  1.1.1.3  christos {
    156      1.1  christos   bfd_mach_o_reloc_info reloc;
    157      1.1  christos 
    158      1.1  christos   if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms))
    159  1.1.1.5  christos     return false;
    160      1.1  christos 
    161      1.1  christos   if (reloc.r_scattered)
    162      1.1  christos     {
    163      1.1  christos       switch (reloc.r_type)
    164  1.1.1.3  christos 	{
    165  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_PAIR:
    166  1.1.1.3  christos 	  /* PR 21813: Check for a corrupt PAIR reloc at the start.  */
    167  1.1.1.3  christos 	  if (res == res_base)
    168  1.1.1.4  christos 	    {
    169  1.1.1.5  christos 	      _bfd_error_handler (_("malformed mach-o ARM reloc pair: "
    170  1.1.1.5  christos 				    "reloc is first reloc"));
    171  1.1.1.5  christos 	      return false;
    172  1.1.1.4  christos 	    }
    173  1.1.1.3  christos 	  if (reloc.r_length == 2)
    174  1.1.1.3  christos 	    {
    175      1.1  christos 	      res->howto = &arm_howto_table[7];
    176      1.1  christos 	      res->address = res[-1].address;
    177  1.1.1.5  christos 	      return true;
    178  1.1.1.3  christos 	    }
    179  1.1.1.3  christos 	  else if (reloc.r_length == 1)
    180      1.1  christos 	    {
    181      1.1  christos 	      res->howto = &arm_howto_table[10];
    182      1.1  christos 	      res->address = res[-1].address;
    183  1.1.1.5  christos 	      return true;
    184      1.1  christos 	    }
    185  1.1.1.5  christos 	  _bfd_error_handler (_("malformed mach-o ARM reloc pair: "
    186  1.1.1.5  christos 				"invalid length: %d"), reloc.r_length);
    187  1.1.1.5  christos 	  return false;
    188  1.1.1.3  christos 
    189  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_SECTDIFF:
    190  1.1.1.3  christos 	  if (reloc.r_length == 2)
    191  1.1.1.3  christos 	    {
    192      1.1  christos 	      res->howto = &arm_howto_table[5];
    193  1.1.1.5  christos 	      return true;
    194  1.1.1.3  christos 	    }
    195  1.1.1.3  christos 	  else if (reloc.r_length == 1)
    196  1.1.1.3  christos 	    {
    197      1.1  christos 	      res->howto = &arm_howto_table[8];
    198  1.1.1.5  christos 	      return true;
    199  1.1.1.3  christos 	    }
    200  1.1.1.5  christos 	  _bfd_error_handler (_("malformed mach-o ARM sectdiff reloc: "
    201  1.1.1.5  christos 				"invalid length: %d"), reloc.r_length);
    202  1.1.1.5  christos 	  return false;
    203  1.1.1.3  christos 
    204  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_LOCAL_SECTDIFF:
    205  1.1.1.3  christos 	  if (reloc.r_length == 2)
    206  1.1.1.3  christos 	    {
    207      1.1  christos 	      res->howto = &arm_howto_table[6];
    208  1.1.1.5  christos 	      return true;
    209  1.1.1.3  christos 	    }
    210  1.1.1.3  christos 	  else if (reloc.r_length == 1)
    211  1.1.1.3  christos 	    {
    212      1.1  christos 	      res->howto = &arm_howto_table[9];
    213  1.1.1.5  christos 	      return true;
    214  1.1.1.3  christos 	    }
    215  1.1.1.5  christos 	  _bfd_error_handler (_("malformed mach-o ARM local sectdiff reloc: "
    216  1.1.1.5  christos 				"invalid length: %d"),
    217  1.1.1.4  christos 			      reloc.r_length);
    218  1.1.1.5  christos 	  return false;
    219  1.1.1.3  christos 
    220      1.1  christos 	case BFD_MACH_O_ARM_RELOC_HALF_SECTDIFF:
    221      1.1  christos 	  switch (reloc.r_length)
    222      1.1  christos 	    {
    223      1.1  christos 	    case 2: /* :lower16: for movw arm.  */
    224      1.1  christos 	      res->howto = &arm_howto_table[12];
    225  1.1.1.5  christos 	      return true;
    226      1.1  christos 	    case 3: /* :upper16: for movt arm.  */
    227      1.1  christos 	      res->howto = &arm_howto_table[14];
    228  1.1.1.5  christos 	      return true;
    229      1.1  christos 	    }
    230  1.1.1.5  christos 	  _bfd_error_handler (_("malformed mach-o ARM half sectdiff reloc: "
    231  1.1.1.5  christos 				"invalid length: %d"),
    232  1.1.1.4  christos 			      reloc.r_length);
    233  1.1.1.5  christos 	  return false;
    234  1.1.1.3  christos 
    235  1.1.1.3  christos 	default:
    236  1.1.1.3  christos 	  break;
    237  1.1.1.3  christos 	}
    238      1.1  christos     }
    239      1.1  christos   else
    240      1.1  christos     {
    241      1.1  christos       switch (reloc.r_type)
    242  1.1.1.3  christos 	{
    243  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_VANILLA:
    244  1.1.1.3  christos 	  switch ((reloc.r_length << 1) | reloc.r_pcrel)
    245  1.1.1.3  christos 	    {
    246  1.1.1.3  christos 	    case 0: /* len = 0, pcrel = 0  */
    247  1.1.1.3  christos 	      res->howto = &arm_howto_table[2];
    248  1.1.1.5  christos 	      return true;
    249  1.1.1.3  christos 	    case 2: /* len = 1, pcrel = 0  */
    250  1.1.1.3  christos 	      res->howto = &arm_howto_table[1];
    251  1.1.1.5  christos 	      return true;
    252  1.1.1.3  christos 	    case 3: /* len = 1, pcrel = 1  */
    253  1.1.1.3  christos 	      res->howto = &arm_howto_table[4];
    254  1.1.1.5  christos 	      return true;
    255  1.1.1.3  christos 	    case 4: /* len = 2, pcrel = 0  */
    256  1.1.1.3  christos 	      res->howto = &arm_howto_table[0];
    257  1.1.1.5  christos 	      return true;
    258  1.1.1.3  christos 	    case 5: /* len = 2, pcrel = 1  */
    259  1.1.1.3  christos 	      res->howto = &arm_howto_table[3];
    260  1.1.1.5  christos 	      return true;
    261  1.1.1.3  christos 	    default:
    262  1.1.1.5  christos 	      _bfd_error_handler (_("malformed mach-o ARM vanilla reloc: "
    263  1.1.1.5  christos 				    "invalid length: %d (pcrel: %d)"),
    264  1.1.1.4  christos 				  reloc.r_length, reloc.r_pcrel);
    265  1.1.1.5  christos 	      return false;
    266  1.1.1.3  christos 	    }
    267  1.1.1.3  christos 	  break;
    268  1.1.1.3  christos 
    269  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_BR24:
    270      1.1  christos 	  if (reloc.r_length == 2 && reloc.r_pcrel == 1)
    271      1.1  christos 	    {
    272  1.1.1.3  christos 	      res->howto = &arm_howto_table[11];
    273  1.1.1.5  christos 	      return true;
    274      1.1  christos 	    }
    275      1.1  christos 	  break;
    276  1.1.1.3  christos 
    277  1.1.1.3  christos 	case BFD_MACH_O_THUMB_RELOC_BR22:
    278      1.1  christos 	  if (reloc.r_length == 2 && reloc.r_pcrel == 1)
    279      1.1  christos 	    {
    280  1.1.1.3  christos 	      res->howto = &arm_howto_table[16];
    281  1.1.1.5  christos 	      return true;
    282      1.1  christos 	    }
    283      1.1  christos 	  break;
    284  1.1.1.3  christos 
    285  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_HALF:
    286      1.1  christos 	  if (reloc.r_pcrel == 0)
    287      1.1  christos 	    switch (reloc.r_length)
    288      1.1  christos 	      {
    289      1.1  christos 	      case 0: /* :lower16: for movw arm.  */
    290      1.1  christos 		res->howto = &arm_howto_table[12];
    291  1.1.1.5  christos 		return true;
    292      1.1  christos 	      case 1: /* :upper16: for movt arm.  */
    293      1.1  christos 		res->howto = &arm_howto_table[14];
    294  1.1.1.5  christos 		return true;
    295      1.1  christos 	      }
    296  1.1.1.3  christos 	  break;
    297  1.1.1.3  christos 
    298  1.1.1.3  christos 	case BFD_MACH_O_ARM_RELOC_PAIR:
    299  1.1.1.5  christos 	  if (res == res_base)
    300  1.1.1.5  christos 	    {
    301  1.1.1.5  christos 	      _bfd_error_handler (_("malformed mach-o ARM reloc pair: "
    302  1.1.1.5  christos 				    "reloc is first reloc"));
    303  1.1.1.5  christos 	      return false;
    304  1.1.1.5  christos 	    }
    305      1.1  christos 	  if (res[-1].howto == &arm_howto_table[12]
    306      1.1  christos 	      && reloc.r_length == 0)
    307      1.1  christos 	    {
    308      1.1  christos 	      /* Pair for :lower16: of movw arm.  */
    309      1.1  christos 	      res->howto = &arm_howto_table[13];
    310      1.1  christos 	      /* This reloc contains the other half in its r_address field.  */
    311      1.1  christos 	      res[-1].addend += (res->address & 0xffff) << 16;
    312      1.1  christos 	      res->address = res[-1].address;
    313  1.1.1.5  christos 	      return true;
    314  1.1.1.3  christos 	    }
    315      1.1  christos 	  else if (res[-1].howto == &arm_howto_table[14]
    316      1.1  christos 		   && reloc.r_length == 1)
    317      1.1  christos 	    {
    318      1.1  christos 	      /* Pair for :upper16: of movt arm.  */
    319      1.1  christos 	      res->howto = &arm_howto_table[15];
    320      1.1  christos 	      /* This reloc contains the other half in its r_address field.  */
    321      1.1  christos 	      res[-1].addend += res->address & 0xffff;
    322      1.1  christos 	      res->address = res[-1].address;
    323  1.1.1.5  christos 	      return true;
    324  1.1.1.3  christos 	    }
    325  1.1.1.3  christos 	  break;
    326  1.1.1.3  christos 
    327  1.1.1.3  christos 	default:
    328  1.1.1.3  christos 	  break;
    329  1.1.1.3  christos 	}
    330      1.1  christos     }
    331  1.1.1.3  christos 
    332  1.1.1.5  christos   _bfd_error_handler (_("malformed mach-o ARM reloc: "
    333  1.1.1.5  christos 			"unknown reloc type: %d"), reloc.r_length);
    334  1.1.1.5  christos   return false;
    335      1.1  christos }
    336      1.1  christos 
    337      1.1  christos static reloc_howto_type *
    338      1.1  christos bfd_mach_o_arm_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    339      1.1  christos 				      bfd_reloc_code_real_type code)
    340      1.1  christos {
    341      1.1  christos   unsigned int i;
    342      1.1  christos 
    343      1.1  christos   for (i = 0; i < sizeof (arm_howto_table) / sizeof (*arm_howto_table); i++)
    344      1.1  christos     if (code == arm_howto_table[i].type)
    345      1.1  christos       return &arm_howto_table[i];
    346      1.1  christos   return NULL;
    347      1.1  christos }
    348      1.1  christos 
    349      1.1  christos static reloc_howto_type *
    350      1.1  christos bfd_mach_o_arm_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    351      1.1  christos 				      const char *name ATTRIBUTE_UNUSED)
    352      1.1  christos {
    353      1.1  christos   return NULL;
    354      1.1  christos }
    355      1.1  christos 
    356  1.1.1.3  christos #define TARGET_NAME		arm_mach_o_vec
    357  1.1.1.3  christos #define TARGET_STRING		"mach-o-arm"
    358      1.1  christos #define TARGET_ARCHITECTURE	bfd_arch_arm
    359      1.1  christos #define TARGET_PAGESIZE		4096
    360  1.1.1.3  christos #define TARGET_BIG_ENDIAN	0
    361  1.1.1.3  christos #define TARGET_ARCHIVE		0
    362      1.1  christos #define TARGET_PRIORITY		0
    363      1.1  christos #include "mach-o-target.c"
    364