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