This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: On resolving the MIPS gas branch reloc issue
On Mar 9, 2003, Thiemo Seufer <ica2_ts at csv dot ica dot uni-stuttgart dot de> wrote:
> http://sources.redhat.com/ml/binutils/2003-02/msg00179.html worked for me,
> but I'm not sure about it's correctness.
Here's my take on it. I wrote this before realizing your patch, that
I believe to be broken, had already gone in, so I post it mostly for
reference. I'll see if I can dig out some testcases to show the
problems I had in mind.
Index: gas/ChangeLog
from Alexandre Oliva <aoliva at redhat dot com>
* config/tc-mips.c (mips_validate_fix): New function.
* config/tc-mips.h (TC_VALIDATE_FIX): Define.
(mips_validate_fix): Declare.
Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/uberbaum/gas/config/tc-mips.c,v
retrieving revision 1.193
diff -u -p -r1.193 tc-mips.c
--- gas/config/tc-mips.c 21 Feb 2003 10:28:27 -0000 1.193
+++ gas/config/tc-mips.c 10 Mar 2003 18:52:46 -0000
@@ -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)
Index: gas/config/tc-mips.h
===================================================================
RCS file: /cvs/uberbaum/gas/config/tc-mips.h,v
retrieving revision 1.23
diff -u -p -r1.23 tc-mips.h
--- gas/config/tc-mips.h 24 Jan 2003 01:12:30 -0000 1.23
+++ gas/config/tc-mips.h 10 Mar 2003 18:52:46 -0000
@@ -140,6 +140,15 @@ extern int mips_fix_adjustable PARAMS ((
#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;
Index: gas/testsuite/ChangeLog
from Alexandre Oliva <aoliva at redhat dot com>
* gas/mips/branch-misc-2.s: Add branch to symbol in another
section.
* gas/mips/branch-misc-2.l: Update error messages and warnings.
Index: gas/testsuite/gas/mips/branch-misc-2.l
===================================================================
RCS file: /cvs/uberbaum/gas/testsuite/gas/mips/Attic/branch-misc-2.l,v
retrieving revision 1.1
diff -u -p -r1.1 branch-misc-2.l
--- gas/testsuite/gas/mips/branch-misc-2.l 12 Dec 2002 04:40:22 -0000 1.1
+++ gas/testsuite/gas/mips/branch-misc-2.l 10 Mar 2003 18:52:50 -0000
@@ -1,9 +1,10 @@
.*: Assembler messages:
-.*:21: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:22: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:23: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:24: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:25: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:26: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:35: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
-.*:36: Error: Can not represent BFD_RELOC_16_PCREL_S2 relocation in this object file format
+.*:21: Warning: Pretending global symbol used as branch target is local.
+.*:22: Warning: Pretending global symbol used as branch target is local.
+.*:23: Warning: Pretending global symbol used as branch target is local.
+.*:24: Warning: Pretending global symbol used as branch target is local.
+.*:25: Warning: Pretending global symbol used as branch target is local.
+.*:26: Warning: Pretending global symbol used as branch target is local.
+.*:35: Error: Cannot branch to undefined symbol.
+.*:36: Error: Cannot branch to undefined symbol.
+.*:37: Error: Cannot branch to symbol in another section.
Index: gas/testsuite/gas/mips/branch-misc-2.s
===================================================================
RCS file: /cvs/uberbaum/gas/testsuite/gas/mips/branch-misc-2.s,v
retrieving revision 1.2
diff -u -p -r1.2 branch-misc-2.s
--- gas/testsuite/gas/mips/branch-misc-2.s 12 Dec 2002 04:40:22 -0000 1.2
+++ gas/testsuite/gas/mips/branch-misc-2.s 10 Mar 2003 18:52:50 -0000
@@ -34,6 +34,10 @@ g6:
b x1
b x2
+ b .Ldata
# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
.space 8
+
+ .data
+.Ldata:
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva at {redhat dot com, gcc.gnu.org}
CS PhD student at IC-Unicamp oliva at {lsd dot ic dot unicamp dot br, gnu.org}
Free Software Evangelist Professional serial bug killer