* elf32-i860.c (i860_howto_pc26_reloc): Finish relocation here
[binutils-gdb.git] / bfd / elf32-i860.c
1 /* Intel i860 specific support for 32-bit ELF.
2 Copyright 1993, 1995, 1999, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
4
5 Full i860 support contributed by Jason Eckhardt <jle@cygnus.com>.
6
7 This file is part of BFD, the Binary File Descriptor library.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23 #include "bfd.h"
24 #include "sysdep.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27 #include "elf/i860.h"
28
29 /* special_function for R_860_PC26 relocation.
30 Derived from bfd_elf_generic_reloc (elf.c) with modifications. */
31 static bfd_reloc_status_type
32 i860_howto_pc26_reloc (bfd *abfd ATTRIBUTE_UNUSED,
33 arelent *reloc_entry,
34 asymbol *symbol,
35 void *data ATTRIBUTE_UNUSED,
36 asection *input_section,
37 bfd *output_bfd,
38 char **error_message ATTRIBUTE_UNUSED)
39 {
40 bfd_vma insn;
41 bfd_vma relocation;
42 bfd_byte *addr;
43
44 if (output_bfd != NULL
45 && (symbol->flags & BSF_SECTION_SYM) == 0
46 && (! reloc_entry->howto->partial_inplace
47 || reloc_entry->addend == 0))
48 {
49 reloc_entry->address += input_section->output_offset;
50 return bfd_reloc_ok;
51 }
52
53 /* Used elf32-mips.c as an example. */
54 if (bfd_is_und_section (symbol->section)
55 && output_bfd == (bfd *) NULL)
56 return bfd_reloc_undefined;
57
58 if (bfd_is_com_section (symbol->section))
59 relocation = 0;
60 else
61 relocation = symbol->value;
62
63 relocation += symbol->section->output_section->vma;
64 relocation += symbol->section->output_offset;
65 relocation += reloc_entry->addend;
66
67 if (reloc_entry->address > input_section->_cooked_size)
68 return bfd_reloc_outofrange;
69
70 /* Adjust for PC-relative relocation. */
71 relocation -= (input_section->output_section->vma
72 + input_section->output_offset
73 + reloc_entry->address
74 + 4);
75
76 /* Check for target out of range. */
77 if ((bfd_signed_vma)relocation > (0x3ffffff << 2)
78 || (bfd_signed_vma)relocation < (-0x4000000 << 2))
79 return bfd_reloc_outofrange;
80
81 addr = (bfd_byte *) data + reloc_entry->address;
82 insn = bfd_get_32 (abfd, addr);
83
84 relocation >>= reloc_entry->howto->rightshift;
85 insn = (insn & ~reloc_entry->howto->dst_mask)
86 | (relocation & reloc_entry->howto->dst_mask);
87
88 bfd_put_32 (abfd, (bfd_vma) insn, addr);
89
90 return bfd_reloc_ok;
91 }
92
93 /* special_function for R_860_PC16 relocation. */
94 static bfd_reloc_status_type
95 i860_howto_pc16_reloc (bfd *abfd,
96 arelent *reloc_entry,
97 asymbol *symbol,
98 void *data,
99 asection *input_section,
100 bfd *output_bfd,
101 char **error_message ATTRIBUTE_UNUSED)
102 {
103 bfd_vma insn;
104 bfd_vma relocation;
105 bfd_byte *addr;
106
107 if (output_bfd != NULL
108 && (symbol->flags & BSF_SECTION_SYM) == 0
109 && (! reloc_entry->howto->partial_inplace
110 || reloc_entry->addend == 0))
111 {
112 reloc_entry->address += input_section->output_offset;
113 return bfd_reloc_ok;
114 }
115
116 /* Used elf32-mips.c as an example. */
117 if (bfd_is_und_section (symbol->section)
118 && output_bfd == (bfd *) NULL)
119 return bfd_reloc_undefined;
120
121 if (bfd_is_com_section (symbol->section))
122 relocation = 0;
123 else
124 relocation = symbol->value;
125
126 relocation += symbol->section->output_section->vma;
127 relocation += symbol->section->output_offset;
128 relocation += reloc_entry->addend;
129
130 if (reloc_entry->address > input_section->_cooked_size)
131 return bfd_reloc_outofrange;
132
133 /* Adjust for PC-relative relocation. */
134 relocation -= (input_section->output_section->vma
135 + input_section->output_offset
136 + reloc_entry->address
137 + 4);
138
139 /* Check for target out of range. */
140 if ((bfd_signed_vma)relocation > (0x7fff << 2)
141 || (bfd_signed_vma)relocation < (-0x8000 << 2))
142 return bfd_reloc_outofrange;
143
144 addr = (bfd_byte *) data + reloc_entry->address;
145 insn = bfd_get_32 (abfd, addr);
146
147 relocation >>= reloc_entry->howto->rightshift;
148 relocation = (((relocation & 0xf800) << 5) | (relocation & 0x7ff))
149 & reloc_entry->howto->dst_mask;
150 insn = (insn & ~reloc_entry->howto->dst_mask) | relocation;
151
152 bfd_put_32 (abfd, (bfd_vma) insn, addr);
153
154 return bfd_reloc_ok;
155 }
156
157 /* special_function for R_860_HIGHADJ relocation. */
158 static bfd_reloc_status_type
159 i860_howto_highadj_reloc (bfd *abfd,
160 arelent *reloc_entry,
161 asymbol *symbol,
162 void *data,
163 asection *input_section,
164 bfd *output_bfd,
165 char **error_message ATTRIBUTE_UNUSED)
166 {
167 bfd_vma insn;
168 bfd_vma relocation;
169 bfd_byte *addr;
170
171 if (output_bfd != NULL
172 && (symbol->flags & BSF_SECTION_SYM) == 0
173 && (! reloc_entry->howto->partial_inplace
174 || reloc_entry->addend == 0))
175 {
176 reloc_entry->address += input_section->output_offset;
177 return bfd_reloc_ok;
178 }
179
180 /* Used elf32-mips.c as an example. */
181 if (bfd_is_und_section (symbol->section)
182 && output_bfd == (bfd *) NULL)
183 return bfd_reloc_undefined;
184
185 if (bfd_is_com_section (symbol->section))
186 relocation = 0;
187 else
188 relocation = symbol->value;
189
190 relocation += symbol->section->output_section->vma;
191 relocation += symbol->section->output_offset;
192 relocation += reloc_entry->addend;
193 relocation += 0x8000;
194
195 if (reloc_entry->address > input_section->_cooked_size)
196 return bfd_reloc_outofrange;
197
198 addr = (bfd_byte *) data + reloc_entry->address;
199 insn = bfd_get_32 (abfd, addr);
200
201 relocation = ((relocation >> 16) & 0xffff);
202
203 insn = (insn & 0xffff0000) | relocation;
204
205 bfd_put_32 (abfd, (bfd_vma) insn, addr);
206
207 return bfd_reloc_ok;
208 }
209
210 /* special_function for R_860_SPLITn relocations. */
211 static bfd_reloc_status_type
212 i860_howto_splitn_reloc (bfd *abfd,
213 arelent *reloc_entry,
214 asymbol *symbol,
215 void *data,
216 asection *input_section,
217 bfd *output_bfd,
218 char **error_message ATTRIBUTE_UNUSED)
219 {
220 bfd_vma insn;
221 bfd_vma relocation;
222 bfd_byte *addr;
223
224 if (output_bfd != NULL
225 && (symbol->flags & BSF_SECTION_SYM) == 0
226 && (! reloc_entry->howto->partial_inplace
227 || reloc_entry->addend == 0))
228 {
229 reloc_entry->address += input_section->output_offset;
230 return bfd_reloc_ok;
231 }
232
233 /* Used elf32-mips.c as an example. */
234 if (bfd_is_und_section (symbol->section)
235 && output_bfd == (bfd *) NULL)
236 return bfd_reloc_undefined;
237
238 if (bfd_is_com_section (symbol->section))
239 relocation = 0;
240 else
241 relocation = symbol->value;
242
243 relocation += symbol->section->output_section->vma;
244 relocation += symbol->section->output_offset;
245 relocation += reloc_entry->addend;
246
247 if (reloc_entry->address > input_section->_cooked_size)
248 return bfd_reloc_outofrange;
249
250 addr = (bfd_byte *) data + reloc_entry->address;
251 insn = bfd_get_32 (abfd, addr);
252
253 relocation = (((relocation & 0xf800) << 5) | (relocation & 0x7ff))
254 & reloc_entry->howto->dst_mask;
255 insn = (insn & ~reloc_entry->howto->dst_mask) | relocation;
256
257 bfd_put_32 (abfd, (bfd_vma) insn, addr);
258
259 return bfd_reloc_ok;
260 }
261
262 /* This howto table is preliminary. */
263 static reloc_howto_type elf32_i860_howto_table [] =
264 {
265 /* This relocation does nothing. */
266 HOWTO (R_860_NONE, /* type */
267 0, /* rightshift */
268 2, /* size (0 = byte, 1 = short, 2 = long) */
269 32, /* bitsize */
270 FALSE, /* pc_relative */
271 0, /* bitpos */
272 complain_overflow_bitfield, /* complain_on_overflow */
273 bfd_elf_generic_reloc, /* special_function */
274 "R_860_NONE", /* name */
275 FALSE, /* partial_inplace */
276 0, /* src_mask */
277 0, /* dst_mask */
278 FALSE), /* pcrel_offset */
279
280 /* A 32-bit absolute relocation. */
281 HOWTO (R_860_32, /* type */
282 0, /* rightshift */
283 2, /* size (0 = byte, 1 = short, 2 = long) */
284 32, /* bitsize */
285 FALSE, /* pc_relative */
286 0, /* bitpos */
287 complain_overflow_bitfield, /* complain_on_overflow */
288 bfd_elf_generic_reloc, /* special_function */
289 "R_860_32", /* name */
290 FALSE, /* partial_inplace */
291 0xffffffff, /* src_mask */
292 0xffffffff, /* dst_mask */
293 FALSE), /* pcrel_offset */
294
295 HOWTO (R_860_COPY, /* type */
296 0, /* rightshift */
297 2, /* size (0 = byte, 1 = short, 2 = long) */
298 32, /* bitsize */
299 FALSE, /* pc_relative */
300 0, /* bitpos */
301 complain_overflow_bitfield, /* complain_on_overflow */
302 bfd_elf_generic_reloc, /* special_function */
303 "R_860_COPY", /* name */
304 TRUE, /* partial_inplace */
305 0xffffffff, /* src_mask */
306 0xffffffff, /* dst_mask */
307 FALSE), /* pcrel_offset */
308
309 HOWTO (R_860_GLOB_DAT, /* type */
310 0, /* rightshift */
311 2, /* size (0 = byte, 1 = short, 2 = long) */
312 32, /* bitsize */
313 FALSE, /* pc_relative */
314 0, /* bitpos */
315 complain_overflow_bitfield, /* complain_on_overflow */
316 bfd_elf_generic_reloc, /* special_function */
317 "R_860_GLOB_DAT", /* name */
318 TRUE, /* partial_inplace */
319 0xffffffff, /* src_mask */
320 0xffffffff, /* dst_mask */
321 FALSE), /* pcrel_offset */
322
323 HOWTO (R_860_JUMP_SLOT, /* type */
324 0, /* rightshift */
325 2, /* size (0 = byte, 1 = short, 2 = long) */
326 32, /* bitsize */
327 FALSE, /* pc_relative */
328 0, /* bitpos */
329 complain_overflow_bitfield, /* complain_on_overflow */
330 bfd_elf_generic_reloc, /* special_function */
331 "R_860_JUMP_SLOT", /* name */
332 TRUE, /* partial_inplace */
333 0xffffffff, /* src_mask */
334 0xffffffff, /* dst_mask */
335 FALSE), /* pcrel_offset */
336
337 HOWTO (R_860_RELATIVE, /* type */
338 0, /* rightshift */
339 2, /* size (0 = byte, 1 = short, 2 = long) */
340 32, /* bitsize */
341 FALSE, /* pc_relative */
342 0, /* bitpos */
343 complain_overflow_bitfield, /* complain_on_overflow */
344 bfd_elf_generic_reloc, /* special_function */
345 "R_860_RELATIVE", /* name */
346 TRUE, /* partial_inplace */
347 0xffffffff, /* src_mask */
348 0xffffffff, /* dst_mask */
349 FALSE), /* pcrel_offset */
350
351 /* A 26-bit PC-relative relocation. */
352 HOWTO (R_860_PC26, /* type */
353 2, /* rightshift */
354 2, /* size (0 = byte, 1 = short, 2 = long) */
355 26, /* bitsize */
356 TRUE, /* pc_relative */
357 0, /* bitpos */
358 complain_overflow_bitfield, /* complain_on_overflow */
359 i860_howto_pc26_reloc, /* special_function */
360 "R_860_PC26", /* name */
361 FALSE, /* partial_inplace */
362 0x3ffffff, /* src_mask */
363 0x3ffffff, /* dst_mask */
364 TRUE), /* pcrel_offset */
365
366 HOWTO (R_860_PLT26, /* type */
367 0, /* rightshift */
368 2, /* size (0 = byte, 1 = short, 2 = long) */
369 26, /* bitsize */
370 TRUE, /* pc_relative */
371 0, /* bitpos */
372 complain_overflow_bitfield, /* complain_on_overflow */
373 bfd_elf_generic_reloc, /* special_function */
374 "R_860_PLT26", /* name */
375 TRUE, /* partial_inplace */
376 0xffffffff, /* src_mask */
377 0xffffffff, /* dst_mask */
378 TRUE), /* pcrel_offset */
379
380 /* A 16-bit PC-relative relocation. */
381 HOWTO (R_860_PC16, /* type */
382 2, /* rightshift */
383 2, /* size (0 = byte, 1 = short, 2 = long) */
384 16, /* bitsize */
385 TRUE, /* pc_relative */
386 0, /* bitpos */
387 complain_overflow_bitfield, /* complain_on_overflow */
388 i860_howto_pc16_reloc, /* special_function */
389 "R_860_PC16", /* name */
390 FALSE, /* partial_inplace */
391 0x1f07ff, /* src_mask */
392 0x1f07ff, /* dst_mask */
393 TRUE), /* pcrel_offset */
394
395 HOWTO (R_860_LOW0, /* type */
396 0, /* rightshift */
397 2, /* size (0 = byte, 1 = short, 2 = long) */
398 16, /* bitsize */
399 FALSE, /* pc_relative */
400 0, /* bitpos */
401 complain_overflow_dont, /* complain_on_overflow */
402 bfd_elf_generic_reloc, /* special_function */
403 "R_860_LOW0", /* name */
404 FALSE, /* partial_inplace */
405 0xffff, /* src_mask */
406 0xffff, /* dst_mask */
407 FALSE), /* pcrel_offset */
408
409 HOWTO (R_860_SPLIT0, /* type */
410 0, /* rightshift */
411 2, /* size (0 = byte, 1 = short, 2 = long) */
412 16, /* bitsize */
413 FALSE, /* pc_relative */
414 0, /* bitpos */
415 complain_overflow_dont, /* complain_on_overflow */
416 i860_howto_splitn_reloc, /* special_function */
417 "R_860_SPLIT0", /* name */
418 FALSE, /* partial_inplace */
419 0x1f07ff, /* src_mask */
420 0x1f07ff, /* dst_mask */
421 FALSE), /* pcrel_offset */
422
423 HOWTO (R_860_LOW1, /* type */
424 0, /* rightshift */
425 2, /* size (0 = byte, 1 = short, 2 = long) */
426 16, /* bitsize */
427 FALSE, /* pc_relative */
428 0, /* bitpos */
429 complain_overflow_dont, /* complain_on_overflow */
430 bfd_elf_generic_reloc, /* special_function */
431 "R_860_LOW1", /* name */
432 FALSE, /* partial_inplace */
433 0xfffe, /* src_mask */
434 0xfffe, /* dst_mask */
435 FALSE), /* pcrel_offset */
436
437 HOWTO (R_860_SPLIT1, /* type */
438 0, /* rightshift */
439 2, /* size (0 = byte, 1 = short, 2 = long) */
440 16, /* bitsize */
441 FALSE, /* pc_relative */
442 0, /* bitpos */
443 complain_overflow_dont, /* complain_on_overflow */
444 i860_howto_splitn_reloc, /* special_function */
445 "R_860_SPLIT1", /* name */
446 FALSE, /* partial_inplace */
447 0x1f07fe, /* src_mask */
448 0x1f07fe, /* dst_mask */
449 FALSE), /* pcrel_offset */
450
451 HOWTO (R_860_LOW2, /* type */
452 0, /* rightshift */
453 2, /* size (0 = byte, 1 = short, 2 = long) */
454 16, /* bitsize */
455 FALSE, /* pc_relative */
456 0, /* bitpos */
457 complain_overflow_dont, /* complain_on_overflow */
458 bfd_elf_generic_reloc, /* special_function */
459 "R_860_LOW2", /* name */
460 FALSE, /* partial_inplace */
461 0xfffc, /* src_mask */
462 0xfffc, /* dst_mask */
463 FALSE), /* pcrel_offset */
464
465 HOWTO (R_860_SPLIT2, /* type */
466 0, /* rightshift */
467 2, /* size (0 = byte, 1 = short, 2 = long) */
468 16, /* bitsize */
469 FALSE, /* pc_relative */
470 0, /* bitpos */
471 complain_overflow_dont, /* complain_on_overflow */
472 i860_howto_splitn_reloc, /* special_function */
473 "R_860_SPLIT2", /* name */
474 FALSE, /* partial_inplace */
475 0x1f07fc, /* src_mask */
476 0x1f07fc, /* dst_mask */
477 FALSE), /* pcrel_offset */
478
479 HOWTO (R_860_LOW3, /* type */
480 0, /* rightshift */
481 2, /* size (0 = byte, 1 = short, 2 = long) */
482 16, /* bitsize */
483 FALSE, /* pc_relative */
484 0, /* bitpos */
485 complain_overflow_dont, /* complain_on_overflow */
486 bfd_elf_generic_reloc, /* special_function */
487 "R_860_LOW3", /* name */
488 FALSE, /* partial_inplace */
489 0xfff8, /* src_mask */
490 0xfff8, /* dst_mask */
491 FALSE), /* pcrel_offset */
492
493 HOWTO (R_860_LOGOT0, /* type */
494 0, /* rightshift */
495 2, /* size (0 = byte, 1 = short, 2 = long) */
496 16, /* bitsize */
497 FALSE, /* pc_relative */
498 0, /* bitpos */
499 complain_overflow_dont, /* complain_on_overflow */
500 bfd_elf_generic_reloc, /* special_function */
501 "R_860_LOGOT0", /* name */
502 FALSE, /* partial_inplace */
503 0, /* src_mask */
504 0xffff, /* dst_mask */
505 TRUE), /* pcrel_offset */
506
507 HOWTO (R_860_SPGOT0, /* type */
508 0, /* rightshift */
509 2, /* size (0 = byte, 1 = short, 2 = long) */
510 16, /* bitsize */
511 FALSE, /* pc_relative */
512 0, /* bitpos */
513 complain_overflow_dont, /* complain_on_overflow */
514 bfd_elf_generic_reloc, /* special_function */
515 "R_860_SPGOT0", /* name */
516 FALSE, /* partial_inplace */
517 0, /* src_mask */
518 0xffff, /* dst_mask */
519 TRUE), /* pcrel_offset */
520
521 HOWTO (R_860_LOGOT1, /* type */
522 0, /* rightshift */
523 2, /* size (0 = byte, 1 = short, 2 = long) */
524 16, /* bitsize */
525 FALSE, /* pc_relative */
526 0, /* bitpos */
527 complain_overflow_dont, /* complain_on_overflow */
528 bfd_elf_generic_reloc, /* special_function */
529 "R_860_LOGOT1", /* name */
530 FALSE, /* partial_inplace */
531 0, /* src_mask */
532 0xffff, /* dst_mask */
533 TRUE), /* pcrel_offset */
534
535 HOWTO (R_860_SPGOT1, /* type */
536 0, /* rightshift */
537 2, /* size (0 = byte, 1 = short, 2 = long) */
538 16, /* bitsize */
539 FALSE, /* pc_relative */
540 0, /* bitpos */
541 complain_overflow_dont, /* complain_on_overflow */
542 bfd_elf_generic_reloc, /* special_function */
543 "R_860_SPGOT1", /* name */
544 FALSE, /* partial_inplace */
545 0, /* src_mask */
546 0xffff, /* dst_mask */
547 TRUE), /* pcrel_offset */
548
549 HOWTO (R_860_LOGOTOFF0, /* type */
550 0, /* rightshift */
551 2, /* size (0 = byte, 1 = short, 2 = long) */
552 32, /* bitsize */
553 FALSE, /* pc_relative */
554 0, /* bitpos */
555 complain_overflow_dont, /* complain_on_overflow */
556 bfd_elf_generic_reloc, /* special_function */
557 "R_860_LOGOTOFF0", /* name */
558 TRUE, /* partial_inplace */
559 0xffffffff, /* src_mask */
560 0xffffffff, /* dst_mask */
561 FALSE), /* pcrel_offset */
562
563 HOWTO (R_860_SPGOTOFF0, /* type */
564 0, /* rightshift */
565 2, /* size (0 = byte, 1 = short, 2 = long) */
566 32, /* bitsize */
567 FALSE, /* pc_relative */
568 0, /* bitpos */
569 complain_overflow_dont, /* complain_on_overflow */
570 bfd_elf_generic_reloc, /* special_function */
571 "R_860_SPGOTOFF0", /* name */
572 TRUE, /* partial_inplace */
573 0xffffffff, /* src_mask */
574 0xffffffff, /* dst_mask */
575 FALSE), /* pcrel_offset */
576
577 HOWTO (R_860_LOGOTOFF1, /* type */
578 0, /* rightshift */
579 2, /* size (0 = byte, 1 = short, 2 = long) */
580 32, /* bitsize */
581 FALSE, /* pc_relative */
582 0, /* bitpos */
583 complain_overflow_dont, /* complain_on_overflow */
584 bfd_elf_generic_reloc, /* special_function */
585 "R_860_LOGOTOFF1", /* name */
586 TRUE, /* partial_inplace */
587 0xffffffff, /* src_mask */
588 0xffffffff, /* dst_mask */
589 FALSE), /* pcrel_offset */
590
591 HOWTO (R_860_SPGOTOFF1, /* type */
592 0, /* rightshift */
593 2, /* size (0 = byte, 1 = short, 2 = long) */
594 32, /* bitsize */
595 FALSE, /* pc_relative */
596 0, /* bitpos */
597 complain_overflow_dont, /* complain_on_overflow */
598 bfd_elf_generic_reloc, /* special_function */
599 "R_860_SPGOTOFF1", /* name */
600 TRUE, /* partial_inplace */
601 0xffffffff, /* src_mask */
602 0xffffffff, /* dst_mask */
603 FALSE), /* pcrel_offset */
604
605 HOWTO (R_860_LOGOTOFF2, /* type */
606 0, /* rightshift */
607 2, /* size (0 = byte, 1 = short, 2 = long) */
608 32, /* bitsize */
609 FALSE, /* pc_relative */
610 0, /* bitpos */
611 complain_overflow_dont, /* complain_on_overflow */
612 bfd_elf_generic_reloc, /* special_function */
613 "R_860_LOGOTOFF2", /* name */
614 TRUE, /* partial_inplace */
615 0xffffffff, /* src_mask */
616 0xffffffff, /* dst_mask */
617 FALSE), /* pcrel_offset */
618
619 HOWTO (R_860_LOGOTOFF3, /* type */
620 0, /* rightshift */
621 2, /* size (0 = byte, 1 = short, 2 = long) */
622 32, /* bitsize */
623 FALSE, /* pc_relative */
624 0, /* bitpos */
625 complain_overflow_dont, /* complain_on_overflow */
626 bfd_elf_generic_reloc, /* special_function */
627 "R_860_LOGOTOFF3", /* name */
628 TRUE, /* partial_inplace */
629 0xffffffff, /* src_mask */
630 0xffffffff, /* dst_mask */
631 FALSE), /* pcrel_offset */
632
633 HOWTO (R_860_LOPC, /* type */
634 0, /* rightshift */
635 2, /* size (0 = byte, 1 = short, 2 = long) */
636 16, /* bitsize */
637 TRUE, /* pc_relative */
638 0, /* bitpos */
639 complain_overflow_bitfield, /* complain_on_overflow */
640 bfd_elf_generic_reloc, /* special_function */
641 "R_860_LOPC", /* name */
642 FALSE, /* partial_inplace */
643 0xffff, /* src_mask */
644 0xffff, /* dst_mask */
645 TRUE), /* pcrel_offset */
646
647 HOWTO (R_860_HIGHADJ, /* type */
648 0, /* rightshift */
649 2, /* size (0 = byte, 1 = short, 2 = long) */
650 16, /* bitsize */
651 FALSE, /* pc_relative */
652 0, /* bitpos */
653 complain_overflow_dont, /* complain_on_overflow */
654 i860_howto_highadj_reloc, /* special_function */
655 "R_860_HIGHADJ", /* name */
656 FALSE, /* partial_inplace */
657 0xffff, /* src_mask */
658 0xffff, /* dst_mask */
659 FALSE), /* pcrel_offset */
660
661 HOWTO (R_860_HAGOT, /* type */
662 0, /* rightshift */
663 2, /* size (0 = byte, 1 = short, 2 = long) */
664 16, /* bitsize */
665 FALSE, /* pc_relative */
666 0, /* bitpos */
667 complain_overflow_dont, /* complain_on_overflow */
668 bfd_elf_generic_reloc, /* special_function */
669 "R_860_HAGOT", /* name */
670 FALSE, /* partial_inplace */
671 0, /* src_mask */
672 0xffff, /* dst_mask */
673 TRUE), /* pcrel_offset */
674
675 HOWTO (R_860_HAGOTOFF, /* type */
676 0, /* rightshift */
677 2, /* size (0 = byte, 1 = short, 2 = long) */
678 32, /* bitsize */
679 FALSE, /* pc_relative */
680 0, /* bitpos */
681 complain_overflow_dont, /* complain_on_overflow */
682 bfd_elf_generic_reloc, /* special_function */
683 "R_860_HAGOTOFF", /* name */
684 TRUE, /* partial_inplace */
685 0xffffffff, /* src_mask */
686 0xffffffff, /* dst_mask */
687 FALSE), /* pcrel_offset */
688
689 HOWTO (R_860_HAPC, /* type */
690 0, /* rightshift */
691 2, /* size (0 = byte, 1 = short, 2 = long) */
692 16, /* bitsize */
693 TRUE, /* pc_relative */
694 0, /* bitpos */
695 complain_overflow_bitfield, /* complain_on_overflow */
696 bfd_elf_generic_reloc, /* special_function */
697 "R_860_HAPC", /* name */
698 FALSE, /* partial_inplace */
699 0xffff, /* src_mask */
700 0xffff, /* dst_mask */
701 TRUE), /* pcrel_offset */
702
703 HOWTO (R_860_HIGH, /* type */
704 16, /* rightshift */
705 2, /* size (0 = byte, 1 = short, 2 = long) */
706 16, /* bitsize */
707 FALSE, /* pc_relative */
708 0, /* bitpos */
709 complain_overflow_dont, /* complain_on_overflow */
710 bfd_elf_generic_reloc, /* special_function */
711 "R_860_HIGH", /* name */
712 FALSE, /* partial_inplace */
713 0xffff, /* src_mask */
714 0xffff, /* dst_mask */
715 FALSE), /* pcrel_offset */
716
717 HOWTO (R_860_HIGOT, /* type */
718 0, /* rightshift */
719 2, /* size (0 = byte, 1 = short, 2 = long) */
720 16, /* bitsize */
721 FALSE, /* pc_relative */
722 0, /* bitpos */
723 complain_overflow_dont, /* complain_on_overflow */
724 bfd_elf_generic_reloc, /* special_function */
725 "R_860_HIGOT", /* name */
726 FALSE, /* partial_inplace */
727 0, /* src_mask */
728 0xffff, /* dst_mask */
729 TRUE), /* pcrel_offset */
730
731 HOWTO (R_860_HIGOTOFF, /* type */
732 0, /* rightshift */
733 2, /* size (0 = byte, 1 = short, 2 = long) */
734 32, /* bitsize */
735 FALSE, /* pc_relative */
736 0, /* bitpos */
737 complain_overflow_dont, /* complain_on_overflow */
738 bfd_elf_generic_reloc, /* special_function */
739 "R_860_HIGOTOFF", /* name */
740 TRUE, /* partial_inplace */
741 0xffffffff, /* src_mask */
742 0xffffffff, /* dst_mask */
743 FALSE), /* pcrel_offset */
744 };
745 \f
746 static unsigned char elf_code_to_howto_index[R_860_max + 1];
747
748 static reloc_howto_type *
749 lookup_howto (unsigned int rtype)
750 {
751 static int initialized = 0;
752 int i;
753 int howto_tbl_size = (int) (sizeof (elf32_i860_howto_table)
754 / sizeof (elf32_i860_howto_table[0]));
755
756 if (! initialized)
757 {
758 initialized = 1;
759 memset (elf_code_to_howto_index, 0xff,
760 sizeof (elf_code_to_howto_index));
761 for (i = 0; i < howto_tbl_size; i++)
762 elf_code_to_howto_index[elf32_i860_howto_table[i].type] = i;
763 }
764
765 BFD_ASSERT (rtype <= R_860_max);
766 i = elf_code_to_howto_index[rtype];
767 if (i >= howto_tbl_size)
768 return 0;
769 return elf32_i860_howto_table + i;
770 }
771
772 /* Given a BFD reloc, return the matching HOWTO structure. */
773 static reloc_howto_type *
774 elf32_i860_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
775 bfd_reloc_code_real_type code)
776 {
777 unsigned int rtype;
778
779 switch (code)
780 {
781 case BFD_RELOC_NONE:
782 rtype = R_860_NONE;
783 break;
784 case BFD_RELOC_32:
785 rtype = R_860_32;
786 break;
787 case BFD_RELOC_860_COPY:
788 rtype = R_860_COPY;
789 break;
790 case BFD_RELOC_860_GLOB_DAT:
791 rtype = R_860_GLOB_DAT;
792 break;
793 case BFD_RELOC_860_JUMP_SLOT:
794 rtype = R_860_JUMP_SLOT;
795 break;
796 case BFD_RELOC_860_RELATIVE:
797 rtype = R_860_RELATIVE;
798 break;
799 case BFD_RELOC_860_PC26:
800 rtype = R_860_PC26;
801 break;
802 case BFD_RELOC_860_PLT26:
803 rtype = R_860_PLT26;
804 break;
805 case BFD_RELOC_860_PC16:
806 rtype = R_860_PC16;
807 break;
808 case BFD_RELOC_860_LOW0:
809 rtype = R_860_LOW0;
810 break;
811 case BFD_RELOC_860_SPLIT0:
812 rtype = R_860_SPLIT0;
813 break;
814 case BFD_RELOC_860_LOW1:
815 rtype = R_860_LOW1;
816 break;
817 case BFD_RELOC_860_SPLIT1:
818 rtype = R_860_SPLIT1;
819 break;
820 case BFD_RELOC_860_LOW2:
821 rtype = R_860_LOW2;
822 break;
823 case BFD_RELOC_860_SPLIT2:
824 rtype = R_860_SPLIT2;
825 break;
826 case BFD_RELOC_860_LOW3:
827 rtype = R_860_LOW3;
828 break;
829 case BFD_RELOC_860_LOGOT0:
830 rtype = R_860_LOGOT0;
831 break;
832 case BFD_RELOC_860_SPGOT0:
833 rtype = R_860_SPGOT0;
834 break;
835 case BFD_RELOC_860_LOGOT1:
836 rtype = R_860_LOGOT1;
837 break;
838 case BFD_RELOC_860_SPGOT1:
839 rtype = R_860_SPGOT1;
840 break;
841 case BFD_RELOC_860_LOGOTOFF0:
842 rtype = R_860_LOGOTOFF0;
843 break;
844 case BFD_RELOC_860_SPGOTOFF0:
845 rtype = R_860_SPGOTOFF0;
846 break;
847 case BFD_RELOC_860_LOGOTOFF1:
848 rtype = R_860_LOGOTOFF1;
849 break;
850 case BFD_RELOC_860_SPGOTOFF1:
851 rtype = R_860_SPGOTOFF1;
852 break;
853 case BFD_RELOC_860_LOGOTOFF2:
854 rtype = R_860_LOGOTOFF2;
855 break;
856 case BFD_RELOC_860_LOGOTOFF3:
857 rtype = R_860_LOGOTOFF3;
858 break;
859 case BFD_RELOC_860_LOPC:
860 rtype = R_860_LOPC;
861 break;
862 case BFD_RELOC_860_HIGHADJ:
863 rtype = R_860_HIGHADJ;
864 break;
865 case BFD_RELOC_860_HAGOT:
866 rtype = R_860_HAGOT;
867 break;
868 case BFD_RELOC_860_HAGOTOFF:
869 rtype = R_860_HAGOTOFF;
870 break;
871 case BFD_RELOC_860_HAPC:
872 rtype = R_860_HAPC;
873 break;
874 case BFD_RELOC_860_HIGH:
875 rtype = R_860_HIGH;
876 break;
877 case BFD_RELOC_860_HIGOT:
878 rtype = R_860_HIGOT;
879 break;
880 case BFD_RELOC_860_HIGOTOFF:
881 rtype = R_860_HIGOTOFF;
882 break;
883 default:
884 rtype = 0;
885 break;
886 }
887 return lookup_howto (rtype);
888 }
889
890 /* Given a ELF reloc, return the matching HOWTO structure. */
891 static void
892 elf32_i860_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
893 arelent *bfd_reloc,
894 Elf_Internal_Rela *elf_reloc)
895 {
896 bfd_reloc->howto
897 = lookup_howto ((unsigned) ELF32_R_TYPE (elf_reloc->r_info));
898 }
899 \f
900 /* Specialized relocation handler for R_860_SPLITn. These relocations
901 involves a 16-bit field that is split into two contiguous parts. */
902 static bfd_reloc_status_type
903 elf32_i860_relocate_splitn (bfd *input_bfd,
904 Elf_Internal_Rela *rello,
905 bfd_byte *contents,
906 bfd_vma value)
907 {
908 bfd_vma insn;
909 reloc_howto_type *howto;
910 howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info));
911 insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
912
913 /* Relocate. */
914 value += rello->r_addend;
915
916 /* Separate the fields and insert. */
917 value = (((value & 0xf800) << 5) | (value & 0x7ff)) & howto->dst_mask;
918 insn = (insn & ~howto->dst_mask) | value;
919
920 bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
921 return bfd_reloc_ok;
922 }
923
924 /* Specialized relocation handler for R_860_PC16. This relocation
925 involves a 16-bit, PC-relative field that is split into two contiguous
926 parts. */
927 static bfd_reloc_status_type
928 elf32_i860_relocate_pc16 (bfd *input_bfd,
929 asection *input_section,
930 Elf_Internal_Rela *rello,
931 bfd_byte *contents,
932 bfd_vma value)
933 {
934 bfd_vma insn;
935 reloc_howto_type *howto;
936 howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info));
937 insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
938
939 /* Adjust for PC-relative relocation. */
940 value -= (input_section->output_section->vma
941 + input_section->output_offset);
942 value -= rello->r_offset;
943
944 /* Relocate. */
945 value += rello->r_addend;
946
947 /* Adjust the value by 4, then separate the fields and insert. */
948 value = (value - 4) >> howto->rightshift;
949 value = (((value & 0xf800) << 5) | (value & 0x7ff)) & howto->dst_mask;
950 insn = (insn & ~howto->dst_mask) | value;
951
952 bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
953 return bfd_reloc_ok;
954
955 }
956
957 /* Specialized relocation handler for R_860_PC26. This relocation
958 involves a 26-bit, PC-relative field which must be adjusted by 4. */
959 static bfd_reloc_status_type
960 elf32_i860_relocate_pc26 (bfd *input_bfd,
961 asection *input_section,
962 Elf_Internal_Rela *rello,
963 bfd_byte *contents,
964 bfd_vma value)
965 {
966 bfd_vma insn;
967 reloc_howto_type *howto;
968 howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info));
969 insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
970
971 /* Adjust for PC-relative relocation. */
972 value -= (input_section->output_section->vma
973 + input_section->output_offset);
974 value -= rello->r_offset;
975
976 /* Relocate. */
977 value += rello->r_addend;
978
979 /* Adjust value by 4 and insert the field. */
980 value = ((value - 4) >> howto->rightshift) & howto->dst_mask;
981 insn = (insn & ~howto->dst_mask) | value;
982
983 bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
984 return bfd_reloc_ok;
985
986 }
987
988 /* Specialized relocation handler for R_860_HIGHADJ. */
989 static bfd_reloc_status_type
990 elf32_i860_relocate_highadj (bfd *input_bfd,
991 Elf_Internal_Rela *rel,
992 bfd_byte *contents,
993 bfd_vma value)
994 {
995 bfd_vma insn;
996
997 insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
998
999 value += rel->r_addend;
1000 value += 0x8000;
1001 value = ((value >> 16) & 0xffff);
1002
1003 insn = (insn & 0xffff0000) | value;
1004
1005 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
1006 return bfd_reloc_ok;
1007 }
1008
1009 /* Perform a single relocation. By default we use the standard BFD
1010 routines. However, we handle some specially. */
1011 static bfd_reloc_status_type
1012 i860_final_link_relocate (reloc_howto_type *howto,
1013 bfd *input_bfd,
1014 asection *input_section,
1015 bfd_byte *contents,
1016 Elf_Internal_Rela *rel,
1017 bfd_vma relocation)
1018 {
1019 return _bfd_final_link_relocate (howto, input_bfd, input_section,
1020 contents, rel->r_offset, relocation,
1021 rel->r_addend);
1022 }
1023
1024 /* Relocate an i860 ELF section.
1025
1026 This is boiler-plate code copied from fr30.
1027
1028 The RELOCATE_SECTION function is called by the new ELF backend linker
1029 to handle the relocations for a section.
1030
1031 The relocs are always passed as Rela structures; if the section
1032 actually uses Rel structures, the r_addend field will always be
1033 zero.
1034
1035 This function is responsible for adjusting the section contents as
1036 necessary, and (if using Rela relocs and generating a relocatable
1037 output file) adjusting the reloc addend as necessary.
1038
1039 This function does not have to worry about setting the reloc
1040 address or the reloc symbol index.
1041
1042 LOCAL_SYMS is a pointer to the swapped in local symbols.
1043
1044 LOCAL_SECTIONS is an array giving the section in the input file
1045 corresponding to the st_shndx field of each local symbol.
1046
1047 The global hash table entry for the global symbols can be found
1048 via elf_sym_hashes (input_bfd).
1049
1050 When generating relocatable output, this function must handle
1051 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
1052 going to be the section symbol corresponding to the output
1053 section, which means that the addend must be adjusted
1054 accordingly. */
1055 static bfd_boolean
1056 elf32_i860_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
1057 struct bfd_link_info *info,
1058 bfd *input_bfd,
1059 asection *input_section,
1060 bfd_byte *contents,
1061 Elf_Internal_Rela *relocs,
1062 Elf_Internal_Sym *local_syms,
1063 asection **local_sections)
1064 {
1065 Elf_Internal_Shdr *symtab_hdr;
1066 struct elf_link_hash_entry **sym_hashes;
1067 Elf_Internal_Rela *rel;
1068 Elf_Internal_Rela *relend;
1069
1070 if (info->relocatable)
1071 return TRUE;
1072
1073 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
1074 sym_hashes = elf_sym_hashes (input_bfd);
1075 relend = relocs + input_section->reloc_count;
1076
1077 for (rel = relocs; rel < relend; rel ++)
1078 {
1079 reloc_howto_type * howto;
1080 unsigned long r_symndx;
1081 Elf_Internal_Sym * sym;
1082 asection * sec;
1083 struct elf_link_hash_entry * h;
1084 bfd_vma relocation;
1085 bfd_reloc_status_type r;
1086 const char * name = NULL;
1087 int r_type;
1088
1089 r_type = ELF32_R_TYPE (rel->r_info);
1090
1091 #if 0
1092 if ( r_type == R_860_GNU_VTINHERIT
1093 || r_type == R_860_GNU_VTENTRY)
1094 continue;
1095 #endif
1096
1097 r_symndx = ELF32_R_SYM (rel->r_info);
1098
1099 howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
1100 h = NULL;
1101 sym = NULL;
1102 sec = NULL;
1103
1104 if (r_symndx < symtab_hdr->sh_info)
1105 {
1106 sym = local_syms + r_symndx;
1107 sec = local_sections [r_symndx];
1108 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
1109
1110 name = bfd_elf_string_from_elf_section
1111 (input_bfd, symtab_hdr->sh_link, sym->st_name);
1112 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
1113 }
1114 else
1115 {
1116 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
1117
1118 while (h->root.type == bfd_link_hash_indirect
1119 || h->root.type == bfd_link_hash_warning)
1120 h = (struct elf_link_hash_entry *) h->root.u.i.link;
1121
1122 name = h->root.root.string;
1123
1124 if (h->root.type == bfd_link_hash_defined
1125 || h->root.type == bfd_link_hash_defweak)
1126 {
1127 sec = h->root.u.def.section;
1128 relocation = (h->root.u.def.value
1129 + sec->output_section->vma
1130 + sec->output_offset);
1131 }
1132 else if (h->root.type == bfd_link_hash_undefweak)
1133 {
1134 relocation = 0;
1135 }
1136 else
1137 {
1138 if (! ((*info->callbacks->undefined_symbol)
1139 (info, h->root.root.string, input_bfd,
1140 input_section, rel->r_offset, TRUE)))
1141 return FALSE;
1142 relocation = 0;
1143 }
1144 }
1145
1146 switch (r_type)
1147 {
1148 default:
1149 r = i860_final_link_relocate (howto, input_bfd, input_section,
1150 contents, rel, relocation);
1151 break;
1152
1153 case R_860_HIGHADJ:
1154 r = elf32_i860_relocate_highadj (input_bfd, rel, contents,
1155 relocation);
1156 break;
1157
1158 case R_860_PC16:
1159 r = elf32_i860_relocate_pc16 (input_bfd, input_section, rel,
1160 contents, relocation);
1161 break;
1162
1163 case R_860_PC26:
1164 r = elf32_i860_relocate_pc26 (input_bfd, input_section, rel,
1165 contents, relocation);
1166 break;
1167
1168 case R_860_SPLIT0:
1169 case R_860_SPLIT1:
1170 case R_860_SPLIT2:
1171 r = elf32_i860_relocate_splitn (input_bfd, rel, contents,
1172 relocation);
1173 break;
1174
1175 /* We do not yet handle GOT/PLT/Dynamic relocations. */
1176 case R_860_COPY:
1177 case R_860_GLOB_DAT:
1178 case R_860_JUMP_SLOT:
1179 case R_860_RELATIVE:
1180 case R_860_PLT26:
1181 case R_860_LOGOT0:
1182 case R_860_SPGOT0:
1183 case R_860_LOGOT1:
1184 case R_860_SPGOT1:
1185 case R_860_LOGOTOFF0:
1186 case R_860_SPGOTOFF0:
1187 case R_860_LOGOTOFF1:
1188 case R_860_SPGOTOFF1:
1189 case R_860_LOGOTOFF2:
1190 case R_860_LOGOTOFF3:
1191 case R_860_LOPC:
1192 case R_860_HAGOT:
1193 case R_860_HAGOTOFF:
1194 case R_860_HAPC:
1195 case R_860_HIGOT:
1196 case R_860_HIGOTOFF:
1197 r = bfd_reloc_notsupported;
1198 break;
1199 }
1200
1201 if (r != bfd_reloc_ok)
1202 {
1203 const char * msg = (const char *) NULL;
1204
1205 switch (r)
1206 {
1207 case bfd_reloc_overflow:
1208 r = info->callbacks->reloc_overflow
1209 (info, name, howto->name, (bfd_vma) 0,
1210 input_bfd, input_section, rel->r_offset);
1211 break;
1212
1213 case bfd_reloc_undefined:
1214 r = info->callbacks->undefined_symbol
1215 (info, name, input_bfd, input_section, rel->r_offset, TRUE);
1216 break;
1217
1218 case bfd_reloc_outofrange:
1219 msg = _("internal error: out of range error");
1220 break;
1221
1222 case bfd_reloc_notsupported:
1223 msg = _("internal error: unsupported relocation error");
1224 break;
1225
1226 case bfd_reloc_dangerous:
1227 msg = _("internal error: dangerous relocation");
1228 break;
1229
1230 default:
1231 msg = _("internal error: unknown error");
1232 break;
1233 }
1234
1235 if (msg)
1236 r = info->callbacks->warning
1237 (info, msg, name, input_bfd, input_section, rel->r_offset);
1238
1239 if (! r)
1240 return FALSE;
1241 }
1242 }
1243
1244 return TRUE;
1245 }
1246
1247 /* Return whether a symbol name implies a local label. SVR4/860 compilers
1248 generate labels of the form ".ep.function_name" to denote the end of a
1249 function prolog. These should be local.
1250 ??? Do any other SVR4 compilers have this convention? If so, this should
1251 be added to the generic routine. */
1252 static bfd_boolean
1253 elf32_i860_is_local_label_name (bfd *abfd, const char *name)
1254 {
1255 if (name[0] == '.' && name[1] == 'e' && name[2] == 'p' && name[3] == '.')
1256 return TRUE;
1257
1258 return _bfd_elf_is_local_label_name (abfd, name);
1259 }
1260 \f
1261 #define TARGET_BIG_SYM bfd_elf32_i860_vec
1262 #define TARGET_BIG_NAME "elf32-i860"
1263 #define TARGET_LITTLE_SYM bfd_elf32_i860_little_vec
1264 #define TARGET_LITTLE_NAME "elf32-i860-little"
1265 #define ELF_ARCH bfd_arch_i860
1266 #define ELF_MACHINE_CODE EM_860
1267 #define ELF_MAXPAGESIZE 4096
1268
1269 #define elf_backend_rela_normal 1
1270 #define elf_info_to_howto_rel NULL
1271 #define elf_info_to_howto elf32_i860_info_to_howto_rela
1272 #define elf_backend_relocate_section elf32_i860_relocate_section
1273 #define bfd_elf32_bfd_reloc_type_lookup elf32_i860_reloc_type_lookup
1274 #define bfd_elf32_bfd_is_local_label_name elf32_i860_is_local_label_name
1275
1276 #include "elf32-target.h"