This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
.gpdword support, elf64-mips fixes
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: binutils at sources dot redhat dot com, echristo at redhat dot com
- Date: 12 Oct 2002 02:44:39 -0300
- Subject: .gpdword support, elf64-mips fixes
- Organization: GCC Team, Red Hat
This patch implements .gpdword (thanks for the starting point, Eric!),
arranges for .cpadd to be usable in n32 and n64, and fixes a few
problems with gp-relative relocations that I ran into while playing
with it. I have a patch for GCC that exercises these features, and I
couldn't figure out how to do multi-stage relocatable links of large
files, that would be necessary to test all of the problems this patch
fixes. I hope this is still acceptable.
One of the problems was with GPREL32, that could no longer be
truncated to 32 bits when its value was actually being composed with a
_64 relocation (that's how the MIPS ELF64 ABI says 64-bit GPREL
relocations are supposed to be represented; eek! :-)
The other problems were in GPREL16 relocations, whose addends were
truncated to 16 bits even though they could be (and were!) wider than
that with RELA relocations. Also, I had problems with symbols that
were forced local with linker scripts: we'd add gp0 to them even
though the original gp value hadn't been subtracted from their addends
in earlier relocatable links.
No regressions on mips-elf. Ok to install?
Index: bfd/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* elfxx-mips.c (mips_elf_calculate_relocation): Take
save_addend argument. Don't apply the 32-bit mask to a
GPREL32 value if it's to be used in another relocation. Don't
use forced-check computation of local_p to decide whether to
add gp0 to GPREL16 value. Don't use only the lowest 16 bits
of the addend of a non-in-place GPREL16 relocation.
(_bfd_mips_elf_relocate_section): Pass use_saved_addend_p to
mips_elf_calculate_relocation().
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.26
diff -u -p -r1.26 elfxx-mips.c
--- bfd/elfxx-mips.c 11 Oct 2002 08:33:11 -0000 1.26
+++ bfd/elfxx-mips.c 12 Oct 2002 05:27:58 -0000
@@ -345,7 +345,7 @@ static bfd_reloc_status_type mips_elf_ca
PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
Elf_Internal_Sym *, asection **, bfd_vma *, const char **,
- boolean *));
+ boolean *, boolean));
static bfd_vma mips_elf_obtain_contents
PARAMS ((reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *));
static boolean mips_elf_perform_relocation
@@ -2006,7 +2006,7 @@ static bfd_reloc_status_type
mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
relocation, addend, howto, local_syms,
local_sections, valuep, namep,
- require_jalxp)
+ require_jalxp, save_addend)
bfd *abfd;
bfd *input_bfd;
asection *input_section;
@@ -2019,6 +2019,7 @@ mips_elf_calculate_relocation (abfd, inp
bfd_vma *valuep;
const char **namep;
boolean *require_jalxp;
+ boolean save_addend;
{
/* The eventual value we will return. */
bfd_vma value;
@@ -2043,7 +2044,7 @@ mips_elf_calculate_relocation (abfd, inp
struct mips_elf_link_hash_entry *h = NULL;
/* True if the symbol referred to by this relocation is a local
symbol. */
- boolean local_p;
+ boolean local_p, was_local_p;
/* True if the symbol referred to by this relocation is "_gp_disp". */
boolean gp_disp_p = false;
Elf_Internal_Shdr *symtab_hdr;
@@ -2071,6 +2072,7 @@ mips_elf_calculate_relocation (abfd, inp
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
local_p = mips_elf_local_relocation_p (input_bfd, relocation,
local_sections, false);
+ was_local_p = local_p;
if (! elf_bad_symtab (input_bfd))
extsymoff = symtab_hdr->sh_info;
else
@@ -2458,10 +2460,19 @@ mips_elf_calculate_relocation (abfd, inp
order. We don't need to do anything special here; the
differences are handled in mips_elf_perform_relocation. */
case R_MIPS_GPREL16:
- if (local_p)
- value = mips_elf_sign_extend (addend, 16) + symbol + gp0 - gp;
- else
- value = mips_elf_sign_extend (addend, 16) + symbol - gp;
+ /* Only sign-extend the addend if it was extracted from the
+ 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);
+ value = symbol + addend - gp;
+ /* If the symbol was local, any earlier relocatable links will
+ have adjusted its addend with the gp offset, so compensate
+ for that now. Don't do it for symbols forced local in this
+ link, though, since they won't have had the gp offset applied
+ to them before. */
+ if (was_local_p)
+ value += gp0;
overflowed_p = mips_elf_overflow_p (value, 16);
break;
@@ -2494,7 +2505,9 @@ mips_elf_calculate_relocation (abfd, inp
break;
case R_MIPS_GPREL32:
- value = (addend + symbol + gp0 - gp) & howto->dst_mask;
+ value = (addend + symbol + gp0 - gp);
+ if (!save_addend)
+ value &= howto->dst_mask;
break;
case R_MIPS_PC16:
@@ -5251,7 +5264,8 @@ _bfd_mips_elf_relocate_section (output_b
input_section, info, rel,
addend, howto, local_syms,
local_sections, &value,
- &name, &require_jalx))
+ &name, &require_jalx,
+ use_saved_addend_p))
{
case bfd_reloc_continue:
/* There's nothing to do. */
Index: gas/ChangeLog
from Eric Christopher <echristo@redhat.com>, Alexandre Oliva <aoliva@redhat.com>
* config/tc-mips.c (s_gpdword): New function.
(mips_pseudo_table): Add .gpdword.
(mips_need_elf_addend_fixup): never for NEWABI.
(md_apply_fix3): Don't mark BFD_RELOC64 after GPREL16 or
GPREL32 as done.
(s_cpadd): Generate .cpadd on NEWABI.
Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.172
diff -u -p -r1.172 tc-mips.c
--- gas/config/tc-mips.c 12 Oct 2002 05:23:32 -0000 1.172
+++ gas/config/tc-mips.c 12 Oct 2002 05:44:09 -0000
@@ -860,6 +860,7 @@ static void s_cprestore PARAMS ((int));
static void s_cpreturn PARAMS ((int));
static void s_gpvalue PARAMS ((int));
static void s_gpword PARAMS ((int));
+static void s_gpdword PARAMS ((int));
static void s_cpadd PARAMS ((int));
static void s_insn PARAMS ((int));
static void md_obj_begin PARAMS ((void));
@@ -961,6 +962,7 @@ static const pseudo_typeS mips_pseudo_ta
{"cpreturn", s_cpreturn, 0},
{"gpvalue", s_gpvalue, 0},
{"gpword", s_gpword, 0},
+ {"gpdword", s_gpdword, 0},
{"cpadd", s_cpadd, 0},
{"insn", s_insn, 0},
@@ -11105,6 +11107,9 @@ md_apply_fix3 (fixP, valP, seg)
/* 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
+ || (fixP->fx_r_type == BFD_RELOC_64
+ && (previous_fx_r_type == BFD_RELOC_GPREL32
+ || previous_fx_r_type == BFD_RELOC_GPREL16))
|| (previous_fx_r_type == BFD_RELOC_MIPS_SUB
&& (fixP->fx_r_type == BFD_RELOC_HI16_S
|| fixP->fx_r_type == BFD_RELOC_LO16))))
@@ -12303,6 +12308,50 @@ s_gpword (ignore)
demand_empty_rest_of_line ();
}
+static void
+s_gpdword (ignore)
+ int ignore ATTRIBUTE_UNUSED;
+{
+ symbolS *label;
+ expressionS ex;
+ char *p;
+
+ /* When not generating PIC code, this is treated as .dword. */
+ if (mips_pic != SVR4_PIC)
+ {
+ s_cons (3);
+ return;
+ }
+
+ label = insn_labels != NULL ? insn_labels->label : NULL;
+ mips_emit_delays (true);
+ if (auto_align)
+ mips_align (3, 0, label);
+ mips_clear_insn_labels ();
+
+ expression (&ex);
+
+ if (ex.X_op != O_symbol || ex.X_add_number != 0)
+ {
+ as_bad (_("Unsupported use of .gpdword"));
+ ignore_rest_of_line ();
+ }
+
+ p = frag_more (8);
+ md_number_to_chars (p, (valueT) 0, 8);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &ex, false,
+ BFD_RELOC_GPREL32);
+
+ /* GPREL32 composed with 64 gives a 64-bit GP offset. */
+ ex.X_op = O_absent;
+ ex.X_add_symbol = 0;
+ ex.X_add_number = 0;
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &ex, false,
+ BFD_RELOC_64);
+
+ demand_empty_rest_of_line ();
+}
+
/* Handle the .cpadd pseudo-op. This is used when dealing with switch
tables in SVR4 PIC code. */
@@ -12313,9 +12362,8 @@ s_cpadd (ignore)
int icnt = 0;
int reg;
- /* This is ignored when not generating SVR4 PIC code or if this is NewABI
- code. */
- if (mips_pic != SVR4_PIC || HAVE_NEWABI)
+ /* This is ignored when not generating SVR4 PIC code. */
+ if (mips_pic != SVR4_PIC)
{
s_ignore (0);
return;
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist Professional serial bug killer