/* BFD back-end data structures for ELF files.
Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
bfd_boolean (*elf_backend_modify_program_headers)
(bfd *, struct bfd_link_info *);
+ /* This function is called before section garbage collection to
+ mark entry symbol sections. */
+ void (*gc_keep)
+ (struct bfd_link_info *);
+
/* This function is called during section garbage collection to
mark sections that define global symbols. */
bfd_boolean (*gc_mark_dynamic_ref)
- (struct elf_link_hash_entry *h, void *inf);
+ (struct elf_link_hash_entry *, void *);
/* This function is called during section gc to discover the section a
particular relocation refers to. */
/* This function, if defined, is called after the first gc marking pass
to allow the backend to mark additional sections. */
bfd_boolean (*gc_mark_extra_sections)
- (struct bfd_link_info *info, elf_gc_mark_hook_fn gc_mark_hook);
+ (struct bfd_link_info *, elf_gc_mark_hook_fn);
/* This function, if defined, is called during the sweep phase of gc
in order that a backend might update any data structures it might
be maintaining. */
bfd_boolean (*gc_sweep_hook)
- (bfd *abfd, struct bfd_link_info *info, asection *o,
- const Elf_Internal_Rela *relocs);
+ (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
/* This function, if defined, is called after the ELF headers have
been created. This allows for things like the OS and ABI versions
extern bfd_boolean bfd_elf_final_link
(bfd *, struct bfd_link_info *);
+extern void _bfd_elf_gc_keep
+ (struct bfd_link_info *info);
+
extern bfd_boolean bfd_elf_gc_mark_dynamic_ref_symbol
(struct elf_link_hash_entry *h, void *inf);
/* PowerPC64-specific support for 64-bit ELF.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor.
#define elf_backend_as_needed_cleanup ppc64_elf_as_needed_cleanup
#define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup
#define elf_backend_check_relocs ppc64_elf_check_relocs
+#define elf_backend_gc_keep ppc64_elf_gc_keep
#define elf_backend_gc_mark_dynamic_ref ppc64_elf_gc_mark_dynamic_ref
#define elf_backend_gc_mark_hook ppc64_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook ppc64_elf_gc_sweep_hook
{
struct bfd_elf_section_data elf;
- /* An array with one entry for each opd function descriptor. */
union
{
- /* Points to the function code section for local opd entries. */
- asection **opd_func_sec;
- /* After editing .opd, adjust references to opd local syms. */
- long *opd_adjust;
+ /* An array with one entry for each opd function descriptor. */
+ struct _opd_sec_data
+ {
+ /* Points to the function code section for local opd entries. */
+ asection **func_sec;
+
+ /* After editing .opd, adjust references to opd local syms. */
+ long *adjust;
+ } opd;
/* An array for toc sections, indexed by offset/8.
Specifies the relocation symbol index used at a given toc offset. */
return _bfd_elf_new_section_hook (abfd, sec);
}
-static void *
+static struct _opd_sec_data *
get_opd_info (asection * sec)
{
if (sec != NULL
&& ppc64_elf_section_data (sec) != NULL
&& ppc64_elf_section_data (sec)->sec_type == sec_opd)
- return ppc64_elf_section_data (sec)->u.opd_adjust;
+ return &ppc64_elf_section_data (sec)->u.opd;
return NULL;
}
\f
if we reference an .opd symbol (a function descriptor), we
want to keep the function code symbol's section. This is
easy for global symbols, but for local syms we need to keep
- information about the associated function section. Later, if
- edit_opd deletes entries, we'll use this array to adjust
- local syms in .opd. */
- union opd_info {
- asection *func_section;
- long entry_adjust;
- };
+ information about the associated function section. */
bfd_size_type amt;
- amt = sec->size * sizeof (union opd_info) / 8;
+ amt = sec->size * sizeof (*opd_sym_map) / 8;
opd_sym_map = bfd_zalloc (abfd, amt);
if (opd_sym_map == NULL)
return FALSE;
- ppc64_elf_section_data (sec)->u.opd_func_sec = opd_sym_map;
+ ppc64_elf_section_data (sec)->u.opd.func_sec = opd_sym_map;
BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal);
ppc64_elf_section_data (sec)->sec_type = sec_opd;
}
return val;
}
+/* Mark all our entry sym sections, both opd and code section. */
+
+static void
+ppc64_elf_gc_keep (struct bfd_link_info *info)
+{
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ struct bfd_sym_chain *sym;
+
+ for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
+ {
+ struct ppc_link_hash_entry *eh;
+ asection *sec;
+
+ eh = (struct ppc_link_hash_entry *)
+ elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE);
+ if (eh == NULL)
+ continue;
+ if (eh->elf.root.type != bfd_link_hash_defined
+ && eh->elf.root.type != bfd_link_hash_defweak)
+ continue;
+
+ if (eh->is_func_descriptor
+ && (eh->oh->elf.root.type == bfd_link_hash_defined
+ || eh->oh->elf.root.type == bfd_link_hash_defweak))
+ {
+ sec = eh->oh->elf.root.u.def.section;
+ sec->flags |= SEC_KEEP;
+ }
+ else if (get_opd_info (eh->elf.root.u.def.section) != NULL
+ && opd_entry_value (eh->elf.root.u.def.section,
+ eh->elf.root.u.def.value,
+ &sec, NULL) != (bfd_vma) -1)
+ sec->flags |= SEC_KEEP;
+
+ sec = eh->elf.root.u.def.section;
+ sec->flags |= SEC_KEEP;
+ }
+}
+
/* Mark sections containing dynamically referenced symbols. When
building shared libraries, we must assume that any visible symbol is
referenced. */
static asection *
ppc64_elf_gc_mark_hook (asection *sec,
- struct bfd_link_info *info,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
Elf_Internal_Rela *rel,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
asection *rsec;
- /* First mark all our entry sym sections. */
- if (info->gc_sym_list != NULL)
- {
- struct ppc_link_hash_table *htab = ppc_hash_table (info);
- struct bfd_sym_chain *sym = info->gc_sym_list;
-
- info->gc_sym_list = NULL;
- for (; sym != NULL; sym = sym->next)
- {
- struct ppc_link_hash_entry *eh;
-
- eh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE);
- if (eh == NULL)
- continue;
- if (eh->elf.root.type != bfd_link_hash_defined
- && eh->elf.root.type != bfd_link_hash_defweak)
- continue;
-
- if (eh->is_func_descriptor
- && (eh->oh->elf.root.type == bfd_link_hash_defined
- || eh->oh->elf.root.type == bfd_link_hash_defweak))
- rsec = eh->oh->elf.root.u.def.section;
- else if (get_opd_info (eh->elf.root.u.def.section) != NULL
- && opd_entry_value (eh->elf.root.u.def.section,
- eh->elf.root.u.def.value,
- &rsec, NULL) != (bfd_vma) -1)
- ;
- else
- continue;
-
- if (!rsec->gc_mark)
- _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
-
- rsec = eh->elf.root.u.def.section;
- if (!rsec->gc_mark)
- _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
- }
- }
-
/* Syms return NULL if we're marking .opd, so we avoid marking all
function sections, as all functions are referenced in .opd. */
rsec = NULL;
|| eh->oh->elf.root.type == bfd_link_hash_defweak))
{
/* They also mark their opd section. */
- if (!eh->elf.root.u.def.section->gc_mark)
- _bfd_elf_gc_mark (info, eh->elf.root.u.def.section,
- ppc64_elf_gc_mark_hook);
+ eh->elf.root.u.def.section->gc_mark = 1;
rsec = eh->oh->elf.root.u.def.section;
}
&& opd_entry_value (eh->elf.root.u.def.section,
eh->elf.root.u.def.value,
&rsec, NULL) != (bfd_vma) -1)
- {
- if (!eh->elf.root.u.def.section->gc_mark)
- _bfd_elf_gc_mark (info, eh->elf.root.u.def.section,
- ppc64_elf_gc_mark_hook);
- }
+ eh->elf.root.u.def.section->gc_mark = 1;
else
rsec = h->root.u.def.section;
break;
}
else
{
- asection **opd_sym_section;
+ struct _opd_sec_data *opd;
rsec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
- opd_sym_section = get_opd_info (rsec);
- if (opd_sym_section != NULL)
+ opd = get_opd_info (rsec);
+ if (opd != NULL && opd->func_sec != NULL)
{
- if (!rsec->gc_mark)
- _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
+ rsec->gc_mark = 1;
- rsec = opd_sym_section[(sym->st_value + rel->r_addend) / 8];
+ rsec = opd->func_sec[(sym->st_value + rel->r_addend) / 8];
}
}
{
struct ppc_link_hash_entry *eh;
asection *sym_sec;
- long *opd_adjust;
+ struct _opd_sec_data *opd;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
return TRUE;
sym_sec = eh->elf.root.u.def.section;
- opd_adjust = get_opd_info (sym_sec);
- if (opd_adjust != NULL)
+ opd = get_opd_info (sym_sec);
+ if (opd != NULL && opd->adjust != NULL)
{
- long adjust = opd_adjust[eh->elf.root.u.def.value / 8];
+ long adjust = opd->adjust[eh->elf.root.u.def.value / 8];
if (adjust == -1)
{
/* This entry has been deleted. */
bfd_boolean
ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
- bfd_boolean no_opd_opt,
bfd_boolean non_overlapping)
{
bfd *ibfd;
Elf_Internal_Sym *local_syms;
struct elf_link_hash_entry **sym_hashes;
bfd_vma offset;
- bfd_size_type amt;
- long *opd_adjust;
+ struct _opd_sec_data *opd;
bfd_boolean need_edit, add_aux_fields;
bfd_size_type cnt_16b = 0;
if (sec == NULL || sec->size == 0)
continue;
- amt = sec->size * sizeof (long) / 8;
- opd_adjust = get_opd_info (sec);
- if (opd_adjust == NULL)
- {
- /* check_relocs hasn't been called. Must be a ld -r link
- or --just-symbols object. */
- opd_adjust = bfd_alloc (obfd, amt);
- if (opd_adjust == NULL)
- return FALSE;
- ppc64_elf_section_data (sec)->u.opd_adjust = opd_adjust;
- BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal);
- ppc64_elf_section_data (sec)->sec_type = sec_opd;
- }
- memset (opd_adjust, 0, amt);
-
- if (no_opd_opt)
- continue;
-
if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
continue;
bfd_byte *new_contents = NULL;
bfd_boolean skip;
long opd_ent_size;
+ bfd_size_type amt;
+
+ amt = sec->size * sizeof (long) / 8;
+ opd = &ppc64_elf_section_data (sec)->u.opd;
+ opd->adjust = bfd_zalloc (obfd, amt);
+ if (opd->adjust == NULL)
+ return FALSE;
+ ppc64_elf_section_data (sec)->sec_type = sec_opd;
/* This seems a waste of time as input .opd sections are all
zeros as generated by gcc, but I suppose there's no reason
fdh->elf.root.u.def.value = 0;
fdh->elf.root.u.def.section = sym_sec;
}
- opd_adjust[rel->r_offset / 8] = -1;
+ opd->adjust[rel->r_offset / 8] = -1;
}
else
{
for the function descriptor sym which we
don't have at the moment. So keep an
array of adjustments. */
- opd_adjust[rel->r_offset / 8]
+ opd->adjust[rel->r_offset / 8]
= (wptr - new_contents) - (rptr - sec->contents);
if (wptr != rptr)
/* We need to adjust any reloc offsets to point to the
new opd entries. While we're at it, we may as well
remove redundant relocs. */
- rel->r_offset += opd_adjust[(offset - opd_ent_size) / 8];
+ rel->r_offset += opd->adjust[(offset - opd_ent_size) / 8];
if (write_rel != rel)
memcpy (write_rel, rel, sizeof (*rel));
++write_rel;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sym_sec;
- long *opd_adjust;
+ struct _opd_sec_data *opd;
bfd_vma sym_value;
bfd_vma dest;
sym_value += rel->r_addend;
/* If this branch reloc uses an opd sym, find the code section. */
- opd_adjust = get_opd_info (sym_sec);
- if (opd_adjust != NULL)
+ opd = get_opd_info (sym_sec);
+ if (opd != NULL)
{
- if (h == NULL)
+ if (h == NULL && opd->adjust != NULL)
{
long adjust;
- adjust = opd_adjust[sym->st_value / 8];
+ adjust = opd->adjust[sym->st_value / 8];
if (adjust == -1)
/* Assume deleted functions won't ever be called. */
continue;
Elf_Internal_Sym *sym;
char *stub_name;
const asection *id_sec;
- long *opd_adjust;
+ struct _opd_sec_data *opd;
r_type = ELF64_R_TYPE (irela->r_info);
r_indx = ELF64_R_SYM (irela->r_info);
}
code_sec = sym_sec;
- opd_adjust = get_opd_info (sym_sec);
- if (opd_adjust != NULL)
+ opd = get_opd_info (sym_sec);
+ if (opd != NULL)
{
bfd_vma dest;
- if (hash == NULL)
+ if (hash == NULL && opd->adjust != NULL)
{
- long adjust = opd_adjust[sym_value / 8];
+ long adjust = opd->adjust[sym_value / 8];
if (adjust == -1)
continue;
sym_value += adjust;
if (r_symndx < symtab_hdr->sh_info)
{
/* It's a local symbol. */
- long *opd_adjust;
+ struct _opd_sec_data *opd;
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
sym_type = ELF64_ST_TYPE (sym->st_info);
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
- opd_adjust = get_opd_info (sec);
- if (opd_adjust != NULL)
+ opd = get_opd_info (sec);
+ if (opd != NULL && opd->adjust != NULL)
{
- long adjust = opd_adjust[(sym->st_value + rel->r_addend) / 8];
+ long adjust = opd->adjust[(sym->st_value + rel->r_addend) / 8];
if (adjust == -1)
relocation = 0;
else
asection *input_sec,
struct elf_link_hash_entry *h)
{
- long *opd_adjust, adjust;
+ struct _opd_sec_data *opd;
+ long adjust;
bfd_vma value;
if (h != NULL)
return TRUE;
- opd_adjust = get_opd_info (input_sec);
- if (opd_adjust == NULL)
+ opd = get_opd_info (input_sec);
+ if (opd == NULL || opd->adjust == NULL)
return TRUE;
value = elfsym->st_value - input_sec->output_offset;
if (!info->relocatable)
value -= input_sec->output_section->vma;
- adjust = opd_adjust[value / 8];
+ adjust = opd->adjust[value / 8];
if (adjust == -1)
elfsym->st_value = 0;
else