Home | History | Annotate | Download | only in bfd
      1 /* BFD backend for MIPS BSD (a.out) binaries.
      2    Copyright (C) 1993-2016 Free Software Foundation, Inc.
      3    Written by Ralph Campbell.
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 
     23 /* #define ENTRY_CAN_BE_ZERO */
     24 #define N_HEADER_IN_TEXT(x) 1
     25 #define N_TXTADDR(x) \
     26     (N_MAGIC(x) != ZMAGIC ? (x)->a_entry :	/* object file or NMAGIC */\
     27 	    TEXT_START_ADDR + EXEC_BYTES_SIZE	/* no padding */\
     28     )
     29 #define N_DATADDR(x) (N_TXTADDR(x)+N_TXTSIZE(x))
     30 #define TEXT_START_ADDR 4096
     31 #define TARGET_PAGE_SIZE 4096
     32 #define SEGMENT_SIZE TARGET_PAGE_SIZE
     33 #define DEFAULT_ARCH bfd_arch_mips
     34 #define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \
     35 			    || (mtype) == M_MIPS1 || (mtype) == M_MIPS2)
     36 #define MY_symbol_leading_char '\0'
     37 
     38 /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
     39    remove whitespace added here, and thus will fail to concatenate
     40    the tokens.  */
     41 #define MY(OP) CONCAT2 (mipsbsd_,OP)
     42 
     43 #include "sysdep.h"
     44 #include "bfd.h"
     45 #include "libbfd.h"
     46 #include "libaout.h"
     47 
     48 #define SET_ARCH_MACH(ABFD, EXECP) \
     49   MY(set_arch_mach) (ABFD, N_MACHTYPE (EXECP)); \
     50   MY(choose_reloc_size) (ABFD);
     51 static void MY(set_arch_mach) (bfd *, unsigned long);
     52 static void MY(choose_reloc_size) (bfd *);
     53 
     54 #define MY_write_object_contents MY(write_object_contents)
     55 static bfd_boolean MY(write_object_contents) (bfd *);
     56 
     57 /* We can't use MY(x) here because it leads to a recursive call to CONCAT2
     58    when expanded inside JUMP_TABLE.  */
     59 #define MY_bfd_reloc_type_lookup mipsbsd_reloc_type_lookup
     60 #define MY_bfd_reloc_name_lookup mipsbsd_reloc_name_lookup
     61 #define MY_canonicalize_reloc mipsbsd_canonicalize_reloc
     62 
     63 #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
     64 #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols
     65 #define MY_final_link_callback unused
     66 #define MY_bfd_final_link _bfd_generic_final_link
     67 
     68 #define MY_backend_data &MY(backend_data)
     69 #define MY_BFD_TARGET
     70 
     71 #include "aout-target.h"
     72 
     73 static bfd_reloc_status_type mips_fix_jmp_addr
     74   (bfd *, arelent *, struct bfd_symbol *, void *, asection *,
     75    bfd *, char **);
     76 
     77 long MY(canonicalize_reloc) (bfd *, sec_ptr, arelent **, asymbol **);
     78 
     79 static void
     80 MY(set_arch_mach) (bfd *abfd, unsigned long machtype)
     81 {
     82   enum bfd_architecture arch;
     83   unsigned int machine;
     84 
     85   /* Determine the architecture and machine type of the object file.  */
     86   switch (machtype)
     87     {
     88     case M_MIPS1:
     89       arch = bfd_arch_mips;
     90       machine = bfd_mach_mips3000;
     91       break;
     92 
     93     case M_MIPS2:
     94       arch = bfd_arch_mips;
     95       machine = bfd_mach_mips4000;
     96       break;
     97 
     98     default:
     99       arch = bfd_arch_obscure;
    100       machine = 0;
    101       break;
    102     }
    103 
    104   bfd_set_arch_mach (abfd, arch, machine);
    105 }
    106 
    107 /* Determine the size of a relocation entry, based on the architecture */
    108 static void
    109 MY (choose_reloc_size) (bfd *abfd)
    110 {
    111   switch (bfd_get_arch (abfd))
    112     {
    113     case bfd_arch_sparc:
    114     case bfd_arch_mips:
    115       obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
    116       break;
    117     default:
    118       obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
    119       break;
    120     }
    121 }
    122 
    123 /* Write an object file in BSD a.out format.
    124   Section contents have already been written.  We write the
    125   file header, symbols, and relocation.  */
    126 
    127 static bfd_boolean
    128 MY (write_object_contents) (bfd *abfd)
    129 {
    130   struct external_exec exec_bytes;
    131   struct internal_exec *execp = exec_hdr (abfd);
    132 
    133   /* Magic number, maestro, please!  */
    134   switch (bfd_get_arch (abfd))
    135     {
    136     case bfd_arch_m68k:
    137       switch (bfd_get_mach (abfd))
    138 	{
    139 	case bfd_mach_m68010:
    140 	  N_SET_MACHTYPE (execp, M_68010);
    141 	  break;
    142 	default:
    143 	case bfd_mach_m68020:
    144 	  N_SET_MACHTYPE (execp, M_68020);
    145 	  break;
    146 	}
    147       break;
    148     case bfd_arch_sparc:
    149       N_SET_MACHTYPE (execp, M_SPARC);
    150       break;
    151     case bfd_arch_i386:
    152       N_SET_MACHTYPE (execp, M_386);
    153       break;
    154     case bfd_arch_mips:
    155       switch (bfd_get_mach (abfd))
    156 	{
    157 	case bfd_mach_mips4000:
    158 	case bfd_mach_mips6000:
    159 	  N_SET_MACHTYPE (execp, M_MIPS2);
    160 	  break;
    161 	default:
    162 	  N_SET_MACHTYPE (execp, M_MIPS1);
    163 	  break;
    164 	}
    165       break;
    166     default:
    167       N_SET_MACHTYPE (execp, M_UNKNOWN);
    168     }
    169 
    170   MY (choose_reloc_size) (abfd);
    171 
    172   WRITE_HEADERS (abfd, execp);
    173 
    174   return TRUE;
    175 }
    176 
    177 /* MIPS relocation types.  */
    178 #define MIPS_RELOC_32		0
    179 #define MIPS_RELOC_JMP		1
    180 #define MIPS_RELOC_WDISP16	2
    181 #define MIPS_RELOC_HI16		3
    182 #define MIPS_RELOC_HI16_S	4
    183 #define MIPS_RELOC_LO16		5
    184 
    185 /* This is only called when performing a BFD_RELOC_MIPS_JMP relocation.
    186    The jump destination address is formed from the upper 4 bits of the
    187    "current" program counter concatenated with the jump instruction's
    188    26 bit field and two trailing zeros.
    189    If the destination address is not in the same segment as the "current"
    190    program counter, then we need to signal an error.  */
    191 
    192 static bfd_reloc_status_type
    193 mips_fix_jmp_addr (bfd *abfd ATTRIBUTE_UNUSED,
    194 		   arelent *reloc_entry,
    195 		   struct bfd_symbol *symbol,
    196 		   void * data ATTRIBUTE_UNUSED,
    197 		   asection *input_section,
    198 		   bfd *output_bfd,
    199 		   char **error_message ATTRIBUTE_UNUSED)
    200 {
    201   bfd_vma relocation, pc;
    202 
    203   /* If this is a partial relocation, just continue.  */
    204   if (output_bfd != (bfd *) NULL)
    205     return bfd_reloc_continue;
    206 
    207   /* If this is an undefined symbol, return error */
    208   if (bfd_is_und_section (symbol->section)
    209       && (symbol->flags & BSF_WEAK) == 0)
    210     return bfd_reloc_undefined;
    211 
    212   /* Work out which section the relocation is targeted at and the
    213      initial relocation command value.  */
    214   if (bfd_is_com_section (symbol->section))
    215     relocation = 0;
    216   else
    217     relocation = symbol->value;
    218 
    219   relocation += symbol->section->output_section->vma;
    220   relocation += symbol->section->output_offset;
    221   relocation += reloc_entry->addend;
    222 
    223   pc = input_section->output_section->vma + input_section->output_offset +
    224     reloc_entry->address + 4;
    225 
    226   if ((relocation & 0xF0000000) != (pc & 0xF0000000))
    227     return bfd_reloc_overflow;
    228 
    229   return bfd_reloc_continue;
    230 }
    231 
    232 /* This is only called when performing a BFD_RELOC_HI16_S relocation.
    233    We need to see if bit 15 is set in the result. If it is, we add
    234    0x10000 and continue normally. This will compensate for the sign extension
    235    when the low bits are added at run time.  */
    236 
    237 static bfd_reloc_status_type
    238 mips_fix_hi16_s (bfd *abfd ATTRIBUTE_UNUSED,
    239 		 arelent *reloc_entry,
    240 		 asymbol *symbol,
    241 		 void * data ATTRIBUTE_UNUSED,
    242 		 asection *input_section ATTRIBUTE_UNUSED,
    243 		 bfd *output_bfd,
    244 		 char **error_message ATTRIBUTE_UNUSED)
    245 {
    246   bfd_vma relocation;
    247 
    248   /* If this is a partial relocation, just continue.  */
    249   if (output_bfd != (bfd *)NULL)
    250     return bfd_reloc_continue;
    251 
    252   /* If this is an undefined symbol, return error.  */
    253   if (bfd_is_und_section (symbol->section)
    254       && (symbol->flags & BSF_WEAK) == 0)
    255     return bfd_reloc_undefined;
    256 
    257   /* Work out which section the relocation is targeted at and the
    258      initial relocation command value.  */
    259   if (bfd_is_com_section (symbol->section))
    260     relocation = 0;
    261   else
    262     relocation = symbol->value;
    263 
    264   relocation += symbol->section->output_section->vma;
    265   relocation += symbol->section->output_offset;
    266   relocation += reloc_entry->addend;
    267 
    268   if (relocation & 0x8000)
    269     reloc_entry->addend += 0x10000;
    270 
    271   return bfd_reloc_continue;
    272 }
    273 
    274 static reloc_howto_type mips_howto_table_ext[] =
    275 {
    276   {MIPS_RELOC_32,      0, 2, 32, FALSE, 0,  complain_overflow_bitfield, 0,
    277 	"32",       FALSE, 0, 0xffffffff, FALSE},
    278   {MIPS_RELOC_JMP,     2, 2, 26, FALSE, 0, complain_overflow_dont,
    279 	mips_fix_jmp_addr,
    280 	"MIPS_JMP", FALSE, 0, 0x03ffffff, FALSE},
    281   {MIPS_RELOC_WDISP16, 2, 2, 16, TRUE,  0, complain_overflow_signed, 0,
    282 	"WDISP16",  FALSE, 0, 0x0000ffff, FALSE},
    283   {MIPS_RELOC_HI16,   16, 2, 16, FALSE, 0, complain_overflow_bitfield, 0,
    284 	"HI16",     FALSE, 0, 0x0000ffff, FALSE},
    285   {MIPS_RELOC_HI16_S, 16, 2, 16, FALSE, 0, complain_overflow_bitfield,
    286         mips_fix_hi16_s,
    287         "HI16_S",   FALSE, 0, 0x0000ffff, FALSE},
    288   {MIPS_RELOC_LO16,    0, 2, 16, FALSE, 0, complain_overflow_dont, 0,
    289 	"LO16",     FALSE, 0, 0x0000ffff, FALSE},
    290 };
    291 
    292 static reloc_howto_type *
    293 MY(reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
    294 {
    295   if (bfd_get_arch (abfd) != bfd_arch_mips)
    296     return NULL;
    297 
    298   switch (code)
    299     {
    300     case BFD_RELOC_CTOR:
    301     case BFD_RELOC_32:
    302       return (&mips_howto_table_ext[MIPS_RELOC_32]);
    303     case BFD_RELOC_MIPS_JMP:
    304       return (&mips_howto_table_ext[MIPS_RELOC_JMP]);
    305     case BFD_RELOC_16_PCREL_S2:
    306       return (&mips_howto_table_ext[MIPS_RELOC_WDISP16]);
    307     case BFD_RELOC_HI16:
    308       return (&mips_howto_table_ext[MIPS_RELOC_HI16]);
    309     case BFD_RELOC_HI16_S:
    310       return (&mips_howto_table_ext[MIPS_RELOC_HI16_S]);
    311     case BFD_RELOC_LO16:
    312       return (&mips_howto_table_ext[MIPS_RELOC_LO16]);
    313     default:
    314       return NULL;
    315     }
    316 }
    317 
    318 static reloc_howto_type *
    319 MY(reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED,
    320 		       const char *r_name)
    321 {
    322   unsigned int i;
    323 
    324   for (i = 0;
    325        i < sizeof (mips_howto_table_ext) / sizeof (mips_howto_table_ext[0]);
    326        i++)
    327     if (mips_howto_table_ext[i].name != NULL
    328 	&& strcasecmp (mips_howto_table_ext[i].name, r_name) == 0)
    329       return &mips_howto_table_ext[i];
    330 
    331   return NULL;
    332 }
    333 
    334 /* This is just like the standard aoutx.h version but we need to do our
    335    own mapping of external reloc type values to howto entries.  */
    336 long
    337 MY(canonicalize_reloc) (bfd *abfd,
    338 			sec_ptr section,
    339 			arelent **relptr,
    340 			asymbol **symbols)
    341 {
    342   arelent *tblptr = section->relocation;
    343   unsigned int count, c;
    344   extern reloc_howto_type NAME(aout,ext_howto_table)[];
    345 
    346   /* If we have already read in the relocation table, return the values.  */
    347   if (section->flags & SEC_CONSTRUCTOR)
    348     {
    349       arelent_chain *chain = section->constructor_chain;
    350 
    351       for (count = 0; count < section->reloc_count; count++)
    352 	{
    353 	  *relptr++ = &chain->relent;
    354 	  chain = chain->next;
    355 	}
    356       *relptr = 0;
    357       return section->reloc_count;
    358     }
    359 
    360   if (tblptr && section->reloc_count)
    361     {
    362       for (count = 0; count++ < section->reloc_count;)
    363 	*relptr++ = tblptr++;
    364       *relptr = 0;
    365       return section->reloc_count;
    366     }
    367 
    368   if (!NAME(aout,slurp_reloc_table) (abfd, section, symbols))
    369     return -1;
    370   tblptr = section->relocation;
    371 
    372   /* fix up howto entries.  */
    373   for (count = 0; count++ < section->reloc_count;)
    374     {
    375       c = tblptr->howto - NAME(aout,ext_howto_table);
    376       tblptr->howto = &mips_howto_table_ext[c];
    377 
    378       *relptr++ = tblptr++;
    379     }
    380   *relptr = 0;
    381   return section->reloc_count;
    382 }
    383 
    384 static const struct aout_backend_data MY(backend_data) =
    385 {
    386   0,				/* zmagic contiguous */
    387   1,				/* text incl header */
    388   0,				/* entry is text address */
    389   0,				/* exec_hdr_flags */
    390   TARGET_PAGE_SIZE,			/* text vma */
    391   MY_set_sizes,
    392   0,				/* text size includes exec header */
    393   0,				/* add_dynamic_symbols */
    394   0,				/* add_one_symbol */
    395   0,				/* link_dynamic_object */
    396   0,				/* write_dynamic_symbol */
    397   0,				/* check_dynamic_reloc */
    398   0				/* finish_dynamic_link */
    399 };
    400 
    401 extern const bfd_target mips_aout_be_vec;
    402 
    403 const bfd_target mips_aout_le_vec =
    404 {
    405     "a.out-mips-little",		/* name */
    406     bfd_target_aout_flavour,
    407     BFD_ENDIAN_LITTLE,		/* target byte order (little) */
    408     BFD_ENDIAN_LITTLE,		/* target headers byte order (little) */
    409     (HAS_RELOC | EXEC_P |		/* object flags */
    410      HAS_LINENO | HAS_DEBUG |
    411      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
    412     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
    413     MY_symbol_leading_char,
    414     ' ',				/* ar_pad_char */
    415     15,				/* ar_max_namelen */
    416     0,				/* match priority.  */
    417     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    418     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    419     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
    420     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    421     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    422     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
    423     {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
    424      bfd_generic_archive_p, MY_core_file_p},
    425     {bfd_false, MY_mkobject,	/* bfd_set_format */
    426      _bfd_generic_mkarchive, bfd_false},
    427     {bfd_false, MY_write_object_contents, /* bfd_write_contents */
    428      _bfd_write_archive_contents, bfd_false},
    429 
    430     BFD_JUMP_TABLE_GENERIC (MY),
    431     BFD_JUMP_TABLE_COPY (MY),
    432     BFD_JUMP_TABLE_CORE (MY),
    433     BFD_JUMP_TABLE_ARCHIVE (MY),
    434     BFD_JUMP_TABLE_SYMBOLS (MY),
    435     BFD_JUMP_TABLE_RELOCS (MY),
    436     BFD_JUMP_TABLE_WRITE (MY),
    437     BFD_JUMP_TABLE_LINK (MY),
    438     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    439 
    440     & mips_aout_be_vec,
    441 
    442     MY_backend_data
    443   };
    444 
    445 const bfd_target mips_aout_be_vec =
    446   {
    447     "a.out-mips-big",		/* name */
    448     bfd_target_aout_flavour,
    449     BFD_ENDIAN_BIG,		/* target byte order (big) */
    450     BFD_ENDIAN_BIG,		/* target headers byte order (big) */
    451     (HAS_RELOC | EXEC_P |		/* object flags */
    452      HAS_LINENO | HAS_DEBUG |
    453      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
    454     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
    455     MY_symbol_leading_char,
    456     ' ',				/* ar_pad_char */
    457     15,				/* ar_max_namelen */
    458     0,				/* match priority.  */
    459     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    460     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    461     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
    462     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    463     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    464     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
    465     {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
    466      bfd_generic_archive_p, MY_core_file_p},
    467     {bfd_false, MY_mkobject,	/* bfd_set_format */
    468      _bfd_generic_mkarchive, bfd_false},
    469     {bfd_false, MY_write_object_contents, /* bfd_write_contents */
    470      _bfd_write_archive_contents, bfd_false},
    471 
    472     BFD_JUMP_TABLE_GENERIC (MY),
    473     BFD_JUMP_TABLE_COPY (MY),
    474     BFD_JUMP_TABLE_CORE (MY),
    475     BFD_JUMP_TABLE_ARCHIVE (MY),
    476     BFD_JUMP_TABLE_SYMBOLS (MY),
    477     BFD_JUMP_TABLE_RELOCS (MY),
    478     BFD_JUMP_TABLE_WRITE (MY),
    479     BFD_JUMP_TABLE_LINK (MY),
    480     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    481 
    482     & mips_aout_le_vec,
    483 
    484     MY_backend_data
    485   };
    486