This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
fix alpha hidden undefweak ld tests
- From: Richard Henderson <rth at twiddle dot net>
- To: binutils at gcc dot gnu dot org
- Date: Sun, 22 May 2005 15:21:06 -0700
- Subject: fix alpha hidden undefweak ld tests
To fix the bug, the minimum change is in elf64_alpha_relocate_section.
There, we were applying RELATIVE relocs to the undefweak symbol, which
of course made the runtime value non-zero.
The elf64_alpha_calc_dynrel_sizes and elf64_alpha_size_rela_got_1 changes
fix up the relocation section sizes so that we don't wind up with extra
NONE relocations where the RELATIVE relocations would have gone.
The relax changes recognize that there are lots of ways to get at zero
without using a .got entry. Since virtually all applications have at
least one undefweak call in crtbegin.o (_Jv_RegisterClasses), this seemed
worthwhile.
r~
* elf64-alpha.c (elf64_alpha_relax_with_lituse): Relax jsr to
undefweak to use zero register. Call elf64_alpha_relax_got_load
if not all uses removed.
(elf64_alpha_relax_got_load): Relax undefweak to lda zero.
(elf64_alpha_relax_section): Handle undefweak symbols.
(elf64_alpha_calc_dynrel_sizes): Don't add relocs for undefweak.
(elf64_alpha_size_rela_got_1): Likewise.
(elf64_alpha_relocate_section): Likewise.
Index: elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.133
diff -u -p -d -r1.133 elf64-alpha.c
--- elf64-alpha.c 22 May 2005 22:07:31 -0000 1.133
+++ elf64-alpha.c 22 May 2005 22:09:36 -0000
@@ -1300,9 +1300,7 @@ elf64_alpha_relax_with_lituse (info, sym
/* Extract the displacement from the instruction, sign-extending
it if necessary, then test whether it is within 16 or 32 bits
displacement from GP. */
- insn_disp = insn & 0x0000ffff;
- if (insn_disp & 0x8000)
- insn_disp |= ~0xffff; /* Negative: sign-extend. */
+ insn_disp = ((insn & 0xffff) ^ 0x8000) - 0x8000;
xdisp = disp + insn_disp;
fits16 = (xdisp >= - (bfd_signed_vma) 0x8000 && xdisp < 0x8000);
@@ -1371,6 +1369,19 @@ elf64_alpha_relax_with_lituse (info, sym
bfd_vma optdest, org;
bfd_signed_vma odisp;
+ /* For undefined weak symbols, we're mostly interested in getting
+ rid of the got entry whenever possible, so optimize this to a
+ use of the zero register. */
+ if (info->h && info->h->root.root.type == bfd_link_hash_undefweak)
+ {
+ insn |= 31 << 16;
+ bfd_put_32 (info->abfd, (bfd_vma) insn,
+ info->contents + urel->r_offset);
+
+ info->changed_contents = TRUE;
+ break;
+ }
+
/* If not zero, place to jump without needing pv. */
optdest = elf64_alpha_relax_opt_call (info, symval);
org = (info->sec->output_section->vma
@@ -1474,9 +1485,11 @@ elf64_alpha_relax_with_lituse (info, sym
info->contents + irel->r_offset);
info->changed_contents = TRUE;
}
- }
- return TRUE;
+ return TRUE;
+ }
+ else
+ return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL);
}
static bfd_vma
@@ -1583,7 +1596,25 @@ elf64_alpha_relax_got_load (info, symval
return TRUE;
if (r_type == R_ALPHA_LITERAL)
- disp = symval - info->gp;
+ {
+ /* Look for nice constant addresses. This includes the not-uncommon
+ special case of 0 for undefweak symbols. */
+ if ((info->h && info->h->root.root.type == bfd_link_hash_undefweak)
+ || (!info->link_info->shared
+ && (symval >= (bfd_vma)-0x8000 || symval < 0x8000)))
+ {
+ disp = 0;
+ insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
+ insn |= (symval & 0xffff);
+ r_type = R_ALPHA_NONE;
+ }
+ else
+ {
+ disp = symval - info->gp;
+ insn = (OP_LDA << 26) | (insn & 0x03ff0000);
+ r_type = R_ALPHA_GPREL16;
+ }
+ }
else
{
bfd_vma dtp_base, tp_base;
@@ -1592,17 +1623,26 @@ elf64_alpha_relax_got_load (info, symval
dtp_base = alpha_get_dtprel_base (info->link_info);
tp_base = alpha_get_tprel_base (info->link_info);
disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
+
+ insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
+
+ switch (r_type)
+ {
+ case R_ALPHA_GOTDTPREL:
+ r_type = R_ALPHA_DTPREL16;
+ break;
+ case R_ALPHA_GOTTPREL:
+ r_type = R_ALPHA_TPREL16;
+ break;
+ default:
+ BFD_ASSERT (0);
+ return FALSE;
+ }
}
if (disp < -0x8000 || disp >= 0x8000)
return TRUE;
- /* Exchange LDQ for LDA. In the case of the TLS relocs, we're loading
- a constant, so force the base register to be $31. */
- if (r_type == R_ALPHA_LITERAL)
- insn = (OP_LDA << 26) | (insn & 0x03ff0000);
- else
- insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
info->changed_contents = TRUE;
@@ -1617,22 +1657,6 @@ elf64_alpha_relax_got_load (info, symval
}
/* Smash the existing GOT relocation for its 16-bit immediate pair. */
- switch (r_type)
- {
- case R_ALPHA_LITERAL:
- r_type = R_ALPHA_GPREL16;
- break;
- case R_ALPHA_GOTDTPREL:
- r_type = R_ALPHA_DTPREL16;
- break;
- case R_ALPHA_GOTTPREL:
- r_type = R_ALPHA_TPREL16;
- break;
- default:
- BFD_ASSERT (0);
- return FALSE;
- }
-
irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type);
info->changed_relocs = TRUE;
@@ -2103,13 +2127,17 @@ elf64_alpha_relax_section (abfd, sec, li
h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
/* If the symbol is undefined, we can't do anything with it. */
- if (h->root.root.type == bfd_link_hash_undefweak
- || h->root.root.type == bfd_link_hash_undefined)
+ if (h->root.root.type == bfd_link_hash_undefined)
continue;
- /* If the symbol isn't defined in the current module, again
- we can't do anything. */
- if (!h->root.def_regular)
+ /* If the symbol isn't defined in the current module,
+ again we can't do anything. */
+ if (h->root.root.type == bfd_link_hash_undefweak)
+ {
+ info.tsec = bfd_abs_section_ptr;
+ symval = 0;
+ }
+ else if (!h->root.def_regular)
{
/* Except for TLSGD relocs, which can sometimes be
relaxed to GOTTPREL relocs. */
@@ -3860,9 +3888,14 @@ elf64_alpha_calc_dynrel_sizes (h, info)
/* If the symbol is dynamic, we'll need all the relocations in their
natural form. If this is a shared object, and it has been forced
local, we'll need the same number of RELATIVE relocations. */
-
dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
+ /* If the symbol is a hidden undefined weak, then we never have any
+ relocations. Avoid the loop which may want to add RELATIVE relocs
+ based on info->shared. */
+ if (h->root.root.type == bfd_link_hash_undefweak && !dynamic)
+ return TRUE;
+
for (relent = h->reloc_entries; relent; relent = relent->next)
{
entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
@@ -3950,9 +3983,14 @@ elf64_alpha_size_rela_got_1 (h, info)
/* If the symbol is dynamic, we'll need all the relocations in their
natural form. If this is a shared object, and it has been forced
local, we'll need the same number of RELATIVE relocations. */
-
dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
+ /* If the symbol is a hidden undefined weak, then we never have any
+ relocations. Avoid the loop which may want to add RELATIVE relocs
+ based on info->shared. */
+ if (h->root.root.type == bfd_link_hash_undefweak && !dynamic)
+ return TRUE;
+
entries = 0;
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
if (gotent->use_count > 0)
@@ -4445,7 +4483,7 @@ elf64_alpha_relocate_section (output_bfd
/* If the symbol has been forced local, output a
RELATIVE reloc, otherwise it will be handled in
finish_dynamic_symbol. */
- if (info->shared && !dynamic_symbol_p)
+ if (info->shared && !dynamic_symbol_p && !undef_weak_ref)
elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
gotent->got_offset, 0,
R_ALPHA_RELATIVE, value);
@@ -4617,7 +4655,8 @@ elf64_alpha_relocate_section (output_bfd
}
else if (info->shared
&& r_symndx != 0
- && (input_section->flags & SEC_ALLOC))
+ && (input_section->flags & SEC_ALLOC)
+ && !undef_weak_ref)
{
if (r_type == R_ALPHA_REFLONG)
{
@@ -4650,6 +4689,14 @@ elf64_alpha_relocate_section (output_bfd
input_bfd, h->root.root.root.string);
ret_val = FALSE;
}
+ else if ((info->shared || info->pie) && undef_weak_ref)
+ {
+ (*_bfd_error_handler)
+ (_("%B: pc-relative relocation against undefined weak symbol %s"),
+ input_bfd, h->root.root.root.string);
+ ret_val = FALSE;
+ }
+
/* ??? .eh_frame references to discarded sections will be smashed
to relocations against SHN_UNDEF. The .eh_frame format allows