* elf32-sparc.c (WILL_CALL_FINISH_DYNAMIC_SYMBOL): New.

(elf32_sparc_relocate_section): Use it to figure out when to
        initialize .got entries.
        * elf64-sparc.c: Similarly.
This commit is contained in:
Richard Henderson
2002-04-01 10:00:49 +00:00
parent 2fccf04a44
commit e36f7d5326
3 changed files with 106 additions and 174 deletions

View File

@ -1,3 +1,10 @@
2002-04-01 Richard Henderson <rth@redhat.com>
* elf32-sparc.c (WILL_CALL_FINISH_DYNAMIC_SYMBOL): New.
(elf32_sparc_relocate_section): Use it to figure out when to
initialize .got entries.
* elf64-sparc.c: Similarly.
2002-03-28 Alan Modra <amodra@bigpond.net.au> 2002-03-28 Alan Modra <amodra@bigpond.net.au>
* linker.c (link_action): Ignore duplicate warning syms. * linker.c (link_action): Ignore duplicate warning syms.

View File

@ -1084,6 +1084,17 @@ elf32_sparc_relax_section (abfd, section, link_info, again)
return true; return true;
} }
/* This is the condition under which finish_dynamic_symbol will be called
from elflink.h. If elflink.h doesn't call our finish_dynamic_symbol
routine, we'll need to do something about initializing any .plt and .got
entries in relocate_section. */
#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \
((DYN) \
&& ((INFO)->shared \
|| ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \
&& ((H)->dynindx != -1 \
|| ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
/* Relocate a SPARC ELF section. */ /* Relocate a SPARC ELF section. */
static boolean static boolean
@ -1133,9 +1144,10 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
struct elf_link_hash_entry *h; struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym; Elf_Internal_Sym *sym;
asection *sec; asection *sec;
bfd_vma relocation; bfd_vma relocation, off;
bfd_reloc_status_type r; bfd_reloc_status_type r;
boolean is_plt = false; boolean is_plt = false;
boolean unresolved_reloc;
r_type = ELF32_R_TYPE (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info);
@ -1175,6 +1187,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
h = NULL; h = NULL;
sym = NULL; sym = NULL;
sec = NULL; sec = NULL;
unresolved_reloc = false;
if (r_symndx < symtab_hdr->sh_info) if (r_symndx < symtab_hdr->sh_info)
{ {
sym = local_syms + r_symndx; sym = local_syms + r_symndx;
@ -1187,71 +1200,30 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
while (h->root.type == bfd_link_hash_indirect while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning) || h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link; h = (struct elf_link_hash_entry *) h->root.u.i.link;
relocation = 0;
if (h->root.type == bfd_link_hash_defined if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak) || h->root.type == bfd_link_hash_defweak)
{ {
sec = h->root.u.def.section; sec = h->root.u.def.section;
if (((r_type == R_SPARC_WPLT30 if (sec->output_section == NULL)
|| r_type == R_SPARC_PLT32) /* Set a flag that will be cleared later if we find a
&& h->plt.offset != (bfd_vma) -1) relocation value for this symbol. output_section
|| ((r_type == R_SPARC_GOT10 is typically NULL for symbols satisfied by a shared
|| r_type == R_SPARC_GOT13 library. */
|| r_type == R_SPARC_GOT22) unresolved_reloc = true;
&& elf_hash_table (info)->dynamic_sections_created
&& (! info->shared
|| (! info->symbolic && h->dynindx != -1)
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0))
|| (info->shared
&& ((! info->symbolic && h->dynindx != -1)
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0)
&& (r_type == R_SPARC_8
|| r_type == R_SPARC_16
|| r_type == R_SPARC_32
|| r_type == R_SPARC_DISP8
|| r_type == R_SPARC_DISP16
|| r_type == R_SPARC_DISP32
|| r_type == R_SPARC_WDISP30
|| r_type == R_SPARC_WDISP22
|| r_type == R_SPARC_WDISP19
|| r_type == R_SPARC_WDISP16
|| r_type == R_SPARC_HI22
|| r_type == R_SPARC_22
|| r_type == R_SPARC_13
|| r_type == R_SPARC_LO10
|| r_type == R_SPARC_UA16
|| r_type == R_SPARC_UA32
|| ((r_type == R_SPARC_PC10
|| r_type == R_SPARC_PC22)
&& strcmp (h->root.root.string,
"_GLOBAL_OFFSET_TABLE_") != 0))
&& ((input_section->flags & SEC_ALLOC) != 0
/* DWARF will emit R_SPARC_32 relocations in its
sections against symbols defined externally
in shared libraries. We can't do anything
with them here. */
|| ((input_section->flags & SEC_DEBUGGING) != 0
&& (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_DYNAMIC) != 0))))
{
/* In these cases, we don't need the relocation
value. We check specially because in some
obscure cases sec->output_section will be NULL. */
relocation = 0;
}
else else
relocation = (h->root.u.def.value relocation = (h->root.u.def.value
+ sec->output_section->vma + sec->output_section->vma
+ sec->output_offset); + sec->output_offset);
} }
else if (h->root.type == bfd_link_hash_undefweak) else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0; ;
else if (info->shared else if (info->shared
&& (!info->symbolic || info->allow_shlib_undefined) && (!info->symbolic || info->allow_shlib_undefined)
&& !info->no_undefined && !info->no_undefined
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
relocation = 0; ;
else else
{ {
if (! ((*info->callbacks->undefined_symbol) if (! ((*info->callbacks->undefined_symbol)
@ -1260,7 +1232,6 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
(!info->shared || info->no_undefined (!info->shared || info->no_undefined
|| ELF_ST_VISIBILITY (h->other))))) || ELF_ST_VISIBILITY (h->other)))))
return false; return false;
relocation = 0;
} }
} }
@ -1279,14 +1250,17 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
if (h != NULL) if (h != NULL)
{ {
bfd_vma off; boolean dyn;
off = h->got.offset; off = h->got.offset;
BFD_ASSERT (off != (bfd_vma) -1); BFD_ASSERT (off != (bfd_vma) -1);
dyn = elf_hash_table (info)->dynamic_sections_created;
if (! elf_hash_table (info)->dynamic_sections_created if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
|| (info->shared || (info->shared
&& (info->symbolic || h->dynindx == -1) && (info->symbolic
|| h->dynindx == -1
|| (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
{ {
/* This is actually a static link, or it is a /* This is actually a static link, or it is a
@ -1310,13 +1284,11 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
h->got.offset |= 1; h->got.offset |= 1;
} }
} }
else
relocation = sgot->output_offset + off - got_base; unresolved_reloc = false;
} }
else else
{ {
bfd_vma off;
BFD_ASSERT (local_got_offsets != NULL BFD_ASSERT (local_got_offsets != NULL
&& local_got_offsets[r_symndx] != (bfd_vma) -1); && local_got_offsets[r_symndx] != (bfd_vma) -1);
@ -1355,10 +1327,8 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
local_got_offsets[r_symndx] |= 1; local_got_offsets[r_symndx] |= 1;
} }
relocation = sgot->output_offset + off - got_base;
} }
relocation = sgot->output_offset + off - got_base;
break; break;
case R_SPARC_PLT32: case R_SPARC_PLT32:
@ -1396,6 +1366,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
relocation = (splt->output_section->vma relocation = (splt->output_section->vma
+ splt->output_offset + splt->output_offset
+ h->plt.offset); + h->plt.offset);
unresolved_reloc = false;
if (r_type == R_SPARC_PLT32) if (r_type == R_SPARC_PLT32)
{ {
r_type = R_SPARC_32; r_type = R_SPARC_32;
@ -1582,6 +1553,18 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
break; break;
} }
/* ??? Copied from elf32-i386.c, debugging section check and all. */
if (unresolved_reloc
&& !(info->shared
&& (input_section->flags & SEC_DEBUGGING) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
(*_bfd_error_handler)
(_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
bfd_archive_filename (input_bfd),
bfd_get_section_name (input_bfd, input_section),
(long) rel->r_offset,
h->root.root.string);
r = bfd_reloc_continue; r = bfd_reloc_continue;
if (r_type == R_SPARC_WDISP16) if (r_type == R_SPARC_WDISP16)
{ {

View File

@ -1881,6 +1881,17 @@ sparc64_elf_relax_section (abfd, section, link_info, again)
return true; return true;
} }
/* This is the condition under which finish_dynamic_symbol will be called
from elflink.h. If elflink.h doesn't call our finish_dynamic_symbol
routine, we'll need to do something about initializing any .plt and
.got entries in relocate_section. */
#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \
((DYN) \
&& ((INFO)->shared \
|| ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \
&& ((H)->dynindx != -1 \
|| ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
/* Relocate a SPARC64 ELF section. */ /* Relocate a SPARC64 ELF section. */
static boolean static boolean
@ -1928,9 +1939,10 @@ sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
struct elf_link_hash_entry *h; struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym; Elf_Internal_Sym *sym;
asection *sec; asection *sec;
bfd_vma relocation; bfd_vma relocation, off;
bfd_reloc_status_type r; bfd_reloc_status_type r;
boolean is_plt = false; boolean is_plt = false;
boolean unresolved_reloc;
r_type = ELF64_R_TYPE_ID (rel->r_info); r_type = ELF64_R_TYPE_ID (rel->r_info);
if (r_type < 0 || r_type >= (int) R_SPARC_max_std) if (r_type < 0 || r_type >= (int) R_SPARC_max_std)
@ -1965,6 +1977,7 @@ sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
h = NULL; h = NULL;
sym = NULL; sym = NULL;
sec = NULL; sec = NULL;
unresolved_reloc = false;
if (r_symndx < symtab_hdr->sh_info) if (r_symndx < symtab_hdr->sh_info)
{ {
sym = local_syms + r_symndx; sym = local_syms + r_symndx;
@ -1977,116 +1990,30 @@ sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
while (h->root.type == bfd_link_hash_indirect while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning) || h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link; h = (struct elf_link_hash_entry *) h->root.u.i.link;
relocation = 0;
if (h->root.type == bfd_link_hash_defined if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak) || h->root.type == bfd_link_hash_defweak)
{ {
boolean skip_it = false;
sec = h->root.u.def.section; sec = h->root.u.def.section;
if (sec->output_section == NULL)
switch (r_type) /* Set a flag that will be cleared later if we find a
{ relocation value for this symbol. output_section
case R_SPARC_WPLT30: is typically NULL for symbols satisfied by a shared
case R_SPARC_PLT32: library. */
case R_SPARC_HIPLT22: unresolved_reloc = true;
case R_SPARC_LOPLT10:
case R_SPARC_PCPLT32:
case R_SPARC_PCPLT22:
case R_SPARC_PCPLT10:
case R_SPARC_PLT64:
if (h->plt.offset != (bfd_vma) -1)
skip_it = true;
break;
case R_SPARC_GOT10:
case R_SPARC_GOT13:
case R_SPARC_GOT22:
if (elf_hash_table(info)->dynamic_sections_created
&& (!info->shared
|| (!info->symbolic && h->dynindx != -1)
|| !(h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR)))
skip_it = true;
break;
case R_SPARC_PC10:
case R_SPARC_PC22:
case R_SPARC_PC_HH22:
case R_SPARC_PC_HM10:
case R_SPARC_PC_LM22:
if (!strcmp(h->root.root.string, "_GLOBAL_OFFSET_TABLE_"))
break;
/* FALLTHRU */
case R_SPARC_8:
case R_SPARC_16:
case R_SPARC_32:
case R_SPARC_DISP8:
case R_SPARC_DISP16:
case R_SPARC_DISP32:
case R_SPARC_WDISP30:
case R_SPARC_WDISP22:
case R_SPARC_HI22:
case R_SPARC_22:
case R_SPARC_13:
case R_SPARC_LO10:
case R_SPARC_UA32:
case R_SPARC_10:
case R_SPARC_11:
case R_SPARC_64:
case R_SPARC_OLO10:
case R_SPARC_HH22:
case R_SPARC_HM10:
case R_SPARC_LM22:
case R_SPARC_WDISP19:
case R_SPARC_WDISP16:
case R_SPARC_7:
case R_SPARC_5:
case R_SPARC_6:
case R_SPARC_DISP64:
case R_SPARC_HIX22:
case R_SPARC_LOX10:
case R_SPARC_H44:
case R_SPARC_M44:
case R_SPARC_L44:
case R_SPARC_UA64:
case R_SPARC_UA16:
if (info->shared
&& ((!info->symbolic && h->dynindx != -1)
|| !(h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR))
&& ((input_section->flags & SEC_ALLOC) != 0
/* DWARF will emit R_SPARC_{32,64} relocations in
its sections against symbols defined externally
in shared libraries. We can't do anything
with them here. */
|| ((input_section->flags & SEC_DEBUGGING) != 0
&& (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_DYNAMIC) != 0)))
skip_it = true;
break;
}
if (skip_it)
{
/* In these cases, we don't need the relocation
value. We check specially because in some
obscure cases sec->output_section will be NULL. */
relocation = 0;
}
else else
{
relocation = (h->root.u.def.value relocation = (h->root.u.def.value
+ sec->output_section->vma + sec->output_section->vma
+ sec->output_offset); + sec->output_offset);
} }
}
else if (h->root.type == bfd_link_hash_undefweak) else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0; ;
else if (info->shared else if (info->shared
&& (!info->symbolic || info->allow_shlib_undefined) && (!info->symbolic || info->allow_shlib_undefined)
&& !info->no_undefined && !info->no_undefined
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
relocation = 0; ;
else else
{ {
if (! ((*info->callbacks->undefined_symbol) if (! ((*info->callbacks->undefined_symbol)
@ -2107,7 +2034,7 @@ sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
} }
} }
do_dynreloc: do_dynreloc:
/* When generating a shared object, these relocations are copied /* When generating a shared object, these relocations are copied
into the output file to be resolved at run time. */ into the output file to be resolved at run time. */
if (info->shared && r_symndx != 0 && (input_section->flags & SEC_ALLOC)) if (info->shared && r_symndx != 0 && (input_section->flags & SEC_ALLOC))
@ -2326,14 +2253,18 @@ do_dynreloc:
if (h != NULL) if (h != NULL)
{ {
bfd_vma off = h->got.offset; boolean dyn;
BFD_ASSERT (off != (bfd_vma) -1);
if (! elf_hash_table (info)->dynamic_sections_created off = h->got.offset;
BFD_ASSERT (off != (bfd_vma) -1);
dyn = elf_hash_table (info)->dynamic_sections_created;
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
|| (info->shared || (info->shared
&& (info->symbolic || h->dynindx == -1) && (info->symbolic
&& (h->elf_link_hash_flags || h->dynindx == -1
& ELF_LINK_HASH_DEF_REGULAR))) || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
{ {
/* This is actually a static link, or it is a -Bsymbolic /* This is actually a static link, or it is a -Bsymbolic
link and the symbol is defined locally, or the symbol link and the symbol is defined locally, or the symbol
@ -2356,12 +2287,11 @@ do_dynreloc:
h->got.offset |= 1; h->got.offset |= 1;
} }
} }
relocation = sgot->output_offset + off - got_base; else
unresolved_reloc = false;
} }
else else
{ {
bfd_vma off;
BFD_ASSERT (local_got_offsets != NULL); BFD_ASSERT (local_got_offsets != NULL);
off = local_got_offsets[r_symndx]; off = local_got_offsets[r_symndx];
BFD_ASSERT (off != (bfd_vma) -1); BFD_ASSERT (off != (bfd_vma) -1);
@ -2407,8 +2337,8 @@ do_dynreloc:
else else
bfd_put_64 (output_bfd, relocation, sgot->contents + off); bfd_put_64 (output_bfd, relocation, sgot->contents + off);
} }
relocation = sgot->output_offset + off - got_base;
} }
relocation = sgot->output_offset + off - got_base;
goto do_default; goto do_default;
case R_SPARC_WPLT30: case R_SPARC_WPLT30:
@ -2440,6 +2370,7 @@ do_dynreloc:
relocation = (splt->output_section->vma relocation = (splt->output_section->vma
+ splt->output_offset + splt->output_offset
+ sparc64_elf_plt_entry_offset (h->plt.offset)); + sparc64_elf_plt_entry_offset (h->plt.offset));
unresolved_reloc = false;
if (r_type == R_SPARC_WPLT30) if (r_type == R_SPARC_WPLT30)
goto do_wplt30; goto do_wplt30;
if (r_type == R_SPARC_PLT32 || r_type == R_SPARC_PLT64) if (r_type == R_SPARC_PLT32 || r_type == R_SPARC_PLT64)
@ -2623,6 +2554,17 @@ do_dynreloc:
break; break;
} }
if (unresolved_reloc
&& !(info->shared
&& (input_section->flags & SEC_DEBUGGING) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
(*_bfd_error_handler)
(_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
bfd_archive_filename (input_bfd),
bfd_get_section_name (input_bfd, input_section),
(long) rel->r_offset,
h->root.root.string);
switch (r) switch (r)
{ {
case bfd_reloc_ok: case bfd_reloc_ok: