f9d12b096d55b4fcd65bd456459183aa63d86a76
[external/binutils.git] / bfd / coff-arm.c
1 /* BFD back-end for Intel arm COFF files.
2    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3    Written by Cygnus Support.
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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "bfd.h"
22 #include "sysdep.h"
23 #include "libbfd.h"
24 #include "obstack.h"
25
26 #include "coff/arm.h"
27
28 #include "coff/internal.h"
29
30 #ifdef COFF_WITH_PE
31 #include "coff/pe.h"
32 #endif
33
34 #include "libcoff.h"
35
36 static bfd_reloc_status_type
37 aoutarm_fix_pcrel_26_done PARAMS ((bfd *, arelent *, asymbol *, PTR,
38                                   asection *, bfd *, char **));
39
40 static bfd_reloc_status_type
41 aoutarm_fix_pcrel_26 PARAMS ((bfd *, arelent *, asymbol *, PTR,
42                              asection *, bfd *, char **));
43
44
45 static bfd_reloc_status_type coff_arm_reloc 
46   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
47
48 static bfd_reloc_status_type
49 coff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
50                  error_message)
51      bfd *abfd;
52      arelent *reloc_entry;
53      asymbol *symbol;
54      PTR data;
55      asection *input_section;
56      bfd *output_bfd;
57      char **error_message;
58 {
59   symvalue diff;
60
61   if (output_bfd == (bfd *) NULL)
62     return bfd_reloc_continue;
63
64   if (bfd_is_com_section (symbol->section))
65     {
66       /* We are relocating a common symbol.  The current value in the
67          object file is ORIG + OFFSET, where ORIG is the value of the
68          common symbol as seen by the object file when it was compiled
69          (this may be zero if the symbol was undefined) and OFFSET is
70          the offset into the common symbol (normally zero, but may be
71          non-zero when referring to a field in a common structure).
72          ORIG is the negative of reloc_entry->addend, which is set by
73          the CALC_ADDEND macro below.  We want to replace the value in
74          the object file with NEW + OFFSET, where NEW is the value of
75          the common symbol which we are going to put in the final
76          object file.  NEW is symbol->value.  */
77       diff = symbol->value + reloc_entry->addend;
78     }
79   else
80     {
81       /* For some reason bfd_perform_relocation always effectively
82          ignores the addend for a COFF target when producing
83          relocateable output.  This seems to be always wrong for 386
84          COFF, so we handle the addend here instead.  */
85       diff = reloc_entry->addend;
86     }
87
88 #define DOIT(x) \
89   x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
90
91   if (diff != 0)
92     {
93       reloc_howto_type *howto = reloc_entry->howto;
94       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
95
96       switch (howto->size)
97         {
98         case 0:
99           {
100             char x = bfd_get_8 (abfd, addr);
101             DOIT (x);
102             bfd_put_8 (abfd, x, addr);
103           }
104           break;
105
106         case 1:
107           {
108             short x = bfd_get_16 (abfd, addr);
109             DOIT (x);
110             bfd_put_16 (abfd, x, addr);
111           }
112           break;
113
114         case 2:
115           {
116             long x = bfd_get_32 (abfd, addr);
117             DOIT (x);
118             bfd_put_32 (abfd, x, addr);
119           }
120           break;
121
122         default:
123           abort ();
124         }
125     }
126
127   /* Now let bfd_perform_relocation finish everything up.  */
128   return bfd_reloc_continue;
129 }
130
131 static reloc_howto_type aoutarm_std_reloc_howto[] = 
132 {
133   /* type              rs size bsz  pcrel bitpos ovrf                     sf name     part_inpl readmask  setmask    pcdone */
134   HOWTO(0,                      /* type */
135         0,                      /* rs */
136         0,                      /* size */
137         8,                      /* bsz */
138         false,                  /* pcrel */
139         0,                      /* bitpos */
140         complain_overflow_bitfield, /* ovf */
141         coff_arm_reloc,         /* sf */
142         "8",                    /*name */
143         true,                   /* partial */
144         0x000000ff,             /*read mask */
145         0x000000ff,             /* setmask */
146         PCRELOFFSET             /* pcdone */),
147   HOWTO(1,  
148         0, 
149         1, 
150         16, 
151         false,
152         0,
153         complain_overflow_bitfield,
154         coff_arm_reloc,
155         "16", 
156         true,
157         0x0000ffff,
158         0x0000ffff, 
159         PCRELOFFSET),
160   HOWTO( 2, 
161         0,
162         2, 
163         32,
164         false,
165         0,
166         complain_overflow_bitfield,
167         coff_arm_reloc,
168         "32",
169         true,
170         0xffffffff,
171         0xffffffff,
172         PCRELOFFSET),
173   HOWTO( 3,
174         2,
175         3, 
176         26,
177         true,
178         0,
179         complain_overflow_signed,
180         aoutarm_fix_pcrel_26 ,
181         "ARM26",
182         true, 
183         0x00ffffff,
184         0x00ffffff, 
185         PCRELOFFSET),
186   HOWTO( 4,        
187         0,
188         0,
189         8, 
190         true,
191         0,
192         complain_overflow_signed, 
193         coff_arm_reloc,
194         "DISP8",  
195         true,
196         0x000000ff,
197         0x000000ff,
198         true),
199   HOWTO( 5, 
200         0,
201         1,
202         16,
203         true,
204         0,
205         complain_overflow_signed, 
206         coff_arm_reloc,
207         "DISP16",
208         true,
209         0x0000ffff,
210         0x0000ffff,
211         true),
212   HOWTO( 6,
213         0,
214         2,
215         32,
216         true,
217         0,
218         complain_overflow_signed, 
219         coff_arm_reloc,
220         "DISP32",
221         true,
222         0xffffffff,
223         0xffffffff,
224         true),
225   HOWTO( 7,  
226         2, 
227         3,   
228         26,
229         false,
230         0,
231         complain_overflow_signed,
232         aoutarm_fix_pcrel_26_done, 
233         "ARM26D",
234         true,
235         0x00ffffff,
236         0x00ffffff, 
237         false),
238   {-1},
239   HOWTO( 9,
240         0,
241         -1,
242         16,
243         false,
244         0, 
245         complain_overflow_bitfield,
246         coff_arm_reloc,
247         "NEG16",
248         true, 
249         0x0000ffff,
250         0x0000ffff, 
251         false),
252   HOWTO( 10, 
253         0, 
254         -2,
255         32,
256         false,
257         0,
258         complain_overflow_bitfield,
259         coff_arm_reloc,
260         "NEG32",
261         true,
262         0xffffffff,
263         0xffffffff,
264         false)
265 };
266
267
268
269 #define RTYPE2HOWTO(cache_ptr, dst) \
270             (cache_ptr)->howto = aoutarm_std_reloc_howto + (dst)->r_type;
271
272 static bfd_reloc_status_type
273 aoutarm_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section,
274                           output_bfd, error_message)
275      bfd *abfd;
276      arelent *reloc_entry;
277      asymbol *symbol;
278      PTR data;
279      asection *input_section;
280      bfd *output_bfd;
281      char **error_message;
282 {
283   /* This is dead simple at present.  */
284   return bfd_reloc_ok;
285 }
286
287 static bfd_reloc_status_type
288 aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
289                      output_bfd, error_message)
290      bfd *abfd;
291      arelent *reloc_entry;
292      asymbol *symbol;
293      PTR data;
294      asection *input_section;
295      bfd *output_bfd;
296      char **error_message;
297 {
298   bfd_vma relocation;
299   bfd_size_type addr = reloc_entry->address;
300   long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
301   bfd_reloc_status_type flag = bfd_reloc_ok;
302   
303   /* If this is an undefined symbol, return error */
304   if (symbol->section == &bfd_und_section
305       && (symbol->flags & BSF_WEAK) == 0)
306     return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
307
308   /* If the sections are different, and we are doing a partial relocation,
309      just ignore it for now.  */
310   if (symbol->section->name != input_section->name
311       && output_bfd != (bfd *)NULL)
312     return bfd_reloc_continue;
313
314   relocation = (target & 0x00ffffff) << 2;
315   relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */
316   relocation += symbol->value;
317   relocation += symbol->section->output_section->vma;
318   relocation += symbol->section->output_offset;
319   relocation += reloc_entry->addend;
320   relocation -= input_section->output_section->vma;
321   relocation -= input_section->output_offset;
322   relocation -= addr;
323   if (relocation & 3)
324     return bfd_reloc_overflow;
325
326   /* Check for overflow */
327   if (relocation & 0x02000000)
328     {
329       if ((relocation & ~0x03ffffff) != ~0x03ffffff)
330         flag = bfd_reloc_overflow;
331     }
332   else if (relocation & ~0x03ffffff)
333     flag = bfd_reloc_overflow;
334
335   target &= ~0x00ffffff;
336   target |= (relocation >> 2) & 0x00ffffff;
337   bfd_put_32 (abfd, target, (bfd_byte *) data + addr);
338
339   /* Now the ARM magic... Change the reloc type so that it is marked as done.
340      Strictly this is only necessary if we are doing a partial relocation.  */
341   reloc_entry->howto = &aoutarm_std_reloc_howto[7];
342   
343   return flag;
344 }
345
346 static CONST struct reloc_howto_struct *
347 arm_reloc_type_lookup(abfd,code)
348       bfd *abfd;
349       bfd_reloc_code_real_type code;
350 {
351 #define ASTD(i,j)       case i: return &aoutarm_std_reloc_howto[j]
352   if (code == BFD_RELOC_CTOR)
353     switch (bfd_get_arch_info (abfd)->bits_per_address)
354       {
355       case 32:
356         code = BFD_RELOC_32;
357         break;
358       default: return (CONST struct reloc_howto_struct *) 0;
359       }
360
361   switch (code)
362     {
363       ASTD (BFD_RELOC_16, 1);
364       ASTD (BFD_RELOC_32, 2);
365       ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
366       ASTD (BFD_RELOC_8_PCREL, 4);
367       ASTD (BFD_RELOC_16_PCREL, 5);
368       ASTD (BFD_RELOC_32_PCREL, 6);
369     default: return (CONST struct reloc_howto_struct *) 0;
370     }
371 }
372
373
374 #define coff_bfd_reloc_type_lookup arm_reloc_type_lookup
375
376 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
377 /* The page size is a guess based on ELF.  */
378 #define COFF_PAGE_SIZE 0x1000
379
380 /* For some reason when using arm COFF the value stored in the .text
381    section for a reference to a common symbol is the value itself plus
382    any desired offset.  Ian Taylor, Cygnus Support.  */
383
384 /* If we are producing relocateable output, we need to do some
385    adjustments to the object file that are not done by the
386    bfd_perform_relocation function.  This function is called by every
387    reloc type to make any required adjustments.  */
388
389 static bfd_reloc_status_type
390 aacoff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
391                  error_message)
392      bfd *abfd;
393      arelent *reloc_entry;
394      asymbol *symbol;
395      PTR data;
396      asection *input_section;
397      bfd *output_bfd;
398      char **error_message;
399 {
400   symvalue diff;
401
402   if (output_bfd == (bfd *) NULL)
403     return bfd_reloc_continue;
404
405   if (bfd_is_com_section (symbol->section))
406     {
407       /* We are relocating a common symbol.  The current value in the
408          object file is ORIG + OFFSET, where ORIG is the value of the
409          common symbol as seen by the object file when it was compiled
410          (this may be zero if the symbol was undefined) and OFFSET is
411          the offset into the common symbol (normally zero, but may be
412          non-zero when referring to a field in a common structure).
413          ORIG is the negative of reloc_entry->addend, which is set by
414          the CALC_ADDEND macro below.  We want to replace the value in
415          the object file with NEW + OFFSET, where NEW is the value of
416          the common symbol which we are going to put in the final
417          object file.  NEW is symbol->value.  */
418       diff = symbol->value + reloc_entry->addend;
419     }
420   else
421     {
422       /* For some reason bfd_perform_relocation always effectively
423          ignores the addend for a COFF target when producing
424          relocateable output.  This seems to be always wrong for arm
425          COFF, so we handle the addend here instead.  */
426       diff = reloc_entry->addend;
427     }
428
429 #define DOIT(x) \
430   x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
431
432   if (diff != 0)
433     {
434       reloc_howto_type *howto = reloc_entry->howto;
435       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
436
437       switch (howto->size)
438         {
439         case 0:
440           {
441             char x = bfd_get_8 (abfd, addr);
442             DOIT (x);
443             bfd_put_8 (abfd, x, addr);
444           }
445           break;
446
447         case 1:
448           {
449             short x = bfd_get_16 (abfd, addr);
450             DOIT (x);
451             bfd_put_16 (abfd, x, addr);
452           }
453           break;
454
455         case 2:
456           {
457             long x = bfd_get_32 (abfd, addr);
458             DOIT (x);
459             bfd_put_32 (abfd, x, addr);
460           }
461           break;
462
463         default:
464           abort ();
465         }
466     }
467
468   /* Now let bfd_perform_relocation finish everything up.  */
469   return bfd_reloc_continue;
470 }
471
472
473
474
475
476 /* Turn a howto into a reloc  nunmber */
477
478 #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
479 #define BADMAG(x) ARMBADMAG(x)
480 #define ARM 1                   /* Customize coffcode.h */
481
482
483 /* On SCO Unix 3.2.2 the native assembler generates two .data
484    sections.  We handle that by renaming the second one to .data2.  It
485    does no harm to do this for any arm COFF target.  */
486 #define TWO_DATA_SECS
487
488 /* For arm COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
489    library.  On some other COFF targets STYP_BSS is normally
490    STYP_NOLOAD.  */
491 #define BSS_NOLOAD_IS_SHARED_LIBRARY
492
493
494 /* We use the special COFF backend linker.  */
495 #define coff_relocate_section _bfd_coff_generic_relocate_section
496
497
498
499 #include "coffcode.h"
500
501 static const bfd_target *
502 i3coff_object_p(a)
503      bfd *a;
504 {
505   return coff_object_p(a);
506 }
507
508 const bfd_target
509 #ifdef TARGET_SYM
510   TARGET_SYM =
511 #else
512   armcoff_vec =
513 #endif
514 {
515 #ifdef TARGET_NAME
516   TARGET_NAME,
517 #else
518   "coff-arm",                   /* name */
519 #endif
520   bfd_target_coff_flavour,
521   false,                        /* data byte order is little */
522   false,                        /* header byte order is little */
523
524   (HAS_RELOC | EXEC_P |         /* object flags */
525    HAS_LINENO | HAS_DEBUG |
526    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
527
528   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
529 #ifdef TARGET_UNDERSCORE
530   TARGET_UNDERSCORE,            /* leading underscore */
531 #else
532   0,                            /* leading underscore */
533 #endif
534   '/',                          /* ar_pad_char */
535   15,                           /* ar_max_namelen */
536
537   2,                            /* minimum alignment power */
538   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
539      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
540      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
541   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
542      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
543      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
544
545 /* Note that we allow an object file to be treated as a core file as well. */
546     {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */
547        bfd_generic_archive_p, i3coff_object_p},
548     {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
549        bfd_false},
550     {bfd_false, coff_write_object_contents, /* bfd_write_contents */
551        _bfd_write_archive_contents, bfd_false},
552
553      BFD_JUMP_TABLE_GENERIC (coff),
554      BFD_JUMP_TABLE_COPY (coff),
555      BFD_JUMP_TABLE_CORE (_bfd_nocore),
556      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
557      BFD_JUMP_TABLE_SYMBOLS (coff),
558      BFD_JUMP_TABLE_RELOCS (coff),
559      BFD_JUMP_TABLE_WRITE (coff),
560      BFD_JUMP_TABLE_LINK (coff),
561      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
562
563   COFF_SWAP_TABLE,
564 };