Back to index

cell-binutils  2.17cvs20070401
aout-ns32k.c
Go to the documentation of this file.
00001 /* BFD back-end for ns32k a.out-ish binaries.
00002    Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
00003    2002, 2003, 2005, 2007 Free Software Foundation, Inc.
00004    Contributed by Ian Dall (idall@eleceng.adelaide.edu.au).
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 #include "bfd.h"
00023 #include "aout/aout64.h"
00024 #include "ns32k.h"
00025 
00026 /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
00027    remove whitespace added here, and thus will fail to concatenate
00028    the tokens.  */
00029 #define MYNS(OP) CONCAT2 (ns32kaout_,OP)
00030 
00031 reloc_howto_type * MYNS (bfd_reloc_type_lookup) (bfd *, bfd_reloc_code_real_type);
00032 reloc_howto_type * MYNS (bfd_reloc_name_lookup) (bfd *, const char *);
00033 bfd_boolean        MYNS (write_object_contents) (bfd *);
00034 
00035 /* Avoid multiple definitions from aoutx if supporting
00036    standard a.out format(s) as well as this one.  */
00037 #define NAME(x,y) CONCAT3 (ns32kaout,_32_,y)
00038 
00039 void bfd_ns32k_arch (void);
00040 
00041 #include "libaout.h"
00042 
00043 #define MY(OP) MYNS (OP)
00044 
00045 #define MY_swap_std_reloc_in   MY (swap_std_reloc_in)
00046 #define MY_swap_std_reloc_out  MY (swap_std_reloc_out)
00047 
00048 /* The ns32k series is ah, unusual, when it comes to relocation.
00049    There are three storage methods for relocatable objects.  There
00050    are displacements, immediate operands and ordinary twos complement
00051    data. Of these, only the last fits into the standard relocation
00052    scheme.  Immediate operands are stored huffman encoded and
00053    immediate operands are stored big endian (where as the natural byte
00054    order is little endian for this architecture).
00055 
00056    Note that the ns32k displacement storage method is orthogonal to
00057    whether the relocation is pc relative or not. The "displacement"
00058    storage scheme is used for essentially all address constants. The
00059    displacement can be relative to zero (absolute displacement),
00060    relative to the pc (pc relative), the stack pointer, the frame
00061    pointer, the static base register and general purpose register etc.
00062 
00063    For example:
00064 
00065    sym1: .long .      # pc relative 2's complement
00066    sym1: .long foo    # 2's complement not pc relative
00067 
00068    self:  movd @self, r0 # pc relative displacement
00069           movd foo, r0   # non pc relative displacement
00070 
00071    self:  movd self, r0  # pc relative immediate
00072           movd foo, r0   # non pc relative immediate
00073 
00074    In addition, for historical reasons the encoding of the relocation types
00075    in the a.out format relocation entries is such that even the relocation
00076    methods which are standard are not encoded the standard way.  */
00077 
00078 reloc_howto_type MY (howto_table)[] =
00079 {
00080   /* ns32k immediate operands.  */
00081   HOWTO (BFD_RELOC_NS32K_IMM_8, 0, 0, 8, FALSE, 0, complain_overflow_signed,
00082         _bfd_ns32k_reloc_imm, "NS32K_IMM_8",
00083         TRUE, 0x000000ff,0x000000ff, FALSE),
00084   HOWTO (BFD_RELOC_NS32K_IMM_16, 0, 1, 16, FALSE, 0, complain_overflow_signed,
00085         _bfd_ns32k_reloc_imm,  "NS32K_IMM_16",
00086         TRUE, 0x0000ffff,0x0000ffff, FALSE),
00087   HOWTO (BFD_RELOC_NS32K_IMM_32, 0, 2, 32, FALSE, 0, complain_overflow_signed,
00088         _bfd_ns32k_reloc_imm, "NS32K_IMM_32",
00089         TRUE, 0xffffffff,0xffffffff, FALSE),
00090   HOWTO (BFD_RELOC_NS32K_IMM_8_PCREL, 0, 0, 8, TRUE, 0, complain_overflow_signed,
00091         _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_8",
00092         TRUE, 0x000000ff, 0x000000ff, FALSE),
00093   HOWTO (BFD_RELOC_NS32K_IMM_16_PCREL, 0, 1, 16, TRUE, 0, complain_overflow_signed,
00094         _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_16",
00095         TRUE, 0x0000ffff,0x0000ffff, FALSE),
00096   HOWTO (BFD_RELOC_NS32K_IMM_32_PCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed,
00097         _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_32",
00098         TRUE, 0xffffffff,0xffffffff, FALSE),
00099 
00100   /* ns32k displacements.  */
00101   HOWTO (BFD_RELOC_NS32K_DISP_8, 0, 0, 7, FALSE, 0, complain_overflow_signed,
00102         _bfd_ns32k_reloc_disp, "NS32K_DISP_8",
00103         TRUE, 0x000000ff,0x000000ff, FALSE),
00104   HOWTO (BFD_RELOC_NS32K_DISP_16, 0, 1, 14, FALSE, 0, complain_overflow_signed,
00105         _bfd_ns32k_reloc_disp, "NS32K_DISP_16",
00106         TRUE, 0x0000ffff, 0x0000ffff, FALSE),
00107   HOWTO (BFD_RELOC_NS32K_DISP_32, 0, 2, 30, FALSE, 0, complain_overflow_signed,
00108         _bfd_ns32k_reloc_disp, "NS32K_DISP_32",
00109         TRUE, 0xffffffff, 0xffffffff, FALSE),
00110   HOWTO (BFD_RELOC_NS32K_DISP_8_PCREL, 0, 0, 7, TRUE, 0, complain_overflow_signed,
00111           _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_8",
00112         TRUE, 0x000000ff,0x000000ff, FALSE),
00113   HOWTO (BFD_RELOC_NS32K_DISP_16_PCREL, 0, 1, 14, TRUE, 0, complain_overflow_signed,
00114         _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_16",
00115         TRUE, 0x0000ffff,0x0000ffff, FALSE),
00116   HOWTO (BFD_RELOC_NS32K_DISP_32_PCREL, 0, 2, 30, TRUE, 0, complain_overflow_signed,
00117         _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_32",
00118         TRUE, 0xffffffff,0xffffffff, FALSE),
00119 
00120   /* Normal 2's complement.  */
00121   HOWTO (BFD_RELOC_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,0,
00122         "8", TRUE, 0x000000ff,0x000000ff, FALSE),
00123   HOWTO (BFD_RELOC_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,0,
00124         "16", TRUE, 0x0000ffff,0x0000ffff, FALSE),
00125   HOWTO (BFD_RELOC_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,0,
00126         "32", TRUE, 0xffffffff,0xffffffff, FALSE),
00127   HOWTO (BFD_RELOC_8_PCREL, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0,
00128         "PCREL_8", TRUE, 0x000000ff,0x000000ff, FALSE),
00129   HOWTO (BFD_RELOC_16_PCREL, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0,
00130         "PCREL_16", TRUE, 0x0000ffff,0x0000ffff, FALSE),
00131   HOWTO (BFD_RELOC_32_PCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0,
00132         "PCREL_32", TRUE, 0xffffffff,0xffffffff, FALSE),
00133 };
00134 
00135 #define CTOR_TABLE_RELOC_HOWTO(BFD) (MY (howto_table) + 14)
00136 
00137 #define RELOC_STD_BITS_NS32K_TYPE_BIG            0x06
00138 #define RELOC_STD_BITS_NS32K_TYPE_LITTLE  0x60
00139 #define RELOC_STD_BITS_NS32K_TYPE_SH_BIG  1
00140 #define RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE      5
00141 
00142 static reloc_howto_type *
00143 MY (reloc_howto) (bfd *abfd ATTRIBUTE_UNUSED,
00144                 struct reloc_std_external *rel,
00145                 int *r_index,
00146                 int *r_extern,
00147                 int *r_pcrel)
00148 {
00149   unsigned int r_length;
00150   int r_ns32k_type;
00151 
00152   *r_index =  ((rel->r_index[2] << 16)
00153               | (rel->r_index[1] << 8)
00154               |  rel->r_index[0] );
00155   *r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
00156   *r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
00157   r_length  =  ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
00158               >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
00159   r_ns32k_type  =  ((rel->r_type[0] & RELOC_STD_BITS_NS32K_TYPE_LITTLE)
00160                   >> RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE);
00161   return (MY (howto_table) + r_length + 3 * (*r_pcrel) + 6 * r_ns32k_type);
00162 }
00163 
00164 #define MY_reloc_howto(BFD, REL, IN, EX, PC) \
00165   MY (reloc_howto) (BFD, REL, &IN, &EX, &PC)
00166 
00167 static void
00168 MY (put_reloc) (bfd *abfd,
00169               int r_extern,
00170               int r_index,
00171               bfd_vma value,
00172               reloc_howto_type *howto,
00173               struct reloc_std_external *reloc)
00174 {
00175   unsigned int r_length;
00176   int r_pcrel;
00177   int r_ns32k_type;
00178 
00179   PUT_WORD (abfd, value, reloc->r_address);
00180   r_length = howto->size ;  /* Size as a power of two.  */
00181   r_pcrel  = (int) howto->pc_relative; /* Relative to PC?  */
00182   r_ns32k_type = (howto - MY (howto_table) )/6;
00183 
00184   reloc->r_index[2] = r_index >> 16;
00185   reloc->r_index[1] = r_index >> 8;
00186   reloc->r_index[0] = r_index;
00187   reloc->r_type[0] =
00188     (r_extern?    RELOC_STD_BITS_EXTERN_LITTLE: 0)
00189       | (r_pcrel?     RELOC_STD_BITS_PCREL_LITTLE: 0)
00190        | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE)
00191          | (r_ns32k_type <<  RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE);
00192 }
00193 
00194 #define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \
00195   MY (put_reloc) (BFD, EXT, IDX, VAL, HOWTO, RELOC)
00196 
00197 #define STAT_FOR_EXEC
00198 
00199 #define MY_final_link_relocate _bfd_ns32k_final_link_relocate
00200 #define MY_relocate_contents   _bfd_ns32k_relocate_contents
00201 
00202 static void MY_swap_std_reloc_in (bfd *, struct reloc_std_external *, arelent *, asymbol **, bfd_size_type);
00203 static void MY_swap_std_reloc_out (bfd *, arelent *, struct reloc_std_external *);
00204 
00205 #include "aoutx.h"
00206 
00207 reloc_howto_type *
00208 MY (bfd_reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
00209 {
00210 #define ENTRY(i,j)   case i: return &MY (howto_table)[j]
00211 
00212   int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
00213 
00214   BFD_ASSERT (ext == 0);
00215   if (code == BFD_RELOC_CTOR)
00216     switch (bfd_get_arch_info (abfd)->bits_per_address)
00217       {
00218       case 32:
00219        code = BFD_RELOC_32;
00220        break;
00221       default:
00222        break;
00223       }
00224   switch (code)
00225     {
00226       ENTRY (BFD_RELOC_NS32K_IMM_8, 0);
00227       ENTRY (BFD_RELOC_NS32K_IMM_16, 1);
00228       ENTRY (BFD_RELOC_NS32K_IMM_32, 2);
00229       ENTRY (BFD_RELOC_NS32K_IMM_8_PCREL, 3);
00230       ENTRY (BFD_RELOC_NS32K_IMM_16_PCREL, 4);
00231       ENTRY (BFD_RELOC_NS32K_IMM_32_PCREL, 5);
00232       ENTRY (BFD_RELOC_NS32K_DISP_8, 6);
00233       ENTRY (BFD_RELOC_NS32K_DISP_16, 7);
00234       ENTRY (BFD_RELOC_NS32K_DISP_32, 8);
00235       ENTRY (BFD_RELOC_NS32K_DISP_8_PCREL, 9);
00236       ENTRY (BFD_RELOC_NS32K_DISP_16_PCREL, 10);
00237       ENTRY (BFD_RELOC_NS32K_DISP_32_PCREL, 11);
00238       ENTRY (BFD_RELOC_8, 12);
00239       ENTRY (BFD_RELOC_16, 13);
00240       ENTRY (BFD_RELOC_32, 14);
00241       ENTRY (BFD_RELOC_8_PCREL, 15);
00242       ENTRY (BFD_RELOC_16_PCREL, 16);
00243       ENTRY (BFD_RELOC_32_PCREL, 17);
00244     default:
00245       return NULL;
00246     }
00247 #undef ENTRY
00248 }
00249 
00250 reloc_howto_type *
00251 MY (bfd_reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED,
00252                          const char *r_name)
00253 {
00254   unsigned int i;
00255 
00256   for (i = 0;
00257        i < sizeof (MY (howto_table)) / sizeof (MY (howto_table)[0]);
00258        i++)
00259     if (MY (howto_table)[i].name != NULL
00260        && strcasecmp (MY (howto_table)[i].name, r_name) == 0)
00261       return &MY (howto_table)[i];
00262 
00263   return NULL;
00264 }
00265 
00266 static void
00267 MY_swap_std_reloc_in (bfd *abfd,
00268                     struct reloc_std_external *bytes,
00269                     arelent *cache_ptr,
00270                     asymbol **symbols,
00271                     bfd_size_type symcount ATTRIBUTE_UNUSED)
00272 {
00273   int r_index;
00274   int r_extern;
00275   int r_pcrel;
00276   struct aoutdata  *su = &(abfd->tdata.aout_data->a);
00277 
00278   cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
00279 
00280   /* Now the fun stuff.  */
00281   cache_ptr->howto = MY_reloc_howto (abfd, bytes, r_index, r_extern, r_pcrel);
00282 
00283   MOVE_ADDRESS (0);
00284 }
00285 
00286 static void
00287 MY_swap_std_reloc_out (bfd *abfd,
00288                      arelent *g,
00289                      struct reloc_std_external *natptr)
00290 {
00291   int r_index;
00292   asymbol *sym = *(g->sym_ptr_ptr);
00293   int r_extern;
00294   asection *output_section = sym->section->output_section;
00295 
00296   /* Name was clobbered by aout_write_syms to be symbol index.  */
00297 
00298   /* If this relocation is relative to a symbol then set the
00299      r_index to the symbols index, and the r_extern bit.
00300 
00301      Absolute symbols can come in in two ways, either as an offset
00302      from the abs section, or as a symbol which has an abs value.
00303      Check for that here.  */
00304   if (bfd_is_com_section (output_section)
00305       || output_section == &bfd_abs_section
00306       || output_section == &bfd_und_section)
00307     {
00308       if (bfd_abs_section.symbol == sym)
00309        {
00310          /* Whoops, looked like an abs symbol, but is really an offset
00311             from the abs section.  */
00312          r_index = 0;
00313          r_extern = 0;
00314        }
00315       else
00316        {
00317          /* Fill in symbol.  */
00318          r_extern = 1;
00319 #undef KEEPIT
00320 #define KEEPIT udata.i
00321          r_index =  (*(g->sym_ptr_ptr))->KEEPIT;
00322 #undef KEEPIT
00323        }
00324     }
00325   else
00326     {
00327       /* Just an ordinary section.  */
00328       r_extern = 0;
00329       r_index  = output_section->target_index;
00330     }
00331 
00332   MY_put_reloc (abfd, r_extern, r_index, g->address, g->howto, natptr);
00333 }
00334 
00335 bfd_reloc_status_type
00336 _bfd_ns32k_relocate_contents (reloc_howto_type *howto,
00337                            bfd *input_bfd,
00338                            bfd_vma relocation,
00339                            bfd_byte *location)
00340 {
00341   int r_ns32k_type = (howto - MY (howto_table)) / 6;
00342   bfd_vma (*get_data) (bfd_byte *, int);
00343   void (*put_data) (bfd_vma, bfd_byte *, int);
00344 
00345   switch (r_ns32k_type)
00346     {
00347     case 0:
00348       get_data = _bfd_ns32k_get_immediate;
00349       put_data = _bfd_ns32k_put_immediate;
00350       break;
00351     case 1:
00352       get_data = _bfd_ns32k_get_displacement;
00353       put_data = _bfd_ns32k_put_displacement;
00354       break;
00355     case 2:
00356       return _bfd_relocate_contents (howto, input_bfd, relocation,
00357                                 location);
00358     default:
00359       return bfd_reloc_notsupported;
00360     }
00361   return _bfd_do_ns32k_reloc_contents (howto, input_bfd, relocation,
00362                                    location, get_data, put_data);
00363 }