From: Alexandre Oliva Date: Wed, 12 Mar 2003 23:07:38 +0000 (+0000) Subject: * config/tc-mips.c (mips_validate_fix): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=45f8dfe8f6af5672a4be59192873d8622849916f;p=binutils-gdb.git * config/tc-mips.c (mips_validate_fix): New function. * config/tc-mips.h (TC_VALIDATE_FIX): Define. (mips_validate_fix): Declare. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index c122423be89..148a04b9165 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2003-03-12 Alexandre Oliva + + * config/tc-mips.c (mips_validate_fix): New function. + * config/tc-mips.h (TC_VALIDATE_FIX): Define. + (mips_validate_fix): Declare. + 2003-03-12 Alexandre Oliva * Reverted 2003-03-02's patch. diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 295061125ae..f26f91b3c29 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -11026,6 +11026,85 @@ mips_force_relocation (fixp) || fixp->fx_r_type == BFD_RELOC_PCREL_LO16)); } +/* This hook is called before a fix is simplified. We don't really + decide whether to skip a fix here. Rather, we turn global symbols + used as branch targets into local symbols, such that they undergo + simplification. We can only do this if the symbol is defined and + it is in the same section as the branch. If this doesn't hold, we + emit a better error message than just saying the relocation is not + valid for the selected object format. + + FIXP is the fix-up we're going to try to simplify, SEG is the + segment in which the fix up occurs. The return value should be + non-zero to indicate the fix-up is valid for further + simplifications. */ + +int +mips_validate_fix (fixP, seg) + struct fix *fixP; + asection *seg; +{ + /* There's a lot of discussion on whether it should be possible to + use R_MIPS_PC16 to represent branch relocations. The outcome + seems to be that it can, but gas/bfd are very broken in creating + RELA relocations for this, so for now we only accept branches to + symbols in the same section. Anything else is of dubious value, + since there's no guarantee that at link time the symbol would be + in range. Even for branches to local symbols this is arguably + wrong, since it we assume the symbol is not going to be + overridden, which should be possible per ELF library semantics, + but then, there isn't a dynamic relocation that could be used to + this effect, and the target would likely be out of range as well. + + Unfortunately, it seems that there is too much code out there + that relies on branches to symbols that are global to be resolved + as if they were local, like the IRIX tools do, so we do it as + well, but with a warning so that people are reminded to fix their + code. If we ever get back to using R_MIPS_PC16 for branch + targets, this entire block should go away (and probably the + whole function). */ + + if (fixP->fx_r_type == BFD_RELOC_16_PCREL_S2 + && (((OUTPUT_FLAVOR == bfd_target_ecoff_flavour + || OUTPUT_FLAVOR == bfd_target_elf_flavour) + && mips_pic != EMBEDDED_PIC) + || bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16_PCREL_S2) == NULL) + && fixP->fx_addsy) + { + if (! S_IS_DEFINED (fixP->fx_addsy)) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Cannot branch to undefined symbol.")); + /* Avoid any further errors about this fixup. */ + fixP->fx_done = 1; + } + else if (S_GET_SEGMENT (fixP->fx_addsy) != seg) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Cannot branch to symbol in another section.")); + fixP->fx_done = 1; + } + else if (S_IS_EXTERNAL (fixP->fx_addsy)) + { + symbolS *sym = fixP->fx_addsy; + + as_warn_where (fixP->fx_file, fixP->fx_line, + _("Pretending global symbol used as branch target is local.")); + + fixP->fx_addsy = symbol_create (S_GET_NAME (sym), + S_GET_SEGMENT (sym), + S_GET_VALUE (sym), + symbol_get_frag (sym)); + copy_symbol_attributes (fixP->fx_addsy, sym); + S_CLEAR_EXTERNAL (fixP->fx_addsy); + assert (symbol_resolved_p (sym)); + symbol_mark_resolved (fixP->fx_addsy); + } + } + + return 1; +} + #ifdef OBJ_ELF static int mips_need_elf_addend_fixup (fixP) diff --git a/gas/config/tc-mips.h b/gas/config/tc-mips.h index e566d330519..b3c2d018cfe 100644 --- a/gas/config/tc-mips.h +++ b/gas/config/tc-mips.h @@ -140,6 +140,15 @@ extern int mips_fix_adjustable PARAMS ((struct fix *)); #define TC_FORCE_RELOCATION(FIX) mips_force_relocation (FIX) extern int mips_force_relocation PARAMS ((struct fix *)); +/* We use this to turn branches to global symbols into branches to + local symbols, so that they can be simplified. */ +#define TC_VALIDATE_FIX(fixp, this_segment, skip_label) \ + do \ + if (! mips_validate_fix ((fixp), (this_segment))) \ + goto skip_label; \ + while (0) +extern int mips_validate_fix PARAMS ((struct fix *, asection *)); + /* Register mask variables. These are set by the MIPS assembly code and used by ECOFF and possibly other object file formats. */ extern unsigned long mips_gprmask;