Back to index

cell-binutils  2.17cvs20070401
mipsbsd.c
Go to the documentation of this file.
00001 /* BFD backend for MIPS BSD (a.out) binaries.
00002    Copyright 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
00003    2007 Free Software Foundation, Inc.
00004    Written by Ralph Campbell.
00005 
00006 This file is part of BFD, the Binary File Descriptor library.
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 /* #define ENTRY_CAN_BE_ZERO */
00023 #define N_HEADER_IN_TEXT(x) 1
00024 #define N_SHARED_LIB(x) 0
00025 #define N_TXTADDR(x) \
00026     (N_MAGIC(x) != ZMAGIC ? (x).a_entry : /* object file or NMAGIC */\
00027            TEXT_START_ADDR + EXEC_BYTES_SIZE     /* no padding */\
00028     )
00029 #define N_DATADDR(x) (N_TXTADDR(x)+N_TXTSIZE(x))
00030 #define TEXT_START_ADDR 4096
00031 #define TARGET_PAGE_SIZE 4096
00032 #define SEGMENT_SIZE TARGET_PAGE_SIZE
00033 #define DEFAULT_ARCH bfd_arch_mips
00034 #define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \
00035                          || (mtype) == M_MIPS1 || (mtype) == M_MIPS2)
00036 #define MY_symbol_leading_char '\0'
00037 
00038 /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
00039    remove whitespace added here, and thus will fail to concatenate
00040    the tokens.  */
00041 #define MY(OP) CONCAT2 (mipsbsd_,OP)
00042 
00043 #include "bfd.h"
00044 #include "sysdep.h"
00045 #include "libbfd.h"
00046 #include "libaout.h"
00047 
00048 #define SET_ARCH_MACH(ABFD, EXEC) \
00049   MY(set_arch_mach) (ABFD, N_MACHTYPE (EXEC)); \
00050   MY(choose_reloc_size) (ABFD);
00051 static void MY(set_arch_mach) PARAMS ((bfd *abfd, unsigned long machtype));
00052 static void MY(choose_reloc_size) PARAMS ((bfd *abfd));
00053 
00054 #define MY_write_object_contents MY(write_object_contents)
00055 static bfd_boolean MY(write_object_contents) PARAMS ((bfd *abfd));
00056 
00057 /* We can't use MY(x) here because it leads to a recursive call to CONCAT2
00058    when expanded inside JUMP_TABLE.  */
00059 #define MY_bfd_reloc_type_lookup mipsbsd_reloc_type_lookup
00060 #define MY_bfd_reloc_name_lookup mipsbsd_reloc_name_lookup
00061 #define MY_canonicalize_reloc mipsbsd_canonicalize_reloc
00062 
00063 #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
00064 #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols
00065 #define MY_final_link_callback unused
00066 #define MY_bfd_final_link _bfd_generic_final_link
00067 
00068 #define MY_backend_data &MY(backend_data)
00069 #define MY_BFD_TARGET
00070 
00071 #include "aout-target.h"
00072 
00073 static bfd_reloc_status_type mips_fix_jmp_addr
00074   PARAMS ((bfd *, arelent *, struct bfd_symbol *, PTR, asection *,
00075           bfd *, char **));
00076 
00077 long MY(canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
00078 
00079 static void
00080 MY(set_arch_mach) (abfd, machtype)
00081      bfd *abfd;
00082      unsigned long machtype;
00083 {
00084   enum bfd_architecture arch;
00085   unsigned int machine;
00086 
00087   /* Determine the architecture and machine type of the object file.  */
00088   switch (machtype)
00089     {
00090     case M_MIPS1:
00091       arch = bfd_arch_mips;
00092       machine = bfd_mach_mips3000;
00093       break;
00094 
00095     case M_MIPS2:
00096       arch = bfd_arch_mips;
00097       machine = bfd_mach_mips4000;
00098       break;
00099 
00100     default:
00101       arch = bfd_arch_obscure;
00102       machine = 0;
00103       break;
00104     }
00105 
00106   bfd_set_arch_mach (abfd, arch, machine);
00107 }
00108 
00109 /* Determine the size of a relocation entry, based on the architecture */
00110 static void
00111 MY (choose_reloc_size) (abfd)
00112      bfd *abfd;
00113 {
00114   switch (bfd_get_arch (abfd))
00115     {
00116     case bfd_arch_sparc:
00117     case bfd_arch_mips:
00118       obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
00119       break;
00120     default:
00121       obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
00122       break;
00123     }
00124 }
00125 
00126 /* Write an object file in BSD a.out format.
00127   Section contents have already been written.  We write the
00128   file header, symbols, and relocation.  */
00129 
00130 static bfd_boolean
00131 MY (write_object_contents) (abfd)
00132      bfd *abfd;
00133 {
00134   struct external_exec exec_bytes;
00135   struct internal_exec *execp = exec_hdr (abfd);
00136 
00137   /* Magic number, maestro, please!  */
00138   switch (bfd_get_arch (abfd))
00139     {
00140     case bfd_arch_m68k:
00141       switch (bfd_get_mach (abfd))
00142        {
00143        case bfd_mach_m68010:
00144          N_SET_MACHTYPE (*execp, M_68010);
00145          break;
00146        default:
00147        case bfd_mach_m68020:
00148          N_SET_MACHTYPE (*execp, M_68020);
00149          break;
00150        }
00151       break;
00152     case bfd_arch_sparc:
00153       N_SET_MACHTYPE (*execp, M_SPARC);
00154       break;
00155     case bfd_arch_i386:
00156       N_SET_MACHTYPE (*execp, M_386);
00157       break;
00158     case bfd_arch_mips:
00159       switch (bfd_get_mach (abfd))
00160        {
00161        case bfd_mach_mips4000:
00162        case bfd_mach_mips6000:
00163          N_SET_MACHTYPE (*execp, M_MIPS2);
00164          break;
00165        default:
00166          N_SET_MACHTYPE (*execp, M_MIPS1);
00167          break;
00168        }
00169       break;
00170     default:
00171       N_SET_MACHTYPE (*execp, M_UNKNOWN);
00172     }
00173 
00174   MY (choose_reloc_size) (abfd);
00175 
00176   WRITE_HEADERS (abfd, execp);
00177 
00178   return TRUE;
00179 }
00180 
00181 /* MIPS relocation types.  */
00182 #define MIPS_RELOC_32              0
00183 #define MIPS_RELOC_JMP             1
00184 #define MIPS_RELOC_WDISP16  2
00185 #define MIPS_RELOC_HI16            3
00186 #define MIPS_RELOC_HI16_S   4
00187 #define MIPS_RELOC_LO16            5
00188 
00189 /* This is only called when performing a BFD_RELOC_MIPS_JMP relocation.
00190    The jump destination address is formed from the upper 4 bits of the
00191    "current" program counter concatenated with the jump instruction's
00192    26 bit field and two trailing zeros.
00193    If the destination address is not in the same segment as the "current"
00194    program counter, then we need to signal an error.  */
00195 
00196 static bfd_reloc_status_type
00197 mips_fix_jmp_addr (abfd, reloc_entry, symbol, data, input_section, output_bfd,
00198                  error_message)
00199      bfd *abfd ATTRIBUTE_UNUSED;
00200      arelent *reloc_entry;
00201      struct bfd_symbol *symbol;
00202      PTR data ATTRIBUTE_UNUSED;
00203      asection *input_section;
00204      bfd *output_bfd;
00205      char **error_message ATTRIBUTE_UNUSED;
00206 {
00207   bfd_vma relocation, pc;
00208 
00209   /* If this is a partial relocation, just continue.  */
00210   if (output_bfd != (bfd *)NULL)
00211     return bfd_reloc_continue;
00212 
00213   /* If this is an undefined symbol, return error */
00214   if (bfd_is_und_section (symbol->section)
00215       && (symbol->flags & BSF_WEAK) == 0)
00216     return bfd_reloc_undefined;
00217 
00218   /* Work out which section the relocation is targeted at and the
00219      initial relocation command value.  */
00220   if (bfd_is_com_section (symbol->section))
00221     relocation = 0;
00222   else
00223     relocation = symbol->value;
00224 
00225   relocation += symbol->section->output_section->vma;
00226   relocation += symbol->section->output_offset;
00227   relocation += reloc_entry->addend;
00228 
00229   pc = input_section->output_section->vma + input_section->output_offset +
00230     reloc_entry->address + 4;
00231 
00232   if ((relocation & 0xF0000000) != (pc & 0xF0000000))
00233     return bfd_reloc_overflow;
00234 
00235   return bfd_reloc_continue;
00236 }
00237 
00238 /* This is only called when performing a BFD_RELOC_HI16_S relocation.
00239    We need to see if bit 15 is set in the result. If it is, we add
00240    0x10000 and continue normally. This will compensate for the sign extension
00241    when the low bits are added at run time.  */
00242 
00243 static bfd_reloc_status_type
00244 mips_fix_hi16_s PARAMS ((bfd *, arelent *, asymbol *, PTR,
00245                       asection *, bfd *, char **));
00246 
00247 static bfd_reloc_status_type
00248 mips_fix_hi16_s (abfd, reloc_entry, symbol, data, input_section,
00249                output_bfd, error_message)
00250      bfd *abfd ATTRIBUTE_UNUSED;
00251      arelent *reloc_entry;
00252      asymbol *symbol;
00253      PTR data ATTRIBUTE_UNUSED;
00254      asection *input_section ATTRIBUTE_UNUSED;
00255      bfd *output_bfd;
00256      char **error_message ATTRIBUTE_UNUSED;
00257 {
00258   bfd_vma relocation;
00259 
00260   /* If this is a partial relocation, just continue.  */
00261   if (output_bfd != (bfd *)NULL)
00262     return bfd_reloc_continue;
00263 
00264   /* If this is an undefined symbol, return error.  */
00265   if (bfd_is_und_section (symbol->section)
00266       && (symbol->flags & BSF_WEAK) == 0)
00267     return bfd_reloc_undefined;
00268 
00269   /* Work out which section the relocation is targeted at and the
00270      initial relocation command value.  */
00271   if (bfd_is_com_section (symbol->section))
00272     relocation = 0;
00273   else
00274     relocation = symbol->value;
00275 
00276   relocation += symbol->section->output_section->vma;
00277   relocation += symbol->section->output_offset;
00278   relocation += reloc_entry->addend;
00279 
00280   if (relocation & 0x8000)
00281     reloc_entry->addend += 0x10000;
00282 
00283   return bfd_reloc_continue;
00284 }
00285 
00286 static reloc_howto_type mips_howto_table_ext[] = {
00287   {MIPS_RELOC_32,      0, 2, 32, FALSE, 0,  complain_overflow_bitfield, 0,
00288        "32",       FALSE, 0, 0xffffffff, FALSE},
00289   {MIPS_RELOC_JMP,     2, 2, 26, FALSE, 0, complain_overflow_dont,
00290        mips_fix_jmp_addr,
00291        "MIPS_JMP", FALSE, 0, 0x03ffffff, FALSE},
00292   {MIPS_RELOC_WDISP16, 2, 2, 16, TRUE,  0, complain_overflow_signed, 0,
00293        "WDISP16",  FALSE, 0, 0x0000ffff, FALSE},
00294   {MIPS_RELOC_HI16,   16, 2, 16, FALSE, 0, complain_overflow_bitfield, 0,
00295        "HI16",     FALSE, 0, 0x0000ffff, FALSE},
00296   {MIPS_RELOC_HI16_S, 16, 2, 16, FALSE, 0, complain_overflow_bitfield,
00297         mips_fix_hi16_s,
00298         "HI16_S",   FALSE, 0, 0x0000ffff, FALSE},
00299   {MIPS_RELOC_LO16,    0, 2, 16, FALSE, 0, complain_overflow_dont, 0,
00300        "LO16",     FALSE, 0, 0x0000ffff, FALSE},
00301 };
00302 
00303 static reloc_howto_type *
00304 MY(reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
00305 {
00306 
00307   if (bfd_get_arch (abfd) != bfd_arch_mips)
00308     return 0;
00309 
00310   switch (code)
00311     {
00312     case BFD_RELOC_CTOR:
00313     case BFD_RELOC_32:
00314       return (&mips_howto_table_ext[MIPS_RELOC_32]);
00315     case BFD_RELOC_MIPS_JMP:
00316       return (&mips_howto_table_ext[MIPS_RELOC_JMP]);
00317     case BFD_RELOC_16_PCREL_S2:
00318       return (&mips_howto_table_ext[MIPS_RELOC_WDISP16]);
00319     case BFD_RELOC_HI16:
00320       return (&mips_howto_table_ext[MIPS_RELOC_HI16]);
00321     case BFD_RELOC_HI16_S:
00322       return (&mips_howto_table_ext[MIPS_RELOC_HI16_S]);
00323     case BFD_RELOC_LO16:
00324       return (&mips_howto_table_ext[MIPS_RELOC_LO16]);
00325     default:
00326       return 0;
00327     }
00328 }
00329 
00330 static reloc_howto_type *
00331 MY(reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED,
00332                           const char *r_name)
00333 {
00334   unsigned int i;
00335 
00336   for (i = 0;
00337        i < sizeof (mips_howto_table_ext) / sizeof (mips_howto_table_ext[0]);
00338        i++)
00339     if (mips_howto_table_ext[i].name != NULL
00340        && strcasecmp (mips_howto_table_ext[i].name, r_name) == 0)
00341       return &mips_howto_table_ext[i];
00342 
00343   return NULL;
00344 }
00345 
00346 /* This is just like the standard aoutx.h version but we need to do our
00347    own mapping of external reloc type values to howto entries.  */
00348 long
00349 MY(canonicalize_reloc) (abfd, section, relptr, symbols)
00350       bfd *abfd;
00351       sec_ptr section;
00352       arelent **relptr;
00353       asymbol **symbols;
00354 {
00355   arelent *tblptr = section->relocation;
00356   unsigned int count, c;
00357   extern reloc_howto_type NAME(aout,ext_howto_table)[];
00358 
00359   /* If we have already read in the relocation table, return the values.  */
00360   if (section->flags & SEC_CONSTRUCTOR)
00361     {
00362       arelent_chain *chain = section->constructor_chain;
00363 
00364       for (count = 0; count < section->reloc_count; count++)
00365        {
00366          *relptr++ = &chain->relent;
00367          chain = chain->next;
00368        }
00369       *relptr = 0;
00370       return section->reloc_count;
00371     }
00372 
00373   if (tblptr && section->reloc_count)
00374     {
00375       for (count = 0; count++ < section->reloc_count;)
00376        *relptr++ = tblptr++;
00377       *relptr = 0;
00378       return section->reloc_count;
00379     }
00380 
00381   if (!NAME(aout,slurp_reloc_table) (abfd, section, symbols))
00382     return -1;
00383   tblptr = section->relocation;
00384 
00385   /* fix up howto entries.  */
00386   for (count = 0; count++ < section->reloc_count;)
00387     {
00388       c = tblptr->howto - NAME(aout,ext_howto_table);
00389       tblptr->howto = &mips_howto_table_ext[c];
00390 
00391       *relptr++ = tblptr++;
00392     }
00393   *relptr = 0;
00394   return section->reloc_count;
00395 }
00396 
00397 static const struct aout_backend_data MY(backend_data) = {
00398   0,                        /* zmagic contiguous */
00399   1,                        /* text incl header */
00400   0,                        /* entry is text address */
00401   0,                        /* exec_hdr_flags */
00402   TARGET_PAGE_SIZE,                /* text vma */
00403   MY_set_sizes,
00404   0,                        /* text size includes exec header */
00405   0,                        /* add_dynamic_symbols */
00406   0,                        /* add_one_symbol */
00407   0,                        /* link_dynamic_object */
00408   0,                        /* write_dynamic_symbol */
00409   0,                        /* check_dynamic_reloc */
00410   0                         /* finish_dynamic_link */
00411 };
00412 
00413 extern const bfd_target aout_mips_big_vec;
00414 
00415 const bfd_target aout_mips_little_vec =
00416   {
00417     "a.out-mips-little",           /* name */
00418     bfd_target_aout_flavour,
00419     BFD_ENDIAN_LITTLE,             /* target byte order (little) */
00420     BFD_ENDIAN_LITTLE,             /* target headers byte order (little) */
00421     (HAS_RELOC | EXEC_P |          /* object flags */
00422      HAS_LINENO | HAS_DEBUG |
00423      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
00424     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
00425     MY_symbol_leading_char,
00426     ' ',                           /* ar_pad_char */
00427     15,                            /* ar_max_namelen */
00428     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
00429     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
00430     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
00431     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
00432     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
00433     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
00434     {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
00435      bfd_generic_archive_p, MY_core_file_p},
00436     {bfd_false, MY_mkobject,       /* bfd_set_format */
00437      _bfd_generic_mkarchive, bfd_false},
00438     {bfd_false, MY_write_object_contents, /* bfd_write_contents */
00439      _bfd_write_archive_contents, bfd_false},
00440 
00441     BFD_JUMP_TABLE_GENERIC (MY),
00442     BFD_JUMP_TABLE_COPY (MY),
00443     BFD_JUMP_TABLE_CORE (MY),
00444     BFD_JUMP_TABLE_ARCHIVE (MY),
00445     BFD_JUMP_TABLE_SYMBOLS (MY),
00446     BFD_JUMP_TABLE_RELOCS (MY),
00447     BFD_JUMP_TABLE_WRITE (MY),
00448     BFD_JUMP_TABLE_LINK (MY),
00449     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
00450 
00451     & aout_mips_big_vec,
00452 
00453     (PTR) MY_backend_data
00454   };
00455 
00456 const bfd_target aout_mips_big_vec =
00457   {
00458     "a.out-mips-big",              /* name */
00459     bfd_target_aout_flavour,
00460     BFD_ENDIAN_BIG,         /* target byte order (big) */
00461     BFD_ENDIAN_BIG,         /* target headers byte order (big) */
00462     (HAS_RELOC | EXEC_P |          /* object flags */
00463      HAS_LINENO | HAS_DEBUG |
00464      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
00465     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
00466     MY_symbol_leading_char,
00467     ' ',                           /* ar_pad_char */
00468     15,                            /* ar_max_namelen */
00469     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
00470     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
00471     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
00472     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
00473     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
00474     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
00475     {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
00476      bfd_generic_archive_p, MY_core_file_p},
00477     {bfd_false, MY_mkobject,       /* bfd_set_format */
00478      _bfd_generic_mkarchive, bfd_false},
00479     {bfd_false, MY_write_object_contents, /* bfd_write_contents */
00480      _bfd_write_archive_contents, bfd_false},
00481 
00482     BFD_JUMP_TABLE_GENERIC (MY),
00483     BFD_JUMP_TABLE_COPY (MY),
00484     BFD_JUMP_TABLE_CORE (MY),
00485     BFD_JUMP_TABLE_ARCHIVE (MY),
00486     BFD_JUMP_TABLE_SYMBOLS (MY),
00487     BFD_JUMP_TABLE_RELOCS (MY),
00488     BFD_JUMP_TABLE_WRITE (MY),
00489     BFD_JUMP_TABLE_LINK (MY),
00490     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
00491 
00492     & aout_mips_little_vec,
00493 
00494     (PTR) MY_backend_data
00495   };