OSDN Git Service

Update the FSF address in the copyright/GPL notice
[pf3gnuchains/pf3gnuchains3x.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., 59 Temple Place - Suite 330, 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   unsigned int r_addend;
278   asection *output_section = sym->section->output_section;
279
280   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
281
282   /* Name was clobbered by aout_write_syms to be symbol index.  */
283
284   /* If this relocation is relative to a symbol then set the
285      r_index to the symbols index, and the r_extern bit.
286
287      Absolute symbols can come in in two ways, either as an offset
288      from the abs section, or as a symbol which has an abs value.
289      Check for that here.  */
290   if (bfd_is_com_section (output_section)
291       || output_section == &bfd_abs_section
292       || output_section == &bfd_und_section)
293     {
294       if (bfd_abs_section.symbol == sym)
295         {
296           /* Whoops, looked like an abs symbol, but is really an offset
297              from the abs section.  */
298           r_index = 0;
299           r_extern = 0;
300         }
301       else
302         {
303           /* Fill in symbol.  */
304           r_extern = 1;
305 #undef KEEPIT
306 #define KEEPIT udata.i
307           r_index =  (*(g->sym_ptr_ptr))->KEEPIT;
308 #undef KEEPIT
309         }
310     }
311   else
312     {
313       /* Just an ordinary section.  */
314       r_extern = 0;
315       r_index  = output_section->target_index;
316     }
317
318   MY_put_reloc (abfd, r_extern, r_index, g->address, g->howto, natptr);
319 }
320
321 bfd_reloc_status_type
322 _bfd_ns32k_relocate_contents (reloc_howto_type *howto,
323                               bfd *input_bfd,
324                               bfd_vma relocation,
325                               bfd_byte *location)
326 {
327   int r_ns32k_type = (howto - MY (howto_table)) / 6;
328   bfd_vma (*get_data) (bfd_byte *, int);
329   void (*put_data) (bfd_vma, bfd_byte *, int);
330
331   switch (r_ns32k_type)
332     {
333     case 0:
334       get_data = _bfd_ns32k_get_immediate;
335       put_data = _bfd_ns32k_put_immediate;
336       break;
337     case 1:
338       get_data = _bfd_ns32k_get_displacement;
339       put_data = _bfd_ns32k_put_displacement;
340       break;
341     case 2:
342       return _bfd_relocate_contents (howto, input_bfd, relocation,
343                                     location);
344       break;
345     default:
346       return bfd_reloc_notsupported;
347     }
348   return _bfd_do_ns32k_reloc_contents (howto, input_bfd, relocation,
349                                        location, get_data, put_data);
350 }