diff options
Diffstat (limited to 'binutils-2.24/bfd')
-rw-r--r-- | binutils-2.24/bfd/ChangeLog | 66 | ||||
-rw-r--r-- | binutils-2.24/bfd/aoutx.h | 6 | ||||
-rw-r--r-- | binutils-2.24/bfd/archures.c | 6 | ||||
-rw-r--r-- | binutils-2.24/bfd/bfd-in2.h | 12 | ||||
-rw-r--r-- | binutils-2.24/bfd/config.bfd | 2 | ||||
-rw-r--r-- | binutils-2.24/bfd/cpu-mips.c | 12 | ||||
-rw-r--r-- | binutils-2.24/bfd/elf32-mips.c | 104 | ||||
-rw-r--r-- | binutils-2.24/bfd/elf64-mips.c | 198 | ||||
-rw-r--r-- | binutils-2.24/bfd/elfn32-mips.c | 198 | ||||
-rw-r--r-- | binutils-2.24/bfd/elfxx-mips.c | 1396 | ||||
-rw-r--r-- | binutils-2.24/bfd/elfxx-mips.h | 4 | ||||
-rw-r--r-- | binutils-2.24/bfd/libbfd.h | 4 | ||||
-rw-r--r-- | binutils-2.24/bfd/reloc.c | 11 |
13 files changed, 1695 insertions, 324 deletions
diff --git a/binutils-2.24/bfd/ChangeLog b/binutils-2.24/bfd/ChangeLog index 2c4719c..b225e10 100644 --- a/binutils-2.24/bfd/ChangeLog +++ b/binutils-2.24/bfd/ChangeLog @@ -1,3 +1,55 @@ +2014-05-07 Andrew Bennett <andrew.bennett@imgtec.com> + + * aoutx.h (NAME (aout, machine_type)): Add mips32r3, mips64r3, + mips32r5 and mips64r5. + * archures.c (bfd_architecture): Likewise. + * bfd-in2.h (bfd_architecture): Likewise. + * cpu-mips.c (arch_info_struct): Likewise. + * elfxx-mips.c (mips_set_isa_flags): Likewise. + +2014-05-06 Richard Sandiford <rdsandiford@googlemail.com> + + * elfxx-mips.h (elfxx-mips.h): Declare. + * elfxx-mips.c (mips_elf_merge_obj_attributes): Use it to report + Tag_GNU_MIPS_ABI_FP mismatches. + (_bfd_mips_fp_abi_string): New function. + +2014-04-17 Kwok Cheung Yeung <kcy@codesourcery.com> + + * elfxx-mips.c (struct mips_got_info): Delete assigned_gotno + field. Add assigned_low_gotno and assigned_high_gotno fields. + (mips_elf_create_local_got_entry): Update out-of-space condition. + Set index of new GOT entry to assigned_low_gotno if required by + the current relocation, else set it to assigned_high_gotno. + (mips_elf_set_global_gotidx): Replace uses of assigned_gotno + with assigned_low_gotno. + (mips_elf_multi_got): Initialize assigned_low_gotno and + assigned_high_gotno in secondary GOTs. Use assigned_low_gotno + in place of assigned_gotno when handling global GOT entries. + (mips_elf_lay_out_got): Initialize assigned_low_gotno and + assigned_high_gotno. + (_bfd_mips_elf_finish_dynamic_sections): Account for a possible + gap in the middle of local GOT space. + +2014-03-04 Heiher <r@hev.cc> + + * elfxx-mips.c (mips_set_isa_flags): Use E_MIPS_ARCH_64R2 for + Loongson-3A. + (mips_mach_extensions): Make bfd_mach_mips_loongson_3a an + extension of bfd_mach_mipsisa64r2. + +2014-02-18 Jack Carter <jack.carter@imgtec.com> + + * elfxx-mips.c(_bfd_mips_elf_modify_segment_map): Deleted hard coding of + PT_DYNAMIC segment flags. + +2014-01-16 Alan Modra <amodra@gmail.com> + + * elfxx-mips.c (mips_elf_record_got_page_entry): Pass in a + mips_elf_traverse_got_arg* rather than mips_got_info*. + Adjust caller. Alloc on output_bfd rather than symbol section + owner. + 2013-12-02 Tristan Gingold <gingold@adacore.com> * configure.in: Bump version to 2.24 @@ -219,6 +271,20 @@ * elf.c (copy_elf_program_header): Only consider SEC_ALLOC sections when finding lowest_section. +2013-10-14 Chao-ying Fu <Chao-ying.Fu@imgtec.com> + + * elfxx-mips.c (mips_elf_obj_tdata): Add abi_msa_bfd. + (mips_elf_merge_obj_attributes): Set abi_msa_bfd to the first object + file that has a Tag_GNU_MIPS_ABI_MSA attribute. + Merge Tag_GNU_MIPS_ABI_MSA attributes. + +2013-10-13 Richard Sandiford <rdsandiford@googlemail.com> + + * elfxx-mips.c (mips_use_local_got_p): New function. + (mips_elf_count_got_symbols, mips_elf_calculate_relocation): Use it. + (_bfd_mips_elf_check_relocs): Set pointer_equality_needed for + GOT and absolute references. + 2013-10-09 Roland McGrath <mcgrathr@google.com> * elf64-alpha.c (elf64_alpha_relax_tls_get_addr): Cast switch diff --git a/binutils-2.24/bfd/aoutx.h b/binutils-2.24/bfd/aoutx.h index 1e0ad38..e54366c 100644 --- a/binutils-2.24/bfd/aoutx.h +++ b/binutils-2.24/bfd/aoutx.h @@ -793,9 +793,15 @@ NAME (aout, machine_type) (enum bfd_architecture arch, case bfd_mach_mips16: case bfd_mach_mipsisa32: case bfd_mach_mipsisa32r2: + case bfd_mach_mipsisa32r3: + case bfd_mach_mipsisa32r5: + case bfd_mach_mipsisa32r6: case bfd_mach_mips5: case bfd_mach_mipsisa64: case bfd_mach_mipsisa64r2: + case bfd_mach_mipsisa64r3: + case bfd_mach_mipsisa64r5: + case bfd_mach_mipsisa64r6: case bfd_mach_mips_sb1: case bfd_mach_mips_xlr: /* FIXME: These should be MIPS3, MIPS4, MIPS16, MIPS32, etc. */ diff --git a/binutils-2.24/bfd/archures.c b/binutils-2.24/bfd/archures.c index 97c540a..be78a22 100644 --- a/binutils-2.24/bfd/archures.c +++ b/binutils-2.24/bfd/archures.c @@ -180,8 +180,14 @@ DESCRIPTION .#define bfd_mach_mips_xlr 887682 {* decimal 'XLR' *} .#define bfd_mach_mipsisa32 32 .#define bfd_mach_mipsisa32r2 33 +.#define bfd_mach_mipsisa32r3 34 +.#define bfd_mach_mipsisa32r5 36 +.#define bfd_mach_mipsisa32r6 37 .#define bfd_mach_mipsisa64 64 .#define bfd_mach_mipsisa64r2 65 +.#define bfd_mach_mipsisa64r3 66 +.#define bfd_mach_mipsisa64r5 68 +.#define bfd_mach_mipsisa64r6 69 .#define bfd_mach_mips_micromips 96 . bfd_arch_i386, {* Intel 386 *} .#define bfd_mach_i386_intel_syntax (1 << 0) diff --git a/binutils-2.24/bfd/bfd-in2.h b/binutils-2.24/bfd/bfd-in2.h index 756af87..3097f04 100644 --- a/binutils-2.24/bfd/bfd-in2.h +++ b/binutils-2.24/bfd/bfd-in2.h @@ -1935,8 +1935,14 @@ enum bfd_architecture #define bfd_mach_mips_xlr 887682 /* decimal 'XLR' */ #define bfd_mach_mipsisa32 32 #define bfd_mach_mipsisa32r2 33 +#define bfd_mach_mipsisa32r3 34 +#define bfd_mach_mipsisa32r5 36 +#define bfd_mach_mipsisa32r6 37 #define bfd_mach_mipsisa64 64 #define bfd_mach_mipsisa64r2 65 +#define bfd_mach_mipsisa64r3 66 +#define bfd_mach_mipsisa64r5 68 +#define bfd_mach_mipsisa64r6 69 #define bfd_mach_mips_micromips 96 bfd_arch_i386, /* Intel 386 */ #define bfd_mach_i386_intel_syntax (1 << 0) @@ -2896,6 +2902,12 @@ to compensate for the borrow when the low bits are added. */ BFD_RELOC_MICROMIPS_10_PCREL_S1, BFD_RELOC_MICROMIPS_16_PCREL_S1, +/* MIPS PC-relative relocations. */ + BFD_RELOC_MIPS_21_PCREL_S2, + BFD_RELOC_MIPS_26_PCREL_S2, + BFD_RELOC_MIPS_18_PCREL_S3, + BFD_RELOC_MIPS_19_PCREL_S2, + /* microMIPS versions of generic BFD relocs. */ BFD_RELOC_MICROMIPS_GPREL16, BFD_RELOC_MICROMIPS_HI16, diff --git a/binutils-2.24/bfd/config.bfd b/binutils-2.24/bfd/config.bfd index 5324d39..d1643cc 100644 --- a/binutils-2.24/bfd/config.bfd +++ b/binutils-2.24/bfd/config.bfd @@ -1024,7 +1024,7 @@ case "${targ}" in targ_defvec=bfd_elf32_tradlittlemips_vec targ_selvecs="bfd_elf32_tradbigmips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" ;; - mips*-sde-elf* | mips*-mti-elf*) + mips*-sde-elf* | mips*-mti-elf* | mips*-img-elf*) targ_defvec=bfd_elf32_tradbigmips_vec targ_selvecs="bfd_elf32_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" ;; diff --git a/binutils-2.24/bfd/cpu-mips.c b/binutils-2.24/bfd/cpu-mips.c index 59a7c16..fc37cbe 100644 --- a/binutils-2.24/bfd/cpu-mips.c +++ b/binutils-2.24/bfd/cpu-mips.c @@ -89,8 +89,14 @@ enum I_mips5, I_mipsisa32, I_mipsisa32r2, + I_mipsisa32r3, + I_mipsisa32r5, + I_mipsisa32r6, I_mipsisa64, I_mipsisa64r2, + I_mipsisa64r3, + I_mipsisa64r5, + I_mipsisa64r6, I_sb1, I_loongson_2e, I_loongson_2f, @@ -133,8 +139,14 @@ static const bfd_arch_info_type arch_info_struct[] = N (64, 64, bfd_mach_mips5, "mips:mips5", FALSE, NN(I_mips5)), N (32, 32, bfd_mach_mipsisa32, "mips:isa32", FALSE, NN(I_mipsisa32)), N (32, 32, bfd_mach_mipsisa32r2,"mips:isa32r2", FALSE, NN(I_mipsisa32r2)), + N (32, 32, bfd_mach_mipsisa32r3,"mips:isa32r3", FALSE, NN(I_mipsisa32r3)), + N (32, 32, bfd_mach_mipsisa32r5,"mips:isa32r5", FALSE, NN(I_mipsisa32r5)), + N (32, 32, bfd_mach_mipsisa32r6,"mips:isa32r6", FALSE, NN(I_mipsisa32r6)), N (64, 64, bfd_mach_mipsisa64, "mips:isa64", FALSE, NN(I_mipsisa64)), N (64, 64, bfd_mach_mipsisa64r2,"mips:isa64r2", FALSE, NN(I_mipsisa64r2)), + N (64, 64, bfd_mach_mipsisa64r3,"mips:isa64r3", FALSE, NN(I_mipsisa64r3)), + N (64, 64, bfd_mach_mipsisa64r5,"mips:isa64r5", FALSE, NN(I_mipsisa64r5)), + N (64, 64, bfd_mach_mipsisa64r6,"mips:isa64r6", FALSE, NN(I_mipsisa64r6)), N (64, 64, bfd_mach_mips_sb1, "mips:sb1", FALSE, NN(I_sb1)), N (64, 64, bfd_mach_mips_loongson_2e, "mips:loongson_2e", FALSE, NN(I_loongson_2e)), N (64, 64, bfd_mach_mips_loongson_2f, "mips:loongson_2f", FALSE, NN(I_loongson_2f)), diff --git a/binutils-2.24/bfd/elf32-mips.c b/binutils-2.24/bfd/elf32-mips.c index eec2ef7..c9c4cc3 100644 --- a/binutils-2.24/bfd/elf32-mips.c +++ b/binutils-2.24/bfd/elf32-mips.c @@ -717,6 +717,100 @@ static reloc_howto_type elf_mips_howto_table_rel[] = 0x0, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (52), + EMPTY_HOWTO (53), + EMPTY_HOWTO (54), + EMPTY_HOWTO (55), + EMPTY_HOWTO (56), + EMPTY_HOWTO (57), + EMPTY_HOWTO (58), + EMPTY_HOWTO (59), + + HOWTO (R_MIPS_PC21_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC21_S2", /* name */ + TRUE, /* partial_inplace */ + 0x001fffff, /* src_mask */ + 0x001fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC26_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC26_S2", /* name */ + TRUE, /* partial_inplace */ + 0x03ffffff, /* src_mask */ + 0x03ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC18_S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC18_S3", /* name */ + TRUE, /* partial_inplace */ + 0x0003ffff, /* src_mask */ + 0x0003ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC19_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC19_S2", /* name */ + TRUE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCHI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCHI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCLO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCLO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + }; /* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link. This @@ -1906,7 +2000,13 @@ static const struct elf_reloc_map mips_reloc_map[] = { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 } + { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }, + { BFD_RELOC_MIPS_21_PCREL_S2, R_MIPS_PC21_S2 }, + { BFD_RELOC_MIPS_26_PCREL_S2, R_MIPS_PC26_S2 }, + { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 }, + { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 }, + { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 }, + { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 } }; static const struct elf_reloc_map mips16_reloc_map[] = @@ -2316,6 +2416,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define elf_backend_collect TRUE #define elf_backend_type_change_ok TRUE #define elf_backend_can_gc_sections TRUE +#define elf_backend_gc_mark_extra_sections \ + _bfd_mips_elf_gc_mark_extra_sections #define elf_info_to_howto mips_info_to_howto_rela #define elf_info_to_howto_rel mips_info_to_howto_rel #define elf_backend_sym_is_global mips_elf_sym_is_global diff --git a/binutils-2.24/bfd/elf64-mips.c b/binutils-2.24/bfd/elf64-mips.c index a0c5cc5..c090fb7 100644 --- a/binutils-2.24/bfd/elf64-mips.c +++ b/binutils-2.24/bfd/elf64-mips.c @@ -807,6 +807,100 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = 0x0, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (52), + EMPTY_HOWTO (53), + EMPTY_HOWTO (54), + EMPTY_HOWTO (55), + EMPTY_HOWTO (56), + EMPTY_HOWTO (57), + EMPTY_HOWTO (58), + EMPTY_HOWTO (59), + + HOWTO (R_MIPS_PC21_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC21_S2", /* name */ + TRUE, /* partial_inplace */ + 0x001fffff, /* src_mask */ + 0x001fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC26_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC26_S2", /* name */ + TRUE, /* partial_inplace */ + 0x03ffffff, /* src_mask */ + 0x03ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC18_S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC18_S3", /* name */ + TRUE, /* partial_inplace */ + 0x0003ffff, /* src_mask */ + 0x0003ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC19_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC19_S2", /* name */ + TRUE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCHI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCHI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCLO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCLO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + }; /* The relocation table used for SHT_RELA sections. */ @@ -1494,6 +1588,100 @@ static reloc_howto_type mips_elf64_howto_table_rela[] = 0x0, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (52), + EMPTY_HOWTO (53), + EMPTY_HOWTO (54), + EMPTY_HOWTO (55), + EMPTY_HOWTO (56), + EMPTY_HOWTO (57), + EMPTY_HOWTO (58), + EMPTY_HOWTO (59), + + HOWTO (R_MIPS_PC21_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC21_S2", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x001fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC26_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC26_S2", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x03ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC18_S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC18_S3", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0003ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC19_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC19_S2", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0007ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCHI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCHI16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCLO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCLO16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + }; static reloc_howto_type mips16_elf64_howto_table_rel[] = @@ -3204,7 +3392,13 @@ static const struct elf_reloc_map mips_reloc_map[] = { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 } + { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }, + { BFD_RELOC_MIPS_21_PCREL_S2, R_MIPS_PC21_S2 }, + { BFD_RELOC_MIPS_26_PCREL_S2, R_MIPS_PC26_S2 }, + { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 }, + { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 }, + { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 }, + { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 } }; static const struct elf_reloc_map mips16_reloc_map[] = @@ -4187,6 +4381,8 @@ const struct elf_size_info mips_elf64_size_info = #define elf_backend_collect TRUE #define elf_backend_type_change_ok TRUE #define elf_backend_can_gc_sections TRUE +#define elf_backend_gc_mark_extra_sections \ + _bfd_mips_elf_gc_mark_extra_sections #define elf_info_to_howto mips_elf64_info_to_howto_rela #define elf_info_to_howto_rel mips_elf64_info_to_howto_rel #define elf_backend_object_p mips_elf64_object_p diff --git a/binutils-2.24/bfd/elfn32-mips.c b/binutils-2.24/bfd/elfn32-mips.c index 2daf79e..2fb019f 100644 --- a/binutils-2.24/bfd/elfn32-mips.c +++ b/binutils-2.24/bfd/elfn32-mips.c @@ -771,6 +771,100 @@ static reloc_howto_type elf_mips_howto_table_rel[] = 0x0, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (52), + EMPTY_HOWTO (53), + EMPTY_HOWTO (54), + EMPTY_HOWTO (55), + EMPTY_HOWTO (56), + EMPTY_HOWTO (57), + EMPTY_HOWTO (58), + EMPTY_HOWTO (59), + + HOWTO (R_MIPS_PC21_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC21_S2", /* name */ + TRUE, /* partial_inplace */ + 0x001fffff, /* src_mask */ + 0x001fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC26_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC26_S2", /* name */ + TRUE, /* partial_inplace */ + 0x03ffffff, /* src_mask */ + 0x03ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC18_S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC18_S3", /* name */ + TRUE, /* partial_inplace */ + 0x0003ffff, /* src_mask */ + 0x0003ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC19_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC19_S2", /* name */ + TRUE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCHI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCHI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCLO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCLO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + }; /* The relocation table used for SHT_RELA sections. */ @@ -1459,6 +1553,100 @@ static reloc_howto_type elf_mips_howto_table_rela[] = 0x0, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (52), + EMPTY_HOWTO (53), + EMPTY_HOWTO (54), + EMPTY_HOWTO (55), + EMPTY_HOWTO (56), + EMPTY_HOWTO (57), + EMPTY_HOWTO (58), + EMPTY_HOWTO (59), + + HOWTO (R_MIPS_PC21_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC21_S2", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x001fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC26_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC26_S2", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x03ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC18_S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC18_S3", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0003ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PC19_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PC19_S2", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0007ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCHI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCHI16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_MIPS_PCLO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + _bfd_mips_elf_generic_reloc, /* special_function */ + "R_MIPS_PCLO16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + }; static reloc_howto_type elf_mips16_howto_table_rel[] = @@ -3019,7 +3207,13 @@ static const struct elf_reloc_map mips_reloc_map[] = { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 } + { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }, + { BFD_RELOC_MIPS_21_PCREL_S2, R_MIPS_PC21_S2 }, + { BFD_RELOC_MIPS_26_PCREL_S2, R_MIPS_PC26_S2 }, + { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 }, + { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 }, + { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 }, + { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 } }; static const struct elf_reloc_map mips16_reloc_map[] = @@ -3411,6 +3605,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define elf_backend_collect TRUE #define elf_backend_type_change_ok TRUE #define elf_backend_can_gc_sections TRUE +#define elf_backend_gc_mark_extra_sections \ + _bfd_mips_elf_gc_mark_extra_sections #define elf_info_to_howto mips_info_to_howto_rela #define elf_info_to_howto_rel mips_info_to_howto_rel #define elf_backend_sym_is_global mips_elf_sym_is_global diff --git a/binutils-2.24/bfd/elfxx-mips.c b/binutils-2.24/bfd/elfxx-mips.c index d7498e1..4b8bca7 100644 --- a/binutils-2.24/bfd/elfxx-mips.c +++ b/binutils-2.24/bfd/elfxx-mips.c @@ -168,8 +168,10 @@ struct mips_got_info unsigned int page_gotno; /* The number of relocations needed for the GOT entries. */ unsigned int relocs; - /* The number of local .got entries we have used. */ - unsigned int assigned_gotno; + /* The first unused local .got entry. */ + unsigned int assigned_low_gotno; + /* The last unused local .got entry. */ + unsigned int assigned_high_gotno; /* A hash table holding members of the got. */ struct htab *got_entries; /* A hash table holding mips_got_page_ref structures. */ @@ -542,6 +544,13 @@ struct mips_elf_obj_tdata /* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output. */ bfd *abi_fp_bfd; + /* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output. */ + bfd *abi_msa_bfd; + + /* The abiflags for this object. */ + Elf_Internal_ABIFlags_v0 abiflags; + bfd_boolean abiflags_valid; + /* The GOT requirements of input bfds. */ struct mips_got_info *got; @@ -771,6 +780,10 @@ static bfd *reldyn_sorting_bfd; #define PIC_OBJECT_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0) +/* Nonzero if ABFD is using the O32 ABI. */ +#define ABI_O32_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_O32) + /* Nonzero if ABFD is using the N32 ABI. */ #define ABI_N32_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0) @@ -786,6 +799,11 @@ static bfd *reldyn_sorting_bfd; #define MICROMIPS_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0) +/* Nonzero if ABFD is MIPS R6. */ +#define MIPSR6_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6 \ + || (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6) + /* The IRIX compatibility level we are striving for. */ #define IRIX_COMPAT(abfd) \ (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd)) @@ -803,6 +821,10 @@ static bfd *reldyn_sorting_bfd; #define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \ (strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0) +/* True if NAME is the recognized name of any SHT_MIPS_ABIFLAGS section. */ +#define MIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \ + (strcmp (NAME, ".MIPS.abiflags") == 0) + /* Whether the section is readonly. */ #define MIPS_ELF_READONLY_SECTION(sec) \ ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) \ @@ -1083,6 +1105,14 @@ static const bfd_vma mips_exec_plt_entry[] = 0x03200008 /* jr $25 */ }; +static const bfd_vma mipsr6_exec_plt_entry[] = +{ + 0x3c0f0000, /* lui $15, %hi(.got.plt entry) */ + 0x01f90000, /* l[wd] $25, %lo(.got.plt entry)($15) */ + 0x25f80000, /* addiu $24, $15, %lo(.got.plt entry) */ + 0x03200009 /* jr $25 */ +}; + /* The format of subsequent MIPS16 o32 PLT entries. We use v0 ($2) and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not directly addressable. */ @@ -2163,7 +2193,8 @@ hi16_reloc_p (int r_type) { return (r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16 - || r_type == R_MICROMIPS_HI16); + || r_type == R_MICROMIPS_HI16 + || r_type == R_MIPS_PCHI16); } static inline bfd_boolean @@ -2171,7 +2202,8 @@ lo16_reloc_p (int r_type) { return (r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16 - || r_type == R_MICROMIPS_LO16); + || r_type == R_MICROMIPS_LO16 + || r_type == R_MIPS_PCLO16); } static inline bfd_boolean @@ -2189,6 +2221,13 @@ jal_reloc_p (int r_type) } static inline bfd_boolean +aligned_pcrel_reloc_p (int r_type) +{ + return (r_type == R_MIPS_PC18_S3 + || r_type == R_MIPS_PC19_S2); +} + +static inline bfd_boolean micromips_branch_reloc_p (int r_type) { return (r_type == R_MICROMIPS_26_S1 @@ -2659,6 +2698,46 @@ bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in, H_PUT_16 (abfd, in->section, ex->section); H_PUT_32 (abfd, in->info, ex->info); } + +/* Swap in an abiflags structure. */ + +void +bfd_mips_elf_swap_abiflags_v0_in (bfd *abfd, + const Elf_External_ABIFlags_v0 *ex, + Elf_Internal_ABIFlags_v0 *in) +{ + in->version = H_GET_16 (abfd, ex->version); + in->isa_level = H_GET_8 (abfd, ex->isa_level); + in->isa_rev = H_GET_8 (abfd, ex->isa_rev); + in->gpr_size = H_GET_8 (abfd, ex->gpr_size); + in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size); + in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size); + in->fp_abi = H_GET_8 (abfd, ex->fp_abi); + in->isa_ext = H_GET_32 (abfd, ex->isa_ext); + in->ases = H_GET_32 (abfd, ex->ases); + in->flags1 = H_GET_32 (abfd, ex->flags1); + in->flags2 = H_GET_32 (abfd, ex->flags2); +} + +/* Swap out an abiflags structure. */ + +void +bfd_mips_elf_swap_abiflags_v0_out (bfd *abfd, + const Elf_Internal_ABIFlags_v0 *in, + Elf_External_ABIFlags_v0 *ex) +{ + H_PUT_16 (abfd, in->version, ex->version); + H_PUT_8 (abfd, in->isa_level, ex->isa_level); + H_PUT_8 (abfd, in->isa_rev, ex->isa_rev); + H_PUT_8 (abfd, in->gpr_size, ex->gpr_size); + H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size); + H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size); + H_PUT_8 (abfd, in->fp_abi, ex->fp_abi); + H_PUT_32 (abfd, in->isa_ext, ex->isa_ext); + H_PUT_32 (abfd, in->ases, ex->ases); + H_PUT_32 (abfd, in->flags1, ex->flags1); + H_PUT_32 (abfd, in->flags2, ex->flags2); +} /* This function is called via qsort() to sort the dynamic relocation entries by increasing r_symndx value. */ @@ -3632,7 +3711,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, if (entry) return entry; - if (g->assigned_gotno >= g->local_gotno) + if (g->assigned_low_gotno > g->assigned_high_gotno) { /* We didn't allocate enough space in the GOT. */ (*_bfd_error_handler) @@ -3645,7 +3724,14 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, if (!entry) return NULL; - lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; + if (got16_reloc_p (r_type) + || call16_reloc_p (r_type) + || got_page_reloc_p (r_type) + || got_disp_reloc_p (r_type)) + lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_low_gotno++; + else + lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_high_gotno--; + *entry = lookup; *loc = entry; @@ -4086,9 +4172,10 @@ mips_elf_pages_for_range (const struct mips_got_page_range *range) /* Record that G requires a page entry that can reach SEC + ADDEND. */ static bfd_boolean -mips_elf_record_got_page_entry (struct mips_got_info *g, +mips_elf_record_got_page_entry (struct mips_elf_traverse_got_arg *arg, asection *sec, bfd_signed_vma addend) { + struct mips_got_info *g = arg->g; struct mips_got_page_entry lookup, *entry; struct mips_got_page_range **range_ptr, *range; bfd_vma old_pages, new_pages; @@ -4105,7 +4192,7 @@ mips_elf_record_got_page_entry (struct mips_got_info *g, entry = (struct mips_got_page_entry *) *loc; if (!entry) { - entry = bfd_zalloc (sec->owner, sizeof (*entry)); + entry = bfd_zalloc (arg->info->output_bfd, sizeof (*entry)); if (!entry) return FALSE; @@ -4125,7 +4212,7 @@ mips_elf_record_got_page_entry (struct mips_got_info *g, range = *range_ptr; if (!range || addend < range->min_addend - 0xffff) { - range = bfd_zalloc (sec->owner, sizeof (*range)); + range = bfd_zalloc (arg->info->output_bfd, sizeof (*range)); if (!range) return FALSE; @@ -4245,7 +4332,7 @@ mips_elf_resolve_got_page_ref (void **refp, void *data) else addend = isym->st_value + ref->addend; } - if (!mips_elf_record_got_page_entry (arg->g, sec, addend)) + if (!mips_elf_record_got_page_entry (arg, sec, addend)) { arg->g = NULL; return 0; @@ -4299,6 +4386,36 @@ mips_elf_resolve_final_got_entries (struct bfd_link_info *info, return TRUE; } +/* Return true if a GOT entry for H should live in the local rather than + global GOT area. */ + +static bfd_boolean +mips_use_local_got_p (struct bfd_link_info *info, + struct mips_elf_link_hash_entry *h) +{ + /* Symbols that aren't in the dynamic symbol table must live in the + local GOT. This includes symbols that are completely undefined + and which therefore don't bind locally. We'll report undefined + symbols later if appropriate. */ + if (h->root.dynindx == -1) + return TRUE; + + /* Symbols that bind locally can (and in the case of forced-local + symbols, must) live in the local GOT. */ + if (h->got_only_for_calls + ? SYMBOL_CALLS_LOCAL (info, &h->root) + : SYMBOL_REFERENCES_LOCAL (info, &h->root)) + return TRUE; + + /* If this is an executable that must provide a definition of the symbol, + either though PLTs or copy relocations, then that address should go in + the local rather than global GOT. */ + if (info->executable && h->has_static_relocs) + return TRUE; + + return FALSE; +} + /* A mips_elf_link_hash_traverse callback for which DATA points to the link_info structure. Decide whether the hash entry needs an entry in the global part of the primary GOT, setting global_got_area accordingly. @@ -4318,18 +4435,8 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) if (h->global_got_area != GGA_NONE) { /* Make a final decision about whether the symbol belongs in the - local or global GOT. Symbols that bind locally can (and in the - case of forced-local symbols, must) live in the local GOT. - Those that are aren't in the dynamic symbol table must also - live in the local GOT. - - Note that the former condition does not always imply the - latter: symbols do not bind locally if they are completely - undefined. We'll report undefined symbols later if appropriate. */ - if (h->root.dynindx == -1 - || (h->got_only_for_calls - ? SYMBOL_CALLS_LOCAL (info, &h->root) - : SYMBOL_REFERENCES_LOCAL (info, &h->root))) + local or global GOT. */ + if (mips_use_local_got_p (info, h)) /* The symbol belongs in the local GOT. We no longer need this entry if it was only used for relocations; those relocations will be against the null or section symbol instead of H. */ @@ -4604,12 +4711,12 @@ mips_elf_set_global_gotidx (void **entryp, void *data) && entry->symndx == -1 && entry->d.h->global_got_area != GGA_NONE) { - if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_gotno)) + if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_low_gotno)) { arg->g = NULL; return 0; } - arg->g->assigned_gotno += 1; + arg->g->assigned_low_gotno += 1; if (arg->info->shared || (elf_hash_table (arg->info)->dynamic_sections_created @@ -4742,7 +4849,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, htab_traverse (g->got_entries, mips_elf_set_global_got_area, &tga); /* Now go through the GOTs assigning them offset ranges. - [assigned_gotno, local_gotno[ will be set to the range of local + [assigned_low_gotno, local_gotno[ will be set to the range of local entries in each GOT. We can then compute the end of a GOT by adding local_gotno to global_gotno. We reverse the list and make it circular since then we'll be able to quickly compute the @@ -4765,9 +4872,10 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, struct mips_got_info *gn; assign += htab->reserved_gotno; - g->assigned_gotno = assign; + g->assigned_low_gotno = assign; g->local_gotno += assign; g->local_gotno += (pages < g->page_gotno ? pages : g->page_gotno); + g->assigned_high_gotno = g->local_gotno - 1; assign = g->local_gotno + g->global_gotno + g->tls_gotno; /* Take g out of the direct list, and push it onto the reversed @@ -4806,21 +4914,21 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, /* Assign offsets to global GOT entries and count how many relocations they need. */ - save_assign = g->assigned_gotno; - g->assigned_gotno = g->local_gotno; + save_assign = g->assigned_low_gotno; + g->assigned_low_gotno = g->local_gotno; tga.info = info; tga.value = MIPS_ELF_GOT_SIZE (abfd); tga.g = g; htab_traverse (g->got_entries, mips_elf_set_global_gotidx, &tga); if (!tga.g) return FALSE; - BFD_ASSERT (g->assigned_gotno == g->local_gotno + g->global_gotno); - g->assigned_gotno = save_assign; + BFD_ASSERT (g->assigned_low_gotno == g->local_gotno + g->global_gotno); + g->assigned_low_gotno = save_assign; if (info->shared) { - g->relocs += g->local_gotno - g->assigned_gotno; - BFD_ASSERT (g->assigned_gotno == g->next->local_gotno + g->relocs += g->local_gotno - g->assigned_low_gotno; + BFD_ASSERT (g->assigned_low_gotno == g->next->local_gotno + g->next->global_gotno + g->next->tls_gotno + htab->reserved_gotno); @@ -5075,6 +5183,8 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type, { case R_MIPS_26: case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: case R_MICROMIPS_26_S1: case R_MICROMIPS_PC7_S1: case R_MICROMIPS_PC10_S1: @@ -5468,10 +5578,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, && (target_is_16_bit_code_p || target_is_micromips_code_p)))); - local_p = (h == NULL - || (h->got_only_for_calls - ? SYMBOL_CALLS_LOCAL (info, &h->root) - : SYMBOL_REFERENCES_LOCAL (info, &h->root))); + local_p = (h == NULL || mips_use_local_got_p (info, h)); gp0 = _bfd_get_gp_value (input_bfd); gp = _bfd_get_gp_value (abfd); @@ -5862,12 +5969,74 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, case R_MIPS_PC16: case R_MIPS_GNU_REL16_S2: - value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p; + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 18); + value = symbol + addend - p; overflowed_p = mips_elf_overflow_p (value, 18); value >>= howto->rightshift; value &= howto->dst_mask; break; + case R_MIPS_PC21_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 23); + value = symbol + addend - p; + overflowed_p = mips_elf_overflow_p (value, 23); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC26_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 28); + value = symbol + addend - p; + overflowed_p = mips_elf_overflow_p (value, 28); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC18_S3: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 21); + + if ((symbol + addend) & 7) + return bfd_reloc_outofrange; + + value = symbol + addend - ((p | 7) ^ 7); + overflowed_p = mips_elf_overflow_p (value, 21); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC19_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 21); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + overflowed_p = mips_elf_overflow_p (value, 21); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PCHI16: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 16); + value = mips_elf_high (symbol + addend - p); + BFD_ASSERT (howto->rightshift == 16); + overflowed_p = mips_elf_overflow_p (value, 16); + value &= howto->dst_mask; + break; + + case R_MIPS_PCLO16: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 16); + value = symbol + _bfd_mips_elf_sign_extend (addend, 16) - p; + value &= howto->dst_mask; + break; + case R_MICROMIPS_PC7_S1: value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p; overflowed_p = mips_elf_overflow_p (value, 8); @@ -6434,6 +6603,12 @@ _bfd_elf_mips_mach (flagword flags) case E_MIPS_ARCH_64R2: return bfd_mach_mipsisa64r2; + + case E_MIPS_ARCH_32R6: + return bfd_mach_mipsisa32r6; + + case E_MIPS_ARCH_64R6: + return bfd_mach_mipsisa64r6; } } @@ -6879,6 +7054,11 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name)) return FALSE; break; + case SHT_MIPS_ABIFLAGS: + if (!MIPS_ELF_ABIFLAGS_SECTION_NAME_P (name)) + return FALSE; + flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE); + break; case SHT_MIPS_DWARF: if (! CONST_STRNEQ (name, ".debug_") && ! CONST_STRNEQ (name, ".zdebug_")) @@ -6909,6 +7089,20 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, return FALSE; } + if (hdr->sh_type == SHT_MIPS_ABIFLAGS) + { + Elf_External_ABIFlags_v0 ext; + + if (! bfd_get_section_contents (abfd, hdr->bfd_section, + &ext, 0, sizeof ext)) + return FALSE; + bfd_mips_elf_swap_abiflags_v0_in (abfd, &ext, + &mips_elf_tdata (abfd)->abiflags); + if (mips_elf_tdata (abfd)->abiflags.version != 0) + return FALSE; + mips_elf_tdata (abfd)->abiflags_valid = TRUE; + } + /* FIXME: We should record sh_info for a .gptab section. */ /* For a .reginfo section, set the gp value in the tdata information @@ -7075,6 +7269,11 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) hdr->sh_entsize = 1; hdr->sh_flags |= SHF_MIPS_NOSTRIP; } + else if (CONST_STRNEQ (name, ".MIPS.abiflags")) + { + hdr->sh_type = SHT_MIPS_ABIFLAGS; + hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0); + } else if (CONST_STRNEQ (name, ".debug_") || CONST_STRNEQ (name, ".zdebug_")) { @@ -7586,6 +7785,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd, lo16_type = R_MIPS16_LO16; else if (micromips_reloc_p (r_type)) lo16_type = R_MICROMIPS_LO16; + else if (r_type == R_MIPS_PCHI16) + lo16_type = R_MIPS_PCLO16; else lo16_type = R_MIPS_LO16; @@ -7955,6 +8156,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, unsigned int r_type; struct elf_link_hash_entry *h; bfd_boolean can_make_dynamic_p; + bfd_boolean call_reloc_p; + bfd_boolean constrain_symbol_p; r_symndx = ELF_R_SYM (abfd, rel->r_info); r_type = ELF_R_TYPE (abfd, rel->r_info); @@ -7987,12 +8190,30 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this relocation into a dynamic one. */ can_make_dynamic_p = FALSE; + + /* Set CALL_RELOC_P to true if the relocation is for a call, + and if pointer equality therefore doesn't matter. */ + call_reloc_p = FALSE; + + /* Set CONSTRAIN_SYMBOL_P if we need to take the relocation + into account when deciding how to define the symbol. + Relocations in nonallocatable sections such as .pdr and + .debug* should have no effect. */ + constrain_symbol_p = ((sec->flags & SEC_ALLOC) != 0); + switch (r_type) { - case R_MIPS_GOT16: case R_MIPS_CALL16: case R_MIPS_CALL_HI16: case R_MIPS_CALL_LO16: + case R_MIPS16_CALL16: + case R_MICROMIPS_CALL16: + case R_MICROMIPS_CALL_HI16: + case R_MICROMIPS_CALL_LO16: + call_reloc_p = TRUE; + /* Fall through. */ + + case R_MIPS_GOT16: case R_MIPS_GOT_HI16: case R_MIPS_GOT_LO16: case R_MIPS_GOT_PAGE: @@ -8002,14 +8223,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: case R_MIPS16_GOT16: - case R_MIPS16_CALL16: case R_MIPS16_TLS_GOTTPREL: case R_MIPS16_TLS_GD: case R_MIPS16_TLS_LDM: case R_MICROMIPS_GOT16: - case R_MICROMIPS_CALL16: - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_CALL_LO16: case R_MICROMIPS_GOT_HI16: case R_MICROMIPS_GOT_LO16: case R_MICROMIPS_GOT_PAGE: @@ -8030,12 +8247,27 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, bfd_set_error (bfd_error_bad_value); return FALSE; } + can_make_dynamic_p = TRUE; break; - /* This is just a hint; it can safely be ignored. Don't set - has_static_relocs for the corresponding symbol. */ + case R_MIPS_NONE: case R_MIPS_JALR: case R_MICROMIPS_JALR: + /* These relocations have empty fields and are purely there to + provide link information. The symbol value doesn't matter. */ + constrain_symbol_p = FALSE; + break; + + case R_MIPS_GPREL16: + case R_MIPS_GPREL32: + case R_MIPS16_GPREL: + case R_MICROMIPS_GPREL16: + /* GP-relative relocations always resolve to a definition in a + regular input file, ignoring the one-definition rule. This is + important for the GP setup sequence in NewABI code, which + always resolves to a local function even if other relocations + against the symbol wouldn't. */ + constrain_symbol_p = FALSE; break; case R_MIPS_32: @@ -8062,51 +8294,41 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, can_make_dynamic_p = TRUE; if (dynobj == NULL) elf_hash_table (info)->dynobj = dynobj = abfd; - break; } - /* For sections that are not SEC_ALLOC a copy reloc would be - output if possible (implying questionable semantics for - read-only data objects) or otherwise the final link would - fail as ld.so will not process them and could not therefore - handle any outstanding dynamic relocations. - - For such sections that are also SEC_DEBUGGING, we can avoid - these problems by simply ignoring any relocs as these - sections have a predefined use and we know it is safe to do - so. - - This is needed in cases such as a global symbol definition - in a shared library causing a common symbol from an object - file to be converted to an undefined reference. If that - happens, then all the relocations against this symbol from - SEC_DEBUGGING sections in the object file will resolve to - nil. */ - if ((sec->flags & SEC_DEBUGGING) != 0) - break; - /* Fall through. */ - - default: - /* Most static relocations require pointer equality, except - for branches. */ - if (h) - h->pointer_equality_needed = TRUE; - /* Fall through. */ + break; case R_MIPS_26: case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: case R_MIPS16_26: case R_MICROMIPS_26_S1: case R_MICROMIPS_PC7_S1: case R_MICROMIPS_PC10_S1: case R_MICROMIPS_PC16_S1: case R_MICROMIPS_PC23_S2: - if (h) - ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE; + call_reloc_p = TRUE; break; } if (h) { + if (constrain_symbol_p) + { + if (!can_make_dynamic_p) + ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = 1; + + if (!call_reloc_p) + h->pointer_equality_needed = 1; + + /* We must not create a stub for a symbol that has + relocations related to taking the function's address. + This doesn't apply to VxWorks, where CALL relocs refer + to a .got.plt entry instead of a normal .got entry. */ + if (!htab->is_vxworks && (!can_make_dynamic_p || !call_reloc_p)) + ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE; + } + /* Relocations against the special VxWorks __GOTT_BASE__ and __GOTT_INDEX__ symbols must be left to the loader. Allocate room for them in .rela.dyn. */ @@ -8387,28 +8609,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h->plt.plist->need_comp = TRUE; } - /* We must not create a stub for a symbol that has relocations - related to taking the function's address. This doesn't apply to - VxWorks, where CALL relocs refer to a .got.plt entry instead of - a normal .got entry. */ - if (!htab->is_vxworks && h != NULL) - switch (r_type) - { - default: - ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE; - break; - case R_MIPS16_CALL16: - case R_MIPS_CALL16: - case R_MIPS_CALL_HI16: - case R_MIPS_CALL_LO16: - case R_MIPS_JALR: - case R_MICROMIPS_CALL16: - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_JALR: - break; - } - /* See if this reloc would need to refer to a MIPS16 hard-float stub, if there is one. We only need to handle global symbols here; we decide whether to keep or delete stubs for local symbols @@ -8997,7 +9197,7 @@ bfd_boolean _bfd_mips_elf_always_size_sections (bfd *output_bfd, struct bfd_link_info *info) { - asection *ri; + asection *sect; struct mips_elf_link_hash_table *htab; struct mips_htab_traverse_info hti; @@ -9005,9 +9205,14 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd, BFD_ASSERT (htab != NULL); /* The .reginfo section has a fixed size. */ - ri = bfd_get_section_by_name (output_bfd, ".reginfo"); - if (ri != NULL) - bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo)); + sect = bfd_get_section_by_name (output_bfd, ".reginfo"); + if (sect != NULL) + bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo)); + + /* The .MIPS.abiflags section has a fixed size. */ + sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags"); + if (sect != NULL) + bfd_set_section_size (output_bfd, sect, sizeof (Elf_External_ABIFlags_v0)); hti.info = info; hti.output_bfd = output_bfd; @@ -9046,13 +9251,13 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) /* Allocate room for the reserved entries. VxWorks always reserves 3 entries; other objects only reserve 2 entries. */ - BFD_ASSERT (g->assigned_gotno == 0); + BFD_ASSERT (g->assigned_low_gotno == 0); if (htab->is_vxworks) htab->reserved_gotno = 3; else htab->reserved_gotno = 2; g->local_gotno += htab->reserved_gotno; - g->assigned_gotno = htab->reserved_gotno; + g->assigned_low_gotno = htab->reserved_gotno; /* Decide which symbols need to go in the global part of the GOT and count the number of reloc-only GOT symbols. */ @@ -9095,6 +9300,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) page_gotno = g->page_gotno; g->local_gotno += page_gotno; + g->assigned_high_gotno = g->local_gotno - 1; s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd); s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd); @@ -10019,6 +10225,13 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, (info, msg, name, input_bfd, input_section, rel->r_offset); return FALSE; } + if (aligned_pcrel_reloc_p (howto->type)) + { + msg = _("PC-relative load from unaligned address"); + info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + return FALSE; + } /* Fall through. */ default: @@ -10308,7 +10521,11 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, load = MIPS_ELF_LOAD_WORD (output_bfd); /* Fill in the PLT entry itself. */ - plt_entry = mips_exec_plt_entry; + + if (MIPSR6_P (output_bfd)) + plt_entry = mipsr6_exec_plt_entry; + else + plt_entry = mips_exec_plt_entry; bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc); bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load, loc + 4); @@ -11369,10 +11586,14 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, if (! info->shared) continue; - while (got_index < g->assigned_gotno) + for (; got_index < g->local_gotno; got_index++) { + if (got_index >= g->assigned_low_gotno + && got_index <= g->assigned_high_gotno) + continue; + rel[0].r_offset = rel[1].r_offset = rel[2].r_offset - = got_index++ * MIPS_ELF_GOT_SIZE (output_bfd); + = got_index * MIPS_ELF_GOT_SIZE (output_bfd); if (!(mips_elf_create_dynamic_relocation (output_bfd, info, rel, NULL, bfd_abs_section_ptr, @@ -11606,7 +11827,7 @@ mips_set_isa_flags (bfd *abfd) break; case bfd_mach_mips_loongson_3a: - val = E_MIPS_ARCH_64 | E_MIPS_MACH_LS3A; + val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_LS3A; break; case bfd_mach_mips_octeon: @@ -11631,12 +11852,24 @@ mips_set_isa_flags (bfd *abfd) break; case bfd_mach_mipsisa32r2: + case bfd_mach_mipsisa32r3: + case bfd_mach_mipsisa32r5: val = E_MIPS_ARCH_32R2; break; case bfd_mach_mipsisa64r2: + case bfd_mach_mipsisa64r3: + case bfd_mach_mipsisa64r5: val = E_MIPS_ARCH_64R2; break; + + case bfd_mach_mipsisa32r6: + val = E_MIPS_ARCH_32R6; + break; + + case bfd_mach_mipsisa64r6: + val = E_MIPS_ARCH_64R6; + break; } elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); elf_elfheader (abfd)->e_flags |= val; @@ -11745,6 +11978,10 @@ _bfd_mips_elf_additional_program_headers (bfd *abfd, if (s && (s->flags & SEC_LOAD)) ++ret; + /* See if we need a PT_MIPS_ABIFLAGS segment. */ + if (bfd_get_section_by_name (abfd, ".MIPS.abiflags")) + ++ret; + /* See if we need a PT_MIPS_OPTIONS segment. */ if (IRIX_COMPAT (abfd) == ict_irix6 && bfd_get_section_by_name (abfd, @@ -11807,6 +12044,37 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, } } + /* If there is a .MIPS.abiflags section, we need a PT_MIPS_ABIFLAGS + segment. */ + s = bfd_get_section_by_name (abfd, ".MIPS.abiflags"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + for (m = elf_seg_map (abfd); m != NULL; m = m->next) + if (m->p_type == PT_MIPS_ABIFLAGS) + break; + if (m == NULL) + { + amt = sizeof *m; + m = bfd_zalloc (abfd, amt); + if (m == NULL) + return FALSE; + + m->p_type = PT_MIPS_ABIFLAGS; + m->count = 1; + m->sections[0] = s; + + /* We want to put it after the PHDR and INTERP segments. */ + pm = &elf_seg_map (abfd); + while (*pm != NULL + && ((*pm)->p_type == PT_PHDR + || (*pm)->p_type == PT_INTERP)) + pm = &(*pm)->next; + + m->next = *pm; + *pm = m; + } + } + /* For IRIX 6, we don't have .mdebug sections, nor does anything but .dynamic end up in PT_DYNAMIC. However, we do have to insert a PT_MIPS_OPTIONS segment immediately following the program header @@ -11901,18 +12169,6 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, if ((*pm)->p_type == PT_DYNAMIC) break; m = *pm; - if (m != NULL && IRIX_COMPAT (abfd) == ict_none) - { - /* For a normal mips executable the permissions for the PT_DYNAMIC - segment are read, write and execute. We do that here since - the code in elf.c sets only the read permission. This matters - sometimes for the dynamic linker. */ - if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) - { - m->p_flags = PF_R | PF_W | PF_X; - m->p_flags_valid = 1; - } - } /* GNU/Linux binaries do not need the extended PT_DYNAMIC section. glibc's dynamic linker has traditionally derived the number of tags from the p_filesz field, and sometimes allocates stack @@ -12102,6 +12358,36 @@ _bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } + +/* Prevent .MIPS.abiflags from being discarded with --gc-sections. */ + +bfd_boolean +_bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info, + elf_gc_mark_hook_fn gc_mark_hook) +{ + bfd *sub; + + _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); + + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + if (! is_mips_elf (sub)) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + if (!o->gc_mark + && MIPS_ELF_ABIFLAGS_SECTION_NAME_P + (bfd_get_section_name (sub, o))) + { + if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + } + } + + return TRUE; +} /* Copy data from a MIPS ELF indirect symbol to its direct symbol, hiding the old indirect symbol. Process additional relocation @@ -13552,6 +13838,177 @@ _bfd_mips_elf_insn32 (struct bfd_link_info *info, bfd_boolean on) mips_elf_hash_table (info)->insn32 = on; } +/* Return the .MIPS.abiflags value representing each ISA Extension. */ + +unsigned int +bfd_mips_isa_ext (bfd *abfd) +{ + switch (bfd_get_mach (abfd)) + { + case bfd_mach_mips3900: + return AFL_EXT_3900; + case bfd_mach_mips4010: + return AFL_EXT_4010; + case bfd_mach_mips4100: + return AFL_EXT_4100; + case bfd_mach_mips4111: + return AFL_EXT_4111; + case bfd_mach_mips4120: + return AFL_EXT_4120; + case bfd_mach_mips4650: + return AFL_EXT_4650; + case bfd_mach_mips5400: + return AFL_EXT_5400; + case bfd_mach_mips5500: + return AFL_EXT_5500; + case bfd_mach_mips5900: + return AFL_EXT_5900; + case bfd_mach_mips10000: + return AFL_EXT_10000; + case bfd_mach_mips_loongson_2e: + return AFL_EXT_LOONGSON_2E; + case bfd_mach_mips_loongson_2f: + return AFL_EXT_LOONGSON_2F; + case bfd_mach_mips_loongson_3a: + return AFL_EXT_LOONGSON_3A; + case bfd_mach_mips_sb1: + return AFL_EXT_SB1; + case bfd_mach_mips_octeon: + return AFL_EXT_OCTEON; + case bfd_mach_mips_octeonp: + return AFL_EXT_OCTEONP; + case bfd_mach_mips_octeon2: + return AFL_EXT_OCTEON2; + case bfd_mach_mips_xlr: + return AFL_EXT_XLR; + } + return 0; +} + +/* Update the isa_level, isa_rev, isa_ext fields of abiflags. */ + +static void +update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags) +{ + switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) + { + case E_MIPS_ARCH_1: + abiflags->isa_level = 1; + abiflags->isa_rev = 0; + break; + case E_MIPS_ARCH_2: + abiflags->isa_level = 2; + abiflags->isa_rev = 0; + break; + case E_MIPS_ARCH_3: + abiflags->isa_level = 3; + abiflags->isa_rev = 0; + break; + case E_MIPS_ARCH_4: + abiflags->isa_level = 4; + abiflags->isa_rev = 0; + break; + case E_MIPS_ARCH_5: + abiflags->isa_level = 5; + abiflags->isa_rev = 0; + break; + case E_MIPS_ARCH_32: + abiflags->isa_level = 32; + abiflags->isa_rev = 1; + break; + case E_MIPS_ARCH_32R2: + abiflags->isa_level = 32; + /* Handle MIPS32r3 and MIPS32r5 which do not have a header flag. */ + if (abiflags->isa_rev < 2) + abiflags->isa_rev = 2; + break; + case E_MIPS_ARCH_32R6: + abiflags->isa_level = 32; + abiflags->isa_rev = 6; + break; + case E_MIPS_ARCH_64: + abiflags->isa_level = 64; + abiflags->isa_rev = 1; + break; + case E_MIPS_ARCH_64R2: + /* Handle MIPS64r3 and MIPS64r5 which do not have a header flag. */ + abiflags->isa_level = 64; + if (abiflags->isa_rev < 2) + abiflags->isa_rev = 2; + break; + case E_MIPS_ARCH_64R6: + abiflags->isa_level = 64; + abiflags->isa_rev = 6; + break; + default: + (*_bfd_error_handler) + (_("%B: Unknown architecture %s"), + abfd, bfd_printable_name (abfd)); + } + + abiflags->isa_ext = bfd_mips_isa_ext (abfd); +} + +/* Return true if the given ELF header flags describe a 32-bit binary. */ + +static bfd_boolean +mips_32bit_flags_p (flagword flags) +{ + return ((flags & EF_MIPS_32BITMODE) != 0 + || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32 + || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6); +} + +/* Infer the content of the ABI flags based on the elf header. */ + +static void +infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags) +{ + obj_attribute *in_attr; + + memset (abiflags, 0, sizeof (Elf_Internal_ABIFlags_v0)); + update_mips_abiflags_isa (abfd, abiflags); + + if (mips_32bit_flags_p (elf_elfheader (abfd)->e_flags)) + abiflags->gpr_size = AFL_REG_32; + else + abiflags->gpr_size = AFL_REG_64; + + abiflags->cpr1_size = AFL_REG_NONE; + + in_attr = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU]; + abiflags->fp_abi = in_attr[Tag_GNU_MIPS_ABI_FP].i; + + if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_SINGLE + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_XX + || (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE + && abiflags->gpr_size == AFL_REG_32)) + abiflags->cpr1_size = AFL_REG_32; + else if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64 + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64A) + abiflags->cpr1_size = AFL_REG_64; + + abiflags->cpr2_size = AFL_REG_NONE; + + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MDMX) + abiflags->ases |= AFL_ASE_MDMX; + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16) + abiflags->ases |= AFL_ASE_MIPS16; + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) + abiflags->ases |= AFL_ASE_MICROMIPS; + + if (abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_ANY + && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT + && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A) + abiflags->flags1 |= AFL_FLAGS1_ODDSPREG; +} + /* We need to use a special link routine to handle the .reginfo and the .mdebug sections. We need to merge all instances of these sections together, not write them all out sequentially. */ @@ -13562,7 +14019,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) asection *o; struct bfd_link_order *p; asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; - asection *rtproc_sec; + asection *rtproc_sec, *abiflags_sec; Elf32_RegInfo reginfo; struct ecoff_debug_info debug; struct mips_htab_traverse_info hti; @@ -13644,12 +14101,46 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Go through the sections and collect the .reginfo and .mdebug information. */ + abiflags_sec = NULL; reginfo_sec = NULL; mdebug_sec = NULL; gptab_data_sec = NULL; gptab_bss_sec = NULL; for (o = abfd->sections; o != NULL; o = o->next) { + if (strcmp (o->name, ".MIPS.abiflags") == 0) + { + /* We have found the .MIPS.abiflags section in the output file. + Look through all the link_orders comprising it and remove them. + The data is merged in _bfd_mips_elf_merge_private_bfd_data. */ + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + asection *input_section; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_data_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &= ~SEC_HAS_CONTENTS; + } + + /* Size has been set in _bfd_mips_elf_always_size_sections. */ + BFD_ASSERT(o->size == sizeof (Elf_External_ABIFlags_v0)); + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->map_head.link_order = NULL; + + abiflags_sec = o; + } + if (strcmp (o->name, ".reginfo") == 0) { memset (®info, 0, sizeof reginfo); @@ -14134,6 +14625,24 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Now write out the computed sections. */ + if (abiflags_sec != NULL) + { + Elf_External_ABIFlags_v0 ext; + Elf_Internal_ABIFlags_v0 *abiflags; + + abiflags = &mips_elf_tdata (abfd)->abiflags; + + /* Set up the abiflags if no valid input sections were found. */ + if (!mips_elf_tdata (abfd)->abiflags_valid) + { + infer_mips_abiflags (abfd, abiflags); + mips_elf_tdata (abfd)->abiflags_valid = TRUE; + } + bfd_mips_elf_swap_abiflags_v0_out (abfd, abiflags, &ext); + if (! bfd_set_section_contents (abfd, abiflags_sec, &ext, 0, sizeof ext)) + return FALSE; + } + if (reginfo_sec != NULL) { Elf32_External_RegInfo ext; @@ -14202,12 +14711,12 @@ static const struct mips_mach_extension mips_mach_extensions[] = { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp }, { bfd_mach_mips_octeonp, bfd_mach_mips_octeon }, { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 }, + { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64r2 }, /* MIPS64 extensions. */ { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 }, { bfd_mach_mips_sb1, bfd_mach_mipsisa64 }, { bfd_mach_mips_xlr, bfd_mach_mipsisa64 }, - { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64 }, /* MIPS V extensions. */ { bfd_mach_mipsisa64, bfd_mach_mips5 }, @@ -14291,21 +14800,6 @@ mips_mach_extends_p (unsigned long base, unsigned long extension) } -/* Return true if the given ELF header flags describe a 32-bit binary. */ - -static bfd_boolean -mips_32bit_flags_p (flagword flags) -{ - return ((flags & EF_MIPS_32BITMODE) != 0 - || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32 - || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2); -} - - /* Merge object attributes from IBFD into OBFD. Raise an error if there are conflicting attributes. */ static bfd_boolean @@ -14314,12 +14808,18 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) obj_attribute *in_attr; obj_attribute *out_attr; bfd *abi_fp_bfd; + bfd *abi_msa_bfd; abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd; in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY) mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + abi_msa_bfd = mips_elf_tdata (obfd)->abi_msa_bfd; + if (!abi_msa_bfd + && in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY) + mips_elf_tdata (obfd)->abi_msa_bfd = ibfd; + if (!elf_known_obj_attributes_proc (obfd)[0].i) { /* This is the first object. Copy the attributes. */ @@ -14337,175 +14837,111 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i) { - out_attr[Tag_GNU_MIPS_ABI_FP].type = 1; - if (out_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY) - out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; - else if (in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY) - switch (out_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case Val_GNU_MIPS_ABI_FP_DOUBLE: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case Val_GNU_MIPS_ABI_FP_SINGLE: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mdouble-float", "-msingle-float"); - break; + int out_fp, in_fp; - case Val_GNU_MIPS_ABI_FP_SOFT: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float"); - break; - - case Val_GNU_MIPS_ABI_FP_64: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-mdouble-float", "-mips32r2 -mfp64"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-mdouble-float", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } - break; - - case Val_GNU_MIPS_ABI_FP_SINGLE: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case Val_GNU_MIPS_ABI_FP_DOUBLE: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-msingle-float", "-mdouble-float"); - break; - - case Val_GNU_MIPS_ABI_FP_SOFT: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float"); - break; - - case Val_GNU_MIPS_ABI_FP_64: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-msingle-float", "-mips32r2 -mfp64"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-msingle-float", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } - break; - - case Val_GNU_MIPS_ABI_FP_SOFT: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case Val_GNU_MIPS_ABI_FP_DOUBLE: - case Val_GNU_MIPS_ABI_FP_SINGLE: - case Val_GNU_MIPS_ABI_FP_64: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-msoft-float", "-mhard-float"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-msoft-float", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } - break; - - case Val_GNU_MIPS_ABI_FP_64: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case Val_GNU_MIPS_ABI_FP_DOUBLE: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-mips32r2 -mfp64", "-mdouble-float"); - break; - - case Val_GNU_MIPS_ABI_FP_SINGLE: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-mips32r2 -mfp64", "-msingle-float"); - break; - - case Val_GNU_MIPS_ABI_FP_SOFT: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float"); - break; + out_fp = out_attr[Tag_GNU_MIPS_ABI_FP].i; + in_fp = in_attr[Tag_GNU_MIPS_ABI_FP].i; + out_attr[Tag_GNU_MIPS_ABI_FP].type = 1; + if (out_fp == Val_GNU_MIPS_ABI_FP_ANY) + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_fp; + else if (out_fp == Val_GNU_MIPS_ABI_FP_XX + && (in_fp == Val_GNU_MIPS_ABI_FP_DOUBLE + || in_fp == Val_GNU_MIPS_ABI_FP_64 + || in_fp == Val_GNU_MIPS_ABI_FP_64A)) + { + mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; + } + else if (in_fp == Val_GNU_MIPS_ABI_FP_XX + && (out_fp == Val_GNU_MIPS_ABI_FP_DOUBLE + || out_fp == Val_GNU_MIPS_ABI_FP_64 + || out_fp == Val_GNU_MIPS_ABI_FP_64A)) + /* Keep the current setting. */; + else if (out_fp == Val_GNU_MIPS_ABI_FP_64A + && in_fp == Val_GNU_MIPS_ABI_FP_64) + { + mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; + } + else if (in_fp == Val_GNU_MIPS_ABI_FP_64A + && out_fp == Val_GNU_MIPS_ABI_FP_64) + /* Keep the current setting. */; + else if (in_fp != Val_GNU_MIPS_ABI_FP_ANY) + { + const char *out_string, *in_string; + + out_string = _bfd_mips_fp_abi_string (out_fp); + in_string = _bfd_mips_fp_abi_string (in_fp); + /* First warn about cases involving unrecognised ABIs. */ + if (!out_string && !in_string) + _bfd_error_handler + (_("Warning: %B uses unknown floating point ABI %d " + "(set by %B), %B uses unknown floating point ABI %d"), + obfd, abi_fp_bfd, ibfd, out_fp, in_fp); + else if (!out_string) + _bfd_error_handler + (_("Warning: %B uses unknown floating point ABI %d " + "(set by %B), %B uses %s"), + obfd, abi_fp_bfd, ibfd, out_fp, in_string); + else if (!in_string) + _bfd_error_handler + (_("Warning: %B uses %s (set by %B), " + "%B uses unknown floating point ABI %d"), + obfd, abi_fp_bfd, ibfd, out_string, in_fp); + else + { + /* If one of the bfds is soft-float, the other must be + hard-float. The exact choice of hard-float ABI isn't + really relevant to the error message. */ + if (in_fp == Val_GNU_MIPS_ABI_FP_SOFT) + out_string = "-mhard-float"; + else if (out_fp == Val_GNU_MIPS_ABI_FP_SOFT) + in_string = "-mhard-float"; + _bfd_error_handler + (_("Warning: %B uses %s (set by %B), %B uses %s"), + obfd, abi_fp_bfd, ibfd, out_string, in_string); + } + } + } - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-mips32r2 -mfp64", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } + /* Check for conflicting Tag_GNU_MIPS_ABI_MSA attributes and merge + non-conflicting ones. */ + if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != out_attr[Tag_GNU_MIPS_ABI_MSA].i) + { + out_attr[Tag_GNU_MIPS_ABI_MSA].type = 1; + if (out_attr[Tag_GNU_MIPS_ABI_MSA].i == Val_GNU_MIPS_ABI_MSA_ANY) + out_attr[Tag_GNU_MIPS_ABI_MSA].i = in_attr[Tag_GNU_MIPS_ABI_MSA].i; + else if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY) + switch (out_attr[Tag_GNU_MIPS_ABI_MSA].i) + { + case Val_GNU_MIPS_ABI_MSA_128: + _bfd_error_handler + (_("Warning: %B uses %s (set by %B), " + "%B uses unknown MSA ABI %d"), + obfd, abi_msa_bfd, ibfd, + "-mmsa", in_attr[Tag_GNU_MIPS_ABI_MSA].i); break; default: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) + switch (in_attr[Tag_GNU_MIPS_ABI_MSA].i) { - case Val_GNU_MIPS_ABI_FP_DOUBLE: - _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mdouble-float"); - break; - - case Val_GNU_MIPS_ABI_FP_SINGLE: + case Val_GNU_MIPS_ABI_MSA_128: _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " + (_("Warning: %B uses unknown MSA ABI %d " "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msingle-float"); - break; - - case Val_GNU_MIPS_ABI_FP_SOFT: - _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msoft-float"); - break; - - case Val_GNU_MIPS_ABI_FP_64: - _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mips32r2 -mfp64"); - break; + obfd, abi_msa_bfd, ibfd, + out_attr[Tag_GNU_MIPS_ABI_MSA].i, "-mmsa"); + break; default: _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, - in_attr[Tag_GNU_MIPS_ABI_FP].i); + (_("Warning: %B uses unknown MSA ABI %d " + "(set by %B), %B uses unknown MSA ABI %d"), + obfd, abi_msa_bfd, ibfd, + out_attr[Tag_GNU_MIPS_ABI_MSA].i, + in_attr[Tag_GNU_MIPS_ABI_MSA].i); break; } - break; } } @@ -14526,6 +14962,7 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) bfd_boolean ok; bfd_boolean null_input_bfd = TRUE; asection *sec; + obj_attribute *out_attr; /* Check if we have the same endianness. */ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) @@ -14547,17 +14984,98 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return FALSE; } + /* Set up the FP ABI attribute from the abiflags if it is not already + set. */ + if (mips_elf_tdata (ibfd)->abiflags_valid) + { + obj_attribute *in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; + if (in_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY) + in_attr[Tag_GNU_MIPS_ABI_FP].i = + mips_elf_tdata (ibfd)->abiflags.fp_abi; + } + if (!mips_elf_merge_obj_attributes (ibfd, obfd)) return FALSE; - new_flags = elf_elfheader (ibfd)->e_flags; - elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; - old_flags = elf_elfheader (obfd)->e_flags; + /* Check to see if the input BFD actually contains any sections. + If not, its flags may not have been initialised either, but it cannot + actually cause any incompatibility. */ + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + { + /* Ignore synthetic sections and empty .text, .data and .bss sections + which are automatically generated by gas. Also ignore fake + (s)common sections, since merely defining a common symbol does + not affect compatibility. */ + if ((sec->flags & SEC_IS_COMMON) == 0 + && strcmp (sec->name, ".reginfo") + && strcmp (sec->name, ".mdebug") + && (sec->size != 0 + || (strcmp (sec->name, ".text") + && strcmp (sec->name, ".data") + && strcmp (sec->name, ".bss")))) + { + null_input_bfd = FALSE; + break; + } + } + if (null_input_bfd) + return TRUE; + + /* Populate abiflags using existing information. */ + if (!mips_elf_tdata (ibfd)->abiflags_valid) + { + infer_mips_abiflags (ibfd, &mips_elf_tdata (ibfd)->abiflags); + mips_elf_tdata (ibfd)->abiflags_valid = TRUE; + } + else + { + Elf_Internal_ABIFlags_v0 abiflags; + Elf_Internal_ABIFlags_v0 in_abiflags; + infer_mips_abiflags (ibfd, &abiflags); + in_abiflags = mips_elf_tdata (ibfd)->abiflags; + + /* It is not possible to infer the correct ISA revision + for R3 or R5 so drop down to R2 for the checks. */ + if (in_abiflags.isa_rev == 3 || in_abiflags.isa_rev == 5) + in_abiflags.isa_rev = 2; + + if (in_abiflags.isa_level != abiflags.isa_level + || in_abiflags.isa_rev != abiflags.isa_rev + || in_abiflags.isa_ext != abiflags.isa_ext) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent ISA between e_flags and " + ".MIPS.abiflags"), ibfd); + if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY + && in_abiflags.fp_abi != abiflags.fp_abi) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent FP ABI between e_flags and " + ".MIPS.abiflags"), ibfd); + if ((in_abiflags.ases & abiflags.ases) != abiflags.ases) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent ASEs between e_flags and " + ".MIPS.abiflags"), ibfd); + if (in_abiflags.isa_ext != abiflags.isa_ext) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent ISA extensions between e_flags and " + ".MIPS.abiflags"), ibfd); + if (in_abiflags.flags2 != 0) + (*_bfd_error_handler) + (_("%B: warning: Unexpected flag in the flags2 field of " + ".MIPS.abiflags (0x%lx)"), ibfd, + (unsigned long) in_abiflags.flags2); + } + + if (!mips_elf_tdata (obfd)->abiflags_valid) + { + /* Copy input abiflags if output abiflags are not already valid. */ + mips_elf_tdata (obfd)->abiflags = mips_elf_tdata (ibfd)->abiflags; + mips_elf_tdata (obfd)->abiflags_valid = TRUE; + } if (! elf_flags_init (obfd)) { elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; elf_elfheader (obfd)->e_ident[EI_CLASS] = elf_elfheader (ibfd)->e_ident[EI_CLASS]; @@ -14569,11 +15087,42 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd))) return FALSE; + + /* Update the ABI flags isa_level, isa_rev and isa_ext fields. */ + update_mips_abiflags_isa (obfd, &mips_elf_tdata (obfd)->abiflags); } return TRUE; } + /* Update the output abiflags fp_abi using the computed fp_abi. */ + out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; + mips_elf_tdata (obfd)->abiflags.fp_abi = out_attr[Tag_GNU_MIPS_ABI_FP].i; + +#define max(a,b) ((a) > (b) ? (a) : (b)) + /* Merge abiflags. */ + mips_elf_tdata (obfd)->abiflags.isa_rev + = max (mips_elf_tdata (obfd)->abiflags.isa_rev, + mips_elf_tdata (ibfd)->abiflags.isa_rev); + mips_elf_tdata (obfd)->abiflags.gpr_size + = max (mips_elf_tdata (obfd)->abiflags.gpr_size, + mips_elf_tdata (ibfd)->abiflags.gpr_size); + mips_elf_tdata (obfd)->abiflags.cpr1_size + = max (mips_elf_tdata (obfd)->abiflags.cpr1_size, + mips_elf_tdata (ibfd)->abiflags.cpr1_size); + mips_elf_tdata (obfd)->abiflags.cpr2_size + = max (mips_elf_tdata (obfd)->abiflags.cpr2_size, + mips_elf_tdata (ibfd)->abiflags.cpr2_size); +#undef max + mips_elf_tdata (obfd)->abiflags.ases + |= mips_elf_tdata (ibfd)->abiflags.ases; + mips_elf_tdata (obfd)->abiflags.flags1 + |= mips_elf_tdata (ibfd)->abiflags.flags1; + + new_flags = elf_elfheader (ibfd)->e_flags; + elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; + old_flags = elf_elfheader (obfd)->e_flags; + /* Check flag compatibility. */ new_flags &= ~EF_MIPS_NOREORDER; @@ -14596,30 +15145,6 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (new_flags == old_flags) return TRUE; - /* Check to see if the input BFD actually contains any sections. - If not, its flags may not have been initialised either, but it cannot - actually cause any incompatibility. */ - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - /* Ignore synthetic sections and empty .text, .data and .bss sections - which are automatically generated by gas. Also ignore fake - (s)common sections, since merely defining a common symbol does - not affect compatibility. */ - if ((sec->flags & SEC_IS_COMMON) == 0 - && strcmp (sec->name, ".reginfo") - && strcmp (sec->name, ".mdebug") - && (sec->size != 0 - || (strcmp (sec->name, ".text") - && strcmp (sec->name, ".data") - && strcmp (sec->name, ".bss")))) - { - null_input_bfd = FALSE; - break; - } - } - if (null_input_bfd) - return TRUE; - ok = TRUE; if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0) @@ -14660,6 +15185,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) elf_elfheader (obfd)->e_flags |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); + /* Update the ABI flags isa_level, isa_rev, isa_ext fields. */ + update_mips_abiflags_isa (obfd, &mips_elf_tdata (obfd)->abiflags); + /* Copy across the ABI flags if OBFD doesn't use them and if that was what caused us to treat IBFD as 32-bit. */ if ((old_flags & EF_MIPS_ABI) == 0 @@ -14745,6 +15273,20 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) old_flags &= ~EF_MIPS_NAN2008; } + /* Compare FP64 state. */ + if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64)) + { + _bfd_error_handler (_("%B: linking %s module with previous %s modules"), + ibfd, + (new_flags & EF_MIPS_FP64 + ? "-mfp64" : "-mfp32"), + (old_flags & EF_MIPS_FP64 + ? "-mfp64" : "-mfp32")); + ok = FALSE; + new_flags &= ~EF_MIPS_FP64; + old_flags &= ~EF_MIPS_FP64; + } + /* Warn about any other mismatches */ if (new_flags != old_flags) { @@ -14876,6 +15418,188 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag) } } +/* Return the meaning of Tag_GNU_MIPS_ABI_FP value FP, or null if + not known. */ + +const char * +_bfd_mips_fp_abi_string (int fp) +{ + switch (fp) + { + /* These strings aren't translated because they're simply + option lists. */ + case Val_GNU_MIPS_ABI_FP_DOUBLE: + return "-mdouble-float"; + + case Val_GNU_MIPS_ABI_FP_SINGLE: + return "-msingle-float"; + + case Val_GNU_MIPS_ABI_FP_SOFT: + return "-msoft-float"; + + case Val_GNU_MIPS_ABI_FP_OLD_64: + return _("-mips32r2 -mfp64 (12 callee-saved)"); + + case Val_GNU_MIPS_ABI_FP_XX: + return "-mfpxx"; + + case Val_GNU_MIPS_ABI_FP_64: + return "-mgp32 -mfp64"; + + case Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + + default: + return 0; + } +} + +static void +print_mips_ases (FILE *file, unsigned int mask) +{ + if (mask & AFL_ASE_DSP) + fputs ("\n\tDSP ASE", file); + if (mask & AFL_ASE_DSPR2) + fputs ("\n\tDSP R2 ASE", file); + if (mask & AFL_ASE_EVA) + fputs ("\n\tEnhanced VA Scheme", file); + if (mask & AFL_ASE_MCU) + fputs ("\n\tMCU (MicroController) ASE", file); + if (mask & AFL_ASE_MDMX) + fputs ("\n\tMDMX ASE", file); + if (mask & AFL_ASE_MIPS3D) + fputs ("\n\tMIPS-3D ASE", file); + if (mask & AFL_ASE_MT) + fputs ("\n\tMT ASE", file); + if (mask & AFL_ASE_SMARTMIPS) + fputs ("\n\tSmartMIPS ASE", file); + if (mask & AFL_ASE_VIRT) + fputs ("\n\tVZ ASE", file); + if (mask & AFL_ASE_MSA) + fputs ("\n\tMSA ASE", file); + if (mask & AFL_ASE_MIPS16) + fputs ("\n\tMIPS16 ASE", file); + if (mask & AFL_ASE_MICROMIPS) + fputs ("\n\tMICROMIPS ASE", file); + if (mask & AFL_ASE_XPA) + fputs ("\n\tXPA ASE", file); + if (mask == 0) + fprintf (file, "\n\t%s", _("None")); +} + +static void +print_mips_isa_ext (FILE *file, unsigned int isa_ext) +{ + switch (isa_ext) + { + case 0: + fputs (_("None"), file); + break; + case AFL_EXT_XLR: + fputs ("RMI XLR", file); + break; + case AFL_EXT_OCTEON2: + fputs ("Cavium Networks Octeon2", file); + break; + case AFL_EXT_OCTEONP: + fputs ("Cavium Networks OcteonP", file); + break; + case AFL_EXT_LOONGSON_3A: + fputs ("Loongson 3A", file); + break; + case AFL_EXT_OCTEON: + fputs ("Cavium Networks Octeon", file); + break; + case AFL_EXT_5900: + fputs ("Toshiba R5900", file); + break; + case AFL_EXT_4650: + fputs ("MIPS R4650", file); + break; + case AFL_EXT_4010: + fputs ("LSI R4010", file); + break; + case AFL_EXT_4100: + fputs ("NEC VR4100", file); + break; + case AFL_EXT_3900: + fputs ("Toshiba R3900", file); + break; + case AFL_EXT_10000: + fputs ("MIPS R10000", file); + break; + case AFL_EXT_SB1: + fputs ("Broadcom SB-1", file); + break; + case AFL_EXT_4111: + fputs ("NEC VR4111/VR4181", file); + break; + case AFL_EXT_4120: + fputs ("NEC VR4120", file); + break; + case AFL_EXT_5400: + fputs ("NEC VR5400", file); + break; + case AFL_EXT_5500: + fputs ("NEC VR5500", file); + break; + case AFL_EXT_LOONGSON_2E: + fputs ("ST Microelectronics Loongson 2E", file); + break; + case AFL_EXT_LOONGSON_2F: + fputs ("ST Microelectronics Loongson 2F", file); + break; + default: + fputs (_("Unknown"), file); + break; + } +} + +static void +print_mips_fp_abi_value (FILE *file, int val) +{ + switch (val) + { + case Val_GNU_MIPS_ABI_FP_ANY: + fprintf (file, _("Hard or soft float\n")); + break; + case Val_GNU_MIPS_ABI_FP_DOUBLE: + fprintf (file, _("Hard float (double precision)\n")); + break; + case Val_GNU_MIPS_ABI_FP_SINGLE: + fprintf (file, _("Hard float (single precision)\n")); + break; + case Val_GNU_MIPS_ABI_FP_SOFT: + fprintf (file, _("Soft float\n")); + break; + case Val_GNU_MIPS_ABI_FP_OLD_64: + fprintf (file, _("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n")); + break; + case Val_GNU_MIPS_ABI_FP_XX: + fprintf (file, _("Hard float (32-bit CPU, Any FPU)\n")); + break; + case Val_GNU_MIPS_ABI_FP_64: + fprintf (file, _("Hard float (32-bit CPU, 64-bit FPU)\n")); + break; + case Val_GNU_MIPS_ABI_FP_64A: + fprintf (file, _("Hard float compat (32-bit CPU, 64-bit FPU)\n")); + break; + default: + fprintf (file, "??? (%d)\n", val); + break; + } +} + +static int +get_mips_reg_size (int reg_size) +{ + return (reg_size == AFL_REG_NONE) ? 0 + : (reg_size == AFL_REG_32) ? 32 + : (reg_size == AFL_REG_64) ? 64 + : (reg_size == AFL_REG_128) ? 128 + : -1; +} + bfd_boolean _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) { @@ -14924,6 +15648,10 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) fprintf (file, " [mips32r2]"); else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2) fprintf (file, " [mips64r2]"); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6) + fprintf (file, " [mips32r6]"); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6) + fprintf (file, " [mips64r6]"); else fprintf (file, _(" [unknown ISA]")); @@ -14940,7 +15668,7 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) fprintf (file, " [nan2008]"); if (elf_elfheader (abfd)->e_flags & EF_MIPS_FP64) - fprintf (file, " [fp64]"); + fprintf (file, " [old fp64]"); if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE) fprintf (file, " [32bitmode]"); @@ -14964,6 +15692,30 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) fputc ('\n', file); + if (mips_elf_tdata (abfd)->abiflags_valid) + { + Elf_Internal_ABIFlags_v0 *abiflags = &mips_elf_tdata (abfd)->abiflags; + fprintf (file, "\nMIPS ABI Flags Version: %d\n", abiflags->version); + fprintf (file, "\nISA: MIPS%d", abiflags->isa_level); + if (abiflags->isa_rev > 1) + fprintf (file, "r%d", abiflags->isa_rev); + fprintf (file, "\nGPR size: %d", + get_mips_reg_size (abiflags->gpr_size)); + fprintf (file, "\nCPR1 size: %d", + get_mips_reg_size (abiflags->cpr1_size)); + fprintf (file, "\nCPR2 size: %d", + get_mips_reg_size (abiflags->cpr2_size)); + fputs ("\nFP ABI: ", file); + print_mips_fp_abi_value (file, abiflags->fp_abi); + fputs ("ISA Extension: ", file); + print_mips_isa_ext (file, abiflags->isa_ext); + fputs ("\nASEs:", file); + print_mips_ases (file, abiflags->ases); + fprintf (file, "\nFLAGS 1: %8.8lx", abiflags->flags1); + fprintf (file, "\nFLAGS 2: %8.8lx", abiflags->flags2); + fputc ('\n', file); + } + return TRUE; } @@ -15284,4 +16036,8 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info) if (htab->use_plts_and_copy_relocs && !htab->is_vxworks) i_ehdrp->e_ident[EI_ABIVERSION] = 1; } + + if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64 + || mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A) + i_ehdrp->e_ident[EI_ABIVERSION] = 3; } diff --git a/binutils-2.24/bfd/elfxx-mips.h b/binutils-2.24/bfd/elfxx-mips.h index f27dc15..9814e7a 100644 --- a/binutils-2.24/bfd/elfxx-mips.h +++ b/binutils-2.24/bfd/elfxx-mips.h @@ -109,6 +109,8 @@ extern bfd_boolean _bfd_mips_elf_merge_private_bfd_data (bfd *, bfd *); extern bfd_boolean _bfd_mips_elf_set_private_flags (bfd *, flagword); +extern const char * _bfd_mips_fp_abi_string + (int); extern bfd_boolean _bfd_mips_elf_print_private_bfd_data (bfd *, void *); extern bfd_boolean _bfd_mips_elf_discard_info @@ -156,6 +158,8 @@ extern bfd_vma _bfd_mips_elf_plt_sym_val (bfd_vma, const asection *, const arelent *rel); extern long _bfd_mips_elf_get_synthetic_symtab (bfd *, long, asymbol **, long, asymbol **, asymbol **); +extern bfd_boolean _bfd_mips_elf_gc_mark_extra_sections + (struct bfd_link_info *, elf_gc_mark_hook_fn); extern void _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info); diff --git a/binutils-2.24/bfd/libbfd.h b/binutils-2.24/bfd/libbfd.h index 4aaecbf..e29839b 100644 --- a/binutils-2.24/bfd/libbfd.h +++ b/binutils-2.24/bfd/libbfd.h @@ -1128,6 +1128,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MICROMIPS_7_PCREL_S1", "BFD_RELOC_MICROMIPS_10_PCREL_S1", "BFD_RELOC_MICROMIPS_16_PCREL_S1", + "BFD_RELOC_MIPS_21_PCREL_S2", + "BFD_RELOC_MIPS_26_PCREL_S2", + "BFD_RELOC_MIPS_18_PCREL_S3", + "BFD_RELOC_MIPS_19_PCREL_S2", "BFD_RELOC_MICROMIPS_GPREL16", "BFD_RELOC_MICROMIPS_HI16", "BFD_RELOC_MICROMIPS_HI16_S", diff --git a/binutils-2.24/bfd/reloc.c b/binutils-2.24/bfd/reloc.c index 77a04f8..8151d9b 100644 --- a/binutils-2.24/bfd/reloc.c +++ b/binutils-2.24/bfd/reloc.c @@ -2293,6 +2293,17 @@ ENUMDOC microMIPS PC-relative relocations. ENUM + BFD_RELOC_MIPS_21_PCREL_S2 +ENUMX + BFD_RELOC_MIPS_26_PCREL_S2 +ENUMX + BFD_RELOC_MIPS_18_PCREL_S3 +ENUMX + BFD_RELOC_MIPS_19_PCREL_S2 +ENUMDOC + MIPS PC-relative relocations. + +ENUM BFD_RELOC_MICROMIPS_GPREL16 ENUMX BFD_RELOC_MICROMIPS_HI16 |