This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
RFC: Patch to fix MIPS -mno-shared with multi-got...
- From: David Daney <ddaney at avtrex dot com>
- To: binutils at sources dot redhat dot com
- Date: Thu, 03 Mar 2005 13:05:27 -0800
- Subject: RFC: Patch to fix MIPS -mno-shared with multi-got...
This patch added by Ian Lance Taylor:
http://sourceware.org/ml/binutils/2004-12/msg00094.html
Added a new option for the MIPS assembler -mno-shared which as he stated
in the message referenced above:
-------------8<-----------------
This patch adds a new option to the MIPS assembler: -mno-shared.
Normally the .cpload pseudo-op generates code which looks like this:
lui $gp,%hi(_gp_disp)
addiu $gp,$gp,%lo(_gp_disp)
addu $gp,$gp,.cpload argument
With -mno-shared, the .cpload pseudo-op will generate code that looks
like this:
lui $gp,%hi(_gp)
addiu $gp,$gp,%lo(_gp)
------------8<-------------------
When doing a multi-got link the "_gp_disp" virtual symbol refers to one
of the several GOTs in the output.
The problem is that "_gp" points to the primary GOT but the relocations
need to be done against which ever GOT is used by the module being linked
The attached patch adds special handling for "_gp" so that it is treated
in a manner similar to "_gp_disp"
It allows my large (multi-got) application to be compiled with
-Wa,-mno-shared which is good.
One thing I am not sure about is if there is existing code somewhere
that that will break with the patch.
Possible problems are code that use relocations other than R_MIPS_HI16,
R_MIPS_LO16, R_MIPS16_HI16 and R_MIPS16_LO16 against "_gp" as they would
now be illegal. Also multi-got code that for some reason needed to
refer to the "real _gp" instead of the GOT corresponding to the module.
Thoughts?
If it is thought to be a good patch, I could probably create some test
cases for it.
David Daney
--- /home/daney/binutils-050218/bfd/elfxx-mips.c 2005-02-15 20:45:23.000000000 -0800
+++ bfd/elfxx-mips.c 2005-03-03 12:19:30.000000000 -0800
@@ -3039,6 +3039,8 @@ mips_elf_calculate_relocation (bfd *abfd
bfd_boolean local_p, was_local_p;
/* TRUE if the symbol referred to by this relocation is "_gp_disp". */
bfd_boolean gp_disp_p = FALSE;
+ /* TRUE if the symbol referred to by this relocation is "_gp". */
+ bfd_boolean gp_p = FALSE;
Elf_Internal_Shdr *symtab_hdr;
size_t extsymoff;
unsigned long r_symndx;
@@ -3135,6 +3137,20 @@ mips_elf_calculate_relocation (bfd *abfd
gp_disp_p = TRUE;
}
+ /* See if this is the special _gp symbol. Note that such a
+ symbol must always be a global symbol. */
+ else if (strcmp (*namep, "_gp") == 0
+ && ! NEWABI_P (input_bfd))
+ {
+ /* Relocations against _gp are permitted only with
+ R_MIPS_HI16 and R_MIPS_LO16 relocations. */
+ if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16
+ && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
+ return bfd_reloc_notsupported;
+
+ gp_p = TRUE;
+ }
+
/* If this symbol is defined, calculate its address. Note that
_gp_disp is a magic symbol, always implicitly defined by the
linker, so it's inappropriate to check to see whether or not
@@ -3415,12 +3431,7 @@ mips_elf_calculate_relocation (bfd *abfd
case R_MIPS_HI16:
case R_MIPS16_HI16:
- if (!gp_disp_p)
- {
- value = mips_elf_high (addend + symbol);
- value &= howto->dst_mask;
- }
- else
+ if (gp_disp_p)
{
/* For MIPS16 ABI code we generate this sequence
0: li $v0,%hi(_gp_disp)
@@ -3437,13 +3448,21 @@ mips_elf_calculate_relocation (bfd *abfd
value = mips_elf_high (addend + gp - p);
overflowed_p = mips_elf_overflow_p (value, 16);
}
+ else if (gp_p)
+ {
+ value = mips_elf_high (addend + gp);
+ overflowed_p = mips_elf_overflow_p (value, 16);
+ }
+ else
+ {
+ value = mips_elf_high (addend + symbol);
+ value &= howto->dst_mask;
+ }
break;
case R_MIPS_LO16:
case R_MIPS16_LO16:
- if (!gp_disp_p)
- value = (symbol + addend) & howto->dst_mask;
- else
+ if (gp_disp_p)
{
/* See the comment for R_MIPS16_HI16 above for the reason
for this conditional. */
@@ -3468,6 +3487,12 @@ mips_elf_calculate_relocation (bfd *abfd
Therefore, we consider this a bug in the MIPS ABI, and do
not check for overflow here. */
}
+ else if (gp_p)
+ {
+ value = addend + gp;
+ }
+ else
+ value = (symbol + addend) & howto->dst_mask;
break;
case R_MIPS_LITERAL: