1 /* MIPS-specific support for 64-bit ELF
2 Copyright 1996, 1997 Free Software Foundation, Inc.
3 Ian Lance Taylor, Cygnus Support
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
21 /* This file supports the 64-bit MIPS ELF ABI.
23 The MIPS 64-bit ELF ABI uses an unusual reloc format. This file
24 overrides the usual ELF reloc handling, and handles reading and
25 writing the relocations here.
27 The MIPS 64-bit ELF ABI also uses an unusual archive map format. */
38 /* Get the ECOFF swapping routines. The 64-bit ABI is not supposed to
39 use ECOFF. However, we support it anyhow for an easier changeover. */
41 #include "coff/symconst.h"
42 #include "coff/internal.h"
43 #include "coff/ecoff.h"
44 /* The 64 bit versions of the mdebug data structures are in alpha.h. */
45 #include "coff/alpha.h"
47 #include "ecoffswap.h"
49 static void mips_elf64_swap_reloc_in
50 PARAMS ((bfd *, const Elf64_Mips_External_Rel *,
51 Elf64_Mips_Internal_Rel *));
52 static void mips_elf64_swap_reloca_in
53 PARAMS ((bfd *, const Elf64_Mips_External_Rela *,
54 Elf64_Mips_Internal_Rela *));
56 static void mips_elf64_swap_reloc_out
57 PARAMS ((bfd *, const Elf64_Mips_Internal_Rel *,
58 Elf64_Mips_External_Rel *));
60 static void mips_elf64_swap_reloca_out
61 PARAMS ((bfd *, const Elf64_Mips_Internal_Rela *,
62 Elf64_Mips_External_Rela *));
63 static reloc_howto_type *mips_elf64_reloc_type_lookup
64 PARAMS ((bfd *, bfd_reloc_code_real_type));
65 static long mips_elf64_get_reloc_upper_bound PARAMS ((bfd *, asection *));
66 static boolean mips_elf64_slurp_one_reloc_table
67 PARAMS ((bfd *, asection *, asymbol **, const Elf_Internal_Shdr *));
68 static boolean mips_elf64_slurp_reloc_table
69 PARAMS ((bfd *, asection *, asymbol **, boolean));
70 static void mips_elf64_write_relocs PARAMS ((bfd *, asection *, PTR));
71 static boolean mips_elf64_section_from_shdr
72 PARAMS ((bfd *, Elf_Internal_Shdr *, char *));
73 static boolean mips_elf64_section_processing
74 PARAMS ((bfd *, Elf_Internal_Shdr *));
75 static boolean mips_elf64_slurp_armap PARAMS ((bfd *));
76 static boolean mips_elf64_write_armap
77 PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
79 /* The relocation types. */
81 enum mips_elf64_reloc_type
84 /* These are now in elf/mips.h. */
107 R_MIPS_GOT_DISP = 19,
108 R_MIPS_GOT_PAGE = 20,
109 R_MIPS_GOT_OFST = 21,
110 R_MIPS_GOT_HI16 = 22,
111 R_MIPS_GOT_LO16 = 23,
113 R_MIPS_INSERT_A = 25,
114 R_MIPS_INSERT_B = 26,
118 R_MIPS_CALL_HI16 = 30,
119 R_MIPS_CALL_LO16 = 31,
120 R_MIPS_SCN_DISP = 32,
122 R_MIPS_ADD_IMMEDIATE = 34,
127 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
128 from smaller values. Start with zero, widen, *then* decrement. */
129 #define MINUS_ONE (((bfd_vma)0) - 1)
131 /* The relocation table used for SHT_REL sections. */
133 static reloc_howto_type mips_elf64_howto_table_rel[] =
136 HOWTO (R_MIPS_NONE, /* type */
138 0, /* size (0 = byte, 1 = short, 2 = long) */
140 false, /* pc_relative */
142 complain_overflow_dont, /* complain_on_overflow */
143 bfd_elf_generic_reloc, /* special_function */
144 "R_MIPS_NONE", /* name */
145 false, /* partial_inplace */
148 false), /* pcrel_offset */
150 /* 16 bit relocation. */
151 HOWTO (R_MIPS_16, /* type */
153 1, /* size (0 = byte, 1 = short, 2 = long) */
155 false, /* pc_relative */
157 complain_overflow_bitfield, /* complain_on_overflow */
158 bfd_elf_generic_reloc, /* special_function */
159 "R_MIPS_16", /* name */
160 true, /* partial_inplace */
161 0xffff, /* src_mask */
162 0xffff, /* dst_mask */
163 false), /* pcrel_offset */
165 /* 32 bit relocation. */
166 HOWTO (R_MIPS_32, /* type */
168 2, /* size (0 = byte, 1 = short, 2 = long) */
170 false, /* pc_relative */
172 complain_overflow_bitfield, /* complain_on_overflow */
173 bfd_elf_generic_reloc, /* special_function */
174 "R_MIPS_32", /* name */
175 true, /* partial_inplace */
176 0xffffffff, /* src_mask */
177 0xffffffff, /* dst_mask */
178 false), /* pcrel_offset */
180 /* 32 bit symbol relative relocation. */
181 HOWTO (R_MIPS_REL32, /* type */
183 2, /* size (0 = byte, 1 = short, 2 = long) */
185 false, /* pc_relative */
187 complain_overflow_bitfield, /* complain_on_overflow */
188 bfd_elf_generic_reloc, /* special_function */
189 "R_MIPS_REL32", /* name */
190 true, /* partial_inplace */
191 0xffffffff, /* src_mask */
192 0xffffffff, /* dst_mask */
193 false), /* pcrel_offset */
195 /* 26 bit branch address. */
196 HOWTO (R_MIPS_26, /* type */
198 2, /* size (0 = byte, 1 = short, 2 = long) */
200 false, /* pc_relative */
202 complain_overflow_dont, /* complain_on_overflow */
203 /* This needs complex overflow
204 detection, because the upper four
205 bits must match the PC. */
206 bfd_elf_generic_reloc, /* special_function */
207 "R_MIPS_26", /* name */
208 true, /* partial_inplace */
209 0x3ffffff, /* src_mask */
210 0x3ffffff, /* dst_mask */
211 false), /* pcrel_offset */
213 /* High 16 bits of symbol value. */
214 HOWTO (R_MIPS_HI16, /* type */
216 2, /* size (0 = byte, 1 = short, 2 = long) */
218 false, /* pc_relative */
220 complain_overflow_dont, /* complain_on_overflow */
221 _bfd_mips_elf_hi16_reloc, /* special_function */
222 "R_MIPS_HI16", /* name */
223 true, /* partial_inplace */
224 0xffff, /* src_mask */
225 0xffff, /* dst_mask */
226 false), /* pcrel_offset */
228 /* Low 16 bits of symbol value. */
229 HOWTO (R_MIPS_LO16, /* type */
231 2, /* size (0 = byte, 1 = short, 2 = long) */
233 false, /* pc_relative */
235 complain_overflow_dont, /* complain_on_overflow */
236 _bfd_mips_elf_lo16_reloc, /* special_function */
237 "R_MIPS_LO16", /* name */
238 true, /* partial_inplace */
239 0xffff, /* src_mask */
240 0xffff, /* dst_mask */
241 false), /* pcrel_offset */
243 /* GP relative reference. */
244 HOWTO (R_MIPS_GPREL16, /* type */
246 2, /* size (0 = byte, 1 = short, 2 = long) */
248 false, /* pc_relative */
250 complain_overflow_signed, /* complain_on_overflow */
251 _bfd_mips_elf_gprel16_reloc, /* special_function */
252 "R_MIPS_GPREL16", /* name */
253 true, /* partial_inplace */
254 0xffff, /* src_mask */
255 0xffff, /* dst_mask */
256 false), /* pcrel_offset */
258 /* Reference to literal section. */
259 HOWTO (R_MIPS_LITERAL, /* type */
261 2, /* size (0 = byte, 1 = short, 2 = long) */
263 false, /* pc_relative */
265 complain_overflow_signed, /* complain_on_overflow */
266 _bfd_mips_elf_gprel16_reloc, /* special_function */
267 "R_MIPS_LITERAL", /* name */
268 true, /* partial_inplace */
269 0xffff, /* src_mask */
270 0xffff, /* dst_mask */
271 false), /* pcrel_offset */
273 /* Reference to global offset table. */
274 HOWTO (R_MIPS_GOT16, /* type */
276 2, /* size (0 = byte, 1 = short, 2 = long) */
278 false, /* pc_relative */
280 complain_overflow_signed, /* complain_on_overflow */
281 _bfd_mips_elf_got16_reloc, /* special_function */
282 "R_MIPS_GOT16", /* name */
283 false, /* partial_inplace */
285 0xffff, /* dst_mask */
286 false), /* pcrel_offset */
288 /* 16 bit PC relative reference. */
289 HOWTO (R_MIPS_PC16, /* type */
291 2, /* size (0 = byte, 1 = short, 2 = long) */
293 true, /* pc_relative */
295 complain_overflow_signed, /* complain_on_overflow */
296 bfd_elf_generic_reloc, /* special_function */
297 "R_MIPS_PC16", /* name */
298 true, /* partial_inplace */
299 0xffff, /* src_mask */
300 0xffff, /* dst_mask */
301 false), /* pcrel_offset */
303 /* 16 bit call through global offset table. */
304 /* FIXME: This is not handled correctly. */
305 HOWTO (R_MIPS_CALL16, /* type */
307 2, /* size (0 = byte, 1 = short, 2 = long) */
309 false, /* pc_relative */
311 complain_overflow_signed, /* complain_on_overflow */
312 bfd_elf_generic_reloc, /* special_function */
313 "R_MIPS_CALL16", /* name */
314 false, /* partial_inplace */
316 0xffff, /* dst_mask */
317 false), /* pcrel_offset */
319 /* 32 bit GP relative reference. */
320 HOWTO (R_MIPS_GPREL32, /* type */
322 2, /* size (0 = byte, 1 = short, 2 = long) */
324 false, /* pc_relative */
326 complain_overflow_bitfield, /* complain_on_overflow */
327 _bfd_mips_elf_gprel32_reloc, /* special_function */
328 "R_MIPS_GPREL32", /* name */
329 true, /* partial_inplace */
330 0xffffffff, /* src_mask */
331 0xffffffff, /* dst_mask */
332 false), /* pcrel_offset */
338 /* A 5 bit shift field. */
339 HOWTO (R_MIPS_SHIFT5, /* type */
341 2, /* size (0 = byte, 1 = short, 2 = long) */
343 false, /* pc_relative */
345 complain_overflow_bitfield, /* complain_on_overflow */
346 bfd_elf_generic_reloc, /* special_function */
347 "R_MIPS_SHIFT5", /* name */
348 true, /* partial_inplace */
349 0x000007c0, /* src_mask */
350 0x000007c0, /* dst_mask */
351 false), /* pcrel_offset */
353 /* A 6 bit shift field. */
354 /* FIXME: This is not handled correctly; a special function is
355 needed to put the most significant bit in the right place. */
356 HOWTO (R_MIPS_SHIFT6, /* type */
358 2, /* size (0 = byte, 1 = short, 2 = long) */
360 false, /* pc_relative */
362 complain_overflow_bitfield, /* complain_on_overflow */
363 bfd_elf_generic_reloc, /* special_function */
364 "R_MIPS_SHIFT6", /* name */
365 true, /* partial_inplace */
366 0x000007c4, /* src_mask */
367 0x000007c4, /* dst_mask */
368 false), /* pcrel_offset */
370 /* 64 bit relocation. */
371 HOWTO (R_MIPS_64, /* type */
373 4, /* size (0 = byte, 1 = short, 2 = long) */
375 false, /* pc_relative */
377 complain_overflow_bitfield, /* complain_on_overflow */
378 bfd_elf_generic_reloc, /* special_function */
379 "R_MIPS_64", /* name */
380 true, /* partial_inplace */
381 MINUS_ONE, /* src_mask */
382 MINUS_ONE, /* dst_mask */
383 false), /* pcrel_offset */
385 /* Displacement in the global offset table. */
386 /* FIXME: Not handled correctly. */
387 HOWTO (R_MIPS_GOT_DISP, /* type */
389 2, /* size (0 = byte, 1 = short, 2 = long) */
391 false, /* pc_relative */
393 complain_overflow_bitfield, /* complain_on_overflow */
394 bfd_elf_generic_reloc, /* special_function */
395 "R_MIPS_GOT_DISP", /* name */
396 true, /* partial_inplace */
397 0x0000ffff, /* src_mask */
398 0x0000ffff, /* dst_mask */
399 false), /* pcrel_offset */
401 /* Displacement to page pointer in the global offset table. */
402 /* FIXME: Not handled correctly. */
403 HOWTO (R_MIPS_GOT_PAGE, /* type */
405 2, /* size (0 = byte, 1 = short, 2 = long) */
407 false, /* pc_relative */
409 complain_overflow_bitfield, /* complain_on_overflow */
410 bfd_elf_generic_reloc, /* special_function */
411 "R_MIPS_GOT_PAGE", /* name */
412 true, /* partial_inplace */
413 0x0000ffff, /* src_mask */
414 0x0000ffff, /* dst_mask */
415 false), /* pcrel_offset */
417 /* Offset from page pointer in the global offset table. */
418 /* FIXME: Not handled correctly. */
419 HOWTO (R_MIPS_GOT_OFST, /* type */
421 2, /* size (0 = byte, 1 = short, 2 = long) */
423 false, /* pc_relative */
425 complain_overflow_bitfield, /* complain_on_overflow */
426 bfd_elf_generic_reloc, /* special_function */
427 "R_MIPS_GOT_OFST", /* name */
428 true, /* partial_inplace */
429 0x0000ffff, /* src_mask */
430 0x0000ffff, /* dst_mask */
431 false), /* pcrel_offset */
433 /* High 16 bits of displacement in global offset table. */
434 /* FIXME: Not handled correctly. */
435 HOWTO (R_MIPS_GOT_HI16, /* type */
437 2, /* size (0 = byte, 1 = short, 2 = long) */
439 false, /* pc_relative */
441 complain_overflow_dont, /* complain_on_overflow */
442 bfd_elf_generic_reloc, /* special_function */
443 "R_MIPS_GOT_HI16", /* name */
444 true, /* partial_inplace */
445 0x0000ffff, /* src_mask */
446 0x0000ffff, /* dst_mask */
447 false), /* pcrel_offset */
449 /* Low 16 bits of displacement in global offset table. */
450 /* FIXME: Not handled correctly. */
451 HOWTO (R_MIPS_GOT_LO16, /* type */
453 2, /* size (0 = byte, 1 = short, 2 = long) */
455 false, /* pc_relative */
457 complain_overflow_dont, /* complain_on_overflow */
458 bfd_elf_generic_reloc, /* special_function */
459 "R_MIPS_GOT_LO16", /* name */
460 true, /* partial_inplace */
461 0x0000ffff, /* src_mask */
462 0x0000ffff, /* dst_mask */
463 false), /* pcrel_offset */
465 /* 64 bit substraction. */
466 /* FIXME: Not handled correctly. */
467 HOWTO (R_MIPS_SUB, /* type */
469 4, /* size (0 = byte, 1 = short, 2 = long) */
471 false, /* pc_relative */
473 complain_overflow_bitfield, /* complain_on_overflow */
474 bfd_elf_generic_reloc, /* special_function */
475 "R_MIPS_SUB", /* name */
476 true, /* partial_inplace */
477 MINUS_ONE, /* src_mask */
478 MINUS_ONE, /* dst_mask */
479 false), /* pcrel_offset */
481 /* Insert the addend as an instruction. */
482 /* FIXME: Not handled correctly. */
483 HOWTO (R_MIPS_INSERT_A, /* type */
485 0, /* size (0 = byte, 1 = short, 2 = long) */
487 false, /* pc_relative */
489 complain_overflow_dont, /* complain_on_overflow */
490 bfd_elf_generic_reloc, /* special_function */
491 "R_MIPS_INSERT_A", /* name */
492 false, /* partial_inplace */
495 false), /* pcrel_offset */
497 /* Insert the addend as an instruction, and change all relocations
498 to refer to the old instruction at the address. */
499 /* FIXME: Not handled correctly. */
500 HOWTO (R_MIPS_INSERT_B, /* type */
502 0, /* size (0 = byte, 1 = short, 2 = long) */
504 false, /* pc_relative */
506 complain_overflow_dont, /* complain_on_overflow */
507 bfd_elf_generic_reloc, /* special_function */
508 "R_MIPS_INSERT_B", /* name */
509 false, /* partial_inplace */
512 false), /* pcrel_offset */
514 /* Delete a 32 bit instruction. */
515 /* FIXME: Not handled correctly. */
516 HOWTO (R_MIPS_DELETE, /* type */
518 0, /* size (0 = byte, 1 = short, 2 = long) */
520 false, /* pc_relative */
522 complain_overflow_dont, /* complain_on_overflow */
523 bfd_elf_generic_reloc, /* special_function */
524 "R_MIPS_DELETE", /* name */
525 false, /* partial_inplace */
528 false), /* pcrel_offset */
530 /* Get the higher value of a 64 bit addend. */
531 /* FIXME: Not handled correctly. */
532 HOWTO (R_MIPS_HIGHER, /* type */
534 2, /* size (0 = byte, 1 = short, 2 = long) */
536 false, /* pc_relative */
538 complain_overflow_dont, /* complain_on_overflow */
539 bfd_elf_generic_reloc, /* special_function */
540 "R_MIPS_HIGHER", /* name */
541 true, /* partial_inplace */
542 0xffff, /* src_mask */
543 0xffff, /* dst_mask */
544 false), /* pcrel_offset */
546 /* Get the highest value of a 64 bit addend. */
547 /* FIXME: Not handled correctly. */
548 HOWTO (R_MIPS_HIGHEST, /* type */
550 2, /* size (0 = byte, 1 = short, 2 = long) */
552 false, /* pc_relative */
554 complain_overflow_dont, /* complain_on_overflow */
555 bfd_elf_generic_reloc, /* special_function */
556 "R_MIPS_HIGHEST", /* name */
557 true, /* partial_inplace */
558 0xffff, /* src_mask */
559 0xffff, /* dst_mask */
560 false), /* pcrel_offset */
562 /* High 16 bits of displacement in global offset table. */
563 /* FIXME: Not handled correctly. */
564 HOWTO (R_MIPS_CALL_HI16, /* type */
566 2, /* size (0 = byte, 1 = short, 2 = long) */
568 false, /* pc_relative */
570 complain_overflow_dont, /* complain_on_overflow */
571 bfd_elf_generic_reloc, /* special_function */
572 "R_MIPS_CALL_HI16", /* name */
573 true, /* partial_inplace */
574 0x0000ffff, /* src_mask */
575 0x0000ffff, /* dst_mask */
576 false), /* pcrel_offset */
578 /* Low 16 bits of displacement in global offset table. */
579 /* FIXME: Not handled correctly. */
580 HOWTO (R_MIPS_CALL_LO16, /* type */
582 2, /* size (0 = byte, 1 = short, 2 = long) */
584 false, /* pc_relative */
586 complain_overflow_dont, /* complain_on_overflow */
587 bfd_elf_generic_reloc, /* special_function */
588 "R_MIPS_CALL_LO16", /* name */
589 true, /* partial_inplace */
590 0x0000ffff, /* src_mask */
591 0x0000ffff, /* dst_mask */
592 false), /* pcrel_offset */
594 /* I'm not sure what the remaining relocs are, but they are defined
597 HOWTO (R_MIPS_SCN_DISP, /* type */
599 0, /* size (0 = byte, 1 = short, 2 = long) */
601 false, /* pc_relative */
603 complain_overflow_dont, /* complain_on_overflow */
604 bfd_elf_generic_reloc, /* special_function */
605 "R_MIPS_SCN_DISP", /* name */
606 false, /* partial_inplace */
609 false), /* pcrel_offset */
611 HOWTO (R_MIPS_REL16, /* type */
613 0, /* size (0 = byte, 1 = short, 2 = long) */
615 false, /* pc_relative */
617 complain_overflow_dont, /* complain_on_overflow */
618 bfd_elf_generic_reloc, /* special_function */
619 "R_MIPS_REL16", /* name */
620 false, /* partial_inplace */
623 false), /* pcrel_offset */
625 HOWTO (R_MIPS_ADD_IMMEDIATE, /* type */
627 0, /* size (0 = byte, 1 = short, 2 = long) */
629 false, /* pc_relative */
631 complain_overflow_dont, /* complain_on_overflow */
632 bfd_elf_generic_reloc, /* special_function */
633 "R_MIPS_ADD_IMMEDIATE", /* name */
634 false, /* partial_inplace */
637 false), /* pcrel_offset */
639 HOWTO (R_MIPS_PJUMP, /* type */
641 0, /* size (0 = byte, 1 = short, 2 = long) */
643 false, /* pc_relative */
645 complain_overflow_dont, /* complain_on_overflow */
646 bfd_elf_generic_reloc, /* special_function */
647 "R_MIPS_PJUMP", /* name */
648 false, /* partial_inplace */
651 false), /* pcrel_offset */
653 HOWTO (R_MIPS_RELGOT, /* type */
655 0, /* size (0 = byte, 1 = short, 2 = long) */
657 false, /* pc_relative */
659 complain_overflow_dont, /* complain_on_overflow */
660 bfd_elf_generic_reloc, /* special_function */
661 "R_MIPS_RELGOT", /* name */
662 false, /* partial_inplace */
665 false) /* pcrel_offset */
668 /* The relocation table used for SHT_RELA sections. */
670 static reloc_howto_type mips_elf64_howto_table_rela[] =
673 HOWTO (R_MIPS_NONE, /* type */
675 0, /* size (0 = byte, 1 = short, 2 = long) */
677 false, /* pc_relative */
679 complain_overflow_dont, /* complain_on_overflow */
680 bfd_elf_generic_reloc, /* special_function */
681 "R_MIPS_NONE", /* name */
682 false, /* partial_inplace */
685 false), /* pcrel_offset */
687 /* 16 bit relocation. */
688 HOWTO (R_MIPS_16, /* type */
690 1, /* size (0 = byte, 1 = short, 2 = long) */
692 false, /* pc_relative */
694 complain_overflow_bitfield, /* complain_on_overflow */
695 bfd_elf_generic_reloc, /* special_function */
696 "R_MIPS_16", /* name */
697 true, /* partial_inplace */
699 0xffff, /* dst_mask */
700 false), /* pcrel_offset */
702 /* 32 bit relocation. */
703 HOWTO (R_MIPS_32, /* type */
705 2, /* size (0 = byte, 1 = short, 2 = long) */
707 false, /* pc_relative */
709 complain_overflow_bitfield, /* complain_on_overflow */
710 bfd_elf_generic_reloc, /* special_function */
711 "R_MIPS_32", /* name */
712 true, /* partial_inplace */
714 0xffffffff, /* dst_mask */
715 false), /* pcrel_offset */
717 /* 32 bit symbol relative relocation. */
718 HOWTO (R_MIPS_REL32, /* type */
720 2, /* size (0 = byte, 1 = short, 2 = long) */
722 false, /* pc_relative */
724 complain_overflow_bitfield, /* complain_on_overflow */
725 bfd_elf_generic_reloc, /* special_function */
726 "R_MIPS_REL32", /* name */
727 true, /* partial_inplace */
729 0xffffffff, /* dst_mask */
730 false), /* pcrel_offset */
732 /* 26 bit branch address. */
733 HOWTO (R_MIPS_26, /* type */
735 2, /* size (0 = byte, 1 = short, 2 = long) */
737 false, /* pc_relative */
739 complain_overflow_dont, /* complain_on_overflow */
740 /* This needs complex overflow
741 detection, because the upper four
742 bits must match the PC. */
743 bfd_elf_generic_reloc, /* special_function */
744 "R_MIPS_26", /* name */
745 true, /* partial_inplace */
747 0x3ffffff, /* dst_mask */
748 false), /* pcrel_offset */
750 /* High 16 bits of symbol value. */
751 HOWTO (R_MIPS_HI16, /* type */
753 2, /* size (0 = byte, 1 = short, 2 = long) */
755 false, /* pc_relative */
757 complain_overflow_dont, /* complain_on_overflow */
758 bfd_elf_generic_reloc, /* special_function */
759 "R_MIPS_HI16", /* name */
760 true, /* partial_inplace */
762 0xffff, /* dst_mask */
763 false), /* pcrel_offset */
765 /* Low 16 bits of symbol value. */
766 HOWTO (R_MIPS_LO16, /* type */
768 2, /* size (0 = byte, 1 = short, 2 = long) */
770 false, /* pc_relative */
772 complain_overflow_dont, /* complain_on_overflow */
773 bfd_elf_generic_reloc, /* special_function */
774 "R_MIPS_LO16", /* name */
775 true, /* partial_inplace */
777 0xffff, /* dst_mask */
778 false), /* pcrel_offset */
780 /* GP relative reference. */
781 HOWTO (R_MIPS_GPREL16, /* type */
783 2, /* size (0 = byte, 1 = short, 2 = long) */
785 false, /* pc_relative */
787 complain_overflow_signed, /* complain_on_overflow */
788 _bfd_mips_elf_gprel16_reloc, /* special_function */
789 "R_MIPS_GPREL16", /* name */
790 true, /* partial_inplace */
792 0xffff, /* dst_mask */
793 false), /* pcrel_offset */
795 /* Reference to literal section. */
796 HOWTO (R_MIPS_LITERAL, /* type */
798 2, /* size (0 = byte, 1 = short, 2 = long) */
800 false, /* pc_relative */
802 complain_overflow_signed, /* complain_on_overflow */
803 _bfd_mips_elf_gprel16_reloc, /* special_function */
804 "R_MIPS_LITERAL", /* name */
805 true, /* partial_inplace */
807 0xffff, /* dst_mask */
808 false), /* pcrel_offset */
810 /* Reference to global offset table. */
811 /* FIXME: This is not handled correctly. */
812 HOWTO (R_MIPS_GOT16, /* type */
814 2, /* size (0 = byte, 1 = short, 2 = long) */
816 false, /* pc_relative */
818 complain_overflow_signed, /* complain_on_overflow */
819 bfd_elf_generic_reloc, /* special_function */
820 "R_MIPS_GOT16", /* name */
821 false, /* partial_inplace */
823 0xffff, /* dst_mask */
824 false), /* pcrel_offset */
826 /* 16 bit PC relative reference. */
827 HOWTO (R_MIPS_PC16, /* type */
829 2, /* size (0 = byte, 1 = short, 2 = long) */
831 true, /* pc_relative */
833 complain_overflow_signed, /* complain_on_overflow */
834 bfd_elf_generic_reloc, /* special_function */
835 "R_MIPS_PC16", /* name */
836 true, /* partial_inplace */
838 0xffff, /* dst_mask */
839 false), /* pcrel_offset */
841 /* 16 bit call through global offset table. */
842 /* FIXME: This is not handled correctly. */
843 HOWTO (R_MIPS_CALL16, /* type */
845 2, /* size (0 = byte, 1 = short, 2 = long) */
847 false, /* pc_relative */
849 complain_overflow_signed, /* complain_on_overflow */
850 bfd_elf_generic_reloc, /* special_function */
851 "R_MIPS_CALL16", /* name */
852 false, /* partial_inplace */
854 0xffff, /* dst_mask */
855 false), /* pcrel_offset */
857 /* 32 bit GP relative reference. */
858 HOWTO (R_MIPS_GPREL32, /* type */
860 2, /* size (0 = byte, 1 = short, 2 = long) */
862 false, /* pc_relative */
864 complain_overflow_bitfield, /* complain_on_overflow */
865 _bfd_mips_elf_gprel32_reloc, /* special_function */
866 "R_MIPS_GPREL32", /* name */
867 true, /* partial_inplace */
869 0xffffffff, /* dst_mask */
870 false), /* pcrel_offset */
876 /* A 5 bit shift field. */
877 HOWTO (R_MIPS_SHIFT5, /* type */
879 2, /* size (0 = byte, 1 = short, 2 = long) */
881 false, /* pc_relative */
883 complain_overflow_bitfield, /* complain_on_overflow */
884 bfd_elf_generic_reloc, /* special_function */
885 "R_MIPS_SHIFT5", /* name */
886 true, /* partial_inplace */
888 0x000007c0, /* dst_mask */
889 false), /* pcrel_offset */
891 /* A 6 bit shift field. */
892 /* FIXME: This is not handled correctly; a special function is
893 needed to put the most significant bit in the right place. */
894 HOWTO (R_MIPS_SHIFT6, /* type */
896 2, /* size (0 = byte, 1 = short, 2 = long) */
898 false, /* pc_relative */
900 complain_overflow_bitfield, /* complain_on_overflow */
901 bfd_elf_generic_reloc, /* special_function */
902 "R_MIPS_SHIFT6", /* name */
903 true, /* partial_inplace */
905 0x000007c4, /* dst_mask */
906 false), /* pcrel_offset */
908 /* 64 bit relocation. */
909 HOWTO (R_MIPS_64, /* type */
911 4, /* size (0 = byte, 1 = short, 2 = long) */
913 false, /* pc_relative */
915 complain_overflow_bitfield, /* complain_on_overflow */
916 bfd_elf_generic_reloc, /* special_function */
917 "R_MIPS_64", /* name */
918 true, /* partial_inplace */
920 MINUS_ONE, /* dst_mask */
921 false), /* pcrel_offset */
923 /* Displacement in the global offset table. */
924 /* FIXME: Not handled correctly. */
925 HOWTO (R_MIPS_GOT_DISP, /* type */
927 2, /* size (0 = byte, 1 = short, 2 = long) */
929 false, /* pc_relative */
931 complain_overflow_bitfield, /* complain_on_overflow */
932 bfd_elf_generic_reloc, /* special_function */
933 "R_MIPS_GOT_DISP", /* name */
934 true, /* partial_inplace */
936 0x0000ffff, /* dst_mask */
937 false), /* pcrel_offset */
939 /* Displacement to page pointer in the global offset table. */
940 /* FIXME: Not handled correctly. */
941 HOWTO (R_MIPS_GOT_PAGE, /* type */
943 2, /* size (0 = byte, 1 = short, 2 = long) */
945 false, /* pc_relative */
947 complain_overflow_bitfield, /* complain_on_overflow */
948 bfd_elf_generic_reloc, /* special_function */
949 "R_MIPS_GOT_PAGE", /* name */
950 true, /* partial_inplace */
952 0x0000ffff, /* dst_mask */
953 false), /* pcrel_offset */
955 /* Offset from page pointer in the global offset table. */
956 /* FIXME: Not handled correctly. */
957 HOWTO (R_MIPS_GOT_OFST, /* type */
959 2, /* size (0 = byte, 1 = short, 2 = long) */
961 false, /* pc_relative */
963 complain_overflow_bitfield, /* complain_on_overflow */
964 bfd_elf_generic_reloc, /* special_function */
965 "R_MIPS_GOT_OFST", /* name */
966 true, /* partial_inplace */
968 0x0000ffff, /* dst_mask */
969 false), /* pcrel_offset */
971 /* High 16 bits of displacement in global offset table. */
972 /* FIXME: Not handled correctly. */
973 HOWTO (R_MIPS_GOT_HI16, /* type */
975 2, /* size (0 = byte, 1 = short, 2 = long) */
977 false, /* pc_relative */
979 complain_overflow_dont, /* complain_on_overflow */
980 bfd_elf_generic_reloc, /* special_function */
981 "R_MIPS_GOT_HI16", /* name */
982 true, /* partial_inplace */
984 0x0000ffff, /* dst_mask */
985 false), /* pcrel_offset */
987 /* Low 16 bits of displacement in global offset table. */
988 /* FIXME: Not handled correctly. */
989 HOWTO (R_MIPS_GOT_LO16, /* type */
991 2, /* size (0 = byte, 1 = short, 2 = long) */
993 false, /* pc_relative */
995 complain_overflow_dont, /* complain_on_overflow */
996 bfd_elf_generic_reloc, /* special_function */
997 "R_MIPS_GOT_LO16", /* name */
998 true, /* partial_inplace */
1000 0x0000ffff, /* dst_mask */
1001 false), /* pcrel_offset */
1003 /* 64 bit substraction. */
1004 /* FIXME: Not handled correctly. */
1005 HOWTO (R_MIPS_SUB, /* type */
1007 4, /* size (0 = byte, 1 = short, 2 = long) */
1009 false, /* pc_relative */
1011 complain_overflow_bitfield, /* complain_on_overflow */
1012 bfd_elf_generic_reloc, /* special_function */
1013 "R_MIPS_SUB", /* name */
1014 true, /* partial_inplace */
1016 MINUS_ONE, /* dst_mask */
1017 false), /* pcrel_offset */
1019 /* Insert the addend as an instruction. */
1020 /* FIXME: Not handled correctly. */
1021 HOWTO (R_MIPS_INSERT_A, /* type */
1023 0, /* size (0 = byte, 1 = short, 2 = long) */
1025 false, /* pc_relative */
1027 complain_overflow_dont, /* complain_on_overflow */
1028 bfd_elf_generic_reloc, /* special_function */
1029 "R_MIPS_INSERT_A", /* name */
1030 false, /* partial_inplace */
1033 false), /* pcrel_offset */
1035 /* Insert the addend as an instruction, and change all relocations
1036 to refer to the old instruction at the address. */
1037 /* FIXME: Not handled correctly. */
1038 HOWTO (R_MIPS_INSERT_B, /* type */
1040 0, /* size (0 = byte, 1 = short, 2 = long) */
1042 false, /* pc_relative */
1044 complain_overflow_dont, /* complain_on_overflow */
1045 bfd_elf_generic_reloc, /* special_function */
1046 "R_MIPS_INSERT_B", /* name */
1047 false, /* partial_inplace */
1050 false), /* pcrel_offset */
1052 /* Delete a 32 bit instruction. */
1053 /* FIXME: Not handled correctly. */
1054 HOWTO (R_MIPS_DELETE, /* type */
1056 0, /* size (0 = byte, 1 = short, 2 = long) */
1058 false, /* pc_relative */
1060 complain_overflow_dont, /* complain_on_overflow */
1061 bfd_elf_generic_reloc, /* special_function */
1062 "R_MIPS_DELETE", /* name */
1063 false, /* partial_inplace */
1066 false), /* pcrel_offset */
1068 /* Get the higher value of a 64 bit addend. */
1069 /* FIXME: Not handled correctly. */
1070 HOWTO (R_MIPS_HIGHER, /* type */
1072 2, /* size (0 = byte, 1 = short, 2 = long) */
1074 false, /* pc_relative */
1076 complain_overflow_dont, /* complain_on_overflow */
1077 bfd_elf_generic_reloc, /* special_function */
1078 "R_MIPS_HIGHER", /* name */
1079 true, /* partial_inplace */
1081 0xffff, /* dst_mask */
1082 false), /* pcrel_offset */
1084 /* Get the highest value of a 64 bit addend. */
1085 /* FIXME: Not handled correctly. */
1086 HOWTO (R_MIPS_HIGHEST, /* type */
1088 2, /* size (0 = byte, 1 = short, 2 = long) */
1090 false, /* pc_relative */
1092 complain_overflow_dont, /* complain_on_overflow */
1093 bfd_elf_generic_reloc, /* special_function */
1094 "R_MIPS_HIGHEST", /* name */
1095 true, /* partial_inplace */
1097 0xffff, /* dst_mask */
1098 false), /* pcrel_offset */
1100 /* High 16 bits of displacement in global offset table. */
1101 /* FIXME: Not handled correctly. */
1102 HOWTO (R_MIPS_CALL_HI16, /* type */
1104 2, /* size (0 = byte, 1 = short, 2 = long) */
1106 false, /* pc_relative */
1108 complain_overflow_dont, /* complain_on_overflow */
1109 bfd_elf_generic_reloc, /* special_function */
1110 "R_MIPS_CALL_HI16", /* name */
1111 true, /* partial_inplace */
1113 0x0000ffff, /* dst_mask */
1114 false), /* pcrel_offset */
1116 /* Low 16 bits of displacement in global offset table. */
1117 /* FIXME: Not handled correctly. */
1118 HOWTO (R_MIPS_CALL_LO16, /* type */
1120 2, /* size (0 = byte, 1 = short, 2 = long) */
1122 false, /* pc_relative */
1124 complain_overflow_dont, /* complain_on_overflow */
1125 bfd_elf_generic_reloc, /* special_function */
1126 "R_MIPS_CALL_LO16", /* name */
1127 true, /* partial_inplace */
1129 0x0000ffff, /* dst_mask */
1130 false), /* pcrel_offset */
1132 /* I'm not sure what the remaining relocs are, but they are defined
1135 HOWTO (R_MIPS_SCN_DISP, /* type */
1137 0, /* size (0 = byte, 1 = short, 2 = long) */
1139 false, /* pc_relative */
1141 complain_overflow_dont, /* complain_on_overflow */
1142 bfd_elf_generic_reloc, /* special_function */
1143 "R_MIPS_SCN_DISP", /* name */
1144 false, /* partial_inplace */
1147 false), /* pcrel_offset */
1149 HOWTO (R_MIPS_REL16, /* type */
1151 0, /* size (0 = byte, 1 = short, 2 = long) */
1153 false, /* pc_relative */
1155 complain_overflow_dont, /* complain_on_overflow */
1156 bfd_elf_generic_reloc, /* special_function */
1157 "R_MIPS_REL16", /* name */
1158 false, /* partial_inplace */
1161 false), /* pcrel_offset */
1163 HOWTO (R_MIPS_ADD_IMMEDIATE, /* type */
1165 0, /* size (0 = byte, 1 = short, 2 = long) */
1167 false, /* pc_relative */
1169 complain_overflow_dont, /* complain_on_overflow */
1170 bfd_elf_generic_reloc, /* special_function */
1171 "R_MIPS_ADD_IMMEDIATE", /* name */
1172 false, /* partial_inplace */
1175 false), /* pcrel_offset */
1177 HOWTO (R_MIPS_PJUMP, /* type */
1179 0, /* size (0 = byte, 1 = short, 2 = long) */
1181 false, /* pc_relative */
1183 complain_overflow_dont, /* complain_on_overflow */
1184 bfd_elf_generic_reloc, /* special_function */
1185 "R_MIPS_PJUMP", /* name */
1186 false, /* partial_inplace */
1189 false), /* pcrel_offset */
1191 HOWTO (R_MIPS_RELGOT, /* type */
1193 0, /* size (0 = byte, 1 = short, 2 = long) */
1195 false, /* pc_relative */
1197 complain_overflow_dont, /* complain_on_overflow */
1198 bfd_elf_generic_reloc, /* special_function */
1199 "R_MIPS_RELGOT", /* name */
1200 false, /* partial_inplace */
1203 false) /* pcrel_offset */
1206 /* Swap in a MIPS 64-bit Rel reloc. */
1209 mips_elf64_swap_reloc_in (abfd, src, dst)
1211 const Elf64_Mips_External_Rel *src;
1212 Elf64_Mips_Internal_Rel *dst;
1214 dst->r_offset = bfd_h_get_64 (abfd, (bfd_byte *) src->r_offset);
1215 dst->r_sym = bfd_h_get_32 (abfd, (bfd_byte *) src->r_sym);
1216 dst->r_ssym = bfd_h_get_8 (abfd, (bfd_byte *) src->r_ssym);
1217 dst->r_type3 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type3);
1218 dst->r_type2 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type2);
1219 dst->r_type = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type);
1222 /* Swap in a MIPS 64-bit Rela reloc. */
1225 mips_elf64_swap_reloca_in (abfd, src, dst)
1227 const Elf64_Mips_External_Rela *src;
1228 Elf64_Mips_Internal_Rela *dst;
1230 dst->r_offset = bfd_h_get_64 (abfd, (bfd_byte *) src->r_offset);
1231 dst->r_sym = bfd_h_get_32 (abfd, (bfd_byte *) src->r_sym);
1232 dst->r_ssym = bfd_h_get_8 (abfd, (bfd_byte *) src->r_ssym);
1233 dst->r_type3 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type3);
1234 dst->r_type2 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type2);
1235 dst->r_type = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type);
1236 dst->r_addend = bfd_h_get_signed_64 (abfd, (bfd_byte *) src->r_addend);
1241 /* This is not currently used. */
1243 /* Swap out a MIPS 64-bit Rel reloc. */
1246 mips_elf64_swap_reloc_out (abfd, src, dst)
1248 const Elf64_Mips_Internal_Rel *src;
1249 Elf64_Mips_External_Rel *dst;
1251 bfd_h_put_64 (abfd, src->r_offset, (bfd_byte *) dst->r_offset);
1252 bfd_h_put_32 (abfd, src->r_sym, (bfd_byte *) dst->r_sym);
1253 bfd_h_put_8 (abfd, src->r_ssym, (bfd_byte *) dst->r_ssym);
1254 bfd_h_put_8 (abfd, src->r_type3, (bfd_byte *) dst->r_type3);
1255 bfd_h_put_8 (abfd, src->r_type2, (bfd_byte *) dst->r_type2);
1256 bfd_h_put_8 (abfd, src->r_type, (bfd_byte *) dst->r_type);
1261 /* Swap out a MIPS 64-bit Rela reloc. */
1264 mips_elf64_swap_reloca_out (abfd, src, dst)
1266 const Elf64_Mips_Internal_Rela *src;
1267 Elf64_Mips_External_Rela *dst;
1269 bfd_h_put_64 (abfd, src->r_offset, (bfd_byte *) dst->r_offset);
1270 bfd_h_put_32 (abfd, src->r_sym, (bfd_byte *) dst->r_sym);
1271 bfd_h_put_8 (abfd, src->r_ssym, (bfd_byte *) dst->r_ssym);
1272 bfd_h_put_8 (abfd, src->r_type3, (bfd_byte *) dst->r_type3);
1273 bfd_h_put_8 (abfd, src->r_type2, (bfd_byte *) dst->r_type2);
1274 bfd_h_put_8 (abfd, src->r_type, (bfd_byte *) dst->r_type);
1275 bfd_h_put_64 (abfd, src->r_addend, (bfd_byte *) dst->r_addend);
1278 /* A mapping from BFD reloc types to MIPS ELF reloc types. */
1280 struct elf_reloc_map
1282 bfd_reloc_code_real_type bfd_reloc_val;
1283 enum mips_elf64_reloc_type elf_reloc_val;
1286 static CONST struct elf_reloc_map mips_reloc_map[] =
1288 { BFD_RELOC_NONE, R_MIPS_NONE, },
1289 { BFD_RELOC_16, R_MIPS_16 },
1290 { BFD_RELOC_32, R_MIPS_32 },
1291 { BFD_RELOC_64, R_MIPS_64 },
1292 { BFD_RELOC_CTOR, R_MIPS_64 },
1293 { BFD_RELOC_32_PCREL, R_MIPS_REL32 },
1294 { BFD_RELOC_MIPS_JMP, R_MIPS_26 },
1295 { BFD_RELOC_HI16_S, R_MIPS_HI16 },
1296 { BFD_RELOC_LO16, R_MIPS_LO16 },
1297 { BFD_RELOC_MIPS_GPREL, R_MIPS_GPREL16 },
1298 { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL },
1299 { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 },
1300 { BFD_RELOC_16_PCREL, R_MIPS_PC16 },
1301 { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 },
1302 { BFD_RELOC_MIPS_GPREL32, R_MIPS_GPREL32 },
1303 { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 },
1304 { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 },
1305 { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 },
1306 { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 }
1309 /* Given a BFD reloc type, return a howto structure. */
1311 static reloc_howto_type *
1312 mips_elf64_reloc_type_lookup (abfd, code)
1314 bfd_reloc_code_real_type code;
1318 for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++)
1320 if (mips_reloc_map[i].bfd_reloc_val == code)
1324 v = (int) mips_reloc_map[i].elf_reloc_val;
1325 return &mips_elf64_howto_table_rel[v];
1332 /* Since each entry in an SHT_REL or SHT_RELA section can represent up
1333 to three relocs, we must tell the user to allocate more space. */
1336 mips_elf64_get_reloc_upper_bound (abfd, sec)
1340 return (sec->reloc_count * 3 + 1) * sizeof (arelent *);
1343 /* Read the relocations from one reloc section. */
1346 mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, rel_hdr)
1350 const Elf_Internal_Shdr *rel_hdr;
1352 PTR allocated = NULL;
1353 bfd_byte *native_relocs;
1359 reloc_howto_type *howto_table;
1361 allocated = (PTR) bfd_malloc (rel_hdr->sh_size);
1362 if (allocated == NULL)
1365 if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
1366 || (bfd_read (allocated, 1, rel_hdr->sh_size, abfd) != rel_hdr->sh_size))
1369 native_relocs = (bfd_byte *) allocated;
1371 relents = asect->relocation + asect->reloc_count;
1373 entsize = rel_hdr->sh_entsize;
1374 BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel)
1375 || entsize == sizeof (Elf64_Mips_External_Rela));
1377 count = rel_hdr->sh_size / entsize;
1379 if (entsize == sizeof (Elf64_Mips_External_Rel))
1380 howto_table = mips_elf64_howto_table_rel;
1382 howto_table = mips_elf64_howto_table_rela;
1385 for (i = 0; i < count; i++, native_relocs += entsize)
1387 Elf64_Mips_Internal_Rela rela;
1388 boolean used_sym, used_ssym;
1391 if (entsize == sizeof (Elf64_Mips_External_Rela))
1392 mips_elf64_swap_reloca_in (abfd,
1393 (Elf64_Mips_External_Rela *) native_relocs,
1397 Elf64_Mips_Internal_Rel rel;
1399 mips_elf64_swap_reloc_in (abfd,
1400 (Elf64_Mips_External_Rel *) native_relocs,
1402 rela.r_offset = rel.r_offset;
1403 rela.r_sym = rel.r_sym;
1404 rela.r_ssym = rel.r_ssym;
1405 rela.r_type3 = rel.r_type3;
1406 rela.r_type2 = rel.r_type2;
1407 rela.r_type = rel.r_type;
1411 /* Each entry represents up to three actual relocations. */
1415 for (ir = 0; ir < 3; ir++)
1417 enum mips_elf64_reloc_type type;
1424 type = (enum mips_elf64_reloc_type) rela.r_type;
1427 type = (enum mips_elf64_reloc_type) rela.r_type2;
1430 type = (enum mips_elf64_reloc_type) rela.r_type3;
1434 if (type == R_MIPS_NONE)
1436 /* There are no more relocations in this entry. If this
1437 is the first entry, we need to generate a dummy
1438 relocation so that the generic linker knows that
1439 there has been a break in the sequence of relocations
1440 applying to a particular address. */
1443 relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
1444 if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
1445 relent->address = rela.r_offset;
1447 relent->address = rela.r_offset - asect->vma;
1449 relent->howto = &howto_table[(int) R_MIPS_NONE];
1455 /* Some types require symbols, whereas some do not. */
1459 case R_MIPS_LITERAL:
1460 case R_MIPS_INSERT_A:
1461 case R_MIPS_INSERT_B:
1463 relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
1469 if (rela.r_sym == 0)
1470 relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
1475 ps = symbols + rela.r_sym - 1;
1477 if ((s->flags & BSF_SECTION_SYM) == 0)
1478 relent->sym_ptr_ptr = ps;
1480 relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
1485 else if (! used_ssym)
1487 switch (rela.r_ssym)
1490 relent->sym_ptr_ptr =
1491 bfd_abs_section_ptr->symbol_ptr_ptr;
1497 /* FIXME: I think these need to be handled using
1498 special howto structures. */
1510 relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
1515 /* The address of an ELF reloc is section relative for an
1516 object file, and absolute for an executable file or
1517 shared library. The address of a BFD reloc is always
1518 section relative. */
1519 if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
1520 relent->address = rela.r_offset;
1522 relent->address = rela.r_offset - asect->vma;
1524 relent->addend = rela.r_addend;
1526 relent->howto = &howto_table[(int) type];
1532 asect->reloc_count += relent - relents;
1534 if (allocated != NULL)
1540 if (allocated != NULL)
1545 /* Read the relocations. On Irix 6, there can be two reloc sections
1546 associated with a single data section. */
1549 mips_elf64_slurp_reloc_table (abfd, asect, symbols, dynamic)
1555 struct bfd_elf_section_data * const d = elf_section_data (asect);
1559 bfd_set_error (bfd_error_invalid_operation);
1563 if (asect->relocation != NULL
1564 || (asect->flags & SEC_RELOC) == 0
1565 || asect->reloc_count == 0)
1568 /* Allocate space for 3 arelent structures for each Rel structure. */
1569 asect->relocation = ((arelent *)
1571 asect->reloc_count * 3 * sizeof (arelent)));
1572 if (asect->relocation == NULL)
1575 /* The slurp_one_reloc_table routine increments reloc_count. */
1576 asect->reloc_count = 0;
1578 if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, &d->rel_hdr))
1580 if (d->rel_hdr2 != NULL)
1582 if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols,
1590 /* Write out the relocations. */
1593 mips_elf64_write_relocs (abfd, sec, data)
1598 boolean *failedp = (boolean *) data;
1600 Elf_Internal_Shdr *rela_hdr;
1601 Elf64_Mips_External_Rela *ext_rela;
1603 asymbol *last_sym = 0;
1604 int last_sym_idx = 0;
1606 /* If we have already failed, don't do anything. */
1610 if ((sec->flags & SEC_RELOC) == 0)
1613 /* The linker backend writes the relocs out itself, and sets the
1614 reloc_count field to zero to inhibit writing them here. Also,
1615 sometimes the SEC_RELOC flag gets set even when there aren't any
1617 if (sec->reloc_count == 0)
1620 /* We can combine up to three relocs that refer to the same address
1621 if the latter relocs have no associated symbol. */
1623 for (idx = 0; idx < sec->reloc_count; idx++)
1630 addr = sec->orelocation[idx]->address;
1631 for (i = 0; i < 2; i++)
1635 if (idx + 1 >= sec->reloc_count)
1637 r = sec->orelocation[idx + 1];
1638 if (r->address != addr
1639 || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
1640 || (*r->sym_ptr_ptr)->value != 0)
1643 /* We can merge the reloc at IDX + 1 with the reloc at IDX. */
1649 rela_hdr = &elf_section_data (sec)->rel_hdr;
1651 rela_hdr->sh_size = rela_hdr->sh_entsize * count;
1652 rela_hdr->contents = (PTR) bfd_alloc (abfd, rela_hdr->sh_size);
1653 if (rela_hdr->contents == NULL)
1659 ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents;
1660 for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++)
1663 Elf64_Mips_Internal_Rela int_rela;
1668 ptr = sec->orelocation[idx];
1670 /* The address of an ELF reloc is section relative for an object
1671 file, and absolute for an executable file or shared library.
1672 The address of a BFD reloc is always section relative. */
1673 if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
1674 int_rela.r_offset = ptr->address;
1676 int_rela.r_offset = ptr->address + sec->vma;
1678 sym = *ptr->sym_ptr_ptr;
1679 if (sym == last_sym)
1684 n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
1695 int_rela.r_addend = ptr->addend;
1697 int_rela.r_ssym = RSS_UNDEF;
1699 if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
1700 && ! _bfd_elf_validate_reloc (abfd, ptr))
1706 int_rela.r_type = ptr->howto->type;
1707 int_rela.r_type2 = (int) R_MIPS_NONE;
1708 int_rela.r_type3 = (int) R_MIPS_NONE;
1710 for (i = 0; i < 2; i++)
1714 if (idx + 1 >= sec->reloc_count)
1716 r = sec->orelocation[idx + 1];
1717 if (r->address != ptr->address
1718 || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
1719 || (*r->sym_ptr_ptr)->value != 0)
1722 /* We can merge the reloc at IDX + 1 with the reloc at IDX. */
1725 int_rela.r_type2 = r->howto->type;
1727 int_rela.r_type3 = r->howto->type;
1732 mips_elf64_swap_reloca_out (abfd, &int_rela, ext_rela);
1735 BFD_ASSERT (ext_rela - (Elf64_Mips_External_Rela *) rela_hdr->contents
1739 /* Handle a 64-bit MIPS ELF specific section. */
1742 mips_elf64_section_from_shdr (abfd, hdr, name)
1744 Elf_Internal_Shdr *hdr;
1747 if (! _bfd_mips_elf_section_from_shdr (abfd, hdr, name))
1750 /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and
1751 set the gp value based on what we find. We may see both
1752 SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case,
1753 they should agree. */
1754 if (hdr->sh_type == SHT_MIPS_OPTIONS)
1756 bfd_byte *contents, *l, *lend;
1758 contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
1759 if (contents == NULL)
1761 if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents,
1762 (file_ptr) 0, hdr->sh_size))
1768 lend = contents + hdr->sh_size;
1769 while (l + sizeof (Elf_External_Options) <= lend)
1771 Elf_Internal_Options intopt;
1773 bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
1775 if (intopt.kind == ODK_REGINFO)
1777 Elf64_Internal_RegInfo intreg;
1779 bfd_mips_elf64_swap_reginfo_in
1781 ((Elf64_External_RegInfo *)
1782 (l + sizeof (Elf_External_Options))),
1784 elf_gp (abfd) = intreg.ri_gp_value;
1794 /* Work over a section just before writing it out. We update the GP
1795 value in the SHT_MIPS_OPTIONS section based on the value we are
1799 mips_elf64_section_processing (abfd, hdr)
1801 Elf_Internal_Shdr *hdr;
1803 if (hdr->sh_type == SHT_MIPS_OPTIONS
1804 && hdr->bfd_section != NULL
1805 && elf_section_data (hdr->bfd_section) != NULL
1806 && elf_section_data (hdr->bfd_section)->tdata != NULL)
1808 bfd_byte *contents, *l, *lend;
1810 /* We stored the section contents in the elf_section_data tdata
1811 field in the set_section_contents routine. We save the
1812 section contents so that we don't have to read them again.
1813 At this point we know that elf_gp is set, so we can look
1814 through the section contents to see if there is an
1815 ODK_REGINFO structure. */
1817 contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata;
1819 lend = contents + hdr->sh_size;
1820 while (l + sizeof (Elf_External_Options) <= lend)
1822 Elf_Internal_Options intopt;
1824 bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
1826 if (intopt.kind == ODK_REGINFO)
1833 + sizeof (Elf_External_Options)
1834 + (sizeof (Elf64_External_RegInfo) - 8)),
1837 bfd_h_put_64 (abfd, elf_gp (abfd), buf);
1838 if (bfd_write (buf, 1, 8, abfd) != 8)
1845 return _bfd_mips_elf_section_processing (abfd, hdr);
1848 /* Irix 6 defines a brand new archive map format, so that they can
1849 have archives more than 4 GB in size. */
1851 /* Read an Irix 6 armap. */
1854 mips_elf64_slurp_armap (abfd)
1857 struct artdata *ardata = bfd_ardata (abfd);
1860 bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
1861 struct areltdata *mapdata;
1862 bfd_byte int_buf[8];
1864 bfd_byte *raw_armap = NULL;
1867 ardata->symdefs = NULL;
1869 /* Get the name of the first element. */
1870 arhdrpos = bfd_tell (abfd);
1871 i = bfd_read ((PTR) nextname, 1, 16, abfd);
1877 if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
1880 /* Archives with traditional armaps are still permitted. */
1881 if (strncmp (nextname, "/ ", 16) == 0)
1882 return bfd_slurp_armap (abfd);
1884 if (strncmp (nextname, "/SYM64/ ", 16) != 0)
1886 bfd_has_map (abfd) = false;
1890 mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
1891 if (mapdata == NULL)
1893 parsed_size = mapdata->parsed_size;
1894 bfd_release (abfd, (PTR) mapdata);
1896 if (bfd_read (int_buf, 1, 8, abfd) != 8)
1898 if (bfd_get_error () != bfd_error_system_call)
1899 bfd_set_error (bfd_error_malformed_archive);
1903 nsymz = bfd_getb64 (int_buf);
1904 stringsize = parsed_size - 8 * nsymz - 8;
1906 carsym_size = nsymz * sizeof (carsym);
1907 ptrsize = 8 * nsymz;
1909 ardata->symdefs = (carsym *) bfd_zalloc (abfd, carsym_size + stringsize + 1);
1910 if (ardata->symdefs == NULL)
1912 carsyms = ardata->symdefs;
1913 stringbase = ((char *) ardata->symdefs) + carsym_size;
1915 raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize);
1916 if (raw_armap == NULL)
1919 if (bfd_read (raw_armap, 1, ptrsize, abfd) != ptrsize
1920 || bfd_read (stringbase, 1, stringsize, abfd) != stringsize)
1922 if (bfd_get_error () != bfd_error_system_call)
1923 bfd_set_error (bfd_error_malformed_archive);
1927 for (i = 0; i < nsymz; i++)
1929 carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
1930 carsyms->name = stringbase;
1931 stringbase += strlen (stringbase) + 1;
1936 ardata->symdef_count = nsymz;
1937 ardata->first_file_filepos = arhdrpos + sizeof (struct ar_hdr) + parsed_size;
1939 bfd_has_map (abfd) = true;
1940 bfd_release (abfd, raw_armap);
1945 if (raw_armap != NULL)
1946 bfd_release (abfd, raw_armap);
1947 if (ardata->symdefs != NULL)
1948 bfd_release (abfd, ardata->symdefs);
1952 /* Write out an Irix 6 armap. The Irix 6 tools are supposed to be
1953 able to handle ordinary ELF armaps, but at least on Irix 6.2 the
1957 mips_elf64_write_armap (arch, elength, map, symbol_count, stridx)
1959 unsigned int elength;
1961 unsigned int symbol_count;
1964 unsigned int ranlibsize = (symbol_count * 8) + 8;
1965 unsigned int stringsize = stridx;
1966 unsigned int mapsize = stringsize + ranlibsize;
1967 file_ptr archive_member_file_ptr;
1968 bfd *current = arch->archive_head;
1975 padding = BFD_ALIGN (mapsize, 8) - mapsize;
1978 /* work out where the first object file will go in the archive */
1979 archive_member_file_ptr = (mapsize
1981 + sizeof (struct ar_hdr)
1984 memset ((char *) (&hdr), 0, sizeof (struct ar_hdr));
1985 strcpy (hdr.ar_name, "/SYM64/");
1986 sprintf (hdr.ar_size, "%-10d", (int) mapsize);
1987 sprintf (hdr.ar_date, "%ld", (long) time (NULL));
1988 /* This, at least, is what Intel coff sets the values to.: */
1989 sprintf ((hdr.ar_uid), "%d", 0);
1990 sprintf ((hdr.ar_gid), "%d", 0);
1991 sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0);
1992 strncpy (hdr.ar_fmag, ARFMAG, 2);
1994 for (i = 0; i < sizeof (struct ar_hdr); i++)
1995 if (((char *) (&hdr))[i] == '\0')
1996 (((char *) (&hdr))[i]) = ' ';
1998 /* Write the ar header for this item and the number of symbols */
2000 if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), arch)
2001 != sizeof (struct ar_hdr))
2004 bfd_putb64 (symbol_count, buf);
2005 if (bfd_write (buf, 1, 8, arch) != 8)
2008 /* Two passes, first write the file offsets for each symbol -
2009 remembering that each offset is on a two byte boundary. */
2011 /* Write out the file offset for the file associated with each
2012 symbol, and remember to keep the offsets padded out. */
2014 current = arch->archive_head;
2016 while (current != (bfd *) NULL && count < symbol_count)
2018 /* For each symbol which is used defined in this object, write out
2019 the object file's address in the archive */
2021 while (((bfd *) (map[count]).pos) == current)
2023 bfd_putb64 (archive_member_file_ptr, buf);
2024 if (bfd_write (buf, 1, 8, arch) != 8)
2028 /* Add size of this archive entry */
2029 archive_member_file_ptr += (arelt_size (current)
2030 + sizeof (struct ar_hdr));
2031 /* remember about the even alignment */
2032 archive_member_file_ptr += archive_member_file_ptr % 2;
2033 current = current->next;
2036 /* now write the strings themselves */
2037 for (count = 0; count < symbol_count; count++)
2039 size_t len = strlen (*map[count].name) + 1;
2041 if (bfd_write (*map[count].name, 1, len, arch) != len)
2045 /* The spec says that this should be padded to an 8 byte boundary.
2046 However, the Irix 6.2 tools do not appear to do this. */
2047 while (padding != 0)
2049 if (bfd_write ("", 1, 1, arch) != 1)
2057 /* ECOFF swapping routines. These are used when dealing with the
2058 .mdebug section, which is in the ECOFF debugging format. */
2059 static const struct ecoff_debug_swap mips_elf64_ecoff_debug_swap =
2061 /* Symbol table magic number. */
2063 /* Alignment of debugging information. E.g., 4. */
2065 /* Sizes of external symbolic information. */
2066 sizeof (struct hdr_ext),
2067 sizeof (struct dnr_ext),
2068 sizeof (struct pdr_ext),
2069 sizeof (struct sym_ext),
2070 sizeof (struct opt_ext),
2071 sizeof (struct fdr_ext),
2072 sizeof (struct rfd_ext),
2073 sizeof (struct ext_ext),
2074 /* Functions to swap in external symbolic data. */
2083 _bfd_ecoff_swap_tir_in,
2084 _bfd_ecoff_swap_rndx_in,
2085 /* Functions to swap out external symbolic data. */
2094 _bfd_ecoff_swap_tir_out,
2095 _bfd_ecoff_swap_rndx_out,
2096 /* Function to read in symbolic data. */
2097 _bfd_mips_elf_read_ecoff_info
2100 /* Relocations in the 64 bit MIPS ELF ABI are more complex than in
2101 standard ELF. This structure is used to redirect the relocation
2102 handling routines. */
2104 const struct elf_size_info mips_elf64_size_info =
2106 sizeof (Elf64_External_Ehdr),
2107 sizeof (Elf64_External_Phdr),
2108 sizeof (Elf64_External_Shdr),
2109 sizeof (Elf64_Mips_External_Rel),
2110 sizeof (Elf64_Mips_External_Rela),
2111 sizeof (Elf64_External_Sym),
2112 sizeof (Elf64_External_Dyn),
2113 sizeof (Elf_External_Note),
2118 bfd_elf64_write_out_phdrs,
2119 bfd_elf64_write_shdrs_and_ehdr,
2120 mips_elf64_write_relocs,
2121 bfd_elf64_swap_symbol_out,
2122 mips_elf64_slurp_reloc_table,
2123 bfd_elf64_slurp_symbol_table,
2124 bfd_elf64_swap_dyn_in
2127 #define TARGET_LITTLE_SYM bfd_elf64_littlemips_vec
2128 #define TARGET_LITTLE_NAME "elf64-littlemips"
2129 #define TARGET_BIG_SYM bfd_elf64_bigmips_vec
2130 #define TARGET_BIG_NAME "elf64-bigmips"
2131 #define ELF_ARCH bfd_arch_mips
2132 #define ELF_MACHINE_CODE EM_MIPS
2133 #define ELF_MAXPAGESIZE 0x1000
2134 #define elf_backend_size_info mips_elf64_size_info
2135 #define elf_backend_object_p _bfd_mips_elf_object_p
2136 #define elf_backend_section_from_shdr mips_elf64_section_from_shdr
2137 #define elf_backend_fake_sections _bfd_mips_elf_fake_sections
2138 #define elf_backend_section_from_bfd_section \
2139 _bfd_mips_elf_section_from_bfd_section
2140 #define elf_backend_section_processing mips_elf64_section_processing
2141 #define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing
2142 #define elf_backend_final_write_processing \
2143 _bfd_mips_elf_final_write_processing
2144 #define elf_backend_ecoff_debug_swap &mips_elf64_ecoff_debug_swap
2146 #define bfd_elf64_find_nearest_line _bfd_mips_elf_find_nearest_line
2147 #define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound
2148 #define bfd_elf64_bfd_reloc_type_lookup mips_elf64_reloc_type_lookup
2149 #define bfd_elf64_set_section_contents _bfd_mips_elf_set_section_contents
2150 #define bfd_elf64_bfd_copy_private_bfd_data \
2151 _bfd_mips_elf_copy_private_bfd_data
2152 #define bfd_elf64_bfd_merge_private_bfd_data \
2153 _bfd_mips_elf_merge_private_bfd_data
2154 #define bfd_elf64_bfd_set_private_flags _bfd_mips_elf_set_private_flags
2156 #define bfd_elf64_archive_functions
2157 #define bfd_elf64_archive_slurp_armap mips_elf64_slurp_armap
2158 #define bfd_elf64_archive_slurp_extended_name_table \
2159 _bfd_archive_coff_slurp_extended_name_table
2160 #define bfd_elf64_archive_construct_extended_name_table \
2161 _bfd_archive_coff_construct_extended_name_table
2162 #define bfd_elf64_archive_truncate_arname \
2163 _bfd_archive_coff_truncate_arname
2164 #define bfd_elf64_archive_write_armap mips_elf64_write_armap
2165 #define bfd_elf64_archive_read_ar_hdr _bfd_archive_coff_read_ar_hdr
2166 #define bfd_elf64_archive_openr_next_archived_file \
2167 _bfd_archive_coff_openr_next_archived_file
2168 #define bfd_elf64_archive_get_elt_at_index \
2169 _bfd_archive_coff_get_elt_at_index
2170 #define bfd_elf64_archive_generic_stat_arch_elt \
2171 _bfd_archive_coff_generic_stat_arch_elt
2172 #define bfd_elf64_archive_update_armap_timestamp \
2173 _bfd_archive_coff_update_armap_timestamp
2175 #include "elf64-target.h"