mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 20:14:06 +08:00
* elf32-ppc.c (struct ppc_elf_dyn_relocs): Define.
(struct ppc_elf_link_hash_entry): Define. (ppc_elf_hash_entry): New function. (struct ppc_elf_link_hash_table): Define. (ppc_elf_hash_table): New function. (ppc_elf_link_hash_newfunc): New function. (ppc_elf_link_hash_table_create): New function. (ppc_elf_copy_indirect_symbol): New function. (allocate_dynrelocs): New function. (readonly_dynrelocs): New function. (ppc_elf_size_dynamic_sections): Allocate space for dynamic relocs and determine DT_TEXTREL. (ppc_elf_check_relocs): Don't do that here, just count the dynamic relocs. (ppc_elf_gc_sweep_hook): Discard any dynamic relocs against the removed section. (bfd_elf32_bfd_link_hash_table_create): Define. (elf_backend_copy_indirect_symbol): Define.
This commit is contained in:
parent
1bbc9cec6b
commit
7fce784e9a
@ -1,3 +1,24 @@
|
||||
2003-01-21 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* elf32-ppc.c (struct ppc_elf_dyn_relocs): Define.
|
||||
(struct ppc_elf_link_hash_entry): Define.
|
||||
(ppc_elf_hash_entry): New function.
|
||||
(struct ppc_elf_link_hash_table): Define.
|
||||
(ppc_elf_hash_table): New function.
|
||||
(ppc_elf_link_hash_newfunc): New function.
|
||||
(ppc_elf_link_hash_table_create): New function.
|
||||
(ppc_elf_copy_indirect_symbol): New function.
|
||||
(allocate_dynrelocs): New function.
|
||||
(readonly_dynrelocs): New function.
|
||||
(ppc_elf_size_dynamic_sections): Allocate space for dynamic
|
||||
relocs and determine DT_TEXTREL.
|
||||
(ppc_elf_check_relocs): Don't do that here, just count the
|
||||
dynamic relocs.
|
||||
(ppc_elf_gc_sweep_hook): Discard any dynamic relocs against the
|
||||
removed section.
|
||||
(bfd_elf32_bfd_link_hash_table_create): Define.
|
||||
(elf_backend_copy_indirect_symbol): Define.
|
||||
|
||||
2003-01-21 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* elf64-alpha.c (alpha_dynamic_entries_for_reloc): GOTTPREL and
|
||||
|
333
bfd/elf32-ppc.c
333
bfd/elf32-ppc.c
@ -33,6 +33,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* RELA relocations are used here. */
|
||||
|
||||
static struct bfd_hash_entry *ppc_elf_link_hash_newfunc
|
||||
PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table,
|
||||
const char *string));
|
||||
static struct bfd_link_hash_table *ppc_elf_link_hash_table_create
|
||||
PARAMS ((bfd *abfd));
|
||||
static void ppc_elf_copy_indirect_symbol
|
||||
PARAMS ((struct elf_backend_data *bed, struct elf_link_hash_entry *dir,
|
||||
struct elf_link_hash_entry *ind));
|
||||
static reloc_howto_type *ppc_elf_reloc_type_lookup
|
||||
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
|
||||
static void ppc_elf_info_to_howto
|
||||
@ -77,6 +85,10 @@ static bfd_boolean ppc_elf_gc_sweep_hook
|
||||
const Elf_Internal_Rela *relocs));
|
||||
static bfd_boolean ppc_elf_adjust_dynamic_symbol
|
||||
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
|
||||
static bfd_boolean allocate_dynrelocs
|
||||
PARAMS ((struct elf_link_hash_entry *, PTR));
|
||||
static bfd_boolean readonly_dynrelocs
|
||||
PARAMS ((struct elf_link_hash_entry *, PTR));
|
||||
static bfd_boolean ppc_elf_size_dynamic_sections
|
||||
PARAMS ((bfd *, struct bfd_link_info *));
|
||||
static bfd_boolean ppc_elf_relocate_section
|
||||
@ -134,6 +146,149 @@ static bfd_boolean ppc_elf_grok_psinfo
|
||||
|| ELF_ST_VISIBILITY (H->other) != STV_DEFAULT) \
|
||||
&& (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
|
||||
|
||||
/* The PPC linker needs to keep track of the number of relocs that it
|
||||
decides to copy as dynamic relocs in check_relocs for each symbol.
|
||||
This is so that it can later discard them if they are found to be
|
||||
unnecessary. We store the information in a field extending the
|
||||
regular ELF linker hash table. */
|
||||
|
||||
struct ppc_elf_dyn_relocs
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *next;
|
||||
|
||||
/* The input section of the reloc. */
|
||||
asection *sec;
|
||||
|
||||
/* Total number of relocs copied for the input section. */
|
||||
bfd_size_type count;
|
||||
};
|
||||
|
||||
/* PPC ELF linker hash entry. */
|
||||
|
||||
struct ppc_elf_link_hash_entry
|
||||
{
|
||||
struct elf_link_hash_entry root;
|
||||
|
||||
/* Track dynamic relocs copied for this symbol. */
|
||||
struct ppc_elf_dyn_relocs *dyn_relocs;
|
||||
};
|
||||
|
||||
#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
|
||||
|
||||
/* PPC ELF linker hash table. */
|
||||
|
||||
struct ppc_elf_link_hash_table
|
||||
{
|
||||
struct elf_link_hash_table root;
|
||||
|
||||
/* Small local sym to section mapping cache. */
|
||||
struct sym_sec_cache sym_sec;
|
||||
};
|
||||
|
||||
/* Get the PPC ELF linker hash table from a link_info structure. */
|
||||
|
||||
#define ppc_elf_hash_table(p) \
|
||||
((struct ppc_elf_link_hash_table *) (p)->hash)
|
||||
|
||||
/* Create an entry in a PPC ELF linker hash table. */
|
||||
|
||||
static struct bfd_hash_entry *
|
||||
ppc_elf_link_hash_newfunc (entry, table, string)
|
||||
struct bfd_hash_entry *entry;
|
||||
struct bfd_hash_table *table;
|
||||
const char *string;
|
||||
{
|
||||
/* Allocate the structure if it has not already been allocated by a
|
||||
subclass. */
|
||||
if (entry == NULL)
|
||||
{
|
||||
entry = bfd_hash_allocate (table,
|
||||
sizeof (struct ppc_elf_link_hash_entry));
|
||||
if (entry == NULL)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Call the allocation method of the superclass. */
|
||||
entry = _bfd_elf_link_hash_newfunc (entry, table, string);
|
||||
if (entry != NULL)
|
||||
ppc_elf_hash_entry (entry)->dyn_relocs = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Create a PPC ELF linker hash table. */
|
||||
|
||||
static struct bfd_link_hash_table *
|
||||
ppc_elf_link_hash_table_create (abfd)
|
||||
bfd *abfd;
|
||||
{
|
||||
struct ppc_elf_link_hash_table *ret;
|
||||
|
||||
ret = ((struct ppc_elf_link_hash_table *)
|
||||
bfd_malloc (sizeof (struct ppc_elf_link_hash_table)));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
|
||||
ppc_elf_link_hash_newfunc))
|
||||
{
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->sym_sec.abfd = NULL;
|
||||
|
||||
return &ret->root.root;
|
||||
}
|
||||
|
||||
/* Copy the extra info we tack onto an elf_link_hash_entry. */
|
||||
|
||||
static void
|
||||
ppc_elf_copy_indirect_symbol (bed, dir, ind)
|
||||
struct elf_backend_data *bed;
|
||||
struct elf_link_hash_entry *dir, *ind;
|
||||
{
|
||||
struct ppc_elf_link_hash_entry *edir, *eind;
|
||||
|
||||
edir = (struct ppc_elf_link_hash_entry *) dir;
|
||||
eind = (struct ppc_elf_link_hash_entry *) ind;
|
||||
|
||||
if (eind->dyn_relocs != NULL)
|
||||
{
|
||||
if (edir->dyn_relocs != NULL)
|
||||
{
|
||||
struct ppc_elf_dyn_relocs **pp;
|
||||
struct ppc_elf_dyn_relocs *p;
|
||||
|
||||
if (ind->root.type == bfd_link_hash_indirect)
|
||||
abort ();
|
||||
|
||||
/* Add reloc counts against the weak sym to the strong sym
|
||||
list. Merge any entries against the same section. */
|
||||
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *q;
|
||||
|
||||
for (q = edir->dyn_relocs; q != NULL; q = q->next)
|
||||
if (q->sec == p->sec)
|
||||
{
|
||||
q->count += p->count;
|
||||
*pp = p->next;
|
||||
break;
|
||||
}
|
||||
if (q == NULL)
|
||||
pp = &p->next;
|
||||
}
|
||||
*pp = edir->dyn_relocs;
|
||||
}
|
||||
|
||||
edir->dyn_relocs = eind->dyn_relocs;
|
||||
eind->dyn_relocs = NULL;
|
||||
}
|
||||
|
||||
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
|
||||
}
|
||||
|
||||
static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max];
|
||||
|
||||
static reloc_howto_type ppc_elf_howto_raw[] = {
|
||||
@ -1903,6 +2058,65 @@ ppc_elf_adjust_dynamic_symbol (info, h)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Allocate space in associated reloc sections for dynamic relocs. */
|
||||
|
||||
static bfd_boolean
|
||||
allocate_dynrelocs (h, info)
|
||||
struct elf_link_hash_entry *h;
|
||||
PTR info ATTRIBUTE_UNUSED;
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *p;
|
||||
|
||||
if (h->root.type == bfd_link_hash_indirect)
|
||||
return TRUE;
|
||||
|
||||
if (h->root.type == bfd_link_hash_warning)
|
||||
/* When warning symbols are created, they **replace** the "real"
|
||||
entry in the hash table, thus we never get to see the real
|
||||
symbol in a hash traversal. So look at it now. */
|
||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||
|
||||
for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
|
||||
{
|
||||
asection *sreloc = elf_section_data (p->sec)->sreloc;
|
||||
sreloc->_raw_size += p->count * sizeof (Elf32_External_Rela);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Find any dynamic relocs that apply to read-only sections. */
|
||||
|
||||
static bfd_boolean
|
||||
readonly_dynrelocs (h, info)
|
||||
struct elf_link_hash_entry *h;
|
||||
PTR info;
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *p;
|
||||
|
||||
if (h->root.type == bfd_link_hash_indirect)
|
||||
return TRUE;
|
||||
|
||||
if (h->root.type == bfd_link_hash_warning)
|
||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||
|
||||
for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
|
||||
{
|
||||
asection *s = p->sec->output_section;
|
||||
|
||||
if (s != NULL
|
||||
&& ((s->flags & (SEC_READONLY | SEC_ALLOC))
|
||||
== (SEC_READONLY | SEC_ALLOC)))
|
||||
{
|
||||
((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
|
||||
|
||||
/* Not an error, just cut short the traversal. */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Set the sizes of the dynamic sections. */
|
||||
|
||||
static bfd_boolean
|
||||
@ -1914,6 +2128,7 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
|
||||
asection *s;
|
||||
bfd_boolean plt;
|
||||
bfd_boolean relocs;
|
||||
bfd *ibfd;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "ppc_elf_size_dynamic_sections called\n");
|
||||
@ -1953,6 +2168,45 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate space for local sym dynamic relocs. */
|
||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||
{
|
||||
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
|
||||
continue;
|
||||
|
||||
for (s = ibfd->sections; s != NULL; s = s->next)
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *p;
|
||||
|
||||
for (p = ((struct ppc_elf_dyn_relocs *)
|
||||
elf_section_data (s)->local_dynrel);
|
||||
p != NULL;
|
||||
p = p->next)
|
||||
{
|
||||
if (!bfd_is_abs_section (p->sec)
|
||||
&& bfd_is_abs_section (p->sec->output_section))
|
||||
{
|
||||
/* Input section has been discarded, either because
|
||||
it is a copy of a linkonce section or due to
|
||||
linker script /DISCARD/, so we'll be discarding
|
||||
the relocs too. */
|
||||
}
|
||||
else if (p->count != 0)
|
||||
{
|
||||
elf_section_data (p->sec)->sreloc->_raw_size
|
||||
+= p->count * sizeof (Elf32_External_Rela);
|
||||
if ((p->sec->output_section->flags
|
||||
& (SEC_READONLY | SEC_ALLOC))
|
||||
== (SEC_READONLY | SEC_ALLOC))
|
||||
info->flags |= DF_TEXTREL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate space for global sym dynamic relocs. */
|
||||
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, NULL);
|
||||
|
||||
/* The check_relocs and adjust_dynamic_symbol entry points have
|
||||
determined the sizes of the various dynamic sections. Allocate
|
||||
memory for them. */
|
||||
@ -2064,6 +2318,12 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* If any dynamic relocs apply to a read-only section, then we
|
||||
need a DT_TEXTREL entry. */
|
||||
if ((info->flags & DF_TEXTREL) == 0)
|
||||
elf_link_hash_traverse (elf_hash_table (info), readonly_dynrelocs,
|
||||
(PTR) info);
|
||||
|
||||
if ((info->flags & DF_TEXTREL) != 0)
|
||||
{
|
||||
if (!add_dynamic_entry (DT_TEXTREL, 0))
|
||||
@ -2402,6 +2662,9 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
|
||||
default:
|
||||
if (info->shared)
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *p;
|
||||
struct ppc_elf_dyn_relocs **head;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n",
|
||||
(h && h->root.root.string) ? h->root.root.string : "<unknown>");
|
||||
@ -2436,19 +2699,46 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
|
||||
|| ! bfd_set_section_alignment (dynobj, sreloc, 2))
|
||||
return FALSE;
|
||||
}
|
||||
if ((sec->flags & (SEC_READONLY | SEC_ALLOC))
|
||||
== (SEC_READONLY | SEC_ALLOC))
|
||||
info->flags |= DF_TEXTREL;
|
||||
elf_section_data (sec)->sreloc = sreloc;
|
||||
}
|
||||
|
||||
sreloc->_raw_size += sizeof (Elf32_External_Rela);
|
||||
/* If this is a global symbol, we count the number of
|
||||
relocations we need for this symbol. */
|
||||
if (h != NULL)
|
||||
{
|
||||
head = &ppc_elf_hash_entry (h)->dyn_relocs;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track dynamic relocs needed for local syms too.
|
||||
We really need local syms available to do this
|
||||
easily. Oh well. */
|
||||
|
||||
/* FIXME: We should here do what the m68k and i386
|
||||
backends do: if the reloc is pc-relative, record it
|
||||
in case it turns out that the reloc is unnecessary
|
||||
because the symbol is forced local by versioning or
|
||||
we are linking with -Bdynamic. Fortunately this
|
||||
case is not frequent. */
|
||||
asection *s;
|
||||
s = (bfd_section_from_r_symndx
|
||||
(abfd, &ppc_elf_hash_table (info)->sym_sec,
|
||||
sec, r_symndx));
|
||||
if (s == NULL)
|
||||
return FALSE;
|
||||
|
||||
head = ((struct ppc_elf_dyn_relocs **)
|
||||
&elf_section_data (s)->local_dynrel);
|
||||
}
|
||||
|
||||
p = *head;
|
||||
if (p == NULL || p->sec != sec)
|
||||
{
|
||||
p = ((struct ppc_elf_dyn_relocs *)
|
||||
bfd_alloc (elf_hash_table (info)->dynobj, sizeof *p));
|
||||
if (p == NULL)
|
||||
return FALSE;
|
||||
p->next = *head;
|
||||
*head = p;
|
||||
p->sec = sec;
|
||||
p->count = 0;
|
||||
}
|
||||
|
||||
p->count++;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -2514,6 +2804,8 @@ ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
|
||||
unsigned long r_symndx;
|
||||
struct elf_link_hash_entry *h;
|
||||
|
||||
elf_section_data (sec)->local_dynrel = NULL;
|
||||
|
||||
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
||||
sym_hashes = elf_sym_hashes (abfd);
|
||||
local_got_refcounts = elf_local_got_refcounts (abfd);
|
||||
@ -2552,9 +2844,26 @@ ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
|
||||
if (h->plt.refcount > 0)
|
||||
h->plt.refcount--;
|
||||
}
|
||||
break;
|
||||
/* Fall through */
|
||||
|
||||
default:
|
||||
r_symndx = ELF32_R_SYM (rel->r_info);
|
||||
if (r_symndx >= symtab_hdr->sh_info)
|
||||
{
|
||||
struct ppc_elf_dyn_relocs **pp, *p;
|
||||
|
||||
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
||||
|
||||
for (pp = &ppc_elf_hash_entry (h)->dyn_relocs;
|
||||
(p = *pp) != NULL;
|
||||
pp = &p->next)
|
||||
if (p->sec == sec)
|
||||
{
|
||||
if (--p->count == 0)
|
||||
*pp = p->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4122,6 +4431,7 @@ ppc_elf_final_write_processing (abfd, linker)
|
||||
#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup
|
||||
#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
|
||||
#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link
|
||||
#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create
|
||||
|
||||
#define elf_backend_object_p ppc_elf_object_p
|
||||
#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook
|
||||
@ -4130,6 +4440,7 @@ ppc_elf_final_write_processing (abfd, linker)
|
||||
#define elf_backend_relocate_section ppc_elf_relocate_section
|
||||
#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections
|
||||
#define elf_backend_check_relocs ppc_elf_check_relocs
|
||||
#define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol
|
||||
#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol
|
||||
#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook
|
||||
#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections
|
||||
|
Loading…
Reference in New Issue
Block a user