mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-29 04:53:56 +08:00
* elflink.c (_bfd_elf_link_just_syms, merge_sections_remove_hook,
_bfd_elf_merge_sections, _bfd_elf_link_hash_newfunc, _bfd_elf_link_hash_copy_indirect, _bfd_elf_link_hash_hide_symbol, _bfd_elf_link_hash_table_init, _bfd_elf_link_hash_table_create, bfd_elf_set_dt_needed_name, bfd_elf_get_dyn_lib_class, bfd_elf_set_dyn_lib_class, bfd_elf_get_needed_list, bfd_elf_get_runpath_list, bfd_elf_get_dt_soname, bfd_elf_get_bfd_needed_list, struct elf_symbuf_symbol, struct elf_symbuf_head, struct elf_symbol, elf_sort_elf_symbol, elf_sym_name_compare, elf_create_symbuf, bfd_elf_match_symbols_in_sections, _bfd_elf_match_sections_by_type): Move to here.. * elf.c: ..from here.
This commit is contained in:
parent
f3c7bcacb1
commit
4d269e42e3
@ -1,3 +1,19 @@
|
||||
2007-07-24 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elflink.c (_bfd_elf_link_just_syms, merge_sections_remove_hook,
|
||||
_bfd_elf_merge_sections, _bfd_elf_link_hash_newfunc,
|
||||
_bfd_elf_link_hash_copy_indirect, _bfd_elf_link_hash_hide_symbol,
|
||||
_bfd_elf_link_hash_table_init, _bfd_elf_link_hash_table_create,
|
||||
bfd_elf_set_dt_needed_name, bfd_elf_get_dyn_lib_class,
|
||||
bfd_elf_set_dyn_lib_class, bfd_elf_get_needed_list,
|
||||
bfd_elf_get_runpath_list, bfd_elf_get_dt_soname,
|
||||
bfd_elf_get_bfd_needed_list, struct elf_symbuf_symbol,
|
||||
struct elf_symbuf_head, struct elf_symbol, elf_sort_elf_symbol,
|
||||
elf_sym_name_compare, elf_create_symbuf,
|
||||
bfd_elf_match_symbols_in_sections,
|
||||
_bfd_elf_match_sections_by_type): Move to here..
|
||||
* elf.c: ..from here.
|
||||
|
||||
2007-07-23 Richard Sandiford <richard@codesourcery.com>
|
||||
|
||||
* elflink.c (_bfd_elf_fix_symbol_flags): Only assert the type
|
||||
@ -13,20 +29,20 @@
|
||||
|
||||
2007-07-19 Doug Kwan <dougkwan@google.com>
|
||||
|
||||
PR binutils/4797
|
||||
* dwarf2.c: (find_line) Do not dereference functionname_ptr if
|
||||
do_line is true.
|
||||
PR binutils/4797
|
||||
* dwarf2.c: (find_line) Do not dereference functionname_ptr if
|
||||
do_line is true.
|
||||
|
||||
2007-07-18 Bob Wilson <bob.wilson@acm.org>
|
||||
|
||||
|
||||
* elf32-xtensa.c (xtensa_callback_required_dependence): Ignore
|
||||
non-ELF sections.
|
||||
|
||||
|
||||
2007-07-18 Bob Wilson <bob.wilson@acm.org>
|
||||
|
||||
|
||||
* elf32-xtensa.c (elf_xtensa_finish_dynamic_sections): Get section
|
||||
vma and size for dynamic tags from the output sections.
|
||||
|
||||
|
||||
2007-07-18 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf-bfd.h (struct sym_sec_cache): Delete "sec". Add "shndx".
|
||||
|
721
bfd/elf.c
721
bfd/elf.c
@ -1044,61 +1044,6 @@ bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
return bfd_reloc_continue;
|
||||
}
|
||||
|
||||
/* Make sure sec_info_type is cleared if sec_info is cleared too. */
|
||||
|
||||
static void
|
||||
merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
asection *sec)
|
||||
{
|
||||
BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
|
||||
sec->sec_info_type = ELF_INFO_TYPE_NONE;
|
||||
}
|
||||
|
||||
/* Finish SHF_MERGE section merging. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
|
||||
{
|
||||
bfd *ibfd;
|
||||
asection *sec;
|
||||
|
||||
if (!is_elf_hash_table (info->hash))
|
||||
return FALSE;
|
||||
|
||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||
if ((ibfd->flags & DYNAMIC) == 0)
|
||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||
if ((sec->flags & SEC_MERGE) != 0
|
||||
&& !bfd_is_abs_section (sec->output_section))
|
||||
{
|
||||
struct bfd_elf_section_data *secdata;
|
||||
|
||||
secdata = elf_section_data (sec);
|
||||
if (! _bfd_add_merge_section (abfd,
|
||||
&elf_hash_table (info)->merge_info,
|
||||
sec, &secdata->sec_info))
|
||||
return FALSE;
|
||||
else if (secdata->sec_info)
|
||||
sec->sec_info_type = ELF_INFO_TYPE_MERGE;
|
||||
}
|
||||
|
||||
if (elf_hash_table (info)->merge_info != NULL)
|
||||
_bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
|
||||
merge_sections_remove_hook);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
|
||||
{
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
sec->output_offset = sec->vma;
|
||||
if (!is_elf_hash_table (info->hash))
|
||||
return;
|
||||
|
||||
sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
|
||||
}
|
||||
|
||||
/* Copy the program header and other data from one object module to
|
||||
another. */
|
||||
|
||||
@ -1496,319 +1441,7 @@ bfd_elf_print_symbol (bfd *abfd,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an entry in an ELF linker hash table. */
|
||||
|
||||
struct bfd_hash_entry *
|
||||
_bfd_elf_link_hash_newfunc (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 elf_link_hash_entry));
|
||||
if (entry == NULL)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Call the allocation method of the superclass. */
|
||||
entry = _bfd_link_hash_newfunc (entry, table, string);
|
||||
if (entry != NULL)
|
||||
{
|
||||
struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
|
||||
struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
|
||||
|
||||
/* Set local fields. */
|
||||
ret->indx = -1;
|
||||
ret->dynindx = -1;
|
||||
ret->got = htab->init_got_refcount;
|
||||
ret->plt = htab->init_plt_refcount;
|
||||
memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
|
||||
- offsetof (struct elf_link_hash_entry, size)));
|
||||
/* Assume that we have been called by a non-ELF symbol reader.
|
||||
This flag is then reset by the code which reads an ELF input
|
||||
file. This ensures that a symbol created by a non-ELF symbol
|
||||
reader will have the flag set correctly. */
|
||||
ret->non_elf = 1;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Copy data from an indirect symbol to its direct symbol, hiding the
|
||||
old indirect symbol. Also used for copying flags to a weakdef. */
|
||||
|
||||
void
|
||||
_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
|
||||
struct elf_link_hash_entry *dir,
|
||||
struct elf_link_hash_entry *ind)
|
||||
{
|
||||
struct elf_link_hash_table *htab;
|
||||
|
||||
/* Copy down any references that we may have already seen to the
|
||||
symbol which just became indirect. */
|
||||
|
||||
dir->ref_dynamic |= ind->ref_dynamic;
|
||||
dir->ref_regular |= ind->ref_regular;
|
||||
dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
|
||||
dir->non_got_ref |= ind->non_got_ref;
|
||||
dir->needs_plt |= ind->needs_plt;
|
||||
dir->pointer_equality_needed |= ind->pointer_equality_needed;
|
||||
|
||||
if (ind->root.type != bfd_link_hash_indirect)
|
||||
return;
|
||||
|
||||
/* Copy over the global and procedure linkage table refcount entries.
|
||||
These may have been already set up by a check_relocs routine. */
|
||||
htab = elf_hash_table (info);
|
||||
if (ind->got.refcount > htab->init_got_refcount.refcount)
|
||||
{
|
||||
if (dir->got.refcount < 0)
|
||||
dir->got.refcount = 0;
|
||||
dir->got.refcount += ind->got.refcount;
|
||||
ind->got.refcount = htab->init_got_refcount.refcount;
|
||||
}
|
||||
|
||||
if (ind->plt.refcount > htab->init_plt_refcount.refcount)
|
||||
{
|
||||
if (dir->plt.refcount < 0)
|
||||
dir->plt.refcount = 0;
|
||||
dir->plt.refcount += ind->plt.refcount;
|
||||
ind->plt.refcount = htab->init_plt_refcount.refcount;
|
||||
}
|
||||
|
||||
if (ind->dynindx != -1)
|
||||
{
|
||||
if (dir->dynindx != -1)
|
||||
_bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index);
|
||||
dir->dynindx = ind->dynindx;
|
||||
dir->dynstr_index = ind->dynstr_index;
|
||||
ind->dynindx = -1;
|
||||
ind->dynstr_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
|
||||
struct elf_link_hash_entry *h,
|
||||
bfd_boolean force_local)
|
||||
{
|
||||
h->plt = elf_hash_table (info)->init_plt_offset;
|
||||
h->needs_plt = 0;
|
||||
if (force_local)
|
||||
{
|
||||
h->forced_local = 1;
|
||||
if (h->dynindx != -1)
|
||||
{
|
||||
h->dynindx = -1;
|
||||
_bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
|
||||
h->dynstr_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize an ELF linker hash table. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_link_hash_table_init
|
||||
(struct elf_link_hash_table *table,
|
||||
bfd *abfd,
|
||||
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
|
||||
struct bfd_hash_table *,
|
||||
const char *),
|
||||
unsigned int entsize)
|
||||
{
|
||||
bfd_boolean ret;
|
||||
int can_refcount = get_elf_backend_data (abfd)->can_refcount;
|
||||
|
||||
memset (table, 0, sizeof * table);
|
||||
table->init_got_refcount.refcount = can_refcount - 1;
|
||||
table->init_plt_refcount.refcount = can_refcount - 1;
|
||||
table->init_got_offset.offset = -(bfd_vma) 1;
|
||||
table->init_plt_offset.offset = -(bfd_vma) 1;
|
||||
/* The first dynamic symbol is a dummy. */
|
||||
table->dynsymcount = 1;
|
||||
|
||||
ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
|
||||
table->root.type = bfd_link_elf_hash_table;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create an ELF linker hash table. */
|
||||
|
||||
struct bfd_link_hash_table *
|
||||
_bfd_elf_link_hash_table_create (bfd *abfd)
|
||||
{
|
||||
struct elf_link_hash_table *ret;
|
||||
bfd_size_type amt = sizeof (struct elf_link_hash_table);
|
||||
|
||||
ret = bfd_malloc (amt);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
|
||||
sizeof (struct elf_link_hash_entry)))
|
||||
{
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &ret->root;
|
||||
}
|
||||
|
||||
/* This is a hook for the ELF emulation code in the generic linker to
|
||||
tell the backend linker what file name to use for the DT_NEEDED
|
||||
entry for a dynamic object. */
|
||||
|
||||
void
|
||||
bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
|
||||
{
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
elf_dt_name (abfd) = name;
|
||||
}
|
||||
|
||||
int
|
||||
bfd_elf_get_dyn_lib_class (bfd *abfd)
|
||||
{
|
||||
int lib_class;
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
lib_class = elf_dyn_lib_class (abfd);
|
||||
else
|
||||
lib_class = 0;
|
||||
return lib_class;
|
||||
}
|
||||
|
||||
void
|
||||
bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class)
|
||||
{
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
elf_dyn_lib_class (abfd) = lib_class;
|
||||
}
|
||||
|
||||
/* Get the list of DT_NEEDED entries for a link. This is a hook for
|
||||
the linker ELF emulation code. */
|
||||
|
||||
struct bfd_link_needed_list *
|
||||
bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
if (! is_elf_hash_table (info->hash))
|
||||
return NULL;
|
||||
return elf_hash_table (info)->needed;
|
||||
}
|
||||
|
||||
/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a
|
||||
hook for the linker ELF emulation code. */
|
||||
|
||||
struct bfd_link_needed_list *
|
||||
bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
if (! is_elf_hash_table (info->hash))
|
||||
return NULL;
|
||||
return elf_hash_table (info)->runpath;
|
||||
}
|
||||
|
||||
/* Get the name actually used for a dynamic object for a link. This
|
||||
is the SONAME entry if there is one. Otherwise, it is the string
|
||||
passed to bfd_elf_set_dt_needed_name, or it is the filename. */
|
||||
|
||||
const char *
|
||||
bfd_elf_get_dt_soname (bfd *abfd)
|
||||
{
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
return elf_dt_name (abfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the list of DT_NEEDED entries from a BFD. This is a hook for
|
||||
the ELF linker emulation code. */
|
||||
|
||||
bfd_boolean
|
||||
bfd_elf_get_bfd_needed_list (bfd *abfd,
|
||||
struct bfd_link_needed_list **pneeded)
|
||||
{
|
||||
asection *s;
|
||||
bfd_byte *dynbuf = NULL;
|
||||
int elfsec;
|
||||
unsigned long shlink;
|
||||
bfd_byte *extdyn, *extdynend;
|
||||
size_t extdynsize;
|
||||
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
|
||||
|
||||
*pneeded = NULL;
|
||||
|
||||
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
|
||||
|| bfd_get_format (abfd) != bfd_object)
|
||||
return TRUE;
|
||||
|
||||
s = bfd_get_section_by_name (abfd, ".dynamic");
|
||||
if (s == NULL || s->size == 0)
|
||||
return TRUE;
|
||||
|
||||
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
|
||||
goto error_return;
|
||||
|
||||
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
|
||||
if (elfsec == -1)
|
||||
goto error_return;
|
||||
|
||||
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
|
||||
|
||||
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
|
||||
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
|
||||
|
||||
extdyn = dynbuf;
|
||||
extdynend = extdyn + s->size;
|
||||
for (; extdyn < extdynend; extdyn += extdynsize)
|
||||
{
|
||||
Elf_Internal_Dyn dyn;
|
||||
|
||||
(*swap_dyn_in) (abfd, extdyn, &dyn);
|
||||
|
||||
if (dyn.d_tag == DT_NULL)
|
||||
break;
|
||||
|
||||
if (dyn.d_tag == DT_NEEDED)
|
||||
{
|
||||
const char *string;
|
||||
struct bfd_link_needed_list *l;
|
||||
unsigned int tagv = dyn.d_un.d_val;
|
||||
bfd_size_type amt;
|
||||
|
||||
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
||||
if (string == NULL)
|
||||
goto error_return;
|
||||
|
||||
amt = sizeof *l;
|
||||
l = bfd_alloc (abfd, amt);
|
||||
if (l == NULL)
|
||||
goto error_return;
|
||||
|
||||
l->by = abfd;
|
||||
l->name = string;
|
||||
l->next = *pneeded;
|
||||
*pneeded = l;
|
||||
}
|
||||
}
|
||||
|
||||
free (dynbuf);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error_return:
|
||||
if (dynbuf != NULL)
|
||||
free (dynbuf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Allocate an ELF string table--force the first byte to be zero. */
|
||||
|
||||
struct bfd_strtab_hash *
|
||||
@ -8824,365 +8457,11 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
|
||||
return n;
|
||||
}
|
||||
|
||||
struct elf_symbuf_symbol
|
||||
{
|
||||
unsigned long st_name; /* Symbol name, index in string tbl */
|
||||
unsigned char st_info; /* Type and binding attributes */
|
||||
unsigned char st_other; /* Visibilty, and target specific */
|
||||
};
|
||||
|
||||
struct elf_symbuf_head
|
||||
{
|
||||
struct elf_symbuf_symbol *ssym;
|
||||
bfd_size_type count;
|
||||
unsigned int st_shndx;
|
||||
};
|
||||
|
||||
struct elf_symbol
|
||||
{
|
||||
union
|
||||
{
|
||||
Elf_Internal_Sym *isym;
|
||||
struct elf_symbuf_symbol *ssym;
|
||||
} u;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Sort references to symbols by ascending section number. */
|
||||
|
||||
static int
|
||||
elf_sort_elf_symbol (const void *arg1, const void *arg2)
|
||||
{
|
||||
const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
|
||||
const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
|
||||
|
||||
return s1->st_shndx - s2->st_shndx;
|
||||
}
|
||||
|
||||
static int
|
||||
elf_sym_name_compare (const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
|
||||
const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
|
||||
return strcmp (s1->name, s2->name);
|
||||
}
|
||||
|
||||
static struct elf_symbuf_head *
|
||||
elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
|
||||
{
|
||||
Elf_Internal_Sym **ind, **indbufend, **indbuf
|
||||
= bfd_malloc2 (symcount, sizeof (*indbuf));
|
||||
struct elf_symbuf_symbol *ssym;
|
||||
struct elf_symbuf_head *ssymbuf, *ssymhead;
|
||||
bfd_size_type i, shndx_count;
|
||||
|
||||
if (indbuf == NULL)
|
||||
return NULL;
|
||||
|
||||
for (ind = indbuf, i = 0; i < symcount; i++)
|
||||
if (isymbuf[i].st_shndx != SHN_UNDEF)
|
||||
*ind++ = &isymbuf[i];
|
||||
indbufend = ind;
|
||||
|
||||
qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *),
|
||||
elf_sort_elf_symbol);
|
||||
|
||||
shndx_count = 0;
|
||||
if (indbufend > indbuf)
|
||||
for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++)
|
||||
if (ind[0]->st_shndx != ind[1]->st_shndx)
|
||||
shndx_count++;
|
||||
|
||||
ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
|
||||
+ (indbufend - indbuf) * sizeof (*ssymbuf));
|
||||
if (ssymbuf == NULL)
|
||||
{
|
||||
free (indbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
|
||||
ssymbuf->ssym = NULL;
|
||||
ssymbuf->count = shndx_count;
|
||||
ssymbuf->st_shndx = 0;
|
||||
for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++)
|
||||
{
|
||||
if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx)
|
||||
{
|
||||
ssymhead++;
|
||||
ssymhead->ssym = ssym;
|
||||
ssymhead->count = 0;
|
||||
ssymhead->st_shndx = (*ind)->st_shndx;
|
||||
}
|
||||
ssym->st_name = (*ind)->st_name;
|
||||
ssym->st_info = (*ind)->st_info;
|
||||
ssym->st_other = (*ind)->st_other;
|
||||
ssymhead->count++;
|
||||
}
|
||||
BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
|
||||
|
||||
free (indbuf);
|
||||
return ssymbuf;
|
||||
}
|
||||
|
||||
/* Check if 2 sections define the same set of local and global
|
||||
symbols. */
|
||||
|
||||
bfd_boolean
|
||||
bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
bfd *bfd1, *bfd2;
|
||||
const struct elf_backend_data *bed1, *bed2;
|
||||
Elf_Internal_Shdr *hdr1, *hdr2;
|
||||
bfd_size_type symcount1, symcount2;
|
||||
Elf_Internal_Sym *isymbuf1, *isymbuf2;
|
||||
struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
|
||||
Elf_Internal_Sym *isym, *isymend;
|
||||
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
|
||||
bfd_size_type count1, count2, i;
|
||||
int shndx1, shndx2;
|
||||
bfd_boolean result;
|
||||
|
||||
bfd1 = sec1->owner;
|
||||
bfd2 = sec2->owner;
|
||||
|
||||
/* If both are .gnu.linkonce sections, they have to have the same
|
||||
section name. */
|
||||
if (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
|
||||
&& CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
|
||||
return strcmp (sec1->name + sizeof ".gnu.linkonce",
|
||||
sec2->name + sizeof ".gnu.linkonce") == 0;
|
||||
|
||||
/* Both sections have to be in ELF. */
|
||||
if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
|
||||
|| bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
|
||||
return FALSE;
|
||||
|
||||
if (elf_section_type (sec1) != elf_section_type (sec2))
|
||||
return FALSE;
|
||||
|
||||
if ((elf_section_flags (sec1) & SHF_GROUP) != 0
|
||||
&& (elf_section_flags (sec2) & SHF_GROUP) != 0)
|
||||
{
|
||||
/* If both are members of section groups, they have to have the
|
||||
same group name. */
|
||||
if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
|
||||
shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
|
||||
if (shndx1 == -1 || shndx2 == -1)
|
||||
return FALSE;
|
||||
|
||||
bed1 = get_elf_backend_data (bfd1);
|
||||
bed2 = get_elf_backend_data (bfd2);
|
||||
hdr1 = &elf_tdata (bfd1)->symtab_hdr;
|
||||
symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
|
||||
hdr2 = &elf_tdata (bfd2)->symtab_hdr;
|
||||
symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
|
||||
|
||||
if (symcount1 == 0 || symcount2 == 0)
|
||||
return FALSE;
|
||||
|
||||
result = FALSE;
|
||||
isymbuf1 = NULL;
|
||||
isymbuf2 = NULL;
|
||||
ssymbuf1 = elf_tdata (bfd1)->symbuf;
|
||||
ssymbuf2 = elf_tdata (bfd2)->symbuf;
|
||||
|
||||
if (ssymbuf1 == NULL)
|
||||
{
|
||||
isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
|
||||
NULL, NULL, NULL);
|
||||
if (isymbuf1 == NULL)
|
||||
goto done;
|
||||
|
||||
if (!info->reduce_memory_overheads)
|
||||
elf_tdata (bfd1)->symbuf = ssymbuf1
|
||||
= elf_create_symbuf (symcount1, isymbuf1);
|
||||
}
|
||||
|
||||
if (ssymbuf1 == NULL || ssymbuf2 == NULL)
|
||||
{
|
||||
isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
|
||||
NULL, NULL, NULL);
|
||||
if (isymbuf2 == NULL)
|
||||
goto done;
|
||||
|
||||
if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
|
||||
elf_tdata (bfd2)->symbuf = ssymbuf2
|
||||
= elf_create_symbuf (symcount2, isymbuf2);
|
||||
}
|
||||
|
||||
if (ssymbuf1 != NULL && ssymbuf2 != NULL)
|
||||
{
|
||||
/* Optimized faster version. */
|
||||
bfd_size_type lo, hi, mid;
|
||||
struct elf_symbol *symp;
|
||||
struct elf_symbuf_symbol *ssym, *ssymend;
|
||||
|
||||
lo = 0;
|
||||
hi = ssymbuf1->count;
|
||||
ssymbuf1++;
|
||||
count1 = 0;
|
||||
while (lo < hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
|
||||
hi = mid;
|
||||
else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
|
||||
lo = mid + 1;
|
||||
else
|
||||
{
|
||||
count1 = ssymbuf1[mid].count;
|
||||
ssymbuf1 += mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lo = 0;
|
||||
hi = ssymbuf2->count;
|
||||
ssymbuf2++;
|
||||
count2 = 0;
|
||||
while (lo < hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
|
||||
hi = mid;
|
||||
else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
|
||||
lo = mid + 1;
|
||||
else
|
||||
{
|
||||
count2 = ssymbuf2[mid].count;
|
||||
ssymbuf2 += mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count1 == 0 || count2 == 0 || count1 != count2)
|
||||
goto done;
|
||||
|
||||
symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
|
||||
symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
|
||||
if (symtable1 == NULL || symtable2 == NULL)
|
||||
goto done;
|
||||
|
||||
symp = symtable1;
|
||||
for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
|
||||
ssym < ssymend; ssym++, symp++)
|
||||
{
|
||||
symp->u.ssym = ssym;
|
||||
symp->name = bfd_elf_string_from_elf_section (bfd1,
|
||||
hdr1->sh_link,
|
||||
ssym->st_name);
|
||||
}
|
||||
|
||||
symp = symtable2;
|
||||
for (ssym = ssymbuf2->ssym, ssymend = ssym + count2;
|
||||
ssym < ssymend; ssym++, symp++)
|
||||
{
|
||||
symp->u.ssym = ssym;
|
||||
symp->name = bfd_elf_string_from_elf_section (bfd2,
|
||||
hdr2->sh_link,
|
||||
ssym->st_name);
|
||||
}
|
||||
|
||||
/* Sort symbol by name. */
|
||||
qsort (symtable1, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
qsort (symtable2, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
|
||||
for (i = 0; i < count1; i++)
|
||||
/* Two symbols must have the same binding, type and name. */
|
||||
if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info
|
||||
|| symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other
|
||||
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
|
||||
goto done;
|
||||
|
||||
result = TRUE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
|
||||
symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
|
||||
if (symtable1 == NULL || symtable2 == NULL)
|
||||
goto done;
|
||||
|
||||
/* Count definitions in the section. */
|
||||
count1 = 0;
|
||||
for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
|
||||
if (isym->st_shndx == (unsigned int) shndx1)
|
||||
symtable1[count1++].u.isym = isym;
|
||||
|
||||
count2 = 0;
|
||||
for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
|
||||
if (isym->st_shndx == (unsigned int) shndx2)
|
||||
symtable2[count2++].u.isym = isym;
|
||||
|
||||
if (count1 == 0 || count2 == 0 || count1 != count2)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < count1; i++)
|
||||
symtable1[i].name
|
||||
= bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link,
|
||||
symtable1[i].u.isym->st_name);
|
||||
|
||||
for (i = 0; i < count2; i++)
|
||||
symtable2[i].name
|
||||
= bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link,
|
||||
symtable2[i].u.isym->st_name);
|
||||
|
||||
/* Sort symbol by name. */
|
||||
qsort (symtable1, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
qsort (symtable2, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
|
||||
for (i = 0; i < count1; i++)
|
||||
/* Two symbols must have the same binding, type and name. */
|
||||
if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info
|
||||
|| symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other
|
||||
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
|
||||
goto done;
|
||||
|
||||
result = TRUE;
|
||||
|
||||
done:
|
||||
if (symtable1)
|
||||
free (symtable1);
|
||||
if (symtable2)
|
||||
free (symtable2);
|
||||
if (isymbuf1)
|
||||
free (isymbuf1);
|
||||
if (isymbuf2)
|
||||
free (isymbuf2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* It is only used by x86-64 so far. */
|
||||
asection _bfd_elf_large_com_section
|
||||
= BFD_FAKE_SECTION (_bfd_elf_large_com_section,
|
||||
SEC_IS_COMMON, NULL, "LARGE_COMMON", 0);
|
||||
|
||||
/* Return TRUE if 2 section types are compatible. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec,
|
||||
bfd *bbfd, const asection *bsec)
|
||||
{
|
||||
if (asec == NULL
|
||||
|| bsec == NULL
|
||||
|| abfd->xvec->flavour != bfd_target_elf_flavour
|
||||
|| bbfd->xvec->flavour != bfd_target_elf_flavour)
|
||||
return TRUE;
|
||||
|
||||
return elf_section_type (asec) == elf_section_type (bsec);
|
||||
}
|
||||
|
||||
void
|
||||
_bfd_elf_set_osabi (bfd * abfd,
|
||||
struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
|
||||
|
721
bfd/elflink.c
721
bfd/elflink.c
@ -6389,7 +6389,728 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Indicate that we are only retrieving symbol values from this
|
||||
section. */
|
||||
|
||||
void
|
||||
_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
|
||||
{
|
||||
if (is_elf_hash_table (info->hash))
|
||||
sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
|
||||
_bfd_generic_link_just_syms (sec, info);
|
||||
}
|
||||
|
||||
/* Make sure sec_info_type is cleared if sec_info is cleared too. */
|
||||
|
||||
static void
|
||||
merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
asection *sec)
|
||||
{
|
||||
BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
|
||||
sec->sec_info_type = ELF_INFO_TYPE_NONE;
|
||||
}
|
||||
|
||||
/* Finish SHF_MERGE section merging. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
|
||||
{
|
||||
bfd *ibfd;
|
||||
asection *sec;
|
||||
|
||||
if (!is_elf_hash_table (info->hash))
|
||||
return FALSE;
|
||||
|
||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||
if ((ibfd->flags & DYNAMIC) == 0)
|
||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||
if ((sec->flags & SEC_MERGE) != 0
|
||||
&& !bfd_is_abs_section (sec->output_section))
|
||||
{
|
||||
struct bfd_elf_section_data *secdata;
|
||||
|
||||
secdata = elf_section_data (sec);
|
||||
if (! _bfd_add_merge_section (abfd,
|
||||
&elf_hash_table (info)->merge_info,
|
||||
sec, &secdata->sec_info))
|
||||
return FALSE;
|
||||
else if (secdata->sec_info)
|
||||
sec->sec_info_type = ELF_INFO_TYPE_MERGE;
|
||||
}
|
||||
|
||||
if (elf_hash_table (info)->merge_info != NULL)
|
||||
_bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
|
||||
merge_sections_remove_hook);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Create an entry in an ELF linker hash table. */
|
||||
|
||||
struct bfd_hash_entry *
|
||||
_bfd_elf_link_hash_newfunc (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 elf_link_hash_entry));
|
||||
if (entry == NULL)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Call the allocation method of the superclass. */
|
||||
entry = _bfd_link_hash_newfunc (entry, table, string);
|
||||
if (entry != NULL)
|
||||
{
|
||||
struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
|
||||
struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
|
||||
|
||||
/* Set local fields. */
|
||||
ret->indx = -1;
|
||||
ret->dynindx = -1;
|
||||
ret->got = htab->init_got_refcount;
|
||||
ret->plt = htab->init_plt_refcount;
|
||||
memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
|
||||
- offsetof (struct elf_link_hash_entry, size)));
|
||||
/* Assume that we have been called by a non-ELF symbol reader.
|
||||
This flag is then reset by the code which reads an ELF input
|
||||
file. This ensures that a symbol created by a non-ELF symbol
|
||||
reader will have the flag set correctly. */
|
||||
ret->non_elf = 1;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Copy data from an indirect symbol to its direct symbol, hiding the
|
||||
old indirect symbol. Also used for copying flags to a weakdef. */
|
||||
|
||||
void
|
||||
_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
|
||||
struct elf_link_hash_entry *dir,
|
||||
struct elf_link_hash_entry *ind)
|
||||
{
|
||||
struct elf_link_hash_table *htab;
|
||||
|
||||
/* Copy down any references that we may have already seen to the
|
||||
symbol which just became indirect. */
|
||||
|
||||
dir->ref_dynamic |= ind->ref_dynamic;
|
||||
dir->ref_regular |= ind->ref_regular;
|
||||
dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
|
||||
dir->non_got_ref |= ind->non_got_ref;
|
||||
dir->needs_plt |= ind->needs_plt;
|
||||
dir->pointer_equality_needed |= ind->pointer_equality_needed;
|
||||
|
||||
if (ind->root.type != bfd_link_hash_indirect)
|
||||
return;
|
||||
|
||||
/* Copy over the global and procedure linkage table refcount entries.
|
||||
These may have been already set up by a check_relocs routine. */
|
||||
htab = elf_hash_table (info);
|
||||
if (ind->got.refcount > htab->init_got_refcount.refcount)
|
||||
{
|
||||
if (dir->got.refcount < 0)
|
||||
dir->got.refcount = 0;
|
||||
dir->got.refcount += ind->got.refcount;
|
||||
ind->got.refcount = htab->init_got_refcount.refcount;
|
||||
}
|
||||
|
||||
if (ind->plt.refcount > htab->init_plt_refcount.refcount)
|
||||
{
|
||||
if (dir->plt.refcount < 0)
|
||||
dir->plt.refcount = 0;
|
||||
dir->plt.refcount += ind->plt.refcount;
|
||||
ind->plt.refcount = htab->init_plt_refcount.refcount;
|
||||
}
|
||||
|
||||
if (ind->dynindx != -1)
|
||||
{
|
||||
if (dir->dynindx != -1)
|
||||
_bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index);
|
||||
dir->dynindx = ind->dynindx;
|
||||
dir->dynstr_index = ind->dynstr_index;
|
||||
ind->dynindx = -1;
|
||||
ind->dynstr_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
|
||||
struct elf_link_hash_entry *h,
|
||||
bfd_boolean force_local)
|
||||
{
|
||||
h->plt = elf_hash_table (info)->init_plt_offset;
|
||||
h->needs_plt = 0;
|
||||
if (force_local)
|
||||
{
|
||||
h->forced_local = 1;
|
||||
if (h->dynindx != -1)
|
||||
{
|
||||
h->dynindx = -1;
|
||||
_bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
|
||||
h->dynstr_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize an ELF linker hash table. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_link_hash_table_init
|
||||
(struct elf_link_hash_table *table,
|
||||
bfd *abfd,
|
||||
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
|
||||
struct bfd_hash_table *,
|
||||
const char *),
|
||||
unsigned int entsize)
|
||||
{
|
||||
bfd_boolean ret;
|
||||
int can_refcount = get_elf_backend_data (abfd)->can_refcount;
|
||||
|
||||
memset (table, 0, sizeof * table);
|
||||
table->init_got_refcount.refcount = can_refcount - 1;
|
||||
table->init_plt_refcount.refcount = can_refcount - 1;
|
||||
table->init_got_offset.offset = -(bfd_vma) 1;
|
||||
table->init_plt_offset.offset = -(bfd_vma) 1;
|
||||
/* The first dynamic symbol is a dummy. */
|
||||
table->dynsymcount = 1;
|
||||
|
||||
ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
|
||||
table->root.type = bfd_link_elf_hash_table;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create an ELF linker hash table. */
|
||||
|
||||
struct bfd_link_hash_table *
|
||||
_bfd_elf_link_hash_table_create (bfd *abfd)
|
||||
{
|
||||
struct elf_link_hash_table *ret;
|
||||
bfd_size_type amt = sizeof (struct elf_link_hash_table);
|
||||
|
||||
ret = bfd_malloc (amt);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
|
||||
sizeof (struct elf_link_hash_entry)))
|
||||
{
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &ret->root;
|
||||
}
|
||||
|
||||
/* This is a hook for the ELF emulation code in the generic linker to
|
||||
tell the backend linker what file name to use for the DT_NEEDED
|
||||
entry for a dynamic object. */
|
||||
|
||||
void
|
||||
bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
|
||||
{
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
elf_dt_name (abfd) = name;
|
||||
}
|
||||
|
||||
int
|
||||
bfd_elf_get_dyn_lib_class (bfd *abfd)
|
||||
{
|
||||
int lib_class;
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
lib_class = elf_dyn_lib_class (abfd);
|
||||
else
|
||||
lib_class = 0;
|
||||
return lib_class;
|
||||
}
|
||||
|
||||
void
|
||||
bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class)
|
||||
{
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
elf_dyn_lib_class (abfd) = lib_class;
|
||||
}
|
||||
|
||||
/* Get the list of DT_NEEDED entries for a link. This is a hook for
|
||||
the linker ELF emulation code. */
|
||||
|
||||
struct bfd_link_needed_list *
|
||||
bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
if (! is_elf_hash_table (info->hash))
|
||||
return NULL;
|
||||
return elf_hash_table (info)->needed;
|
||||
}
|
||||
|
||||
/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a
|
||||
hook for the linker ELF emulation code. */
|
||||
|
||||
struct bfd_link_needed_list *
|
||||
bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
if (! is_elf_hash_table (info->hash))
|
||||
return NULL;
|
||||
return elf_hash_table (info)->runpath;
|
||||
}
|
||||
|
||||
/* Get the name actually used for a dynamic object for a link. This
|
||||
is the SONAME entry if there is one. Otherwise, it is the string
|
||||
passed to bfd_elf_set_dt_needed_name, or it is the filename. */
|
||||
|
||||
const char *
|
||||
bfd_elf_get_dt_soname (bfd *abfd)
|
||||
{
|
||||
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
||||
&& bfd_get_format (abfd) == bfd_object)
|
||||
return elf_dt_name (abfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the list of DT_NEEDED entries from a BFD. This is a hook for
|
||||
the ELF linker emulation code. */
|
||||
|
||||
bfd_boolean
|
||||
bfd_elf_get_bfd_needed_list (bfd *abfd,
|
||||
struct bfd_link_needed_list **pneeded)
|
||||
{
|
||||
asection *s;
|
||||
bfd_byte *dynbuf = NULL;
|
||||
int elfsec;
|
||||
unsigned long shlink;
|
||||
bfd_byte *extdyn, *extdynend;
|
||||
size_t extdynsize;
|
||||
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
|
||||
|
||||
*pneeded = NULL;
|
||||
|
||||
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
|
||||
|| bfd_get_format (abfd) != bfd_object)
|
||||
return TRUE;
|
||||
|
||||
s = bfd_get_section_by_name (abfd, ".dynamic");
|
||||
if (s == NULL || s->size == 0)
|
||||
return TRUE;
|
||||
|
||||
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
|
||||
goto error_return;
|
||||
|
||||
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
|
||||
if (elfsec == -1)
|
||||
goto error_return;
|
||||
|
||||
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
|
||||
|
||||
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
|
||||
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
|
||||
|
||||
extdyn = dynbuf;
|
||||
extdynend = extdyn + s->size;
|
||||
for (; extdyn < extdynend; extdyn += extdynsize)
|
||||
{
|
||||
Elf_Internal_Dyn dyn;
|
||||
|
||||
(*swap_dyn_in) (abfd, extdyn, &dyn);
|
||||
|
||||
if (dyn.d_tag == DT_NULL)
|
||||
break;
|
||||
|
||||
if (dyn.d_tag == DT_NEEDED)
|
||||
{
|
||||
const char *string;
|
||||
struct bfd_link_needed_list *l;
|
||||
unsigned int tagv = dyn.d_un.d_val;
|
||||
bfd_size_type amt;
|
||||
|
||||
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
||||
if (string == NULL)
|
||||
goto error_return;
|
||||
|
||||
amt = sizeof *l;
|
||||
l = bfd_alloc (abfd, amt);
|
||||
if (l == NULL)
|
||||
goto error_return;
|
||||
|
||||
l->by = abfd;
|
||||
l->name = string;
|
||||
l->next = *pneeded;
|
||||
*pneeded = l;
|
||||
}
|
||||
}
|
||||
|
||||
free (dynbuf);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error_return:
|
||||
if (dynbuf != NULL)
|
||||
free (dynbuf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct elf_symbuf_symbol
|
||||
{
|
||||
unsigned long st_name; /* Symbol name, index in string tbl */
|
||||
unsigned char st_info; /* Type and binding attributes */
|
||||
unsigned char st_other; /* Visibilty, and target specific */
|
||||
};
|
||||
|
||||
struct elf_symbuf_head
|
||||
{
|
||||
struct elf_symbuf_symbol *ssym;
|
||||
bfd_size_type count;
|
||||
unsigned int st_shndx;
|
||||
};
|
||||
|
||||
struct elf_symbol
|
||||
{
|
||||
union
|
||||
{
|
||||
Elf_Internal_Sym *isym;
|
||||
struct elf_symbuf_symbol *ssym;
|
||||
} u;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Sort references to symbols by ascending section number. */
|
||||
|
||||
static int
|
||||
elf_sort_elf_symbol (const void *arg1, const void *arg2)
|
||||
{
|
||||
const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
|
||||
const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
|
||||
|
||||
return s1->st_shndx - s2->st_shndx;
|
||||
}
|
||||
|
||||
static int
|
||||
elf_sym_name_compare (const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
|
||||
const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
|
||||
return strcmp (s1->name, s2->name);
|
||||
}
|
||||
|
||||
static struct elf_symbuf_head *
|
||||
elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
|
||||
{
|
||||
Elf_Internal_Sym **ind, **indbufend, **indbuf
|
||||
= bfd_malloc2 (symcount, sizeof (*indbuf));
|
||||
struct elf_symbuf_symbol *ssym;
|
||||
struct elf_symbuf_head *ssymbuf, *ssymhead;
|
||||
bfd_size_type i, shndx_count;
|
||||
|
||||
if (indbuf == NULL)
|
||||
return NULL;
|
||||
|
||||
for (ind = indbuf, i = 0; i < symcount; i++)
|
||||
if (isymbuf[i].st_shndx != SHN_UNDEF)
|
||||
*ind++ = &isymbuf[i];
|
||||
indbufend = ind;
|
||||
|
||||
qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *),
|
||||
elf_sort_elf_symbol);
|
||||
|
||||
shndx_count = 0;
|
||||
if (indbufend > indbuf)
|
||||
for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++)
|
||||
if (ind[0]->st_shndx != ind[1]->st_shndx)
|
||||
shndx_count++;
|
||||
|
||||
ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
|
||||
+ (indbufend - indbuf) * sizeof (*ssymbuf));
|
||||
if (ssymbuf == NULL)
|
||||
{
|
||||
free (indbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
|
||||
ssymbuf->ssym = NULL;
|
||||
ssymbuf->count = shndx_count;
|
||||
ssymbuf->st_shndx = 0;
|
||||
for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++)
|
||||
{
|
||||
if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx)
|
||||
{
|
||||
ssymhead++;
|
||||
ssymhead->ssym = ssym;
|
||||
ssymhead->count = 0;
|
||||
ssymhead->st_shndx = (*ind)->st_shndx;
|
||||
}
|
||||
ssym->st_name = (*ind)->st_name;
|
||||
ssym->st_info = (*ind)->st_info;
|
||||
ssym->st_other = (*ind)->st_other;
|
||||
ssymhead->count++;
|
||||
}
|
||||
BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
|
||||
|
||||
free (indbuf);
|
||||
return ssymbuf;
|
||||
}
|
||||
|
||||
/* Check if 2 sections define the same set of local and global
|
||||
symbols. */
|
||||
|
||||
bfd_boolean
|
||||
bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
bfd *bfd1, *bfd2;
|
||||
const struct elf_backend_data *bed1, *bed2;
|
||||
Elf_Internal_Shdr *hdr1, *hdr2;
|
||||
bfd_size_type symcount1, symcount2;
|
||||
Elf_Internal_Sym *isymbuf1, *isymbuf2;
|
||||
struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
|
||||
Elf_Internal_Sym *isym, *isymend;
|
||||
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
|
||||
bfd_size_type count1, count2, i;
|
||||
int shndx1, shndx2;
|
||||
bfd_boolean result;
|
||||
|
||||
bfd1 = sec1->owner;
|
||||
bfd2 = sec2->owner;
|
||||
|
||||
/* If both are .gnu.linkonce sections, they have to have the same
|
||||
section name. */
|
||||
if (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
|
||||
&& CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
|
||||
return strcmp (sec1->name + sizeof ".gnu.linkonce",
|
||||
sec2->name + sizeof ".gnu.linkonce") == 0;
|
||||
|
||||
/* Both sections have to be in ELF. */
|
||||
if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
|
||||
|| bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
|
||||
return FALSE;
|
||||
|
||||
if (elf_section_type (sec1) != elf_section_type (sec2))
|
||||
return FALSE;
|
||||
|
||||
if ((elf_section_flags (sec1) & SHF_GROUP) != 0
|
||||
&& (elf_section_flags (sec2) & SHF_GROUP) != 0)
|
||||
{
|
||||
/* If both are members of section groups, they have to have the
|
||||
same group name. */
|
||||
if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
|
||||
shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
|
||||
if (shndx1 == -1 || shndx2 == -1)
|
||||
return FALSE;
|
||||
|
||||
bed1 = get_elf_backend_data (bfd1);
|
||||
bed2 = get_elf_backend_data (bfd2);
|
||||
hdr1 = &elf_tdata (bfd1)->symtab_hdr;
|
||||
symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
|
||||
hdr2 = &elf_tdata (bfd2)->symtab_hdr;
|
||||
symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
|
||||
|
||||
if (symcount1 == 0 || symcount2 == 0)
|
||||
return FALSE;
|
||||
|
||||
result = FALSE;
|
||||
isymbuf1 = NULL;
|
||||
isymbuf2 = NULL;
|
||||
ssymbuf1 = elf_tdata (bfd1)->symbuf;
|
||||
ssymbuf2 = elf_tdata (bfd2)->symbuf;
|
||||
|
||||
if (ssymbuf1 == NULL)
|
||||
{
|
||||
isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
|
||||
NULL, NULL, NULL);
|
||||
if (isymbuf1 == NULL)
|
||||
goto done;
|
||||
|
||||
if (!info->reduce_memory_overheads)
|
||||
elf_tdata (bfd1)->symbuf = ssymbuf1
|
||||
= elf_create_symbuf (symcount1, isymbuf1);
|
||||
}
|
||||
|
||||
if (ssymbuf1 == NULL || ssymbuf2 == NULL)
|
||||
{
|
||||
isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
|
||||
NULL, NULL, NULL);
|
||||
if (isymbuf2 == NULL)
|
||||
goto done;
|
||||
|
||||
if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
|
||||
elf_tdata (bfd2)->symbuf = ssymbuf2
|
||||
= elf_create_symbuf (symcount2, isymbuf2);
|
||||
}
|
||||
|
||||
if (ssymbuf1 != NULL && ssymbuf2 != NULL)
|
||||
{
|
||||
/* Optimized faster version. */
|
||||
bfd_size_type lo, hi, mid;
|
||||
struct elf_symbol *symp;
|
||||
struct elf_symbuf_symbol *ssym, *ssymend;
|
||||
|
||||
lo = 0;
|
||||
hi = ssymbuf1->count;
|
||||
ssymbuf1++;
|
||||
count1 = 0;
|
||||
while (lo < hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
|
||||
hi = mid;
|
||||
else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
|
||||
lo = mid + 1;
|
||||
else
|
||||
{
|
||||
count1 = ssymbuf1[mid].count;
|
||||
ssymbuf1 += mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lo = 0;
|
||||
hi = ssymbuf2->count;
|
||||
ssymbuf2++;
|
||||
count2 = 0;
|
||||
while (lo < hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
|
||||
hi = mid;
|
||||
else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
|
||||
lo = mid + 1;
|
||||
else
|
||||
{
|
||||
count2 = ssymbuf2[mid].count;
|
||||
ssymbuf2 += mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count1 == 0 || count2 == 0 || count1 != count2)
|
||||
goto done;
|
||||
|
||||
symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
|
||||
symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
|
||||
if (symtable1 == NULL || symtable2 == NULL)
|
||||
goto done;
|
||||
|
||||
symp = symtable1;
|
||||
for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
|
||||
ssym < ssymend; ssym++, symp++)
|
||||
{
|
||||
symp->u.ssym = ssym;
|
||||
symp->name = bfd_elf_string_from_elf_section (bfd1,
|
||||
hdr1->sh_link,
|
||||
ssym->st_name);
|
||||
}
|
||||
|
||||
symp = symtable2;
|
||||
for (ssym = ssymbuf2->ssym, ssymend = ssym + count2;
|
||||
ssym < ssymend; ssym++, symp++)
|
||||
{
|
||||
symp->u.ssym = ssym;
|
||||
symp->name = bfd_elf_string_from_elf_section (bfd2,
|
||||
hdr2->sh_link,
|
||||
ssym->st_name);
|
||||
}
|
||||
|
||||
/* Sort symbol by name. */
|
||||
qsort (symtable1, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
qsort (symtable2, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
|
||||
for (i = 0; i < count1; i++)
|
||||
/* Two symbols must have the same binding, type and name. */
|
||||
if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info
|
||||
|| symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other
|
||||
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
|
||||
goto done;
|
||||
|
||||
result = TRUE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
|
||||
symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
|
||||
if (symtable1 == NULL || symtable2 == NULL)
|
||||
goto done;
|
||||
|
||||
/* Count definitions in the section. */
|
||||
count1 = 0;
|
||||
for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
|
||||
if (isym->st_shndx == (unsigned int) shndx1)
|
||||
symtable1[count1++].u.isym = isym;
|
||||
|
||||
count2 = 0;
|
||||
for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
|
||||
if (isym->st_shndx == (unsigned int) shndx2)
|
||||
symtable2[count2++].u.isym = isym;
|
||||
|
||||
if (count1 == 0 || count2 == 0 || count1 != count2)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < count1; i++)
|
||||
symtable1[i].name
|
||||
= bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link,
|
||||
symtable1[i].u.isym->st_name);
|
||||
|
||||
for (i = 0; i < count2; i++)
|
||||
symtable2[i].name
|
||||
= bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link,
|
||||
symtable2[i].u.isym->st_name);
|
||||
|
||||
/* Sort symbol by name. */
|
||||
qsort (symtable1, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
qsort (symtable2, count1, sizeof (struct elf_symbol),
|
||||
elf_sym_name_compare);
|
||||
|
||||
for (i = 0; i < count1; i++)
|
||||
/* Two symbols must have the same binding, type and name. */
|
||||
if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info
|
||||
|| symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other
|
||||
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
|
||||
goto done;
|
||||
|
||||
result = TRUE;
|
||||
|
||||
done:
|
||||
if (symtable1)
|
||||
free (symtable1);
|
||||
if (symtable2)
|
||||
free (symtable2);
|
||||
if (isymbuf1)
|
||||
free (isymbuf1);
|
||||
if (isymbuf2)
|
||||
free (isymbuf2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return TRUE if 2 section types are compatible. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec,
|
||||
bfd *bbfd, const asection *bsec)
|
||||
{
|
||||
if (asec == NULL
|
||||
|| bsec == NULL
|
||||
|| abfd->xvec->flavour != bfd_target_elf_flavour
|
||||
|| bbfd->xvec->flavour != bfd_target_elf_flavour)
|
||||
return TRUE;
|
||||
|
||||
return elf_section_type (asec) == elf_section_type (bsec);
|
||||
}
|
||||
|
||||
/* Final phase of ELF linker. */
|
||||
|
||||
/* A structure we use to avoid passing large numbers of arguments. */
|
||||
|
Loading…
Reference in New Issue
Block a user