Tue Aug 29 13:50:21 1995 steve chamberlain <sac@slash.cygnus.com>
[binutils-gdb.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 #ifndef PCRELOFFSET
132 #define PCRELOFFSET true
133 #endif
134
135 static reloc_howto_type aoutarm_std_reloc_howto[] =
136 {
137 /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
138 HOWTO(0, /* type */
139 0, /* rs */
140 0, /* size */
141 8, /* bsz */
142 false, /* pcrel */
143 0, /* bitpos */
144 complain_overflow_bitfield, /* ovf */
145 coff_arm_reloc, /* sf */
146 "8", /*name */
147 true, /* partial */
148 0x000000ff, /*read mask */
149 0x000000ff, /* setmask */
150 PCRELOFFSET /* pcdone */),
151 HOWTO(1,
152 0,
153 1,
154 16,
155 false,
156 0,
157 complain_overflow_bitfield,
158 coff_arm_reloc,
159 "16",
160 true,
161 0x0000ffff,
162 0x0000ffff,
163 PCRELOFFSET),
164 HOWTO( 2,
165 0,
166 2,
167 32,
168 false,
169 0,
170 complain_overflow_bitfield,
171 coff_arm_reloc,
172 "32",
173 true,
174 0xffffffff,
175 0xffffffff,
176 PCRELOFFSET),
177 HOWTO( 3,
178 2,
179 2,
180 26,
181 true,
182 0,
183 complain_overflow_signed,
184 aoutarm_fix_pcrel_26 ,
185 "ARM26",
186 true,
187 0x00ffffff,
188 0x00ffffff,
189 PCRELOFFSET),
190 HOWTO( 4,
191 0,
192 0,
193 8,
194 true,
195 0,
196 complain_overflow_signed,
197 coff_arm_reloc,
198 "DISP8",
199 true,
200 0x000000ff,
201 0x000000ff,
202 true),
203 HOWTO( 5,
204 0,
205 1,
206 16,
207 true,
208 0,
209 complain_overflow_signed,
210 coff_arm_reloc,
211 "DISP16",
212 true,
213 0x0000ffff,
214 0x0000ffff,
215 true),
216 HOWTO( 6,
217 0,
218 2,
219 32,
220 true,
221 0,
222 complain_overflow_signed,
223 coff_arm_reloc,
224 "DISP32",
225 true,
226 0xffffffff,
227 0xffffffff,
228 true),
229 HOWTO( 7,
230 2,
231 2,
232 26,
233 false,
234 0,
235 complain_overflow_signed,
236 aoutarm_fix_pcrel_26_done,
237 "ARM26D",
238 true,
239 0x00ffffff,
240 0x00ffffff,
241 false),
242 {-1},
243 HOWTO( 9,
244 0,
245 -1,
246 16,
247 false,
248 0,
249 complain_overflow_bitfield,
250 coff_arm_reloc,
251 "NEG16",
252 true,
253 0x0000ffff,
254 0x0000ffff,
255 false),
256 HOWTO( 10,
257 0,
258 -2,
259 32,
260 false,
261 0,
262 complain_overflow_bitfield,
263 coff_arm_reloc,
264 "NEG32",
265 true,
266 0xffffffff,
267 0xffffffff,
268 false),
269 HOWTO( 11,
270 0,
271 2,
272 32,
273 false,
274 0,
275 complain_overflow_bitfield,
276 coff_arm_reloc,
277 "rva32",
278 true,
279 0xffffffff,
280 0xffffffff,
281 PCRELOFFSET),
282 };
283
284
285
286 #define RTYPE2HOWTO(cache_ptr, dst) \
287 (cache_ptr)->howto = aoutarm_std_reloc_howto + (dst)->r_type;
288
289 static bfd_reloc_status_type
290 aoutarm_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section,
291 output_bfd, error_message)
292 bfd *abfd;
293 arelent *reloc_entry;
294 asymbol *symbol;
295 PTR data;
296 asection *input_section;
297 bfd *output_bfd;
298 char **error_message;
299 {
300 /* This is dead simple at present. */
301 return bfd_reloc_ok;
302 }
303
304 static bfd_reloc_status_type
305 aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
306 output_bfd, error_message)
307 bfd *abfd;
308 arelent *reloc_entry;
309 asymbol *symbol;
310 PTR data;
311 asection *input_section;
312 bfd *output_bfd;
313 char **error_message;
314 {
315 bfd_vma relocation;
316 bfd_size_type addr = reloc_entry->address;
317 long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
318 bfd_reloc_status_type flag = bfd_reloc_ok;
319
320 /* If this is an undefined symbol, return error */
321 if (symbol->section == &bfd_und_section
322 && (symbol->flags & BSF_WEAK) == 0)
323 return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
324
325 /* If the sections are different, and we are doing a partial relocation,
326 just ignore it for now. */
327 if (symbol->section->name != input_section->name
328 && output_bfd != (bfd *)NULL)
329 return bfd_reloc_continue;
330
331 relocation = (target & 0x00ffffff) << 2;
332 relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */
333 relocation += symbol->value;
334 relocation += symbol->section->output_section->vma;
335 relocation += symbol->section->output_offset;
336 relocation += reloc_entry->addend;
337 relocation -= input_section->output_section->vma;
338 relocation -= input_section->output_offset;
339 relocation -= addr;
340 if (relocation & 3)
341 return bfd_reloc_overflow;
342
343 /* Check for overflow */
344 if (relocation & 0x02000000)
345 {
346 if ((relocation & ~0x03ffffff) != ~0x03ffffff)
347 flag = bfd_reloc_overflow;
348 }
349 else if (relocation & ~0x03ffffff)
350 flag = bfd_reloc_overflow;
351
352 target &= ~0x00ffffff;
353 target |= (relocation >> 2) & 0x00ffffff;
354 bfd_put_32 (abfd, target, (bfd_byte *) data + addr);
355
356 /* Now the ARM magic... Change the reloc type so that it is marked as done.
357 Strictly this is only necessary if we are doing a partial relocation. */
358 reloc_entry->howto = &aoutarm_std_reloc_howto[7];
359
360 return flag;
361 }
362
363 static CONST struct reloc_howto_struct *
364 arm_reloc_type_lookup(abfd,code)
365 bfd *abfd;
366 bfd_reloc_code_real_type code;
367 {
368 #define ASTD(i,j) case i: return &aoutarm_std_reloc_howto[j]
369 if (code == BFD_RELOC_CTOR)
370 switch (bfd_get_arch_info (abfd)->bits_per_address)
371 {
372 case 32:
373 code = BFD_RELOC_32;
374 break;
375 default: return (CONST struct reloc_howto_struct *) 0;
376 }
377
378 switch (code)
379 {
380 ASTD (BFD_RELOC_16, 1);
381 ASTD (BFD_RELOC_32, 2);
382 ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
383 ASTD (BFD_RELOC_8_PCREL, 4);
384 ASTD (BFD_RELOC_16_PCREL, 5);
385 ASTD (BFD_RELOC_32_PCREL, 6);
386 ASTD (BFD_RELOC_RVA, 11);
387 default: return (CONST struct reloc_howto_struct *) 0;
388 }
389 }
390
391
392 #define coff_bfd_reloc_type_lookup arm_reloc_type_lookup
393
394 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
395 /* The page size is a guess based on ELF. */
396 #define COFF_PAGE_SIZE 0x1000
397
398 /* For some reason when using arm COFF the value stored in the .text
399 section for a reference to a common symbol is the value itself plus
400 any desired offset. Ian Taylor, Cygnus Support. */
401
402 /* If we are producing relocateable output, we need to do some
403 adjustments to the object file that are not done by the
404 bfd_perform_relocation function. This function is called by every
405 reloc type to make any required adjustments. */
406
407 static bfd_reloc_status_type
408 aacoff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
409 error_message)
410 bfd *abfd;
411 arelent *reloc_entry;
412 asymbol *symbol;
413 PTR data;
414 asection *input_section;
415 bfd *output_bfd;
416 char **error_message;
417 {
418 symvalue diff;
419
420 if (output_bfd == (bfd *) NULL)
421 return bfd_reloc_continue;
422
423 if (bfd_is_com_section (symbol->section))
424 {
425 /* We are relocating a common symbol. The current value in the
426 object file is ORIG + OFFSET, where ORIG is the value of the
427 common symbol as seen by the object file when it was compiled
428 (this may be zero if the symbol was undefined) and OFFSET is
429 the offset into the common symbol (normally zero, but may be
430 non-zero when referring to a field in a common structure).
431 ORIG is the negative of reloc_entry->addend, which is set by
432 the CALC_ADDEND macro below. We want to replace the value in
433 the object file with NEW + OFFSET, where NEW is the value of
434 the common symbol which we are going to put in the final
435 object file. NEW is symbol->value. */
436 diff = symbol->value + reloc_entry->addend;
437 }
438 else
439 {
440 /* For some reason bfd_perform_relocation always effectively
441 ignores the addend for a COFF target when producing
442 relocateable output. This seems to be always wrong for arm
443 COFF, so we handle the addend here instead. */
444 diff = reloc_entry->addend;
445 }
446
447 #define DOIT(x) \
448 x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
449
450 if (diff != 0)
451 {
452 reloc_howto_type *howto = reloc_entry->howto;
453 unsigned char *addr = (unsigned char *) data + reloc_entry->address;
454
455 switch (howto->size)
456 {
457 case 0:
458 {
459 char x = bfd_get_8 (abfd, addr);
460 DOIT (x);
461 bfd_put_8 (abfd, x, addr);
462 }
463 break;
464
465 case 1:
466 {
467 short x = bfd_get_16 (abfd, addr);
468 DOIT (x);
469 bfd_put_16 (abfd, x, addr);
470 }
471 break;
472
473 case 2:
474 {
475 long x = bfd_get_32 (abfd, addr);
476 DOIT (x);
477 bfd_put_32 (abfd, x, addr);
478 }
479 break;
480
481 default:
482 abort ();
483 }
484 }
485
486 /* Now let bfd_perform_relocation finish everything up. */
487 return bfd_reloc_continue;
488 }
489
490
491
492
493
494 /* Turn a howto into a reloc nunmber */
495
496 #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
497 #define BADMAG(x) ARMBADMAG(x)
498 #define ARM 1 /* Customize coffcode.h */
499
500
501 /* On SCO Unix 3.2.2 the native assembler generates two .data
502 sections. We handle that by renaming the second one to .data2. It
503 does no harm to do this for any arm COFF target. */
504 #define TWO_DATA_SECS
505
506 /* For arm COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
507 library. On some other COFF targets STYP_BSS is normally
508 STYP_NOLOAD. */
509 #define BSS_NOLOAD_IS_SHARED_LIBRARY
510
511
512 /* We use the special COFF backend linker. */
513 #define coff_relocate_section _bfd_coff_generic_relocate_section
514
515
516
517 #include "coffcode.h"
518
519 static const bfd_target *
520 i3coff_object_p(a)
521 bfd *a;
522 {
523 return coff_object_p(a);
524 }
525
526 #ifdef TARGET_LITTLE_SYM
527 const bfd_target TARGET_LITTLE_SYM =
528 {
529 TARGET_LITTLE_NAME, /* name or coff-arm-little */
530 bfd_target_coff_flavour,
531 false, /* data byte order is little */
532 false, /* header byte order is little */
533
534 (HAS_RELOC | EXEC_P | /* object flags */
535 HAS_LINENO | HAS_DEBUG |
536 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
537
538 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
539 #ifdef TARGET_UNDERSCORE
540 TARGET_UNDERSCORE, /* leading underscore */
541 #else
542 0, /* leading underscore */
543 #endif
544 '/', /* ar_pad_char */
545 15, /* ar_max_namelen */
546
547 2, /* minimum alignment power */
548 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
549 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
550 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
551 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
552 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
553 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
554
555 /* Note that we allow an object file to be treated as a core file as well. */
556 {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */
557 bfd_generic_archive_p, i3coff_object_p},
558 {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
559 bfd_false},
560 {bfd_false, coff_write_object_contents, /* bfd_write_contents */
561 _bfd_write_archive_contents, bfd_false},
562
563 BFD_JUMP_TABLE_GENERIC (coff),
564 BFD_JUMP_TABLE_COPY (coff),
565 BFD_JUMP_TABLE_CORE (_bfd_nocore),
566 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
567 BFD_JUMP_TABLE_SYMBOLS (coff),
568 BFD_JUMP_TABLE_RELOCS (coff),
569 BFD_JUMP_TABLE_WRITE (coff),
570 BFD_JUMP_TABLE_LINK (coff),
571 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
572
573 COFF_SWAP_TABLE,
574 };
575 #endif
576
577 #ifdef TARGET_BIG_SYM
578 const bfd_target TARGET_BIG_SYM =
579 {
580 TARGET_BIG_NAME, /* name or coff-arm-big */
581 bfd_target_coff_flavour,
582 true, /* data byte order is big */
583 true, /* header byte order is big */
584
585 (HAS_RELOC | EXEC_P | /* object flags */
586 HAS_LINENO | HAS_DEBUG |
587 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
588
589 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
590 #ifdef TARGET_UNDERSCORE
591 TARGET_UNDERSCORE, /* leading underscore */
592 #else
593 0, /* leading underscore */
594 #endif
595 '/', /* ar_pad_char */
596 15, /* ar_max_namelen */
597
598 2, /* minimum alignment power */
599 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
600 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
601 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
602 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
603 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
604 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
605
606 /* Note that we allow an object file to be treated as a core file as well. */
607 {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */
608 bfd_generic_archive_p, i3coff_object_p},
609 {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
610 bfd_false},
611 {bfd_false, coff_write_object_contents, /* bfd_write_contents */
612 _bfd_write_archive_contents, bfd_false},
613
614 BFD_JUMP_TABLE_GENERIC (coff),
615 BFD_JUMP_TABLE_COPY (coff),
616 BFD_JUMP_TABLE_CORE (_bfd_nocore),
617 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
618 BFD_JUMP_TABLE_SYMBOLS (coff),
619 BFD_JUMP_TABLE_RELOCS (coff),
620 BFD_JUMP_TABLE_WRITE (coff),
621 BFD_JUMP_TABLE_LINK (coff),
622 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
623
624 COFF_SWAP_TABLE,
625 };
626 #endif