aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2003-03-12 23:07:38 +0000
committerAlexandre Oliva <aoliva@redhat.com>2003-03-12 23:07:38 +0000
commit45f8dfe8f6af5672a4be59192873d8622849916f (patch)
tree6aee7630ac4054de43be2617acfb41ab852adb86
parentd17b874b6c14caa2f2ed1b5544a48de9f39a1a65 (diff)
downloadgdb-45f8dfe8f6af5672a4be59192873d8622849916f.zip
gdb-45f8dfe8f6af5672a4be59192873d8622849916f.tar.gz
gdb-45f8dfe8f6af5672a4be59192873d8622849916f.tar.bz2
* config/tc-mips.c (mips_validate_fix): New function.
* config/tc-mips.h (TC_VALIDATE_FIX): Define. (mips_validate_fix): Declare.
-rw-r--r--gas/ChangeLog6
-rw-r--r--gas/config/tc-mips.c79
-rw-r--r--gas/config/tc-mips.h9
3 files changed, 94 insertions, 0 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index c122423..148a04b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,11 @@
2003-03-12 Alexandre Oliva <aoliva@redhat.com>
+ * 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 <aoliva@redhat.com>
+
* Reverted 2003-03-02's patch.
2003-03-11 Steve Ellcey <sje@cup.hp.com>
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 2950611..f26f91b 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 e566d33..b3c2d01 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;