diff options
-rw-r--r-- | bfd/ChangeLog | 48 | ||||
-rw-r--r-- | bfd/elf32-mips.c | 239 | ||||
-rw-r--r-- | bfd/elf64-mips.c | 164 | ||||
-rw-r--r-- | bfd/elfn32-mips.c | 98 | ||||
-rw-r--r-- | bfd/elfxx-mips.c | 54 | ||||
-rw-r--r-- | bfd/elfxx-mips.h | 7 | ||||
-rw-r--r-- | gas/ChangeLog | 11 | ||||
-rw-r--r-- | gas/config/tc-mips.c | 309 | ||||
-rw-r--r-- | gas/config/tc-mips.h | 3 |
9 files changed, 492 insertions, 441 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c5de5964..675d3c6 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,51 @@ +2003-06-11 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + + * elf32-mips.c (mips_elf_generic_reloc): New Function. + (elf_mips_howto_table_rel): Use it. + (gprel32_with_gp): Move prototype. + (mips_elf_hi16_reloc): Check for ! BSF_LOCAL instead of zero addend. + Use mips_elf_generic_reloc. + (mips_elf_got16_reloc): Check for ! BSF_LOCAL instead of zero addend. + Code cleanup. + (_bfd_mips_elf32_gprel16_reloc): Check for ! BSF_LOCAL instead of + zero addend. + (mips_elf_gprel32_reloc): Likewise. Use the same GP assignment logic + as in the other *_gprel*_reloc functions. + (gprel32_with_gp): Handle partial_inplace properly. + (mips32_64bit_reloc): Use mips_elf_generic_reloc. + (mips16_gprel_reloc): Check for ! BSF_LOCAL instead of zero addend. + Do addend handling directly instead of calling + _bfd_mips_elf_gprel16_with_gp. Handle partial_inplace properly. + * elf64-mips.c (mips_elf64_hi16_reloc): Check for ! BSF_LOCAL instead + of zero addend. Handle partial_inplace properly. + (mips_elf64_got16_reloc): Check for ! BSF_LOCAL instead of zero + addend. + (mips_elf64_gprel16_reloc): Likewise. + (mips_elf64_literal_reloc): Likewise. + (mips_elf64_gprel32_reloc): Likewise. Use the same GP assignment + logic as in the other *_gprel*_reloc functions. Handle + partial_inplace properly. + (mips_elf64_shift6_reloc): Check for ! BSF_LOCAL instead of zero + addend. Handle partial_inplace properly. + (mips16_gprel_reloc): Likewise. Do addend handling directly instead + of calling _bfd_mips_elf_gprel16_with_gp. + * elfn32-mips.c (mips_elf_got16_reloc): Check for BSF_LOCAL. + (mips_elf_gprel32_reloc): Check for ! BSF_LOCAL instead + of zero addend. + (mips_elf_shift6_reloc): Handle partial_inplace properly. + (mips16_gprel_reloc): Likewise. Do addend handling directly instead + of calling _bfd_mips_elf_gprel16_with_gp. + * elfxx-mips.c (_bfd_mips_elf_gprel16_with_gp): Handle + partial_inplace properly. Fix wrong addend handling. Fix overflow + check. + (_bfd_mips_elf_sign_extend): Renamed from mips_elf_sign_extend and + exported. + (mips_elf_calculate_relocation): Use _bfd_mips_elf_sign_extend. + (_bfd_mips_elf_relocate_section): Likewise. + (mips_elf_create_dynamic_relocation): Update sec_info_type access. + * elfxx-mips.h (_bfd_mips_relax_section): Fix prototype declaration. + (_bfd_mips_elf_sign_extend): New prototype. + 2003-06-11 Federico G. Schwindt <fgsch@lodoss.net> * config.bfd (sparc-*-openbsd[0-2].* | sparc-*-openbsd3.[0-1]): diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 3b47246..67688c9 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -47,12 +47,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define ECOFF_SIGNED_32 #include "ecoffswap.h" +static bfd_reloc_status_type mips_elf_generic_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); static bfd_reloc_status_type mips_elf_got16_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type gprel32_with_gp + PARAMS ((bfd *, asymbol *, arelent *, asection *, bfd_boolean, PTR, + bfd_vma)); static bfd_reloc_status_type mips_elf_gprel32_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); static bfd_reloc_status_type mips32_64bit_reloc @@ -116,7 +121,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_NONE", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -131,7 +136,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -146,7 +151,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_32", /* name */ TRUE, /* partial_inplace */ 0xffffffff, /* src_mask */ @@ -161,7 +166,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_REL32", /* name */ TRUE, /* partial_inplace */ 0xffffffff, /* src_mask */ @@ -179,7 +184,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = /* This needs complex overflow detection, because the upper four bits must match the PC + 4. */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_26", /* name */ TRUE, /* partial_inplace */ 0x03ffffff, /* src_mask */ @@ -269,7 +274,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_PC16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -284,7 +289,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_CALL16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -320,7 +325,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 6, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_SHIFT5", /* name */ TRUE, /* partial_inplace */ 0x000007c0, /* src_mask */ @@ -337,7 +342,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 6, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_SHIFT6", /* name */ TRUE, /* partial_inplace */ 0x000007c4, /* src_mask */ @@ -367,7 +372,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_DISP", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -382,7 +387,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_PAGE", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -397,7 +402,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_OFST", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -412,7 +417,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_HI16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -427,7 +432,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_LO16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -442,7 +447,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_SUB", /* name */ TRUE, /* partial_inplace */ MINUS_ONE, /* src_mask */ @@ -462,7 +467,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_HIGHER", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -477,7 +482,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_HIGHEST", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -492,7 +497,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_CALL_HI16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -507,7 +512,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_CALL_LO16", /* name */ TRUE, /* partial_inplace */ 0x0000ffff, /* src_mask */ @@ -522,7 +527,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_SCN_DISP", /* name */ TRUE, /* partial_inplace */ 0xffffffff, /* src_mask */ @@ -543,7 +548,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] = FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_JALR", /* name */ FALSE, /* partial_inplace */ 0x00000000, /* src_mask */ @@ -645,7 +650,7 @@ static reloc_howto_type elf_mips_gnu_rel16_s2 = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_GNU_REL16_S2", /* name */ TRUE, /* partial_inplace */ 0xffff, /* src_mask */ @@ -661,7 +666,7 @@ static reloc_howto_type elf_mips_gnu_pcrel64 = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_PC64", /* name */ TRUE, /* partial_inplace */ MINUS_ONE, /* src_mask */ @@ -677,7 +682,7 @@ static reloc_howto_type elf_mips_gnu_pcrel32 = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + mips_elf_generic_reloc, /* special_function */ "R_MIPS_PC32", /* name */ TRUE, /* partial_inplace */ 0xffffffff, /* src_mask */ @@ -716,6 +721,33 @@ static reloc_howto_type elf_mips_gnu_vtentry_howto = 0, /* dst_mask */ FALSE); /* pcrel_offset */ +/* We use this instead of bfd_elf_generic_reloc because the latter + gets the handling of zero addends wrong. */ +static bfd_reloc_status_type +mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *reloc_entry; + asymbol *symbol; + PTR data ATTRIBUTE_UNUSED; + asection *input_section; + bfd *output_bfd; + char **error_message ATTRIBUTE_UNUSED; +{ + /* If we're relocating, and this is an external symbol, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (symbol->flags & BSF_LOCAL) != 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Just go on, nothing to see here. */ + return bfd_reloc_continue; +} + /* Do a R_MIPS_HI16 relocation. This has to be done in combination with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to the HI16. Here we just save the information we need; we do the @@ -761,7 +793,7 @@ mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, input_section, to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -923,8 +955,8 @@ mips_elf_lo16_reloc (abfd, reloc_entry, symbol, data, input_section, } /* Now do the LO16 reloc in the usual way. */ - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); + return mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); } /* Do a R_MIPS_GOT16 reloc. This is a reloc against the global offset @@ -956,20 +988,14 @@ mips_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section, to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } - /* If we're relocating, and this is a local symbol, we can handle it - just like HI16. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) != 0) - return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - abort (); + return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); } /* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a @@ -1087,13 +1113,11 @@ _bfd_mips_elf32_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_reloc_status_type ret; bfd_vma gp; - /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ELF - file. */ + /* If we're relocating, and this is an external symbol, we don't want + to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1120,10 +1144,6 @@ _bfd_mips_elf32_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section, /* Do a R_MIPS_GPREL32 relocation. This is a 32 bit value which must become the offset from the gp register. */ -static bfd_reloc_status_type gprel32_with_gp - PARAMS ((bfd *, asymbol *, arelent *, asection *, bfd_boolean, PTR, - bfd_vma)); - static bfd_reloc_status_type mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) @@ -1139,13 +1159,11 @@ mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_reloc_status_type ret; bfd_vma gp; - /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ELF - file. */ + /* If we're relocating, and this is an external symbol, we don't want + to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { *error_message = (char *) _("32bits gp relative relocation occurs for an external symbol"); @@ -1153,21 +1171,18 @@ mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, } if (output_bfd != (bfd *) NULL) - { - relocateable = TRUE; - gp = _bfd_get_gp_value (output_bfd); - } + relocateable = TRUE; else { relocateable = FALSE; output_bfd = symbol->section->output_section->owner; - - ret = mips_elf_final_gp (output_bfd, symbol, relocateable, - error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; } + ret = mips_elf_final_gp (output_bfd, symbol, relocateable, + error_message, &gp); + if (ret != bfd_reloc_ok) + return ret; + return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, gp); } @@ -1184,7 +1199,7 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, bfd_vma gp; { bfd_vma relocation; - unsigned long val; + bfd_vma val; if (bfd_is_com_section (symbol->section)) relocation = 0; @@ -1197,10 +1212,11 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - /* Set val to the offset into the section or symbol. */ - val += reloc_entry->addend; + val = reloc_entry->addend; + + if (reloc_entry->howto->partial_inplace) + val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); /* Adjust val for the final section location and GP value. If we are producing relocateable output, we don't want to do this for @@ -1209,7 +1225,10 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, || (symbol->flags & BSF_SECTION_SYM) != 0) val += relocation - gp; - bfd_put_32 (abfd, (bfd_vma) val, (bfd_byte *) data + reloc_entry->address); + if (reloc_entry->howto->partial_inplace) + bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); + else + reloc_entry->addend = val; if (relocateable) reloc_entry->address += input_section->output_offset; @@ -1237,8 +1256,8 @@ mips32_64bit_reloc (abfd, reloc_entry, symbol, data, input_section, unsigned long val; bfd_size_type addr; - r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); + r = mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); if (r != bfd_reloc_continue) return r; @@ -1315,16 +1334,16 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_boolean relocateable; bfd_reloc_status_type ret; bfd_vma gp; - unsigned short extend, insn; - unsigned long final; + unsigned short extend = 0; + unsigned short insn = 0; + bfd_signed_vma val; + bfd_vma relocation; - /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ELF - file. */ + /* If we're relocating, and this is an external symbol, we don't want + to change anything. */ if (output_bfd != NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1346,33 +1365,55 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - /* Pick up the mips16 extend instruction and the real instruction. */ - extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); - insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2); - - /* Stuff the current addend back as a 32 bit value, do the usual - relocation, and then clean up. */ - bfd_put_32 (abfd, - (bfd_vma) (((extend & 0x1f) << 11) - | (extend & 0x7e0) - | (insn & 0x1f)), - (bfd_byte *) data + reloc_entry->address); - - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocateable, data, gp); - - final = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, - (bfd_vma) ((extend & 0xf800) - | ((final >> 11) & 0x1f) - | (final & 0x7e0)), - (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, - (bfd_vma) ((insn & 0xffe0) - | (final & 0x1f)), - (bfd_byte *) data + reloc_entry->address + 2); + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; - return ret; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + + /* Set val to the offset into the section or symbol. */ + val = reloc_entry->addend; + + if (reloc_entry->howto->partial_inplace) + { + /* Pick up the mips16 extend instruction and the real instruction. */ + extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); + insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2); + val += ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f); + } + + _bfd_mips_elf_sign_extend(val, 16); + + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (! relocateable + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - gp; + + if (reloc_entry->howto->partial_inplace) + { + bfd_put_16 (abfd, + (bfd_vma) ((extend & 0xf800) + | ((val >> 11) & 0x1f) + | (val & 0x7e0)), + (bfd_byte *) data + reloc_entry->address); + bfd_put_16 (abfd, + (bfd_vma) ((insn & 0xffe0) + | (val & 0x1f)), + (bfd_byte *) data + reloc_entry->address + 2); + } + else + reloc_entry->addend = val; + + if (relocateable) + reloc_entry->address += input_section->output_offset; + else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0)) + return bfd_reloc_overflow; + + return bfd_reloc_ok; } /* A mapping from BFD reloc types to MIPS ELF reloc types. */ diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c index a43b3da..baf030a 100644 --- a/bfd/elf64-mips.c +++ b/bfd/elf64-mips.c @@ -1447,15 +1447,17 @@ mips_elf64_hi16_reloc (abfd, reloc_entry, symbol, data, input_section, want to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } - if (((reloc_entry->addend & 0xffff) + 0x8000) & ~0xffff) - reloc_entry->addend += 0x8000; + if (reloc_entry->howto->partial_inplace) + { + if (((reloc_entry->addend & 0xffff) + 0x8000) & ~0xffff) + reloc_entry->addend += 0x8000; + } return bfd_reloc_continue; } @@ -1488,7 +1490,8 @@ mips_elf64_got16_reloc (abfd, reloc_entry, symbol, data, input_section, /* If we're relocating, and this is a local symbol, we can handle it just like an R_MIPS_HI16. */ if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) != 0) + && ((symbol->flags & BSF_SECTION_SYM) != 0 + || (symbol->flags & BSF_LOCAL) == 0)) return mips_elf64_hi16_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); @@ -1610,14 +1613,11 @@ mips_elf64_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_reloc_status_type ret; bfd_vma gp; - /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ELF - file. */ + /* If we're relocating, and this is an external symbol, we don't want + to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1662,8 +1662,7 @@ mips_elf64_literal_reloc (abfd, reloc_entry, symbol, data, input_section, want to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1706,15 +1705,13 @@ mips_elf64_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_reloc_status_type ret; bfd_vma gp; bfd_vma relocation; - unsigned long val; + bfd_vma val; - /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ELF - file. */ + /* If we're relocating, and this is an external symbol, we don't want + to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { *error_message = (char *) _("32bits gp relative relocation occurs for an external symbol"); @@ -1722,21 +1719,18 @@ mips_elf64_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, } if (output_bfd != (bfd *) NULL) - { - relocateable = TRUE; - gp = _bfd_get_gp_value (output_bfd); - } + relocateable = TRUE; else { relocateable = FALSE; output_bfd = symbol->section->output_section->owner; - - ret = mips_elf64_final_gp (output_bfd, symbol, relocateable, - error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; } + ret = mips_elf64_final_gp (output_bfd, symbol, relocateable, + error_message, &gp); + if (ret != bfd_reloc_ok) + return ret; + if (bfd_is_com_section (symbol->section)) relocation = 0; else @@ -1748,16 +1742,11 @@ mips_elf64_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - if (reloc_entry->howto->src_mask == 0) - { - /* This case arises with the 64-bit MIPS ELF ABI. */ - val = 0; - } - else - val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - /* Set val to the offset into the section or symbol. */ - val += reloc_entry->addend; + val = reloc_entry->addend; + + if (reloc_entry->howto->partial_inplace) + val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); /* Adjust val for the final section location and GP value. If we are producing relocateable output, we don't want to do this for @@ -1766,7 +1755,10 @@ mips_elf64_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, || (symbol->flags & BSF_SECTION_SYM) != 0) val += relocation - gp; - bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); + if (reloc_entry->howto->partial_inplace) + bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); + else + reloc_entry->addend = val; if (relocateable) reloc_entry->address += input_section->output_offset; @@ -1792,15 +1784,17 @@ mips_elf64_shift6_reloc (abfd, reloc_entry, symbol, data, input_section, want to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } - reloc_entry->addend = (reloc_entry->addend & 0x00007c0) - | (reloc_entry->addend & 0x00000800) >> 9; + if (reloc_entry->howto->partial_inplace) + { + reloc_entry->addend = ((reloc_entry->addend & 0x00007c0) + | (reloc_entry->addend & 0x00000800) >> 9); + } return bfd_reloc_continue; } @@ -1857,16 +1851,16 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_boolean relocateable; bfd_reloc_status_type ret; bfd_vma gp; - unsigned short extend, insn; - unsigned long final; + unsigned short extend = 0; + unsigned short insn = 0; + bfd_signed_vma val; + bfd_vma relocation; /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ELF - file. */ + addend, we don't want to change anything. */ if (output_bfd != NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1888,33 +1882,55 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - /* Pick up the mips16 extend instruction and the real instruction. */ - extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); - insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2); - - /* Stuff the current addend back as a 32 bit value, do the usual - relocation, and then clean up. */ - bfd_put_32 (abfd, - (bfd_vma) (((extend & 0x1f) << 11) - | (extend & 0x7e0) - | (insn & 0x1f)), - (bfd_byte *) data + reloc_entry->address); - - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocateable, data, gp); - - final = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, - (bfd_vma) ((extend & 0xf800) - | ((final >> 11) & 0x1f) - | (final & 0x7e0)), - (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, - (bfd_vma) ((insn & 0xffe0) - | (final & 0x1f)), - (bfd_byte *) data + reloc_entry->address + 2); + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; - return ret; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + + /* Set val to the offset into the section or symbol. */ + val = reloc_entry->addend; + + if (reloc_entry->howto->partial_inplace) + { + /* Pick up the mips16 extend instruction and the real instruction. */ + extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); + insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2); + val += ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f); + } + + _bfd_mips_elf_sign_extend(val, 16); + + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (! relocateable + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - gp; + + if (reloc_entry->howto->partial_inplace) + { + bfd_put_16 (abfd, + (bfd_vma) ((extend & 0xf800) + | ((val >> 11) & 0x1f) + | (val & 0x7e0)), + (bfd_byte *) data + reloc_entry->address); + bfd_put_16 (abfd, + (bfd_vma) ((insn & 0xffe0) + | (val & 0x1f)), + (bfd_byte *) data + reloc_entry->address + 2); + } + else + reloc_entry->addend = val; + + if (relocateable) + reloc_entry->address += input_section->output_offset; + else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0)) + return bfd_reloc_overflow; + + return bfd_reloc_ok; } /* A mapping from BFD reloc types to MIPS ELF reloc types. */ diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c index 2e49948..1741e35 100644 --- a/bfd/elfn32-mips.c +++ b/bfd/elfn32-mips.c @@ -1453,9 +1453,10 @@ mips_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section, char **error_message; { /* If we're relocating, and this is a local symbol, we can handle it - just like HI16. */ + just like an R_MIPS_HI16. */ if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) != 0) + && ((symbol->flags & BSF_SECTION_SYM) != 0 + || (symbol->flags & BSF_LOCAL) == 0)) return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); @@ -1654,12 +1655,10 @@ mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section) - /* R_MIPS_GPREL32 relocations are defined for local symbols only. - We will only have an addend if this is a newly created reloc, - not read from an ELF file. */ + /* R_MIPS_GPREL32 relocations are defined for local symbols only. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) + && (symbol->flags & BSF_LOCAL) != 0) { *error_message = (char *) _("32bits gp relative relocation occurs for an external symbol"); @@ -1750,8 +1749,11 @@ mips_elf_shift6_reloc (abfd, reloc_entry, symbol, data, input_section, { GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section) - reloc_entry->addend = (reloc_entry->addend & 0x00007c0) - | (reloc_entry->addend & 0x00000800) >> 9; + if (reloc_entry->howto->partial_inplace) + { + reloc_entry->addend = ((reloc_entry->addend & 0x00007c0) + | (reloc_entry->addend & 0x00000800) >> 9); + } SET_RELOC_ADDEND (reloc_entry) @@ -1801,8 +1803,10 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section, bfd_boolean relocateable; bfd_reloc_status_type ret; bfd_vma gp; - unsigned short extend, insn; - unsigned long final; + unsigned short extend = 0; + unsigned short insn = 0; + bfd_signed_vma val; + bfd_vma relocation; GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section) @@ -1822,33 +1826,55 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - /* Pick up the mips16 extend instruction and the real instruction. */ - extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); - insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2); - - /* Stuff the current addend back as a 32 bit value, do the usual - relocation, and then clean up. */ - bfd_put_32 (abfd, - (bfd_vma) (((extend & 0x1f) << 11) - | (extend & 0x7e0) - | (insn & 0x1f)), - (bfd_byte *) data + reloc_entry->address); - - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocateable, data, gp); - - final = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, - (bfd_vma) ((extend & 0xf800) - | ((final >> 11) & 0x1f) - | (final & 0x7e0)), - (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, - (bfd_vma) ((insn & 0xffe0) - | (final & 0x1f)), - (bfd_byte *) data + reloc_entry->address + 2); + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; - return ret; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + + /* Set val to the offset into the section or symbol. */ + val = reloc_entry->addend; + + if (reloc_entry->howto->partial_inplace) + { + /* Pick up the mips16 extend instruction and the real instruction. */ + extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); + insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2); + val += ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f); + } + + _bfd_mips_elf_sign_extend(val, 16); + + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (! relocateable + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - gp; + + if (reloc_entry->howto->partial_inplace) + { + bfd_put_16 (abfd, + (bfd_vma) ((extend & 0xf800) + | ((val >> 11) & 0x1f) + | (val & 0x7e0)), + (bfd_byte *) data + reloc_entry->address); + bfd_put_16 (abfd, + (bfd_vma) ((insn & 0xffe0) + | (val & 0x1f)), + (bfd_byte *) data + reloc_entry->address + 2); + } + else + reloc_entry->addend = val; + + if (relocateable) + reloc_entry->address += input_section->output_offset; + else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0)) + return bfd_reloc_overflow; + + return bfd_reloc_ok; } #undef GET_RELOC_ADDEND diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index e390bed..5feb3bf 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -434,7 +434,6 @@ static const Elf_Internal_Rela *mips_elf_next_relocation const Elf_Internal_Rela *)); static bfd_boolean mips_elf_local_relocation_p PARAMS ((bfd *, const Elf_Internal_Rela *, asection **, bfd_boolean)); -static bfd_vma mips_elf_sign_extend PARAMS ((bfd_vma, int)); static bfd_boolean mips_elf_overflow_p PARAMS ((bfd_vma, int)); static bfd_vma mips_elf_high PARAMS ((bfd_vma)); static bfd_vma mips_elf_higher PARAMS ((bfd_vma)); @@ -1091,8 +1090,8 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section, bfd_vma gp; { bfd_vma relocation; - unsigned long insn; - unsigned long val; + unsigned long insn = 0; + bfd_signed_vma val; if (bfd_is_com_section (symbol->section)) relocation = 0; @@ -1105,21 +1104,17 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - /* Set val to the offset into the section or symbol. */ - if (reloc_entry->howto->src_mask == 0) - { - /* This case occurs with the 64-bit MIPS ELF ABI. */ - val = reloc_entry->addend; - } - else + val = reloc_entry->addend; + + if (reloc_entry->howto->partial_inplace) { - val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; - if (val & 0x8000) - val -= 0x10000; + insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + val += insn & 0xffff; } + _bfd_mips_elf_sign_extend(val, 16); + /* Adjust val for the final section location and GP value. If we are producing relocateable output, we don't want to do this for an external symbol. */ @@ -1127,13 +1122,18 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section, || (symbol->flags & BSF_SECTION_SYM) != 0) val += relocation - gp; - insn = (insn & ~0xffff) | (val & 0xffff); - bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); + if (reloc_entry->howto->partial_inplace) + { + insn = (insn & ~0xffff) | (val & 0xffff); + bfd_put_32 (abfd, (bfd_vma) insn, + (bfd_byte *) data + reloc_entry->address); + } + else + reloc_entry->addend = val; if (relocateable) reloc_entry->address += input_section->output_offset; - - else if ((long) val >= 0x8000 || (long) val < -0x8000) + else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0)) return bfd_reloc_overflow; return bfd_reloc_ok; @@ -2741,8 +2741,8 @@ mips_elf_local_relocation_p (input_bfd, relocation, local_sections, /* Sign-extend VALUE, which has the indicated number of BITS. */ -static bfd_vma -mips_elf_sign_extend (value, bits) +bfd_vma +_bfd_mips_elf_sign_extend (value, bits) bfd_vma value; int bits; { @@ -3305,7 +3305,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, return bfd_reloc_continue; case R_MIPS_16: - value = symbol + mips_elf_sign_extend (addend, 16); + value = symbol + _bfd_mips_elf_sign_extend (addend, 16); overflowed_p = mips_elf_overflow_p (value, 16); break; @@ -3356,7 +3356,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, break; case R_MIPS_GNU_REL16_S2: - value = symbol + mips_elf_sign_extend (addend << 2, 18) - p; + value = symbol + _bfd_mips_elf_sign_extend (addend << 2, 18) - p; overflowed_p = mips_elf_overflow_p (value, 18); value = (value >> 2) & howto->dst_mask; break; @@ -3381,7 +3381,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, if (local_p) value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2; else - value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2; + value = (_bfd_mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2; value &= howto->dst_mask; break; @@ -3441,7 +3441,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, instruction. If the addend was separate, leave it alone, otherwise we may lose significant bits. */ if (howto->partial_inplace) - addend = mips_elf_sign_extend (addend, 16); + addend = _bfd_mips_elf_sign_extend (addend, 16); value = symbol + addend - gp; /* If the symbol was local, any earlier relocatable links will have adjusted its addend with the gp offset, so compensate @@ -3490,7 +3490,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, break; case R_MIPS_PC16: - value = mips_elf_sign_extend (addend, 16) + symbol - p; + value = _bfd_mips_elf_sign_extend (addend, 16) + symbol - p; overflowed_p = mips_elf_overflow_p (value, 16); break; @@ -3853,7 +3853,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, /* We begin by assuming that the offset for the dynamic relocation is the same as for the original relocation. We'll adjust this later to reflect the correct output offsets. */ - if (elf_section_data (input_section)->sec_info_type != ELF_INFO_TYPE_STABS) + if (input_section->sec_info_type != ELF_INFO_TYPE_STABS) { outrel[1].r_offset = rel[1].r_offset; outrel[2].r_offset = rel[2].r_offset; @@ -6353,7 +6353,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, input_bfd, contents); l &= lo16_howto->src_mask; l <<= lo16_howto->rightshift; - l = mips_elf_sign_extend (l, 16); + l = _bfd_mips_elf_sign_extend (l, 16); addend <<= 16; diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h index 3064c39..088dd6a 100644 --- a/bfd/elfxx-mips.h +++ b/bfd/elfxx-mips.h @@ -108,6 +108,7 @@ extern bfd_reloc_status_type _bfd_mips_elf32_gprel16_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); extern unsigned long _bfd_elf_mips_mach PARAMS ((flagword)); -extern bfd_boolean _bfd_mips_relax_section (bfd *, asection *, - struct bfd_link_info *, - bfd_boolean *); +extern bfd_boolean _bfd_mips_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *)); +extern bfd_vma _bfd_mips_elf_sign_extend + PARAMS ((bfd_vma, int)); diff --git a/gas/ChangeLog b/gas/ChangeLog index eeb1a36..45cbabb 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,16 @@ 2003-06-11 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * config/tc-mips.c (md_pcrel_from): Return actual pcrel address. + (md_apply_fix3): Ignore non-special relocations. Remove superfluous + exceptions from size assert. Remove most of the addend fixup + specialcasing. Remove value, use valP directly. simplify fx_addnumber + handling. Remove zero addend specialcases. + (tc_gen_reloc): Use appropriate value for reloc2 addend. Remove + the addend fixup specialcase. + * config/tc-mips.h (MD_APPLY_SYM_VALUE): Define as 0. + +2003-06-11 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * write.c (write_relocs): Use xcalloc. Fix relocs initialization in the RELOC_EXPANSION_POSSIBLE case. diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 16c9a63..0ee8f73 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -11381,13 +11381,16 @@ long md_pcrel_from (fixP) fixS *fixP; { - if (OUTPUT_FLAVOR != bfd_target_aout_flavour - && fixP->fx_addsy != (symbolS *) NULL - && ! S_IS_DEFINED (fixP->fx_addsy)) - return 4; - - /* Return the address of the delay slot. */ - return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; + valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; + switch (fixP->fx_r_type) + { + case BFD_RELOC_16_PCREL_S2: + case BFD_RELOC_MIPS_JMP: + /* Return the address of the delay slot. */ + return addr + 4; + default: + return addr; + } } /* This is called before the symbol table is processed. In order to @@ -11648,133 +11651,79 @@ md_apply_fix3 (fixP, valP, seg) { bfd_byte *buf; long insn; - valueT value; static int previous_fx_r_type = 0; + reloc_howto_type *howto; - /* FIXME: Maybe just return for all reloc types not listed below? - Eric Christopher says: "This is stupid, please rewrite md_apply_fix3. */ - if (fixP->fx_r_type == BFD_RELOC_8) - return; + /* We ignore generic BFD relocations we don't know about. */ + howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); + if (! howto) + return; assert (fixP->fx_size == 4 || fixP->fx_r_type == BFD_RELOC_16 - || fixP->fx_r_type == BFD_RELOC_32 - || fixP->fx_r_type == BFD_RELOC_MIPS_JMP - || fixP->fx_r_type == BFD_RELOC_HI16_S - || fixP->fx_r_type == BFD_RELOC_LO16 - || fixP->fx_r_type == BFD_RELOC_GPREL16 - || fixP->fx_r_type == BFD_RELOC_MIPS_LITERAL - || fixP->fx_r_type == BFD_RELOC_GPREL32 || fixP->fx_r_type == BFD_RELOC_64 || fixP->fx_r_type == BFD_RELOC_CTOR || fixP->fx_r_type == BFD_RELOC_MIPS_SUB - || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHEST - || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHER - || fixP->fx_r_type == BFD_RELOC_MIPS_SCN_DISP - || fixP->fx_r_type == BFD_RELOC_MIPS_REL16 - || fixP->fx_r_type == BFD_RELOC_MIPS_RELGOT || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY - || fixP->fx_r_type == BFD_RELOC_MIPS_JALR); + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY); - value = *valP; + buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where); /* If we aren't adjusting this fixup to be against the section symbol, we need to adjust the value. */ #ifdef OBJ_ELF if (fixP->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour) { - if (mips_need_elf_addend_fixup (fixP)) - { - reloc_howto_type *howto; - valueT symval = S_GET_VALUE (fixP->fx_addsy); - - value -= symval; - - howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); - if (value != 0 && howto && howto->partial_inplace) - { - /* In this case, the bfd_install_relocation routine will - incorrectly add the symbol value back in. We just want - the addend to appear in the object file. - - The condition above used to include - "&& (! fixP->fx_pcrel || howto->pcrel_offset)". - - However, howto can't be trusted here, because we - might change the reloc type in tc_gen_reloc. We can - check howto->partial_inplace because that conversion - happens to preserve howto->partial_inplace; but it - does not preserve howto->pcrel_offset. I've just - eliminated the check, because all MIPS PC-relative - relocations are marked howto->pcrel_offset. - - howto->pcrel_offset was originally added for - R_MIPS_PC16, which is generated for code like - - globl g1 .text - .text - .space 20 - g1: - x: - bal g1 - */ - value -= symval; - - /* Make sure the addend is still non-zero. If it became zero - after the last operation, set it to a spurious value and - subtract the same value from the object file's contents. */ - if (value == 0) - { - value = 8; - - /* The in-place addends for LO16 relocations are signed; - leave the matching HI16 in-place addends as zero. */ - if (fixP->fx_r_type != BFD_RELOC_HI16_S) - { - bfd_vma contents, mask, field; - - contents = bfd_get_bits (fixP->fx_frag->fr_literal - + fixP->fx_where, - fixP->fx_size * 8, - target_big_endian); - - /* MASK has bits set where the relocation should go. - FIELD is -value, shifted into the appropriate place - for this relocation. */ - mask = 1 << (howto->bitsize - 1); - mask = (((mask - 1) << 1) | 1) << howto->bitpos; - field = (-value >> howto->rightshift) << howto->bitpos; - - bfd_put_bits ((field & mask) | (contents & ~mask), - fixP->fx_frag->fr_literal + fixP->fx_where, - fixP->fx_size * 8, - target_big_endian); - } - } - } + if (mips_need_elf_addend_fixup (fixP) + && howto->partial_inplace + && fixP->fx_r_type != BFD_RELOC_GPREL16 + && fixP->fx_r_type != BFD_RELOC_GPREL32 + && fixP->fx_r_type != BFD_RELOC_MIPS16_GPREL) + { + /* In this case, the bfd_install_relocation routine will + incorrectly add the symbol value back in. We just want + the addend to appear in the object file. + + The condition above used to include + "&& (! fixP->fx_pcrel || howto->pcrel_offset)". + + However, howto can't be trusted here, because we + might change the reloc type in tc_gen_reloc. We can + check howto->partial_inplace because that conversion + happens to preserve howto->partial_inplace; but it + does not preserve howto->pcrel_offset. I've just + eliminated the check, because all MIPS PC-relative + relocations are marked howto->pcrel_offset. + + howto->pcrel_offset was originally added for + R_MIPS_PC16, which is generated for code like + + globl g1 .text + .text + .space 20 + g1: + x: + bal g1 + */ + *valP -= S_GET_VALUE (fixP->fx_addsy); } /* This code was generated using trial and error and so is fragile and not trustworthy. If you change it, you should rerun the elf-rel, elf-rel2, and empic testcases and ensure they still pass. */ - if (fixP->fx_pcrel || fixP->fx_subsy != NULL) + if (fixP->fx_pcrel) { - value += fixP->fx_frag->fr_address + fixP->fx_where; + *valP += fixP->fx_frag->fr_address + fixP->fx_where; /* BFD's REL handling, for MIPS, is _very_ weird. This gives the right results, but it can't possibly be the way things are supposed to work. */ - if (fixP->fx_r_type != BFD_RELOC_16_PCREL_S2 - || S_GET_SEGMENT (fixP->fx_addsy) != undefined_section) - value += fixP->fx_frag->fr_address + fixP->fx_where; + *valP += fixP->fx_frag->fr_address + fixP->fx_where; } } #endif - fixP->fx_addnumber = value; /* Remember value for tc_gen_reloc. */ - /* We are not done if this is a composite relocation to set up gp. */ if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel && !(fixP->fx_r_type == BFD_RELOC_MIPS_SUB @@ -11827,15 +11776,13 @@ md_apply_fix3 (fixP, valP, seg) /* We currently always generate a reloc against a symbol, which means that we don't want an addend even if the symbol is defined. */ - fixP->fx_addnumber = 0; + *valP = 0; break; case BFD_RELOC_PCREL_HI16_S: /* The addend for this is tricky if it is internal, so we just do everything here rather than in bfd_install_relocation. */ - if (OUTPUT_FLAVOR == bfd_target_elf_flavour - && !fixP->fx_done - && value != 0) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour && !fixP->fx_done) break; if (fixP->fx_addsy && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0) @@ -11843,30 +11790,26 @@ md_apply_fix3 (fixP, valP, seg) /* For an external symbol adjust by the address to make it pcrel_offset. We use the address of the RELLO reloc which follows this one. */ - value += (fixP->fx_next->fx_frag->fr_address + *valP += (fixP->fx_next->fx_frag->fr_address + fixP->fx_next->fx_where); } - value = ((value + 0x8000) >> 16) & 0xffff; - buf = (bfd_byte *) fixP->fx_frag->fr_literal + fixP->fx_where; + *valP = ((*valP + 0x8000) >> 16) & 0xffff; if (target_big_endian) buf += 2; - md_number_to_chars ((char *) buf, value, 2); + md_number_to_chars ((char *) buf, *valP, 2); break; case BFD_RELOC_PCREL_LO16: /* The addend for this is tricky if it is internal, so we just do everything here rather than in bfd_install_relocation. */ - if (OUTPUT_FLAVOR == bfd_target_elf_flavour - && !fixP->fx_done - && value != 0) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour && !fixP->fx_done) break; if (fixP->fx_addsy && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0) - value += fixP->fx_frag->fr_address + fixP->fx_where; - buf = (bfd_byte *) fixP->fx_frag->fr_literal + fixP->fx_where; + *valP += fixP->fx_frag->fr_address + fixP->fx_where; if (target_big_endian) buf += 2; - md_number_to_chars ((char *) buf, value, 2); + md_number_to_chars ((char *) buf, *valP, 2); break; case BFD_RELOC_64: @@ -11876,24 +11819,19 @@ md_apply_fix3 (fixP, valP, seg) || (mips_pic == EMBEDDED_PIC && SWITCH_TABLE (fixP))) { if (8 <= sizeof (valueT)) - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 8); + md_number_to_chars (buf, *valP, 8); else { - long w1, w2; - long hiv; + valueT hiv; - w1 = w2 = fixP->fx_where; - if (target_big_endian) - w1 += 4; - else - w2 += 4; - md_number_to_chars (fixP->fx_frag->fr_literal + w1, value, 4); - if ((value & 0x80000000) != 0) + if ((*valP & 0x80000000) != 0) hiv = 0xffffffff; else hiv = 0; - md_number_to_chars (fixP->fx_frag->fr_literal + w2, hiv, 4); + md_number_to_chars ((char *)(buf + target_big_endian ? 4 : 0), + *valP, 4); + md_number_to_chars ((char *)(buf + target_big_endian ? 0 : 4), + hiv, 4); } } break; @@ -11907,8 +11845,7 @@ md_apply_fix3 (fixP, valP, seg) entry. */ if (fixP->fx_done || (mips_pic == EMBEDDED_PIC && SWITCH_TABLE (fixP))) - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 4); + md_number_to_chars (buf, *valP, 4); break; case BFD_RELOC_16: @@ -11916,8 +11853,7 @@ md_apply_fix3 (fixP, valP, seg) value now. */ assert (fixP->fx_size == 2); if (fixP->fx_done) - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 2); + md_number_to_chars (buf, *valP, 2); break; case BFD_RELOC_LO16: @@ -11925,82 +11861,69 @@ md_apply_fix3 (fixP, valP, seg) up deleting a LO16 reloc. See the 'o' case in mips_ip. */ if (fixP->fx_done) { - if (value + 0x8000 > 0xffff) + if (*valP + 0x8000 > 0xffff) as_bad_where (fixP->fx_file, fixP->fx_line, _("relocation overflow")); - buf = (bfd_byte *) fixP->fx_frag->fr_literal + fixP->fx_where; if (target_big_endian) buf += 2; - md_number_to_chars ((char *) buf, value, 2); + md_number_to_chars ((char *) buf, *valP, 2); } break; case BFD_RELOC_16_PCREL_S2: - if ((value & 0x3) != 0) + if ((*valP & 0x3) != 0) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch to odd address (%lx)"), (long) value); + _("Branch to odd address (%lx)"), (long) *valP); /* * We need to save the bits in the instruction since fixup_segment() * might be deleting the relocation entry (i.e., a branch within * the current segment). */ - if (!fixP->fx_done && (value != 0 || HAVE_NEWABI)) + if (! fixP->fx_done) break; - /* If 'value' is zero, the remaining reloc code won't actually - do the store, so it must be done here. This is probably - a bug somewhere. */ - if (!fixP->fx_done - && (fixP->fx_r_type != BFD_RELOC_16_PCREL_S2 - || fixP->fx_addsy == NULL /* ??? */ - || ! S_IS_DEFINED (fixP->fx_addsy))) - value -= fixP->fx_frag->fr_address + fixP->fx_where; - - value = (offsetT) value >> 2; /* update old instruction data */ - buf = (bfd_byte *) (fixP->fx_where + fixP->fx_frag->fr_literal); if (target_big_endian) insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; else insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; - if (value + 0x8000 <= 0xffff) - insn |= value & 0xffff; - else + if (*valP + 0x20000 <= 0x3ffff) + { + insn |= (*valP >> 2) & 0xffff; + md_number_to_chars ((char *) buf, (valueT) insn, 4); + } + else if (mips_pic == NO_PIC + && fixP->fx_done + && fixP->fx_frag->fr_address >= text_section->vma + && (fixP->fx_frag->fr_address + < text_section->vma + text_section->_raw_size) + && ((insn & 0xffff0000) == 0x10000000 /* beq $0,$0 */ + || (insn & 0xffff0000) == 0x04010000 /* bgez $0 */ + || (insn & 0xffff0000) == 0x04110000)) /* bgezal $0 */ { /* The branch offset is too large. If this is an unconditional branch, and we are not generating PIC code, we can convert it to an absolute jump instruction. */ - if (mips_pic == NO_PIC - && fixP->fx_done - && fixP->fx_frag->fr_address >= text_section->vma - && (fixP->fx_frag->fr_address - < text_section->vma + text_section->_raw_size) - && ((insn & 0xffff0000) == 0x10000000 /* beq $0,$0 */ - || (insn & 0xffff0000) == 0x04010000 /* bgez $0 */ - || (insn & 0xffff0000) == 0x04110000)) /* bgezal $0 */ - { - if ((insn & 0xffff0000) == 0x04110000) /* bgezal $0 */ - insn = 0x0c000000; /* jal */ - else - insn = 0x08000000; /* j */ - fixP->fx_r_type = BFD_RELOC_MIPS_JMP; - fixP->fx_done = 0; - fixP->fx_addsy = section_symbol (text_section); - fixP->fx_addnumber = (value << 2) + md_pcrel_from (fixP); - } + if ((insn & 0xffff0000) == 0x04110000) /* bgezal $0 */ + insn = 0x0c000000; /* jal */ else - { - /* If we got here, we have branch-relaxation disabled, - and there's nothing we can do to fix this instruction - without turning it into a longer sequence. */ - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch out of range")); - } + insn = 0x08000000; /* j */ + fixP->fx_r_type = BFD_RELOC_MIPS_JMP; + fixP->fx_done = 0; + fixP->fx_addsy = section_symbol (text_section); + *valP += md_pcrel_from (fixP); + md_number_to_chars ((char *) buf, (valueT) insn, 4); + } + else + { + /* If we got here, we have branch-relaxation disabled, + and there's nothing we can do to fix this instruction + without turning it into a longer sequence. */ + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Branch out of range")); } - - md_number_to_chars ((char *) buf, (valueT) insn, 4); break; case BFD_RELOC_VTABLE_INHERIT: @@ -12018,6 +11941,9 @@ md_apply_fix3 (fixP, valP, seg) default: internalError (); } + + /* Remember value for tc_gen_reloc. */ + fixP->fx_addnumber = *valP; } #if 0 @@ -13864,7 +13790,7 @@ tc_gen_reloc (section, fixp) reloc2->address = (reloc->address + (RELAX_RELOC2 (fixp->fx_frag->fr_subtype) - RELAX_RELOC1 (fixp->fx_frag->fr_subtype))); - reloc2->addend = fixp->fx_addnumber + reloc2->addend = fixp->fx_addnumber - S_GET_VALUE (fixp->fx_addsy) + fixp->fx_frag->tc_frag_data.tc_fr_offset; reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16); assert (reloc2->howto != NULL); @@ -13969,27 +13895,6 @@ tc_gen_reloc (section, fixp) } } -#ifdef OBJ_ELF - /* md_apply_fix3 has a double-subtraction hack to get - bfd_install_relocation to behave nicely. GPREL relocations are - handled correctly without this hack, so undo it here. We can't - stop md_apply_fix3 from subtracting twice in the first place since - the fake addend is required for variant frags above. */ - if (fixp->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour - && (code == BFD_RELOC_GPREL16 || code == BFD_RELOC_MIPS16_GPREL) - && reloc->addend != 0 - && mips_need_elf_addend_fixup (fixp)) - { - /* If howto->partial_inplace is false, md_apply_fix3 will only - subtract it once. */ - reloc_howto_type *howto; - - howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (howto->partial_inplace) - reloc->addend += S_GET_VALUE (fixp->fx_addsy); - } -#endif - /* To support a PC relative reloc when generating embedded PIC code for ECOFF, we use a Cygnus extension. We check for that here to make sure that we don't let such a reloc escape normally. */ diff --git a/gas/config/tc-mips.h b/gas/config/tc-mips.h index ef77120..b7277ab 100644 --- a/gas/config/tc-mips.h +++ b/gas/config/tc-mips.h @@ -129,6 +129,9 @@ extern void mips_frob_file_after_relocs PARAMS ((void)); #define tc_fix_adjustable(fixp) mips_fix_adjustable (fixp) extern int mips_fix_adjustable PARAMS ((struct fix *)); +/* Values passed to md_apply_fix3 don't include symbol values. */ +#define MD_APPLY_SYM_VALUE(FIX) 0 + /* Global syms must not be resolved, to support ELF shared libraries. When generating embedded code, we don't have shared libs. */ #define EXTERN_FORCE_RELOC \ |