This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
2.10.91: R_MIPS_CALL* relocation fixes
- To: binutils at sourceware dot cygnus dot com
- Subject: 2.10.91: R_MIPS_CALL* relocation fixes
- From: "Maciej W. Rozycki" <macro at ds2 dot pg dot gda dot pl>
- Date: Mon, 22 Jan 2001 18:02:29 +0100 (MET)
- Organization: Technical University of Gdansk
Hi,
The following changes were discussed back in November 2000 here. In
short, we currently make stubs for all functions even if there are
relocations related to taking a function's address. This renders lazy
binding visible to programs.
The patch to gas is not a perfect one -- we discussed "%call", "%call_hi"
and "%call_lo" operators to designate symbol references that could be
assigned one of R_MIPS_CALL* relocations. This would require gcc changes
and surely cannot be performed in short term. I'm also thinking of
detecting common "la $25,symbol; jr/jalr $25" sequences in PIC code as
well. I hope I will be able to provide these changes by the 2.12 release
but for now, I'm asking to include the patch anyway. It does not make
things worse than they are now (all functions get stubs) and it improves
performance after BFD is fixed (no functions get stubs with gcc).
bfd/ChangeLog:
2001-01-18 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
* elf32-mips.c (struct mips_elf_link_hash_entry): Added no_fn_stub
member to mark symbols that have non-CALL relocations against
them.
(mips_elf_link_hash_newfunc): Initialize no_fn_stub.
(mips_elf_calculate_relocation): Handle R_MIPS_CALL16 like
R_MIPS_GOT16.
(_bfd_mips_elf_check_relocs): Set no_fn_stub for a symbol if a
non-CALL relocation against it is encountered.
(_bfd_mips_elf_copy_indirect_symbol): Merge no_fn_stub as well.
(_bfd_mips_elf_adjust_dynamic_symbol): Only create a stub if
no_fn_stub is not set.
gas/ChangeLog:
2001-01-18 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
* config/tc-mips.c (macro): For M_LA_AB emit a
BFD_RELOC_MIPS_CALL16 relocation or a
BFD_RELOC_MIPS_CALL_HI16/BFD_RELOC_MIPS_CALL_LO16 pair instead of
BFD_RELOC_MIPS_GOT16 and
BFD_RELOC_MIPS_GOT_HI16/BFD_RELOC_MIPS_GOT_LO16, respectively for
loading the jump register when generating SVR4_PIC code.
Maciej
--
+ Maciej W. Rozycki, Technical University of Gdansk, Poland +
+--------------------------------------------------------------+
+ e-mail: macro@ds2.pg.gda.pl, PGP key available +
binutils-2.10.91-20010116-mips-call_reloc.patch
diff -up --recursive --new-file binutils.macro/bfd/elf32-mips.c binutils/bfd/elf32-mips.c
--- binutils.macro/bfd/elf32-mips.c Wed Dec 13 04:26:02 2000
+++ binutils/bfd/elf32-mips.c Thu Jan 18 22:54:41 2001
@@ -80,6 +80,12 @@ struct mips_elf_link_hash_entry
section) against this symbol. */
unsigned int min_dyn_reloc_index;
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address, i.e. any but
+ R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
+ p. 4-20. */
+ boolean no_fn_stub;
+
/* If there is a stub that 32 bit functions should use to call this
16 bit function, this points to the section containing the stub. */
asection *fn_stub;
@@ -3955,6 +3961,7 @@ mips_elf_link_hash_newfunc (entry, table
ret->esym.ifd = -2;
ret->possibly_dynamic_relocs = 0;
ret->min_dyn_reloc_index = 0;
+ ret->no_fn_stub = false;
ret->fn_stub = NULL;
ret->need_fn_stub = false;
ret->call_stub = NULL;
@@ -6225,7 +6232,7 @@ mips_elf_calculate_relocation (abfd,
symbol + addend, sgot->contents + g);
}
}
- else if (r_type == R_MIPS_GOT16)
+ else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
/* There's no need to create a local GOT entry here; the
calculation for a local GOT16 entry does not involve G. */
break;
@@ -6393,6 +6400,7 @@ mips_elf_calculate_relocation (abfd,
break;
case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
if (local_p)
{
boolean forced;
@@ -6415,7 +6423,6 @@ mips_elf_calculate_relocation (abfd,
/* Fall through. */
- case R_MIPS_CALL16:
case R_MIPS_GOT_DISP:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
@@ -7728,10 +7735,10 @@ _bfd_mips_elf_check_relocs (abfd, info,
/* We may need a local GOT entry for this relocation. We
don't count R_MIPS_GOT_PAGE because we can estimate the
maximum number of pages needed by looking at the size of
- the segment. Similar comments apply to R_MIPS_GOT16. We
- don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because
- these are always followed by an R_MIPS_GOT_LO16 or
- R_MIPS_CALL_LO16.
+ the segment. Similar comments apply to R_MIPS_GOT16 and
+ R_MIPS_CALL16. We don't count R_MIPS_GOT_HI16, or
+ R_MIPS_CALL_HI16 because these are always followed by an
+ R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
This estimation is very conservative since we can merge
duplicate entries in the GOT. In order to be less
@@ -7863,6 +7870,25 @@ _bfd_mips_elf_check_relocs (abfd, info,
break;
}
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address. */
+ switch (r_type)
+ {
+ default:
+ if (h != NULL)
+ {
+ struct mips_elf_link_hash_entry *mh;
+
+ mh = (struct mips_elf_link_hash_entry *) h;
+ mh->no_fn_stub = true;
+ }
+ break;
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ break;
+ }
+
/* If this reloc is not a 16 bit call, and it has a global
symbol, then we will need the fn_stub if there is one.
References from a stub section do not count. */
@@ -7998,6 +8024,8 @@ _bfd_mips_elf_copy_indirect_symbol (dir,
|| (indmips->min_dyn_reloc_index != 0
&& indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
+ if (indmips->no_fn_stub)
+ dirmips->no_fn_stub = true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
@@ -8038,8 +8066,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (inf
mips_elf_allocate_dynamic_relocations (dynobj,
hmips->possibly_dynamic_relocs);
- /* For a function, create a stub, if needed. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ /* For a function, create a stub, if allowed. */
+ if (! hmips->no_fn_stub
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
if (! elf_hash_table (info)->dynamic_sections_created)
return true;
diff -up --recursive --new-file binutils.macro/gas/config/tc-mips.c binutils/gas/config/tc-mips.c
--- binutils.macro/gas/config/tc-mips.c Fri Dec 29 04:26:01 2000
+++ binutils/gas/config/tc-mips.c Thu Jan 18 22:51:14 2001
@@ -4213,9 +4213,13 @@ macro (ip)
}
else if (mips_pic == SVR4_PIC && ! mips_big_got)
{
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
/* If this is a reference to an external symbol, and there
is no constant, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ or if tempreg is PIC_CALL_REG
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_CALL16)
For a local symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
@@ -4242,9 +4246,11 @@ macro (ip)
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
frag_grow (32);
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
macro_build ((char *) NULL, &icnt, &offset_expr,
dbl ? "ld" : "lw",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+ "t,o(b)", tempreg, lw_reloc_type, GP);
if (expr1.X_add_number == 0)
{
int off;
@@ -4350,12 +4356,18 @@ macro (ip)
else if (mips_pic == SVR4_PIC)
{
int gpdel;
+ int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
/* This is the large GOT case. If this is a reference to an
external symbol, and there is no constant, we want
lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
addu $tempreg,$tempreg,$gp
lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ or if tempreg is PIC_CALL_REG
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
For a local symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
@@ -4394,8 +4406,13 @@ macro (ip)
gpdel = 4;
else
gpdel = 0;
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ {
+ lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+ }
macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
- tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
+ tempreg, lui_reloc_type);
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
((bfd_arch_bits_per_address (stdoutput) == 32
|| ! ISA_HAS_64BIT_REGS (mips_opts.isa))
@@ -4403,8 +4420,7 @@ macro (ip)
"d,v,t", tempreg, tempreg, GP);
macro_build ((char *) NULL, &icnt, &offset_expr,
dbl ? "ld" : "lw",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
- tempreg);
+ "t,o(b)", tempreg, lw_reloc_type, tempreg);
if (expr1.X_add_number == 0)
{
int off;