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