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