start-sanitize-d10v
[external/binutils.git] / bfd / coff-arm.c
1 /* BFD back-end for 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
49 /* Used by the assembler. */
50 static bfd_reloc_status_type
51 coff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
52                  error_message)
53      bfd *abfd;
54      arelent *reloc_entry;
55      asymbol *symbol;
56      PTR data;
57      asection *input_section;
58      bfd *output_bfd;
59      char **error_message;
60 {
61   symvalue diff;
62   if (output_bfd == (bfd *) NULL)
63     return bfd_reloc_continue;
64
65   diff = reloc_entry->addend;
66
67 #define DOIT(x) \
68   x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
69
70     if (diff != 0)
71       {
72         reloc_howto_type *howto = reloc_entry->howto;
73         unsigned char *addr = (unsigned char *) data + reloc_entry->address;
74
75         switch (howto->size)
76           {
77           case 0:
78             {
79               char x = bfd_get_8 (abfd, addr);
80               DOIT (x);
81               bfd_put_8 (abfd, x, addr);
82             }
83             break;
84
85           case 1:
86             {
87               short x = bfd_get_16 (abfd, addr);
88               DOIT (x);
89               bfd_put_16 (abfd, x, addr);
90             }
91             break;
92
93           case 2:
94             {
95               long x = bfd_get_32 (abfd, addr);
96               DOIT (x);
97               bfd_put_32 (abfd, x, addr);
98             }
99             break;
100
101           default:
102             abort ();
103           }
104       }
105
106   /* Now let bfd_perform_relocation finish everything up.  */
107   return bfd_reloc_continue;
108 }
109
110 #ifndef PCRELOFFSET
111 #define PCRELOFFSET true
112 #endif
113
114 static reloc_howto_type aoutarm_std_reloc_howto[] = 
115 {
116   /* type              rs size bsz  pcrel bitpos ovrf                     sf name     part_inpl readmask  setmask    pcdone */
117   HOWTO(0,                      /* type */
118         0,                      /* rs */
119         0,                      /* size */
120         8,                      /* bsz */
121         false,                  /* pcrel */
122         0,                      /* bitpos */
123         complain_overflow_bitfield, /* ovf */
124         coff_arm_reloc,         /* sf */
125         "8",                    /*name */
126         true,                   /* partial */
127         0x000000ff,             /*read mask */
128         0x000000ff,             /* setmask */
129         PCRELOFFSET             /* pcdone */),
130   HOWTO(1,  
131         0, 
132         1, 
133         16, 
134         false,
135         0,
136         complain_overflow_bitfield,
137         coff_arm_reloc,
138         "16", 
139         true,
140         0x0000ffff,
141         0x0000ffff, 
142         PCRELOFFSET),
143   HOWTO( 2, 
144         0,
145         2, 
146         32,
147         false,
148         0,
149         complain_overflow_bitfield,
150         coff_arm_reloc,
151         "32",
152         true,
153         0xffffffff,
154         0xffffffff,
155         PCRELOFFSET),
156   HOWTO( 3,
157         2,
158         2,
159         26,
160         true,
161         0,
162         complain_overflow_signed,
163         aoutarm_fix_pcrel_26 ,
164         "ARM26",
165         false,
166         0x00ffffff,
167         0x00ffffff, 
168         PCRELOFFSET),
169   HOWTO( 4,        
170         0,
171         0,
172         8, 
173         true,
174         0,
175         complain_overflow_signed, 
176         coff_arm_reloc,
177         "DISP8",  
178         true,
179         0x000000ff,
180         0x000000ff,
181         true),
182   HOWTO( 5, 
183         0,
184         1,
185         16,
186         true,
187         0,
188         complain_overflow_signed, 
189         coff_arm_reloc,
190         "DISP16",
191         true,
192         0x0000ffff,
193         0x0000ffff,
194         true),
195   HOWTO( 6,
196         0,
197         2,
198         32,
199         true,
200         0,
201         complain_overflow_signed, 
202         coff_arm_reloc,
203         "DISP32",
204         true,
205         0xffffffff,
206         0xffffffff,
207         true),
208   HOWTO( 7,  
209         2, 
210         2,
211         26,
212         false,
213         0,
214         complain_overflow_signed,
215         aoutarm_fix_pcrel_26_done, 
216         "ARM26D",
217         true,
218         0x00ffffff,
219         0x00ffffff, 
220         false),
221   {-1},
222   HOWTO( 9,
223         0,
224         -1,
225         16,
226         false,
227         0, 
228         complain_overflow_bitfield,
229         coff_arm_reloc,
230         "NEG16",
231         true, 
232         0x0000ffff,
233         0x0000ffff, 
234         false),
235   HOWTO( 10, 
236         0, 
237         -2,
238         32,
239         false,
240         0,
241         complain_overflow_bitfield,
242         coff_arm_reloc,
243         "NEG32",
244         true,
245         0xffffffff,
246         0xffffffff,
247         false),
248   HOWTO( 11, 
249         0,
250         2, 
251         32,
252         false,
253         0,
254         complain_overflow_bitfield,
255         coff_arm_reloc,
256         "rva32",
257         true,
258         0xffffffff,
259         0xffffffff,
260         PCRELOFFSET),
261 };
262 #ifdef COFF_WITH_PE
263 /* Return true if this relocation should
264    appear in the output .reloc section. */
265
266 static boolean in_reloc_p (abfd, howto)
267      bfd * abfd;
268      reloc_howto_type *howto;
269 {
270   return !howto->pc_relative && howto->type != 11;
271 }     
272 #endif
273
274
275 #define RTYPE2HOWTO(cache_ptr, dst) \
276             (cache_ptr)->howto = aoutarm_std_reloc_howto + (dst)->r_type;
277
278 #define coff_rtype_to_howto coff_arm_rtype_to_howto
279
280 static reloc_howto_type *
281 coff_arm_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
282      bfd *abfd;
283      asection *sec;
284      struct internal_reloc *rel;
285      struct coff_link_hash_entry *h;
286      struct internal_syment *sym;
287      bfd_vma *addendp;
288 {
289   reloc_howto_type *howto;
290
291   howto = aoutarm_std_reloc_howto + rel->r_type;
292
293   if (rel->r_type == 11)
294     {
295       *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
296     }
297   return howto;
298
299 }
300 /* Used by the assembler. */
301
302 static bfd_reloc_status_type
303 aoutarm_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section,
304                           output_bfd, error_message)
305      bfd *abfd;
306      arelent *reloc_entry;
307      asymbol *symbol;
308      PTR data;
309      asection *input_section;
310      bfd *output_bfd;
311      char **error_message;
312 {
313   /* This is dead simple at present.  */
314   return bfd_reloc_ok;
315 }
316
317 /* Used by the assembler. */
318
319 static bfd_reloc_status_type
320 aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
321                      output_bfd, error_message)
322      bfd *abfd;
323      arelent *reloc_entry;
324      asymbol *symbol;
325      PTR data;
326      asection *input_section;
327      bfd *output_bfd;
328      char **error_message;
329 {
330   bfd_vma relocation;
331   bfd_size_type addr = reloc_entry->address;
332   long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
333   bfd_reloc_status_type flag = bfd_reloc_ok;
334   
335   /* If this is an undefined symbol, return error */
336   if (symbol->section == &bfd_und_section
337       && (symbol->flags & BSF_WEAK) == 0)
338     return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
339
340   /* If the sections are different, and we are doing a partial relocation,
341      just ignore it for now.  */
342   if (symbol->section->name != input_section->name
343       && output_bfd != (bfd *)NULL)
344     return bfd_reloc_continue;
345
346   relocation = (target & 0x00ffffff) << 2;
347   relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */
348   relocation += symbol->value;
349   relocation += symbol->section->output_section->vma;
350   relocation += symbol->section->output_offset;
351   relocation += reloc_entry->addend;
352   relocation -= input_section->output_section->vma;
353   relocation -= input_section->output_offset;
354   relocation -= addr;
355   if (relocation & 3)
356     return bfd_reloc_overflow;
357
358   /* Check for overflow */
359   if (relocation & 0x02000000)
360     {
361       if ((relocation & ~0x03ffffff) != ~0x03ffffff)
362         flag = bfd_reloc_overflow;
363     }
364   else if (relocation & ~0x03ffffff)
365     flag = bfd_reloc_overflow;
366
367   target &= ~0x00ffffff;
368   target |= (relocation >> 2) & 0x00ffffff;
369   bfd_put_32 (abfd, target, (bfd_byte *) data + addr);
370
371   /* Now the ARM magic... Change the reloc type so that it is marked as done.
372      Strictly this is only necessary if we are doing a partial relocation.  */
373   reloc_entry->howto = &aoutarm_std_reloc_howto[7];
374
375   return flag;
376 }
377
378
379 static CONST struct reloc_howto_struct *
380 arm_reloc_type_lookup(abfd,code)
381       bfd *abfd;
382       bfd_reloc_code_real_type code;
383 {
384 #define ASTD(i,j)       case i: return &aoutarm_std_reloc_howto[j]
385   if (code == BFD_RELOC_CTOR)
386     switch (bfd_get_arch_info (abfd)->bits_per_address)
387       {
388       case 32:
389         code = BFD_RELOC_32;
390         break;
391       default: return (CONST struct reloc_howto_struct *) 0;
392       }
393
394   switch (code)
395     {
396       ASTD (BFD_RELOC_16, 1);
397       ASTD (BFD_RELOC_32, 2);
398       ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
399       ASTD (BFD_RELOC_8_PCREL, 4);
400       ASTD (BFD_RELOC_16_PCREL, 5);
401       ASTD (BFD_RELOC_32_PCREL, 6);
402       ASTD (BFD_RELOC_RVA, 11);
403     default: return (CONST struct reloc_howto_struct *) 0;
404     }
405 }
406
407
408 #define coff_bfd_reloc_type_lookup arm_reloc_type_lookup
409
410 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
411 #define COFF_PAGE_SIZE 0x1000
412 /* Turn a howto into a reloc  nunmber */
413
414 #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
415 #define BADMAG(x) ARMBADMAG(x)
416 #define ARM 1                   /* Customize coffcode.h */
417
418
419 /* We use the special COFF backend linker.  */
420 #define coff_relocate_section _bfd_coff_generic_relocate_section
421
422
423 #include "coffcode.h"
424
425 const bfd_target
426 #ifdef TARGET_LITTLE_SYM
427 TARGET_LITTLE_SYM =
428 #else
429 armcoff_little_vec =
430 #endif
431 {
432 #ifdef TARGET_LITTLE_NAME
433   TARGET_LITTLE_NAME,
434 #else
435   "coff-arm-little",
436 #endif
437   bfd_target_coff_flavour,
438   false,                        /* data byte order is little */
439   false,                        /* header byte order is little */
440
441   (HAS_RELOC | EXEC_P |         /* object flags */
442    HAS_LINENO | HAS_DEBUG |
443    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
444
445   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
446 #ifdef TARGET_UNDERSCORE
447   TARGET_UNDERSCORE,            /* leading underscore */
448 #else
449   0,                            /* leading underscore */
450 #endif
451   '/',                          /* ar_pad_char */
452   15,                           /* ar_max_namelen */
453
454   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
455      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
456      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
457   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
458      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
459      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
460
461 /* Note that we allow an object file to be treated as a core file as well. */
462     {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
463        bfd_generic_archive_p, coff_object_p},
464     {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
465        bfd_false},
466     {bfd_false, coff_write_object_contents, /* bfd_write_contents */
467        _bfd_write_archive_contents, bfd_false},
468
469      BFD_JUMP_TABLE_GENERIC (coff),
470      BFD_JUMP_TABLE_COPY (coff),
471      BFD_JUMP_TABLE_CORE (_bfd_nocore),
472      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
473      BFD_JUMP_TABLE_SYMBOLS (coff),
474      BFD_JUMP_TABLE_RELOCS (coff),
475      BFD_JUMP_TABLE_WRITE (coff),
476      BFD_JUMP_TABLE_LINK (coff),
477      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
478
479   COFF_SWAP_TABLE,
480 };
481
482 const bfd_target
483 #ifdef TARGET_BIG_SYM
484 TARGET_BIG_SYM =
485 #else
486 armcoff_big_vec =
487 #endif
488 {
489 #ifdef TARGET_BIG_NAME
490   TARGET_BIG_NAME,
491 #else
492   "coff-arm-big",
493 #endif
494   bfd_target_coff_flavour,
495   true,                         /* data byte order is big */
496   true,                         /* header byte order is big */
497
498   (HAS_RELOC | EXEC_P |         /* object flags */
499    HAS_LINENO | HAS_DEBUG |
500    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
501
502   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
503 #ifdef TARGET_UNDERSCORE
504   TARGET_UNDERSCORE,            /* leading underscore */
505 #else
506   0,                            /* leading underscore */
507 #endif
508   '/',                          /* ar_pad_char */
509   15,                           /* ar_max_namelen */
510
511   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
512      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
513      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
514   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
515      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
516      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
517
518 /* Note that we allow an object file to be treated as a core file as well. */
519     {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
520        bfd_generic_archive_p, coff_object_p},
521     {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
522        bfd_false},
523     {bfd_false, coff_write_object_contents, /* bfd_write_contents */
524        _bfd_write_archive_contents, bfd_false},
525
526      BFD_JUMP_TABLE_GENERIC (coff),
527      BFD_JUMP_TABLE_COPY (coff),
528      BFD_JUMP_TABLE_CORE (_bfd_nocore),
529      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
530      BFD_JUMP_TABLE_SYMBOLS (coff),
531      BFD_JUMP_TABLE_RELOCS (coff),
532      BFD_JUMP_TABLE_WRITE (coff),
533      BFD_JUMP_TABLE_LINK (coff),
534      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
535
536   COFF_SWAP_TABLE,
537 };