OSDN Git Service

* version.h: New file.
[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, 2000, 2001
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 *abfd, struct reloc_std_external *bytes,
57                               arelent *cache_ptr, asymbol **symbols,
58                               bfd_size_type symcount));
59 static void
60 MY_swap_std_reloc_out PARAMS ((bfd *abfd, arelent *g,
61                                struct reloc_std_external *natptr));
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     /* ns32k immediate operands.  */
102     HOWTO (BFD_RELOC_NS32K_IMM_8, 0, 0, 8, false, 0, true,
103            _bfd_ns32k_reloc_imm, "NS32K_IMM_8",
104            true, 0x000000ff,0x000000ff, false),
105     HOWTO (BFD_RELOC_NS32K_IMM_16, 0, 1, 16, false, 0, true,
106            _bfd_ns32k_reloc_imm,  "NS32K_IMM_16",
107            true, 0x0000ffff,0x0000ffff, false),
108     HOWTO (BFD_RELOC_NS32K_IMM_32, 0, 2, 32, false, 0, true,
109            _bfd_ns32k_reloc_imm, "NS32K_IMM_32",
110            true, 0xffffffff,0xffffffff, false),
111     HOWTO (BFD_RELOC_NS32K_IMM_8_PCREL, 0, 0, 8, true, 0, false,
112            _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_8",
113            true, 0x000000ff, 0x000000ff, false),
114     HOWTO (BFD_RELOC_NS32K_IMM_16_PCREL, 0, 1, 16, true, 0, false,
115            _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_16",
116            true, 0x0000ffff,0x0000ffff, false),
117     HOWTO (BFD_RELOC_NS32K_IMM_32_PCREL, 0, 2, 32, true, 0, false,
118            _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_32",
119            true, 0xffffffff,0xffffffff, false),
120
121     /* ns32k displacements.  */
122     HOWTO (BFD_RELOC_NS32K_DISP_8, 0, 0, 8, false, 0, true,
123            _bfd_ns32k_reloc_disp, "NS32K_DISP_8",
124            true, 0x000000ff,0x000000ff, false),
125     HOWTO (BFD_RELOC_NS32K_DISP_16, 0, 1, 16, false, 0, true,
126            _bfd_ns32k_reloc_disp, "NS32K_DISP_16",
127            true, 0x0000ffff, 0x0000ffff, false),
128     HOWTO (BFD_RELOC_NS32K_DISP_32, 0, 2, 32, false, 0, true,
129            _bfd_ns32k_reloc_disp, "NS32K_DISP_32",
130            true, 0xffffffff, 0xffffffff, false),
131     HOWTO (BFD_RELOC_NS32K_DISP_8_PCREL, 0, 0, 8, true, 0, false,
132            _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_8",
133            true, 0x000000ff,0x000000ff, false),
134     HOWTO (BFD_RELOC_NS32K_DISP_16_PCREL, 0, 1, 16, true, 0, false,
135            _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_16",
136            true, 0x0000ffff,0x0000ffff, false),
137     HOWTO (BFD_RELOC_NS32K_DISP_32_PCREL, 0, 2, 32, true, 0, false,
138            _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_32",
139            true, 0xffffffff,0xffffffff, false),
140
141     /* Normal 2's complement.  */
142     HOWTO (BFD_RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0,
143            "8", true, 0x000000ff,0x000000ff, false),
144     HOWTO (BFD_RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0,
145            "16", true, 0x0000ffff,0x0000ffff, false),
146     HOWTO (BFD_RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,
147            "32", true, 0xffffffff,0xffffffff, false),
148     HOWTO (BFD_RELOC_8_PCREL, 0, 0, 8, true, 0, complain_overflow_signed, 0,
149            "PCREL_8", true, 0x000000ff,0x000000ff, false),
150     HOWTO (BFD_RELOC_16_PCREL, 0, 1, 16, true, 0, complain_overflow_signed, 0,
151            "PCREL_16", true, 0x0000ffff,0x0000ffff, false),
152     HOWTO (BFD_RELOC_32_PCREL, 0, 2, 32, true, 0, complain_overflow_signed, 0,
153            "PCREL_32", true, 0xffffffff,0xffffffff, false),
154   };
155
156 #define CTOR_TABLE_RELOC_HOWTO(BFD) (MY(howto_table) + 14)
157
158 #define RELOC_STD_BITS_NS32K_TYPE_BIG 0x06
159 #define RELOC_STD_BITS_NS32K_TYPE_LITTLE 0x60
160 #define RELOC_STD_BITS_NS32K_TYPE_SH_BIG 1
161 #define RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE 5
162
163 reloc_howto_type *
164 MY(reloc_howto) (abfd, rel, r_index, r_extern, r_pcrel)
165      bfd *abfd ATTRIBUTE_UNUSED;
166      struct reloc_std_external *rel;
167      int *r_index;
168      int *r_extern;
169      int *r_pcrel;
170 {
171   unsigned int r_length;
172   int r_ns32k_type;
173
174   /*  BFD_ASSERT(bfd_header_little_endian (abfd)); */
175   *r_index =  ((rel->r_index[2] << 16)
176                | (rel->r_index[1] << 8)
177                |  rel->r_index[0] );
178   *r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
179   *r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
180   r_length  =  ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
181                 >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
182   r_ns32k_type  =  ((rel->r_type[0] & RELOC_STD_BITS_NS32K_TYPE_LITTLE)
183                     >> RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE);
184   return (MY(howto_table) + r_length + 3 * (*r_pcrel) + 6 * r_ns32k_type);
185 }
186
187 #define MY_reloc_howto(BFD, REL, IN, EX, PC) \
188   MY(reloc_howto) (BFD, REL, &IN, &EX, &PC)
189
190 void
191 MY(put_reloc) (abfd, r_extern, r_index, value, howto, reloc)
192      bfd *abfd;
193      int r_extern;
194      int r_index;
195      bfd_vma value;
196      reloc_howto_type *howto;
197      struct reloc_std_external *reloc;
198 {
199   unsigned int r_length;
200   int r_pcrel;
201   int r_ns32k_type;
202
203   PUT_WORD (abfd, value, reloc->r_address);
204   r_length = howto->size ;      /* Size as a power of two.  */
205   r_pcrel  = (int) howto->pc_relative; /* Relative to PC?  */
206   r_ns32k_type = (howto - MY(howto_table) )/6;
207
208   /*  BFD_ASSERT (bfd_header_little_endian (abfd)); */
209   reloc->r_index[2] = r_index >> 16;
210   reloc->r_index[1] = r_index >> 8;
211   reloc->r_index[0] = r_index;
212   reloc->r_type[0] =
213     (r_extern?    RELOC_STD_BITS_EXTERN_LITTLE: 0)
214       | (r_pcrel?     RELOC_STD_BITS_PCREL_LITTLE: 0)
215         | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE)
216           | (r_ns32k_type <<  RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE);
217 }
218
219 #define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \
220   MY(put_reloc) (BFD, EXT, IDX, VAL, HOWTO, RELOC)
221
222 #define STAT_FOR_EXEC
223
224 #define MY_final_link_relocate _bfd_ns32k_final_link_relocate
225 #define MY_relocate_contents _bfd_ns32k_relocate_contents
226
227 #include "aoutx.h"
228
229 reloc_howto_type *
230 MY(bfd_reloc_type_lookup) (abfd,code)
231      bfd *abfd;
232      bfd_reloc_code_real_type code;
233 {
234
235 #define ENTRY(i,j)      case i: return &MY(howto_table)[j]
236
237   int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
238
239   BFD_ASSERT(ext == 0);
240   if (code == BFD_RELOC_CTOR)
241     switch (bfd_get_arch_info (abfd)->bits_per_address)
242       {
243       case 32:
244         code = BFD_RELOC_32;
245         break;
246       default:
247         break;
248       }
249   switch (code)
250     {
251       ENTRY(BFD_RELOC_NS32K_IMM_8, 0);
252       ENTRY(BFD_RELOC_NS32K_IMM_16, 1);
253       ENTRY(BFD_RELOC_NS32K_IMM_32, 2);
254       ENTRY(BFD_RELOC_NS32K_IMM_8_PCREL, 3);
255       ENTRY(BFD_RELOC_NS32K_IMM_16_PCREL, 4);
256       ENTRY(BFD_RELOC_NS32K_IMM_32_PCREL, 5);
257       ENTRY(BFD_RELOC_NS32K_DISP_8, 6);
258       ENTRY(BFD_RELOC_NS32K_DISP_16, 7);
259       ENTRY(BFD_RELOC_NS32K_DISP_32, 8);
260       ENTRY(BFD_RELOC_NS32K_DISP_8_PCREL, 9);
261       ENTRY(BFD_RELOC_NS32K_DISP_16_PCREL, 10);
262       ENTRY(BFD_RELOC_NS32K_DISP_32_PCREL, 11);
263       ENTRY(BFD_RELOC_8, 12);
264       ENTRY(BFD_RELOC_16, 13);
265       ENTRY(BFD_RELOC_32, 14);
266       ENTRY(BFD_RELOC_8_PCREL, 15);
267       ENTRY(BFD_RELOC_16_PCREL, 16);
268       ENTRY(BFD_RELOC_32_PCREL, 17);
269     default:
270       return (reloc_howto_type *) NULL;
271     }
272 #undef ENTRY
273 }
274
275 static void
276 MY_swap_std_reloc_in (abfd, bytes, cache_ptr, symbols, symcount)
277      bfd *abfd;
278      struct reloc_std_external *bytes;
279      arelent *cache_ptr;
280      asymbol **symbols;
281      bfd_size_type symcount ATTRIBUTE_UNUSED;
282 {
283   int r_index;
284   int r_extern;
285   int r_pcrel;
286   struct aoutdata  *su = &(abfd->tdata.aout_data->a);
287
288   cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
289
290   /* Now the fun stuff.  */
291   cache_ptr->howto = MY_reloc_howto(abfd, bytes, r_index, r_extern, r_pcrel);
292
293   MOVE_ADDRESS (0);
294 }
295
296 static void
297 MY_swap_std_reloc_out (abfd, g, natptr)
298      bfd *abfd;
299      arelent *g;
300      struct reloc_std_external *natptr;
301 {
302   int r_index;
303   asymbol *sym = *(g->sym_ptr_ptr);
304   int r_extern;
305   unsigned int r_addend;
306   asection *output_section = sym->section->output_section;
307
308   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
309
310   /* Name was clobbered by aout_write_syms to be symbol index.  */
311
312   /* If this relocation is relative to a symbol then set the
313      r_index to the symbols index, and the r_extern bit.
314
315      Absolute symbols can come in in two ways, either as an offset
316      from the abs section, or as a symbol which has an abs value.
317      Check for that here.  */
318   if (bfd_is_com_section (output_section)
319       || output_section == &bfd_abs_section
320       || output_section == &bfd_und_section)
321     {
322       if (bfd_abs_section.symbol == sym)
323         {
324           /* Whoops, looked like an abs symbol, but is really an offset
325              from the abs section.  */
326           r_index = 0;
327           r_extern = 0;
328         }
329       else
330         {
331           /* Fill in symbol.  */
332           r_extern = 1;
333 #undef KEEPIT
334 #define KEEPIT udata.i
335           r_index =  (*(g->sym_ptr_ptr))->KEEPIT;
336 #undef KEEPIT
337         }
338     }
339   else
340     {
341       /* Just an ordinary section.  */
342       r_extern = 0;
343       r_index  = output_section->target_index;
344     }
345
346   MY_put_reloc (abfd, r_extern, r_index, g->address, g->howto, natptr);
347 }
348
349 bfd_reloc_status_type
350 _bfd_ns32k_relocate_contents (howto, input_bfd, relocation, location)
351      reloc_howto_type *howto;
352      bfd *input_bfd;
353      bfd_vma relocation;
354      bfd_byte *location;
355 {
356   int r_ns32k_type = (howto - MY(howto_table)) / 6;
357   bfd_vma (*get_data) PARAMS ((bfd_byte *, int));
358   int (*put_data) PARAMS ((bfd_vma, bfd_byte *, int));
359
360   switch (r_ns32k_type)
361     {
362     case 0:
363       get_data = _bfd_ns32k_get_immediate;
364       put_data = _bfd_ns32k_put_immediate;
365       break;
366     case 1:
367       get_data = _bfd_ns32k_get_displacement;
368       put_data = _bfd_ns32k_put_displacement;
369       break;
370     case 2:
371       return _bfd_relocate_contents (howto, input_bfd, relocation,
372                                     location);
373       /* NOT REACHED */
374       break;
375     default:
376       return bfd_reloc_notsupported;
377     }
378   return _bfd_do_ns32k_reloc_contents (howto, input_bfd, relocation,
379                                        location, get_data, put_data);
380 }