(root)/
binutils-2.41/
bfd/
aout-ns32k.c
       1  /* BFD back-end for ns32k a.out-ish binaries.
       2     Copyright (C) 1990-2023 Free Software Foundation, Inc.
       3     Contributed by Ian Dall (idall@eleceng.adelaide.edu.au).
       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  #include "sysdep.h"
      23  #include "bfd.h"
      24  #include "libbfd.h"
      25  #include "aout/aout64.h"
      26  #include "ns32k.h"
      27  
      28  /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
      29     remove whitespace added here, and thus will fail to concatenate
      30     the tokens.  */
      31  #define MYNS(OP) CONCAT2 (ns32k_aout_,OP)
      32  
      33  reloc_howto_type * MYNS (bfd_reloc_type_lookup) (bfd *, bfd_reloc_code_real_type);
      34  reloc_howto_type * MYNS (bfd_reloc_name_lookup) (bfd *, const char *);
      35  bool MYNS (write_object_contents) (bfd *);
      36  
      37  /* Avoid multiple definitions from aoutx if supporting
      38     standard a.out format(s) as well as this one.  */
      39  #define NAME(x,y) CONCAT3 (ns32kaout,_32_,y)
      40  
      41  void bfd_ns32k_arch (void);
      42  
      43  #include "libaout.h"
      44  
      45  #define MY(OP) MYNS (OP)
      46  
      47  #define MY_swap_std_reloc_in   MY (swap_std_reloc_in)
      48  #define MY_swap_std_reloc_out  MY (swap_std_reloc_out)
      49  
      50  /* The ns32k series is ah, unusual, when it comes to relocation.
      51     There are three storage methods for relocatable objects.  There
      52     are displacements, immediate operands and ordinary twos complement
      53     data. Of these, only the last fits into the standard relocation
      54     scheme.  Immediate operands are stored huffman encoded and
      55     immediate operands are stored big endian (where as the natural byte
      56     order is little endian for this architecture).
      57  
      58     Note that the ns32k displacement storage method is orthogonal to
      59     whether the relocation is pc relative or not. The "displacement"
      60     storage scheme is used for essentially all address constants. The
      61     displacement can be relative to zero (absolute displacement),
      62     relative to the pc (pc relative), the stack pointer, the frame
      63     pointer, the static base register and general purpose register etc.
      64  
      65     For example:
      66  
      67     sym1: .long .	 # pc relative 2's complement
      68     sym1: .long foo	 # 2's complement not pc relative
      69  
      70     self:  movd @self, r0 # pc relative displacement
      71  	  movd foo, r0   # non pc relative displacement
      72  
      73     self:  movd self, r0  # pc relative immediate
      74  	  movd foo, r0   # non pc relative immediate
      75  
      76     In addition, for historical reasons the encoding of the relocation types
      77     in the a.out format relocation entries is such that even the relocation
      78     methods which are standard are not encoded the standard way.  */
      79  
      80  reloc_howto_type MY (howto_table)[] =
      81  {
      82    /* ns32k immediate operands.  */
      83    HOWTO (BFD_RELOC_NS32K_IMM_8, 0, 1, 8, false, 0, complain_overflow_signed,
      84  	 _bfd_ns32k_reloc_imm, "NS32K_IMM_8",
      85  	 true, 0x000000ff,0x000000ff, false),
      86    HOWTO (BFD_RELOC_NS32K_IMM_16, 0, 2, 16, false, 0, complain_overflow_signed,
      87  	 _bfd_ns32k_reloc_imm,  "NS32K_IMM_16",
      88  	 true, 0x0000ffff,0x0000ffff, false),
      89    HOWTO (BFD_RELOC_NS32K_IMM_32, 0, 4, 32, false, 0, complain_overflow_signed,
      90  	 _bfd_ns32k_reloc_imm, "NS32K_IMM_32",
      91  	 true, 0xffffffff,0xffffffff, false),
      92    HOWTO (BFD_RELOC_NS32K_IMM_8_PCREL, 0, 1, 8, true, 0, complain_overflow_signed,
      93  	 _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_8",
      94  	 true, 0x000000ff, 0x000000ff, false),
      95    HOWTO (BFD_RELOC_NS32K_IMM_16_PCREL, 0, 2, 16, true, 0, complain_overflow_signed,
      96  	 _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_16",
      97  	 true, 0x0000ffff,0x0000ffff, false),
      98    HOWTO (BFD_RELOC_NS32K_IMM_32_PCREL, 0, 4, 32, true, 0, complain_overflow_signed,
      99  	 _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_32",
     100  	 true, 0xffffffff,0xffffffff, false),
     101  
     102    /* ns32k displacements.  */
     103    HOWTO (BFD_RELOC_NS32K_DISP_8, 0, 1, 7, false, 0, complain_overflow_signed,
     104  	 _bfd_ns32k_reloc_disp, "NS32K_DISP_8",
     105  	 true, 0x000000ff,0x000000ff, false),
     106    HOWTO (BFD_RELOC_NS32K_DISP_16, 0, 2, 14, false, 0, complain_overflow_signed,
     107  	 _bfd_ns32k_reloc_disp, "NS32K_DISP_16",
     108  	 true, 0x0000ffff, 0x0000ffff, false),
     109    HOWTO (BFD_RELOC_NS32K_DISP_32, 0, 4, 30, false, 0, complain_overflow_signed,
     110  	 _bfd_ns32k_reloc_disp, "NS32K_DISP_32",
     111  	 true, 0xffffffff, 0xffffffff, false),
     112    HOWTO (BFD_RELOC_NS32K_DISP_8_PCREL, 0, 1, 7, true, 0, complain_overflow_signed,
     113  	   _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_8",
     114  	 true, 0x000000ff,0x000000ff, false),
     115    HOWTO (BFD_RELOC_NS32K_DISP_16_PCREL, 0, 2, 14, true, 0, complain_overflow_signed,
     116  	 _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_16",
     117  	 true, 0x0000ffff,0x0000ffff, false),
     118    HOWTO (BFD_RELOC_NS32K_DISP_32_PCREL, 0, 4, 30, true, 0, complain_overflow_signed,
     119  	 _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_32",
     120  	 true, 0xffffffff,0xffffffff, false),
     121  
     122    /* Normal 2's complement.  */
     123    HOWTO (BFD_RELOC_8, 0, 1, 8, false, 0, complain_overflow_bitfield,0,
     124  	 "8", true, 0x000000ff,0x000000ff, false),
     125    HOWTO (BFD_RELOC_16, 0, 2, 16, false, 0, complain_overflow_bitfield,0,
     126  	 "16", true, 0x0000ffff,0x0000ffff, false),
     127    HOWTO (BFD_RELOC_32, 0, 4, 32, false, 0, complain_overflow_bitfield,0,
     128  	 "32", true, 0xffffffff,0xffffffff, false),
     129    HOWTO (BFD_RELOC_8_PCREL, 0, 1, 8, true, 0, complain_overflow_signed, 0,
     130  	 "PCREL_8", true, 0x000000ff,0x000000ff, false),
     131    HOWTO (BFD_RELOC_16_PCREL, 0, 2, 16, true, 0, complain_overflow_signed, 0,
     132  	 "PCREL_16", true, 0x0000ffff,0x0000ffff, false),
     133    HOWTO (BFD_RELOC_32_PCREL, 0, 4, 32, true, 0, complain_overflow_signed, 0,
     134  	 "PCREL_32", true, 0xffffffff,0xffffffff, false),
     135  };
     136  
     137  #define CTOR_TABLE_RELOC_HOWTO(BFD) (MY (howto_table) + 14)
     138  
     139  #define RELOC_STD_BITS_NS32K_TYPE_BIG		0x06
     140  #define RELOC_STD_BITS_NS32K_TYPE_LITTLE	0x60
     141  #define RELOC_STD_BITS_NS32K_TYPE_SH_BIG	1
     142  #define RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE	5
     143  
     144  static reloc_howto_type *
     145  MY (reloc_howto) (bfd *abfd ATTRIBUTE_UNUSED,
     146  		  struct reloc_std_external *rel,
     147  		  unsigned int *r_index,
     148  		  int *r_extern,
     149  		  int *r_pcrel)
     150  {
     151    unsigned int r_length;
     152    unsigned int r_ns32k_type;
     153  
     154    *r_index =  ((rel->r_index[2] << 16)
     155  	       | (rel->r_index[1] << 8)
     156  	       |  rel->r_index[0] );
     157    *r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
     158    *r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
     159    r_length  =  ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
     160  		>> RELOC_STD_BITS_LENGTH_SH_LITTLE);
     161    r_ns32k_type  =  ((rel->r_type[0] & RELOC_STD_BITS_NS32K_TYPE_LITTLE)
     162  		    >> RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE);
     163    if (r_length > 2 || r_ns32k_type > 2)
     164      return NULL;
     165    return (MY (howto_table) + r_length + 3 * (*r_pcrel) + 6 * r_ns32k_type);
     166  }
     167  
     168  #define MY_reloc_howto(BFD, REL, IN, EX, PC) \
     169    MY (reloc_howto) (BFD, REL, &IN, &EX, &PC)
     170  
     171  static void
     172  MY (put_reloc) (bfd *abfd,
     173  		int r_extern,
     174  		int r_index,
     175  		bfd_vma value,
     176  		reloc_howto_type *howto,
     177  		struct reloc_std_external *reloc)
     178  {
     179    unsigned int r_length;
     180    int r_pcrel;
     181    int r_ns32k_type;
     182  
     183    PUT_WORD (abfd, value, reloc->r_address);
     184    r_length = bfd_log2 (bfd_get_reloc_size (howto));
     185    r_pcrel  = (int) howto->pc_relative; /* Relative to PC?  */
     186    r_ns32k_type = (howto - MY (howto_table) )/6;
     187  
     188    reloc->r_index[2] = r_index >> 16;
     189    reloc->r_index[1] = r_index >> 8;
     190    reloc->r_index[0] = r_index;
     191    reloc->r_type[0] =
     192      (r_extern?    RELOC_STD_BITS_EXTERN_LITTLE: 0)
     193        | (r_pcrel?     RELOC_STD_BITS_PCREL_LITTLE: 0)
     194  	| (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE)
     195  	  | (r_ns32k_type <<  RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE);
     196  }
     197  
     198  #define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \
     199    MY (put_reloc) (BFD, EXT, IDX, VAL, HOWTO, RELOC)
     200  
     201  #define STAT_FOR_EXEC
     202  
     203  #define MY_final_link_relocate _bfd_ns32k_final_link_relocate
     204  #define MY_relocate_contents   _bfd_ns32k_relocate_contents
     205  
     206  static void MY_swap_std_reloc_in (bfd *, struct reloc_std_external *, arelent *, asymbol **, bfd_size_type);
     207  static void MY_swap_std_reloc_out (bfd *, arelent *, struct reloc_std_external *);
     208  
     209  #include "aoutx.h"
     210  
     211  reloc_howto_type *
     212  MY (bfd_reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
     213  {
     214  #define ENTRY(i,j)	case i: return &MY (howto_table)[j]
     215  
     216    int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
     217  
     218    BFD_ASSERT (ext == 0);
     219    if (code == BFD_RELOC_CTOR)
     220      switch (bfd_arch_bits_per_address (abfd))
     221        {
     222        case 32:
     223  	code = BFD_RELOC_32;
     224  	break;
     225        default:
     226  	break;
     227        }
     228    switch (code)
     229      {
     230        ENTRY (BFD_RELOC_NS32K_IMM_8, 0);
     231        ENTRY (BFD_RELOC_NS32K_IMM_16, 1);
     232        ENTRY (BFD_RELOC_NS32K_IMM_32, 2);
     233        ENTRY (BFD_RELOC_NS32K_IMM_8_PCREL, 3);
     234        ENTRY (BFD_RELOC_NS32K_IMM_16_PCREL, 4);
     235        ENTRY (BFD_RELOC_NS32K_IMM_32_PCREL, 5);
     236        ENTRY (BFD_RELOC_NS32K_DISP_8, 6);
     237        ENTRY (BFD_RELOC_NS32K_DISP_16, 7);
     238        ENTRY (BFD_RELOC_NS32K_DISP_32, 8);
     239        ENTRY (BFD_RELOC_NS32K_DISP_8_PCREL, 9);
     240        ENTRY (BFD_RELOC_NS32K_DISP_16_PCREL, 10);
     241        ENTRY (BFD_RELOC_NS32K_DISP_32_PCREL, 11);
     242        ENTRY (BFD_RELOC_8, 12);
     243        ENTRY (BFD_RELOC_16, 13);
     244        ENTRY (BFD_RELOC_32, 14);
     245        ENTRY (BFD_RELOC_8_PCREL, 15);
     246        ENTRY (BFD_RELOC_16_PCREL, 16);
     247        ENTRY (BFD_RELOC_32_PCREL, 17);
     248      default:
     249        return NULL;
     250      }
     251  #undef ENTRY
     252  }
     253  
     254  reloc_howto_type *
     255  MY (bfd_reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED,
     256  			    const char *r_name)
     257  {
     258    unsigned int i;
     259  
     260    for (i = 0;
     261         i < sizeof (MY (howto_table)) / sizeof (MY (howto_table)[0]);
     262         i++)
     263      if (MY (howto_table)[i].name != NULL
     264  	&& strcasecmp (MY (howto_table)[i].name, r_name) == 0)
     265        return &MY (howto_table)[i];
     266  
     267    return NULL;
     268  }
     269  
     270  static void
     271  MY_swap_std_reloc_in (bfd *abfd,
     272  		      struct reloc_std_external *bytes,
     273  		      arelent *cache_ptr,
     274  		      asymbol **symbols,
     275  		      bfd_size_type symcount ATTRIBUTE_UNUSED)
     276  {
     277    unsigned int r_index;
     278    int r_extern;
     279    int r_pcrel;
     280    struct aoutdata  *su = &(abfd->tdata.aout_data->a);
     281  
     282    cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
     283  
     284    /* Now the fun stuff.  */
     285    cache_ptr->howto = MY_reloc_howto (abfd, bytes, r_index, r_extern, r_pcrel);
     286  
     287    MOVE_ADDRESS (0);
     288  }
     289  
     290  static void
     291  MY_swap_std_reloc_out (bfd *abfd,
     292  		       arelent *g,
     293  		       struct reloc_std_external *natptr)
     294  {
     295    int r_index;
     296    asymbol *sym = *(g->sym_ptr_ptr);
     297    int r_extern;
     298    asection *output_section = sym->section->output_section;
     299  
     300    /* Name was clobbered by aout_write_syms to be symbol index.  */
     301  
     302    /* If this relocation is relative to a symbol then set the
     303       r_index to the symbols index, and the r_extern bit.
     304  
     305       Absolute symbols can come in in two ways, either as an offset
     306       from the abs section, or as a symbol which has an abs value.
     307       Check for that here.  */
     308    if (bfd_is_com_section (output_section)
     309        || bfd_is_abs_section (output_section)
     310        || bfd_is_und_section (output_section))
     311      {
     312        if (bfd_abs_section_ptr->symbol == sym)
     313  	{
     314  	  /* Whoops, looked like an abs symbol, but is really an offset
     315  	     from the abs section.  */
     316  	  r_index = 0;
     317  	  r_extern = 0;
     318  	}
     319        else
     320  	{
     321  	  /* Fill in symbol.  */
     322  	  r_extern = 1;
     323  #undef KEEPIT
     324  #define KEEPIT udata.i
     325  	  r_index =  (*(g->sym_ptr_ptr))->KEEPIT;
     326  #undef KEEPIT
     327  	}
     328      }
     329    else
     330      {
     331        /* Just an ordinary section.  */
     332        r_extern = 0;
     333        r_index  = output_section->target_index;
     334      }
     335  
     336    MY_put_reloc (abfd, r_extern, r_index, g->address, g->howto, natptr);
     337  }
     338  
     339  bfd_reloc_status_type
     340  _bfd_ns32k_relocate_contents (reloc_howto_type *howto,
     341  			      bfd *input_bfd,
     342  			      bfd_vma relocation,
     343  			      bfd_byte *location)
     344  {
     345    int r_ns32k_type = (howto - MY (howto_table)) / 6;
     346    bfd_vma (*get_data) (bfd_byte *, int);
     347    void (*put_data) (bfd_vma, bfd_byte *, int);
     348  
     349    switch (r_ns32k_type)
     350      {
     351      case 0:
     352        get_data = _bfd_ns32k_get_immediate;
     353        put_data = _bfd_ns32k_put_immediate;
     354        break;
     355      case 1:
     356        get_data = _bfd_ns32k_get_displacement;
     357        put_data = _bfd_ns32k_put_displacement;
     358        break;
     359      case 2:
     360        return _bfd_relocate_contents (howto, input_bfd, relocation,
     361  				    location);
     362      default:
     363        return bfd_reloc_notsupported;
     364      }
     365    return _bfd_do_ns32k_reloc_contents (howto, input_bfd, relocation,
     366  				       location, get_data, put_data);
     367  }