Line 1... |
Line 1... |
/* ELF linking support for BFD.
|
/* ELF linking support for BFD.
|
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
2005, 2006, 2007, 2008, 2009
|
|
Free Software Foundation, Inc.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
Line 27... |
Line 28... |
#include "elf-bfd.h"
|
#include "elf-bfd.h"
|
#include "safe-ctype.h"
|
#include "safe-ctype.h"
|
#include "libiberty.h"
|
#include "libiberty.h"
|
#include "objalloc.h"
|
#include "objalloc.h"
|
|
|
|
/* This struct is used to pass information to routines called via
|
|
elf_link_hash_traverse which must return failure. */
|
|
|
|
struct elf_info_failed
|
|
{
|
|
struct bfd_link_info *info;
|
|
struct bfd_elf_version_tree *verdefs;
|
|
bfd_boolean failed;
|
|
};
|
|
|
|
/* This structure is used to pass information to
|
|
_bfd_elf_link_find_version_dependencies. */
|
|
|
|
struct elf_find_verdep_info
|
|
{
|
|
/* General link information. */
|
|
struct bfd_link_info *info;
|
|
/* The number of dependencies. */
|
|
unsigned int vers;
|
|
/* Whether we had a failure. */
|
|
bfd_boolean failed;
|
|
};
|
|
|
|
static bfd_boolean _bfd_elf_fix_symbol_flags
|
|
(struct elf_link_hash_entry *, struct elf_info_failed *);
|
|
|
/* Define a symbol in a dynamic linkage section. */
|
/* Define a symbol in a dynamic linkage section. */
|
|
|
struct elf_link_hash_entry *
|
struct elf_link_hash_entry *
|
_bfd_elf_define_linkage_sym (bfd *abfd,
|
_bfd_elf_define_linkage_sym (bfd *abfd,
|
struct bfd_link_info *info,
|
struct bfd_link_info *info,
|
Line 72... |
Line 99... |
{
|
{
|
flagword flags;
|
flagword flags;
|
asection *s;
|
asection *s;
|
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
int ptralign;
|
struct elf_link_hash_table *htab = elf_hash_table (info);
|
|
|
/* This function may be called more than once. */
|
/* This function may be called more than once. */
|
s = bfd_get_section_by_name (abfd, ".got");
|
s = bfd_get_section_by_name (abfd, ".got");
|
if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
|
if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
|
return TRUE;
|
return TRUE;
|
|
|
switch (bed->s->arch_size)
|
flags = bed->dynamic_sec_flags;
|
{
|
|
case 32:
|
|
ptralign = 2;
|
|
break;
|
|
|
|
case 64:
|
|
ptralign = 3;
|
|
break;
|
|
|
|
default:
|
s = bfd_make_section_with_flags (abfd,
|
bfd_set_error (bfd_error_bad_value);
|
(bed->rela_plts_and_copies_p
|
|
? ".rela.got" : ".rel.got"),
|
|
(bed->dynamic_sec_flags
|
|
| SEC_READONLY));
|
|
if (s == NULL
|
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
}
|
htab->srelgot = s;
|
|
|
flags = bed->dynamic_sec_flags;
|
|
|
|
s = bfd_make_section_with_flags (abfd, ".got", flags);
|
s = bfd_make_section_with_flags (abfd, ".got", flags);
|
if (s == NULL
|
if (s == NULL
|
|| !bfd_set_section_alignment (abfd, s, ptralign))
|
|| !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
|
htab->sgot = s;
|
|
|
if (bed->want_got_plt)
|
if (bed->want_got_plt)
|
{
|
{
|
s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
|
s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
|
if (s == NULL
|
if (s == NULL
|
|| !bfd_set_section_alignment (abfd, s, ptralign))
|
|| !bfd_set_section_alignment (abfd, s,
|
|
bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
|
htab->sgotplt = s;
|
}
|
}
|
|
|
|
/* The first bit of the global offset table is the header. */
|
|
s->size += bed->got_header_size;
|
|
|
if (bed->want_got_sym)
|
if (bed->want_got_sym)
|
{
|
{
|
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
|
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
|
(or .got.plt) section. We don't do this in the linker script
|
(or .got.plt) section. We don't do this in the linker script
|
because we don't want to define the symbol if we are not creating
|
because we don't want to define the symbol if we are not creating
|
a global offset table. */
|
a global offset table. */
|
h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_");
|
h = _bfd_elf_define_linkage_sym (abfd, info, s,
|
|
"_GLOBAL_OFFSET_TABLE_");
|
elf_hash_table (info)->hgot = h;
|
elf_hash_table (info)->hgot = h;
|
if (h == NULL)
|
if (h == NULL)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
/* The first bit of the global offset table is the header. */
|
|
s->size += bed->got_header_size;
|
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Create a strtab to hold the dynamic symbol names. */
|
/* Create a strtab to hold the dynamic symbol names. */
|
static bfd_boolean
|
static bfd_boolean
|
Line 274... |
Line 300... |
{
|
{
|
flagword flags, pltflags;
|
flagword flags, pltflags;
|
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
asection *s;
|
asection *s;
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
|
struct elf_link_hash_table *htab = elf_hash_table (info);
|
|
|
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
|
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
|
.rel[a].bss sections. */
|
.rel[a].bss sections. */
|
flags = bed->dynamic_sec_flags;
|
flags = bed->dynamic_sec_flags;
|
|
|
Line 294... |
Line 321... |
|
|
s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
|
s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
|
if (s == NULL
|
if (s == NULL
|
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
|
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
|
return FALSE;
|
return FALSE;
|
|
htab->splt = s;
|
|
|
/* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
|
/* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
|
.plt section. */
|
.plt section. */
|
if (bed->want_plt_sym)
|
if (bed->want_plt_sym)
|
{
|
{
|
Line 307... |
Line 335... |
if (h == NULL)
|
if (h == NULL)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
s = bfd_make_section_with_flags (abfd,
|
s = bfd_make_section_with_flags (abfd,
|
(bed->default_use_rela_p
|
(bed->rela_plts_and_copies_p
|
? ".rela.plt" : ".rel.plt"),
|
? ".rela.plt" : ".rel.plt"),
|
flags | SEC_READONLY);
|
flags | SEC_READONLY);
|
if (s == NULL
|
if (s == NULL
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
|
htab->srelplt = s;
|
|
|
if (! _bfd_elf_create_got_section (abfd, info))
|
if (! _bfd_elf_create_got_section (abfd, info))
|
return FALSE;
|
return FALSE;
|
|
|
if (bed->want_dynbss)
|
if (bed->want_dynbss)
|
Line 345... |
Line 374... |
section when generating a shared object, since they do not use
|
section when generating a shared object, since they do not use
|
copy relocs. */
|
copy relocs. */
|
if (! info->shared)
|
if (! info->shared)
|
{
|
{
|
s = bfd_make_section_with_flags (abfd,
|
s = bfd_make_section_with_flags (abfd,
|
(bed->default_use_rela_p
|
(bed->rela_plts_and_copies_p
|
? ".rela.bss" : ".rel.bss"),
|
? ".rela.bss" : ".rel.bss"),
|
flags | SEC_READONLY);
|
flags | SEC_READONLY);
|
if (s == NULL
|
if (s == NULL
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
Line 435... |
Line 464... |
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Mark a symbol dynamic. */
|
/* Mark a symbol dynamic. */
|
|
|
void
|
static void
|
bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
|
bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
|
struct elf_link_hash_entry *h,
|
struct elf_link_hash_entry *h,
|
Elf_Internal_Sym *sym)
|
Elf_Internal_Sym *sym)
|
{
|
{
|
struct bfd_elf_dynamic_list *d = info->dynamic_list;
|
struct bfd_elf_dynamic_list *d = info->dynamic_list;
|
Line 603... |
Line 632... |
for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
|
for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
|
if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
|
if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
|
return 1;
|
return 1;
|
|
|
amt = sizeof (*entry);
|
amt = sizeof (*entry);
|
entry = bfd_alloc (input_bfd, amt);
|
entry = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt);
|
if (entry == NULL)
|
if (entry == NULL)
|
return 0;
|
return 0;
|
|
|
/* Go find the symbol, so that we can find it's name. */
|
/* Go find the symbol, so that we can find it's name. */
|
if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr,
|
if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr,
|
Line 616... |
Line 645... |
bfd_release (input_bfd, entry);
|
bfd_release (input_bfd, entry);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if (entry->isym.st_shndx != SHN_UNDEF
|
if (entry->isym.st_shndx != SHN_UNDEF
|
&& (entry->isym.st_shndx < SHN_LORESERVE
|
&& entry->isym.st_shndx < SHN_LORESERVE)
|
|| entry->isym.st_shndx > SHN_HIRESERVE))
|
|
{
|
{
|
asection *s;
|
asection *s;
|
|
|
s = bfd_section_from_elf_index (input_bfd, entry->isym.st_shndx);
|
s = bfd_section_from_elf_index (input_bfd, entry->isym.st_shndx);
|
if (s == NULL || bfd_is_abs_section (s->output_section))
|
if (s == NULL || bfd_is_abs_section (s->output_section))
|
Line 689... |
Line 717... |
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_link_renumber_hash_table_dynsyms (struct elf_link_hash_entry *h,
|
elf_link_renumber_hash_table_dynsyms (struct elf_link_hash_entry *h,
|
void *data)
|
void *data)
|
{
|
{
|
size_t *count = data;
|
size_t *count = (size_t *) data;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
|
|
if (h->forced_local)
|
if (h->forced_local)
|
Line 711... |
Line 739... |
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h,
|
elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h,
|
void *data)
|
void *data)
|
{
|
{
|
size_t *count = data;
|
size_t *count = (size_t *) data;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
|
|
if (!h->forced_local)
|
if (!h->forced_local)
|
Line 821... |
Line 849... |
|
|
elf_hash_table (info)->dynsymcount = dynsymcount;
|
elf_hash_table (info)->dynsymcount = dynsymcount;
|
return dynsymcount;
|
return dynsymcount;
|
}
|
}
|
|
|
|
/* Merge st_other field. */
|
|
|
|
static void
|
|
elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
|
|
Elf_Internal_Sym *isym, bfd_boolean definition,
|
|
bfd_boolean dynamic)
|
|
{
|
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
|
|
|
/* If st_other has a processor-specific meaning, specific
|
|
code might be needed here. We never merge the visibility
|
|
attribute with the one from a dynamic object. */
|
|
if (bed->elf_backend_merge_symbol_attribute)
|
|
(*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
|
|
dynamic);
|
|
|
|
/* If this symbol has default visibility and the user has requested
|
|
we not re-export it, then mark it as hidden. */
|
|
if (definition
|
|
&& !dynamic
|
|
&& (abfd->no_export
|
|
|| (abfd->my_archive && abfd->my_archive->no_export))
|
|
&& ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
|
|
isym->st_other = (STV_HIDDEN
|
|
| (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
|
|
|
|
if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0)
|
|
{
|
|
unsigned char hvis, symvis, other, nvis;
|
|
|
|
/* Only merge the visibility. Leave the remainder of the
|
|
st_other field to elf_backend_merge_symbol_attribute. */
|
|
other = h->other & ~ELF_ST_VISIBILITY (-1);
|
|
|
|
/* Combine visibilities, using the most constraining one. */
|
|
hvis = ELF_ST_VISIBILITY (h->other);
|
|
symvis = ELF_ST_VISIBILITY (isym->st_other);
|
|
if (! hvis)
|
|
nvis = symvis;
|
|
else if (! symvis)
|
|
nvis = hvis;
|
|
else
|
|
nvis = hvis < symvis ? hvis : symvis;
|
|
|
|
h->other = other | nvis;
|
|
}
|
|
}
|
|
|
/* This function is called when we want to define a new symbol. It
|
/* This function is called when we want to define a new symbol. It
|
handles the various cases which arise when we find a definition in
|
handles the various cases which arise when we find a definition in
|
a dynamic object, or when there is already a definition in a
|
a dynamic object, or when there is already a definition in a
|
dynamic object. The new symbol is described by NAME, SYM, PSEC,
|
dynamic object. The new symbol is described by NAME, SYM, PSEC,
|
and PVALUE. We set SYM_HASH to the hash table entry. We set
|
and PVALUE. We set SYM_HASH to the hash table entry. We set
|
Line 853... |
Line 929... |
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *flip;
|
struct elf_link_hash_entry *flip;
|
int bind;
|
int bind;
|
bfd *oldbfd;
|
bfd *oldbfd;
|
bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
|
bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
|
bfd_boolean newweak, oldweak;
|
bfd_boolean newweak, oldweak, newfunc, oldfunc;
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
|
|
*skip = FALSE;
|
*skip = FALSE;
|
*override = FALSE;
|
*override = FALSE;
|
|
|
Line 880... |
Line 956... |
bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, FALSE, FALSE));
|
bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, FALSE, FALSE));
|
if (h == NULL)
|
if (h == NULL)
|
return FALSE;
|
return FALSE;
|
*sym_hash = h;
|
*sym_hash = h;
|
|
|
|
bed = get_elf_backend_data (abfd);
|
|
|
/* This code is for coping with dynamic objects, and is only useful
|
/* This code is for coping with dynamic objects, and is only useful
|
if we are doing an ELF link. */
|
if we are doing an ELF link. */
|
if (info->output_bfd->xvec != abfd->xvec)
|
if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
|
return TRUE;
|
return TRUE;
|
|
|
/* For merging, we only care about real symbols. */
|
/* For merging, we only care about real symbols. */
|
|
|
while (h->root.type == bfd_link_hash_indirect
|
while (h->root.type == bfd_link_hash_indirect
|
Line 969... |
Line 1047... |
|
|
olddef = (h->root.type != bfd_link_hash_undefined
|
olddef = (h->root.type != bfd_link_hash_undefined
|
&& h->root.type != bfd_link_hash_undefweak
|
&& h->root.type != bfd_link_hash_undefweak
|
&& h->root.type != bfd_link_hash_common);
|
&& h->root.type != bfd_link_hash_common);
|
|
|
bed = get_elf_backend_data (abfd);
|
/* NEWFUNC and OLDFUNC indicate whether the new or old symbol,
|
|
respectively, appear to be a function. */
|
|
|
|
newfunc = (ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
|
|
&& bed->is_function_type (ELF_ST_TYPE (sym->st_info)));
|
|
|
|
oldfunc = (h->type != STT_NOTYPE
|
|
&& bed->is_function_type (h->type));
|
|
|
/* When we try to create a default indirect symbol from the dynamic
|
/* When we try to create a default indirect symbol from the dynamic
|
definition with the default version, we skip it if its type and
|
definition with the default version, we skip it if its type and
|
the type of existing regular definition mismatch. We only do it
|
the type of existing regular definition mismatch. We only do it
|
if the existing regular definition won't be dynamic. */
|
if the existing regular definition won't be dynamic. */
|
if (pold_alignment == NULL
|
if (pold_alignment == NULL
|
Line 985... |
Line 1071... |
&& !olddyn
|
&& !olddyn
|
&& (olddef || h->root.type == bfd_link_hash_common)
|
&& (olddef || h->root.type == bfd_link_hash_common)
|
&& ELF_ST_TYPE (sym->st_info) != h->type
|
&& ELF_ST_TYPE (sym->st_info) != h->type
|
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
|
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
|
&& h->type != STT_NOTYPE
|
&& h->type != STT_NOTYPE
|
&& !(bed->is_function_type (ELF_ST_TYPE (sym->st_info))
|
&& !(newfunc && oldfunc))
|
&& bed->is_function_type (h->type)))
|
|
{
|
{
|
*skip = TRUE;
|
*skip = TRUE;
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
Line 1161... |
Line 1246... |
/* Differentiate strong and weak symbols. */
|
/* Differentiate strong and weak symbols. */
|
newweak = bind == STB_WEAK;
|
newweak = bind == STB_WEAK;
|
oldweak = (h->root.type == bfd_link_hash_defweak
|
oldweak = (h->root.type == bfd_link_hash_defweak
|
|| h->root.type == bfd_link_hash_undefweak);
|
|| h->root.type == bfd_link_hash_undefweak);
|
|
|
|
if (bind == STB_GNU_UNIQUE)
|
|
h->unique_global = 1;
|
|
|
/* If a new weak symbol definition comes from a regular file and the
|
/* If a new weak symbol definition comes from a regular file and the
|
old symbol comes from a dynamic library, we treat the new one as
|
old symbol comes from a dynamic library, we treat the new one as
|
strong. Similarly, an old weak symbol definition from a regular
|
strong. Similarly, an old weak symbol definition from a regular
|
file is treated as strong when the new symbol comes from a dynamic
|
file is treated as strong when the new symbol comes from a dynamic
|
library. Further, an old weak symbol from a dynamic library is
|
library. Further, an old weak symbol from a dynamic library is
|
Line 1177... |
Line 1265... |
if (newdef && !newdyn && olddyn)
|
if (newdef && !newdyn && olddyn)
|
newweak = FALSE;
|
newweak = FALSE;
|
if (olddef && newdyn)
|
if (olddef && newdyn)
|
oldweak = FALSE;
|
oldweak = FALSE;
|
|
|
/* Allow changes between different types of funciton symbol. */
|
/* Allow changes between different types of function symbol. */
|
if (bed->is_function_type (ELF_ST_TYPE (sym->st_info))
|
if (newfunc && oldfunc)
|
&& bed->is_function_type (h->type))
|
|
*type_change_ok = TRUE;
|
*type_change_ok = TRUE;
|
|
|
/* It's OK to change the type if either the existing symbol or the
|
/* It's OK to change the type if either the existing symbol or the
|
new symbol is weak. A type change is also OK if the old symbol
|
new symbol is weak. A type change is also OK if the old symbol
|
is undefined and the new symbol is defined. */
|
is undefined and the new symbol is defined. */
|
Line 1228... |
Line 1315... |
&& newdef
|
&& newdef
|
&& !newweak
|
&& !newweak
|
&& (sec->flags & SEC_ALLOC) != 0
|
&& (sec->flags & SEC_ALLOC) != 0
|
&& (sec->flags & SEC_LOAD) == 0
|
&& (sec->flags & SEC_LOAD) == 0
|
&& sym->st_size > 0
|
&& sym->st_size > 0
|
&& !bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
|
&& !newfunc)
|
newdyncommon = TRUE;
|
newdyncommon = TRUE;
|
else
|
else
|
newdyncommon = FALSE;
|
newdyncommon = FALSE;
|
|
|
if (olddyn
|
if (olddyn
|
Line 1240... |
Line 1327... |
&& h->root.type == bfd_link_hash_defined
|
&& h->root.type == bfd_link_hash_defined
|
&& h->def_dynamic
|
&& h->def_dynamic
|
&& (h->root.u.def.section->flags & SEC_ALLOC) != 0
|
&& (h->root.u.def.section->flags & SEC_ALLOC) != 0
|
&& (h->root.u.def.section->flags & SEC_LOAD) == 0
|
&& (h->root.u.def.section->flags & SEC_LOAD) == 0
|
&& h->size > 0
|
&& h->size > 0
|
&& !bed->is_function_type (h->type))
|
&& !oldfunc)
|
olddyncommon = TRUE;
|
olddyncommon = TRUE;
|
else
|
else
|
olddyncommon = FALSE;
|
olddyncommon = FALSE;
|
|
|
/* We now know everything about the old and new symbols. We ask the
|
/* We now know everything about the old and new symbols. We ask the
|
Line 1300... |
Line 1387... |
|
|
if (newdyn
|
if (newdyn
|
&& newdef
|
&& newdef
|
&& (olddef
|
&& (olddef
|
|| (h->root.type == bfd_link_hash_common
|
|| (h->root.type == bfd_link_hash_common
|
&& (newweak
|
&& (newweak || newfunc))))
|
|| bed->is_function_type (ELF_ST_TYPE (sym->st_info))))))
|
|
{
|
{
|
*override = TRUE;
|
*override = TRUE;
|
newdef = FALSE;
|
newdef = FALSE;
|
newdyncommon = FALSE;
|
newdyncommon = FALSE;
|
|
|
Line 1339... |
Line 1425... |
*size_change_ok = TRUE;
|
*size_change_ok = TRUE;
|
}
|
}
|
|
|
/* Skip weak definitions of symbols that are already defined. */
|
/* Skip weak definitions of symbols that are already defined. */
|
if (newdef && olddef && newweak)
|
if (newdef && olddef && newweak)
|
|
{
|
*skip = TRUE;
|
*skip = TRUE;
|
|
|
|
/* Merge st_other. If the symbol already has a dynamic index,
|
|
but visibility says it should not be visible, turn it into a
|
|
local symbol. */
|
|
elf_merge_st_other (abfd, h, sym, newdef, newdyn);
|
|
if (h->dynindx != -1)
|
|
switch (ELF_ST_VISIBILITY (h->other))
|
|
{
|
|
case STV_INTERNAL:
|
|
case STV_HIDDEN:
|
|
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
|
/* If the old symbol is from a dynamic object, and the new symbol is
|
/* If the old symbol is from a dynamic object, and the new symbol is
|
a definition which is not from a dynamic object, then the new
|
a definition which is not from a dynamic object, then the new
|
symbol overrides the old symbol. Symbols from regular files
|
symbol overrides the old symbol. Symbols from regular files
|
always take precedence over symbols from dynamic objects, even if
|
always take precedence over symbols from dynamic objects, even if
|
they are defined after the dynamic object in the link.
|
they are defined after the dynamic object in the link.
|
Line 1355... |
Line 1456... |
|
|
flip = NULL;
|
flip = NULL;
|
if (!newdyn
|
if (!newdyn
|
&& (newdef
|
&& (newdef
|
|| (bfd_is_com_section (sec)
|
|| (bfd_is_com_section (sec)
|
&& (oldweak
|
&& (oldweak || oldfunc)))
|
|| bed->is_function_type (h->type))))
|
|
&& olddyn
|
&& olddyn
|
&& olddef
|
&& olddef
|
&& h->def_dynamic)
|
&& h->def_dynamic)
|
{
|
{
|
/* Change the hash table entry to undefined, and let
|
/* Change the hash table entry to undefined, and let
|
Line 1376... |
Line 1476... |
|
|
/* We again permit a type change when a common symbol may be
|
/* We again permit a type change when a common symbol may be
|
overriding a function. */
|
overriding a function. */
|
|
|
if (bfd_is_com_section (sec))
|
if (bfd_is_com_section (sec))
|
|
{
|
|
if (oldfunc)
|
|
{
|
|
/* If a common symbol overrides a function, make sure
|
|
that it isn't defined dynamically nor has type
|
|
function. */
|
|
h->def_dynamic = 0;
|
|
h->type = STT_NOTYPE;
|
|
}
|
*type_change_ok = TRUE;
|
*type_change_ok = TRUE;
|
|
}
|
|
|
if ((*sym_hash)->root.type == bfd_link_hash_indirect)
|
if ((*sym_hash)->root.type == bfd_link_hash_indirect)
|
flip = *sym_hash;
|
flip = *sym_hash;
|
else
|
else
|
/* This union may have been set to be non-NULL when this symbol
|
/* This union may have been set to be non-NULL when this symbol
|
Line 1457... |
Line 1567... |
/* This function is called to create an indirect symbol from the
|
/* This function is called to create an indirect symbol from the
|
default for the symbol with the default version if needed. The
|
default for the symbol with the default version if needed. The
|
symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We
|
symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We
|
set DYNSYM if the new indirect symbol is dynamic. */
|
set DYNSYM if the new indirect symbol is dynamic. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_add_default_symbol (bfd *abfd,
|
_bfd_elf_add_default_symbol (bfd *abfd,
|
struct bfd_link_info *info,
|
struct bfd_link_info *info,
|
struct elf_link_hash_entry *h,
|
struct elf_link_hash_entry *h,
|
const char *name,
|
const char *name,
|
Elf_Internal_Sym *sym,
|
Elf_Internal_Sym *sym,
|
Line 1512... |
Line 1622... |
bed = get_elf_backend_data (abfd);
|
bed = get_elf_backend_data (abfd);
|
collect = bed->collect;
|
collect = bed->collect;
|
dynamic = (abfd->flags & DYNAMIC) != 0;
|
dynamic = (abfd->flags & DYNAMIC) != 0;
|
|
|
shortlen = p - name;
|
shortlen = p - name;
|
shortname = bfd_hash_allocate (&info->hash->table, shortlen + 1);
|
shortname = (char *) bfd_hash_allocate (&info->hash->table, shortlen + 1);
|
if (shortname == NULL)
|
if (shortname == NULL)
|
return FALSE;
|
return FALSE;
|
memcpy (shortname, name, shortlen);
|
memcpy (shortname, name, shortlen);
|
shortname[shortlen] = '\0';
|
shortname[shortlen] = '\0';
|
|
|
Line 1623... |
Line 1733... |
/* We also need to define an indirection from the nondefault version
|
/* We also need to define an indirection from the nondefault version
|
of the symbol. */
|
of the symbol. */
|
|
|
nondefault:
|
nondefault:
|
len = strlen (name);
|
len = strlen (name);
|
shortname = bfd_hash_allocate (&info->hash->table, len);
|
shortname = (char *) bfd_hash_allocate (&info->hash->table, len);
|
if (shortname == NULL)
|
if (shortname == NULL)
|
return FALSE;
|
return FALSE;
|
memcpy (shortname, name, shortlen);
|
memcpy (shortname, name, shortlen);
|
memcpy (shortname + shortlen, p + 1, len - shortlen);
|
memcpy (shortname + shortlen, p + 1, len - shortlen);
|
|
|
Line 1694... |
Line 1804... |
}
|
}
|
|
|
/* This routine is used to export all defined symbols into the dynamic
|
/* This routine is used to export all defined symbols into the dynamic
|
symbol table. It is called via elf_link_hash_traverse. */
|
symbol table. It is called via elf_link_hash_traverse. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
|
_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct elf_info_failed *eif = data;
|
struct elf_info_failed *eif = (struct elf_info_failed *) data;
|
|
|
/* Ignore this if we won't export it. */
|
/* Ignore this if we won't export it. */
|
if (!eif->info->export_dynamic && !h->dynamic)
|
if (!eif->info->export_dynamic && !h->dynamic)
|
return TRUE;
|
return TRUE;
|
|
|
Line 1714... |
Line 1824... |
|
|
if (h->dynindx == -1
|
if (h->dynindx == -1
|
&& (h->def_regular
|
&& (h->def_regular
|
|| h->ref_regular))
|
|| h->ref_regular))
|
{
|
{
|
struct bfd_elf_version_tree *t;
|
bfd_boolean hide;
|
struct bfd_elf_version_expr *d;
|
|
|
|
for (t = eif->verdefs; t != NULL; t = t->next)
|
if (eif->verdefs == NULL
|
{
|
|| (bfd_find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
|
if (t->globals.list != NULL)
|
&& !hide))
|
{
|
{
|
d = (*t->match) (&t->globals, NULL, h->root.root.string);
|
|
if (d != NULL)
|
|
goto doit;
|
|
}
|
|
|
|
if (t->locals.list != NULL)
|
|
{
|
|
d = (*t->match) (&t->locals, NULL, h->root.root.string);
|
|
if (d != NULL)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (!eif->verdefs)
|
|
{
|
|
doit:
|
|
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
|
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
|
{
|
{
|
eif->failed = TRUE;
|
eif->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 1753... |
Line 1846... |
/* Look through the symbols which are defined in other shared
|
/* Look through the symbols which are defined in other shared
|
libraries and referenced here. Update the list of version
|
libraries and referenced here. Update the list of version
|
dependencies. This will be put into the .gnu.version_r section.
|
dependencies. This will be put into the .gnu.version_r section.
|
This function is called via elf_link_hash_traverse. */
|
This function is called via elf_link_hash_traverse. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
|
_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
|
void *data)
|
void *data)
|
{
|
{
|
struct elf_find_verdep_info *rinfo = data;
|
struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data;
|
Elf_Internal_Verneed *t;
|
Elf_Internal_Verneed *t;
|
Elf_Internal_Vernaux *a;
|
Elf_Internal_Vernaux *a;
|
bfd_size_type amt;
|
bfd_size_type amt;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (h->root.type == bfd_link_hash_warning)
|
Line 1774... |
Line 1867... |
|| h->dynindx == -1
|
|| h->dynindx == -1
|
|| h->verinfo.verdef == NULL)
|
|| h->verinfo.verdef == NULL)
|
return TRUE;
|
return TRUE;
|
|
|
/* See if we already know about this version. */
|
/* See if we already know about this version. */
|
for (t = elf_tdata (rinfo->output_bfd)->verref; t != NULL; t = t->vn_nextref)
|
for (t = elf_tdata (rinfo->info->output_bfd)->verref;
|
|
t != NULL;
|
|
t = t->vn_nextref)
|
{
|
{
|
if (t->vn_bfd != h->verinfo.verdef->vd_bfd)
|
if (t->vn_bfd != h->verinfo.verdef->vd_bfd)
|
continue;
|
continue;
|
|
|
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
|
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
|
Line 1791... |
Line 1886... |
/* This is a new version. Add it to tree we are building. */
|
/* This is a new version. Add it to tree we are building. */
|
|
|
if (t == NULL)
|
if (t == NULL)
|
{
|
{
|
amt = sizeof *t;
|
amt = sizeof *t;
|
t = bfd_zalloc (rinfo->output_bfd, amt);
|
t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->output_bfd, amt);
|
if (t == NULL)
|
if (t == NULL)
|
{
|
{
|
rinfo->failed = TRUE;
|
rinfo->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
t->vn_bfd = h->verinfo.verdef->vd_bfd;
|
t->vn_bfd = h->verinfo.verdef->vd_bfd;
|
t->vn_nextref = elf_tdata (rinfo->output_bfd)->verref;
|
t->vn_nextref = elf_tdata (rinfo->info->output_bfd)->verref;
|
elf_tdata (rinfo->output_bfd)->verref = t;
|
elf_tdata (rinfo->info->output_bfd)->verref = t;
|
}
|
}
|
|
|
amt = sizeof *a;
|
amt = sizeof *a;
|
a = bfd_zalloc (rinfo->output_bfd, amt);
|
a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt);
|
if (a == NULL)
|
if (a == NULL)
|
{
|
{
|
rinfo->failed = TRUE;
|
rinfo->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 1835... |
Line 1930... |
/* Figure out appropriate versions for all the symbols. We may not
|
/* Figure out appropriate versions for all the symbols. We may not
|
have the version number script until we have read all of the input
|
have the version number script until we have read all of the input
|
files, so until that point we don't know which symbols should be
|
files, so until that point we don't know which symbols should be
|
local. This function is called via elf_link_hash_traverse. */
|
local. This function is called via elf_link_hash_traverse. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
|
_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct elf_assign_sym_version_info *sinfo;
|
struct elf_info_failed *sinfo;
|
struct bfd_link_info *info;
|
struct bfd_link_info *info;
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
struct elf_info_failed eif;
|
struct elf_info_failed eif;
|
char *p;
|
char *p;
|
bfd_size_type amt;
|
bfd_size_type amt;
|
|
|
sinfo = data;
|
sinfo = (struct elf_info_failed *) data;
|
info = sinfo->info;
|
info = sinfo->info;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
|
|
Line 1866... |
Line 1961... |
/* We only need version numbers for symbols defined in regular
|
/* We only need version numbers for symbols defined in regular
|
objects. */
|
objects. */
|
if (!h->def_regular)
|
if (!h->def_regular)
|
return TRUE;
|
return TRUE;
|
|
|
bed = get_elf_backend_data (sinfo->output_bfd);
|
bed = get_elf_backend_data (info->output_bfd);
|
p = strchr (h->root.root.string, ELF_VER_CHR);
|
p = strchr (h->root.root.string, ELF_VER_CHR);
|
if (p != NULL && h->verinfo.vertree == NULL)
|
if (p != NULL && h->verinfo.vertree == NULL)
|
{
|
{
|
struct bfd_elf_version_tree *t;
|
struct bfd_elf_version_tree *t;
|
bfd_boolean hidden;
|
bfd_boolean hidden;
|
Line 1902... |
Line 1997... |
size_t len;
|
size_t len;
|
char *alc;
|
char *alc;
|
struct bfd_elf_version_expr *d;
|
struct bfd_elf_version_expr *d;
|
|
|
len = p - h->root.root.string;
|
len = p - h->root.root.string;
|
alc = bfd_malloc (len);
|
alc = (char *) bfd_malloc (len);
|
if (alc == NULL)
|
if (alc == NULL)
|
{
|
{
|
sinfo->failed = TRUE;
|
sinfo->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 1949... |
Line 2044... |
to worry about it. */
|
to worry about it. */
|
if (h->dynindx == -1)
|
if (h->dynindx == -1)
|
return TRUE;
|
return TRUE;
|
|
|
amt = sizeof *t;
|
amt = sizeof *t;
|
t = bfd_zalloc (sinfo->output_bfd, amt);
|
t = (struct bfd_elf_version_tree *) bfd_zalloc (info->output_bfd, amt);
|
if (t == NULL)
|
if (t == NULL)
|
{
|
{
|
sinfo->failed = TRUE;
|
sinfo->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 1978... |
Line 2073... |
{
|
{
|
/* We could not find the version for a symbol when
|
/* We could not find the version for a symbol when
|
generating a shared archive. Return an error. */
|
generating a shared archive. Return an error. */
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B: version node not found for symbol %s"),
|
(_("%B: version node not found for symbol %s"),
|
sinfo->output_bfd, h->root.root.string);
|
info->output_bfd, h->root.root.string);
|
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
sinfo->failed = TRUE;
|
sinfo->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
Line 1992... |
Line 2087... |
|
|
/* If we don't have a version for this symbol, see if we can find
|
/* If we don't have a version for this symbol, see if we can find
|
something. */
|
something. */
|
if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
|
if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
|
{
|
{
|
struct bfd_elf_version_tree *t;
|
bfd_boolean hide;
|
struct bfd_elf_version_tree *local_ver;
|
|
struct bfd_elf_version_expr *d;
|
|
|
|
/* See if can find what version this symbol is in. If the
|
|
symbol is supposed to be local, then don't actually register
|
|
it. */
|
|
local_ver = NULL;
|
|
for (t = sinfo->verdefs; t != NULL; t = t->next)
|
|
{
|
|
if (t->globals.list != NULL)
|
|
{
|
|
bfd_boolean matched;
|
|
|
|
matched = FALSE;
|
h->verinfo.vertree = bfd_find_version_for_sym (sinfo->verdefs,
|
d = NULL;
|
h->root.root.string, &hide);
|
while ((d = (*t->match) (&t->globals, d,
|
if (h->verinfo.vertree != NULL && hide)
|
h->root.root.string)) != NULL)
|
|
if (d->symver)
|
|
matched = TRUE;
|
|
else
|
|
{
|
|
/* There is a version without definition. Make
|
|
the symbol the default definition for this
|
|
version. */
|
|
h->verinfo.vertree = t;
|
|
local_ver = NULL;
|
|
d->script = 1;
|
|
break;
|
|
}
|
|
if (d != NULL)
|
|
break;
|
|
else if (matched)
|
|
/* There is no undefined version for this symbol. Hide the
|
|
default one. */
|
|
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
|
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
|
}
|
}
|
|
|
if (t->locals.list != NULL)
|
|
{
|
|
d = NULL;
|
|
while ((d = (*t->match) (&t->locals, d,
|
|
h->root.root.string)) != NULL)
|
|
{
|
|
local_ver = t;
|
|
/* If the match is "*", keep looking for a more
|
|
explicit, perhaps even global, match.
|
|
XXX: Shouldn't this be !d->wildcard instead? */
|
|
if (d->pattern[0] != '*' || d->pattern[1] != '\0')
|
|
break;
|
|
}
|
|
|
|
if (d != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (local_ver != NULL)
|
|
{
|
|
h->verinfo.vertree = local_ver;
|
|
if (h->dynindx != -1
|
|
&& ! info->export_dynamic)
|
|
{
|
|
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Read and swap the relocs from the section indicated by SHDR. This
|
/* Read and swap the relocs from the section indicated by SHDR. This
|
may be either a REL or a RELA section. The relocations are
|
may be either a REL or a RELA section. The relocations are
|
Line 2096... |
Line 2131... |
/* Read the relocations. */
|
/* Read the relocations. */
|
if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
|
if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
|
return FALSE;
|
return FALSE;
|
|
|
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
nsyms = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
nsyms = NUM_SHDR_ENTRIES (symtab_hdr);
|
|
|
bed = get_elf_backend_data (abfd);
|
bed = get_elf_backend_data (abfd);
|
|
|
/* Convert the external relocations to the internal format. */
|
/* Convert the external relocations to the internal format. */
|
if (shdr->sh_entsize == bed->s->sizeof_rel)
|
if (shdr->sh_entsize == bed->s->sizeof_rel)
|
Line 2111... |
Line 2146... |
{
|
{
|
bfd_set_error (bfd_error_wrong_format);
|
bfd_set_error (bfd_error_wrong_format);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
erela = external_relocs;
|
erela = (const bfd_byte *) external_relocs;
|
erelaend = erela + shdr->sh_size;
|
erelaend = erela + shdr->sh_size;
|
irela = internal_relocs;
|
irela = internal_relocs;
|
while (erela < erelaend)
|
while (erela < erelaend)
|
{
|
{
|
bfd_vma r_symndx;
|
bfd_vma r_symndx;
|
|
|
(*swap_in) (abfd, erela, irela);
|
(*swap_in) (abfd, erela, irela);
|
r_symndx = ELF32_R_SYM (irela->r_info);
|
r_symndx = ELF32_R_SYM (irela->r_info);
|
if (bed->s->arch_size == 64)
|
if (bed->s->arch_size == 64)
|
r_symndx >>= 24;
|
r_symndx >>= 24;
|
|
if (nsyms > 0)
|
|
{
|
if ((size_t) r_symndx >= nsyms)
|
if ((size_t) r_symndx >= nsyms)
|
{
|
{
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
|
(_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
|
" for offset 0x%lx in section `%A'"),
|
" for offset 0x%lx in section `%A'"),
|
abfd, sec,
|
abfd, sec,
|
(unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
|
(unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
|
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
}
|
|
else if (r_symndx != 0)
|
|
{
|
|
(*_bfd_error_handler)
|
|
(_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'"
|
|
" when the object file has no symbol table"),
|
|
abfd, sec,
|
|
(unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
|
|
bfd_set_error (bfd_error_bad_value);
|
|
return FALSE;
|
|
}
|
irela += bed->s->int_rels_per_ext_rel;
|
irela += bed->s->int_rels_per_ext_rel;
|
erela += shdr->sh_entsize;
|
erela += shdr->sh_entsize;
|
}
|
}
|
|
|
return TRUE;
|
return TRUE;
|
Line 2176... |
Line 2224... |
bfd_size_type size;
|
bfd_size_type size;
|
|
|
size = o->reloc_count;
|
size = o->reloc_count;
|
size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
|
size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
|
if (keep_memory)
|
if (keep_memory)
|
internal_relocs = bfd_alloc (abfd, size);
|
internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
|
else
|
else
|
internal_relocs = alloc2 = bfd_malloc (size);
|
internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size);
|
if (internal_relocs == NULL)
|
if (internal_relocs == NULL)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
if (external_relocs == NULL)
|
if (external_relocs == NULL)
|
Line 2224... |
Line 2272... |
|
|
error_return:
|
error_return:
|
if (alloc1 != NULL)
|
if (alloc1 != NULL)
|
free (alloc1);
|
free (alloc1);
|
if (alloc2 != NULL)
|
if (alloc2 != NULL)
|
|
{
|
|
if (keep_memory)
|
|
bfd_release (abfd, alloc2);
|
|
else
|
free (alloc2);
|
free (alloc2);
|
|
}
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Compute the size of, and allocate space for, REL_HDR which is the
|
/* Compute the size of, and allocate space for, REL_HDR which is the
|
section header for a section containing relocations for O. */
|
section header for a section containing relocations for O. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_link_size_reloc_section (bfd *abfd,
|
_bfd_elf_link_size_reloc_section (bfd *abfd,
|
Elf_Internal_Shdr *rel_hdr,
|
Elf_Internal_Shdr *rel_hdr,
|
asection *o)
|
asection *o)
|
{
|
{
|
bfd_size_type reloc_count;
|
bfd_size_type reloc_count;
|
Line 2256... |
Line 2309... |
|
|
/* The contents field must last into write_object_contents, so we
|
/* The contents field must last into write_object_contents, so we
|
allocate it with bfd_alloc rather than malloc. Also since we
|
allocate it with bfd_alloc rather than malloc. Also since we
|
cannot be sure that the contents will actually be filled in,
|
cannot be sure that the contents will actually be filled in,
|
we zero the allocated space. */
|
we zero the allocated space. */
|
rel_hdr->contents = bfd_zalloc (abfd, rel_hdr->sh_size);
|
rel_hdr->contents = (unsigned char *) bfd_zalloc (abfd, rel_hdr->sh_size);
|
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
|
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
|
return FALSE;
|
return FALSE;
|
|
|
/* We only allocate one set of hash entries, so we only do it the
|
/* We only allocate one set of hash entries, so we only do it the
|
first time we are called. */
|
first time we are called. */
|
if (elf_section_data (o)->rel_hashes == NULL
|
if (elf_section_data (o)->rel_hashes == NULL
|
&& num_rel_hashes)
|
&& num_rel_hashes)
|
{
|
{
|
struct elf_link_hash_entry **p;
|
struct elf_link_hash_entry **p;
|
|
|
p = bfd_zmalloc (num_rel_hashes * sizeof (struct elf_link_hash_entry *));
|
p = (struct elf_link_hash_entry **)
|
|
bfd_zmalloc (num_rel_hashes * sizeof (struct elf_link_hash_entry *));
|
if (p == NULL)
|
if (p == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
elf_section_data (o)->rel_hashes = p;
|
elf_section_data (o)->rel_hashes = p;
|
}
|
}
|
Line 2370... |
Line 2424... |
can only be fixed after all the input files are seen. This is
|
can only be fixed after all the input files are seen. This is
|
currently called by both adjust_dynamic_symbol and
|
currently called by both adjust_dynamic_symbol and
|
assign_sym_version, which is unnecessary but perhaps more robust in
|
assign_sym_version, which is unnecessary but perhaps more robust in
|
the face of future changes. */
|
the face of future changes. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
|
_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
|
struct elf_info_failed *eif)
|
struct elf_info_failed *eif)
|
{
|
{
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
|
|
Line 2513... |
Line 2567... |
|
|
/* Make the backend pick a good value for a dynamic symbol. This is
|
/* Make the backend pick a good value for a dynamic symbol. This is
|
called via elf_link_hash_traverse, and also calls itself
|
called via elf_link_hash_traverse, and also calls itself
|
recursively. */
|
recursively. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
|
_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct elf_info_failed *eif = data;
|
struct elf_info_failed *eif = (struct elf_info_failed *) data;
|
bfd *dynobj;
|
bfd *dynobj;
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
|
|
if (! is_elf_hash_table (eif->info->hash))
|
if (! is_elf_hash_table (eif->info->hash))
|
return FALSE;
|
return FALSE;
|
Line 2550... |
Line 2604... |
even if no regular object refers to it, if we decided to add it
|
even if no regular object refers to it, if we decided to add it
|
to the dynamic symbol table. FIXME: Do we normally need to worry
|
to the dynamic symbol table. FIXME: Do we normally need to worry
|
about symbols which are defined by one dynamic object and
|
about symbols which are defined by one dynamic object and
|
referenced by another one? */
|
referenced by another one? */
|
if (!h->needs_plt
|
if (!h->needs_plt
|
|
&& h->type != STT_GNU_IFUNC
|
&& (h->def_regular
|
&& (h->def_regular
|
|| !h->def_dynamic
|
|| !h->def_dynamic
|
|| (!h->ref_regular
|
|| (!h->ref_regular
|
&& (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1))))
|
&& (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1))))
|
{
|
{
|
Line 2624... |
Line 2679... |
(_("warning: type and size of dynamic symbol `%s' are not defined"),
|
(_("warning: type and size of dynamic symbol `%s' are not defined"),
|
h->root.root.string);
|
h->root.root.string);
|
|
|
dynobj = elf_hash_table (eif->info)->dynobj;
|
dynobj = elf_hash_table (eif->info)->dynobj;
|
bed = get_elf_backend_data (dynobj);
|
bed = get_elf_backend_data (dynobj);
|
|
|
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
|
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
|
{
|
{
|
eif->failed = TRUE;
|
eif->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 2682... |
Line 2738... |
}
|
}
|
|
|
/* Adjust all external symbols pointing into SEC_MERGE sections
|
/* Adjust all external symbols pointing into SEC_MERGE sections
|
to reflect the object merging within the sections. */
|
to reflect the object merging within the sections. */
|
|
|
bfd_boolean
|
static bfd_boolean
|
_bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data)
|
_bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
asection *sec;
|
asection *sec;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (h->root.type == bfd_link_hash_warning)
|
Line 2695... |
Line 2751... |
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)->flags & SEC_MERGE)
|
&& ((sec = h->root.u.def.section)->flags & SEC_MERGE)
|
&& sec->sec_info_type == ELF_INFO_TYPE_MERGE)
|
&& sec->sec_info_type == ELF_INFO_TYPE_MERGE)
|
{
|
{
|
bfd *output_bfd = data;
|
bfd *output_bfd = (bfd *) data;
|
|
|
h->root.u.def.value =
|
h->root.u.def.value =
|
_bfd_merged_section_offset (output_bfd,
|
_bfd_merged_section_offset (output_bfd,
|
&h->root.u.def.section,
|
&h->root.u.def.section,
|
elf_section_data (sec)->sec_info,
|
elf_section_data (sec)->sec_info,
|
Line 2787... |
Line 2843... |
|
|
/* If it's a local sym, of course we resolve locally. */
|
/* If it's a local sym, of course we resolve locally. */
|
if (h == NULL)
|
if (h == NULL)
|
return TRUE;
|
return TRUE;
|
|
|
|
/* STV_HIDDEN or STV_INTERNAL ones must be local. */
|
|
if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
|
|
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
|
|
return TRUE;
|
|
|
/* Common symbols that become definitions don't get the DEF_REGULAR
|
/* Common symbols that become definitions don't get the DEF_REGULAR
|
flag set, so test it first, and don't bail out. */
|
flag set, so test it first, and don't bail out. */
|
if (ELF_COMMON_DEF_P (h))
|
if (ELF_COMMON_DEF_P (h))
|
/* Do nothing. */;
|
/* Do nothing. */;
|
/* If we don't have a definition in a regular file, then we can't
|
/* If we don't have a definition in a regular file, then we can't
|
Line 2815... |
Line 2876... |
/* Now deal with defined dynamic symbols in shared libraries. Ones
|
/* Now deal with defined dynamic symbols in shared libraries. Ones
|
with default visibility might not resolve locally. */
|
with default visibility might not resolve locally. */
|
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
|
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
|
return FALSE;
|
return FALSE;
|
|
|
/* However, STV_HIDDEN or STV_INTERNAL ones must be local. */
|
|
if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED)
|
|
return TRUE;
|
|
|
|
hash_table = elf_hash_table (info);
|
hash_table = elf_hash_table (info);
|
if (!is_elf_hash_table (hash_table))
|
if (!is_elf_hash_table (hash_table))
|
return TRUE;
|
return TRUE;
|
|
|
bed = get_elf_backend_data (hash_table->dynobj);
|
bed = get_elf_backend_data (hash_table->dynobj);
|
Line 3009... |
Line 3066... |
bed = get_elf_backend_data (hash_table->dynobj);
|
bed = get_elf_backend_data (hash_table->dynobj);
|
s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
|
s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
|
BFD_ASSERT (s != NULL);
|
BFD_ASSERT (s != NULL);
|
|
|
newsize = s->size + bed->s->sizeof_dyn;
|
newsize = s->size + bed->s->sizeof_dyn;
|
newcontents = bfd_realloc (s->contents, newsize);
|
newcontents = (bfd_byte *) bfd_realloc (s->contents, newsize);
|
if (newcontents == NULL)
|
if (newcontents == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
dyn.d_tag = tag;
|
dyn.d_tag = tag;
|
dyn.d_un.d_val = val;
|
dyn.d_un.d_val = val;
|
Line 3086... |
Line 3143... |
_bfd_elf_strtab_delref (hash_table->dynstr, strindex);
|
_bfd_elf_strtab_delref (hash_table->dynstr, strindex);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
static bfd_boolean
|
|
on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
|
|
{
|
|
for (; needed != NULL; needed = needed->next)
|
|
if (strcmp (soname, needed->name) == 0)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
/* Sort symbol by value and section. */
|
/* Sort symbol by value and section. */
|
static int
|
static int
|
elf_sort_symbol (const void *arg1, const void *arg2)
|
elf_sort_symbol (const void *arg1, const void *arg2)
|
{
|
{
|
const struct elf_link_hash_entry *h1;
|
const struct elf_link_hash_entry *h1;
|
Line 3114... |
Line 3181... |
dynamic symbols. This is called via elf_link_hash_traverse. */
|
dynamic symbols. This is called via elf_link_hash_traverse. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
|
elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct elf_strtab_hash *dynstr = data;
|
struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
|
|
if (h->dynindx != -1)
|
if (h->dynindx != -1)
|
Line 3289... |
Line 3356... |
/* Add symbols from an ELF object file to the linker hash table. */
|
/* Add symbols from an ELF object file to the linker hash table. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
|
elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
|
{
|
{
|
|
Elf_Internal_Ehdr *ehdr;
|
Elf_Internal_Shdr *hdr;
|
Elf_Internal_Shdr *hdr;
|
bfd_size_type symcount;
|
bfd_size_type symcount;
|
bfd_size_type extsymcount;
|
bfd_size_type extsymcount;
|
bfd_size_type extsymoff;
|
bfd_size_type extsymoff;
|
struct elf_link_hash_entry **sym_hash;
|
struct elf_link_hash_entry **sym_hash;
|
Line 3344... |
Line 3412... |
bfd_set_error (bfd_error_wrong_format);
|
bfd_set_error (bfd_error_wrong_format);
|
goto error_return;
|
goto error_return;
|
}
|
}
|
}
|
}
|
|
|
|
ehdr = elf_elfheader (abfd);
|
|
if (info->warn_alternate_em
|
|
&& bed->elf_machine_code != ehdr->e_machine
|
|
&& ((bed->elf_machine_alt1 != 0
|
|
&& ehdr->e_machine == bed->elf_machine_alt1)
|
|
|| (bed->elf_machine_alt2 != 0
|
|
&& ehdr->e_machine == bed->elf_machine_alt2)))
|
|
info->callbacks->einfo
|
|
(_("%P: alternate ELF machine code found (%d) in %B, expecting %d\n"),
|
|
ehdr->e_machine, abfd, bed->elf_machine_code);
|
|
|
/* As a GNU extension, any input sections which are named
|
/* As a GNU extension, any input sections which are named
|
.gnu.warning.SYMBOL are treated as warning symbols for the given
|
.gnu.warning.SYMBOL are treated as warning symbols for the given
|
symbol. This differs from .gnu.warning sections, which generate
|
symbol. This differs from .gnu.warning sections, which generate
|
warnings when they are included in an output file. */
|
warnings when they are included in an output file. */
|
if (info->executable)
|
if (info->executable)
|
Line 3393... |
Line 3472... |
continue;
|
continue;
|
}
|
}
|
}
|
}
|
|
|
sz = s->size;
|
sz = s->size;
|
msg = bfd_alloc (abfd, sz + 1);
|
msg = (char *) bfd_alloc (abfd, sz + 1);
|
if (msg == NULL)
|
if (msg == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
if (! bfd_get_section_contents (abfd, s, msg, 0, sz))
|
if (! bfd_get_section_contents (abfd, s, msg, 0, sz))
|
goto error_return;
|
goto error_return;
|
Line 3469... |
Line 3548... |
s = bfd_get_section_by_name (abfd, ".dynamic");
|
s = bfd_get_section_by_name (abfd, ".dynamic");
|
if (s != NULL)
|
if (s != NULL)
|
{
|
{
|
bfd_byte *dynbuf;
|
bfd_byte *dynbuf;
|
bfd_byte *extdyn;
|
bfd_byte *extdyn;
|
int elfsec;
|
unsigned int elfsec;
|
unsigned long shlink;
|
unsigned long shlink;
|
|
|
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
|
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
|
goto error_free_dyn;
|
{
|
|
error_free_dyn:
|
|
free (dynbuf);
|
|
goto error_return;
|
|
}
|
|
|
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
|
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
|
if (elfsec == -1)
|
if (elfsec == SHN_BAD)
|
goto error_free_dyn;
|
goto error_free_dyn;
|
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
|
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
|
|
|
for (extdyn = dynbuf;
|
for (extdyn = dynbuf;
|
extdyn < dynbuf + s->size;
|
extdyn < dynbuf + s->size;
|
Line 3501... |
Line 3584... |
struct bfd_link_needed_list *n, **pn;
|
struct bfd_link_needed_list *n, **pn;
|
char *fnm, *anm;
|
char *fnm, *anm;
|
unsigned int tagv = dyn.d_un.d_val;
|
unsigned int tagv = dyn.d_un.d_val;
|
|
|
amt = sizeof (struct bfd_link_needed_list);
|
amt = sizeof (struct bfd_link_needed_list);
|
n = bfd_alloc (abfd, amt);
|
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
|
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
if (n == NULL || fnm == NULL)
|
if (n == NULL || fnm == NULL)
|
goto error_free_dyn;
|
goto error_free_dyn;
|
amt = strlen (fnm) + 1;
|
amt = strlen (fnm) + 1;
|
anm = bfd_alloc (abfd, amt);
|
anm = (char *) bfd_alloc (abfd, amt);
|
if (anm == NULL)
|
if (anm == NULL)
|
goto error_free_dyn;
|
goto error_free_dyn;
|
memcpy (anm, fnm, amt);
|
memcpy (anm, fnm, amt);
|
n->name = anm;
|
n->name = anm;
|
n->by = abfd;
|
n->by = abfd;
|
Line 3524... |
Line 3607... |
struct bfd_link_needed_list *n, **pn;
|
struct bfd_link_needed_list *n, **pn;
|
char *fnm, *anm;
|
char *fnm, *anm;
|
unsigned int tagv = dyn.d_un.d_val;
|
unsigned int tagv = dyn.d_un.d_val;
|
|
|
amt = sizeof (struct bfd_link_needed_list);
|
amt = sizeof (struct bfd_link_needed_list);
|
n = bfd_alloc (abfd, amt);
|
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
|
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
if (n == NULL || fnm == NULL)
|
if (n == NULL || fnm == NULL)
|
goto error_free_dyn;
|
goto error_free_dyn;
|
amt = strlen (fnm) + 1;
|
amt = strlen (fnm) + 1;
|
anm = bfd_alloc (abfd, amt);
|
anm = (char *) bfd_alloc (abfd, amt);
|
if (anm == NULL)
|
if (anm == NULL)
|
goto error_free_dyn;
|
goto error_free_dyn;
|
memcpy (anm, fnm, amt);
|
memcpy (anm, fnm, amt);
|
n->name = anm;
|
n->name = anm;
|
n->by = abfd;
|
n->by = abfd;
|
Line 3550... |
Line 3633... |
struct bfd_link_needed_list *n, **pn;
|
struct bfd_link_needed_list *n, **pn;
|
char *fnm, *anm;
|
char *fnm, *anm;
|
unsigned int tagv = dyn.d_un.d_val;
|
unsigned int tagv = dyn.d_un.d_val;
|
|
|
amt = sizeof (struct bfd_link_needed_list);
|
amt = sizeof (struct bfd_link_needed_list);
|
n = bfd_alloc (abfd, amt);
|
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
|
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
if (n == NULL || fnm == NULL)
|
if (n == NULL || fnm == NULL)
|
goto error_free_dyn;
|
goto error_free_dyn;
|
amt = strlen (fnm) + 1;
|
amt = strlen (fnm) + 1;
|
anm = bfd_alloc (abfd, amt);
|
anm = (char *) bfd_alloc (abfd, amt);
|
if (anm == NULL)
|
if (anm == NULL)
|
{
|
goto error_free_dyn;
|
error_free_dyn:
|
|
free (dynbuf);
|
|
goto error_return;
|
|
}
|
|
memcpy (anm, fnm, amt);
|
memcpy (anm, fnm, amt);
|
n->name = anm;
|
n->name = anm;
|
n->by = abfd;
|
n->by = abfd;
|
n->next = NULL;
|
n->next = NULL;
|
for (pn = & rpath;
|
for (pn = & rpath;
|
Line 3663... |
Line 3742... |
goto error_return;
|
goto error_return;
|
|
|
/* We store a pointer to the hash table entry for each external
|
/* We store a pointer to the hash table entry for each external
|
symbol. */
|
symbol. */
|
amt = extsymcount * sizeof (struct elf_link_hash_entry *);
|
amt = extsymcount * sizeof (struct elf_link_hash_entry *);
|
sym_hash = bfd_alloc (abfd, amt);
|
sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
|
if (sym_hash == NULL)
|
if (sym_hash == NULL)
|
goto error_free_sym;
|
goto error_free_sym;
|
elf_sym_hashes (abfd) = sym_hash;
|
elf_sym_hashes (abfd) = sym_hash;
|
}
|
}
|
|
|
Line 3683... |
Line 3762... |
if (elf_dynversym (abfd) != 0)
|
if (elf_dynversym (abfd) != 0)
|
{
|
{
|
Elf_Internal_Shdr *versymhdr;
|
Elf_Internal_Shdr *versymhdr;
|
|
|
versymhdr = &elf_tdata (abfd)->dynversym_hdr;
|
versymhdr = &elf_tdata (abfd)->dynversym_hdr;
|
extversym = bfd_malloc (versymhdr->sh_size);
|
extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
|
if (extversym == NULL)
|
if (extversym == NULL)
|
goto error_free_sym;
|
goto error_free_sym;
|
amt = versymhdr->sh_size;
|
amt = versymhdr->sh_size;
|
if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
|
if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
|
|| bfd_bread (extversym, amt, abfd) != amt)
|
|| bfd_bread (extversym, amt, abfd) != amt)
|
Line 3795... |
Line 3874... |
value = isym->st_value;
|
value = isym->st_value;
|
*sym_hash = NULL;
|
*sym_hash = NULL;
|
common = bed->common_definition (isym);
|
common = bed->common_definition (isym);
|
|
|
bind = ELF_ST_BIND (isym->st_info);
|
bind = ELF_ST_BIND (isym->st_info);
|
if (bind == STB_LOCAL)
|
switch (bind)
|
{
|
{
|
|
case STB_LOCAL:
|
/* This should be impossible, since ELF requires that all
|
/* This should be impossible, since ELF requires that all
|
global symbols follow all local symbols, and that sh_info
|
global symbols follow all local symbols, and that sh_info
|
point to the first global symbol. Unfortunately, Irix 5
|
point to the first global symbol. Unfortunately, Irix 5
|
screws this up. */
|
screws this up. */
|
continue;
|
continue;
|
}
|
|
else if (bind == STB_GLOBAL)
|
case STB_GLOBAL:
|
{
|
|
if (isym->st_shndx != SHN_UNDEF && !common)
|
if (isym->st_shndx != SHN_UNDEF && !common)
|
flags = BSF_GLOBAL;
|
flags = BSF_GLOBAL;
|
}
|
break;
|
else if (bind == STB_WEAK)
|
|
|
case STB_WEAK:
|
flags = BSF_WEAK;
|
flags = BSF_WEAK;
|
else
|
break;
|
{
|
|
|
case STB_GNU_UNIQUE:
|
|
flags = BSF_GNU_UNIQUE;
|
|
break;
|
|
|
|
default:
|
/* Leave it up to the processor backend. */
|
/* Leave it up to the processor backend. */
|
|
break;
|
}
|
}
|
|
|
if (isym->st_shndx == SHN_UNDEF)
|
if (isym->st_shndx == SHN_UNDEF)
|
sec = bfd_und_section_ptr;
|
sec = bfd_und_section_ptr;
|
else if (isym->st_shndx < SHN_LORESERVE
|
else if (isym->st_shndx == SHN_ABS)
|
|| isym->st_shndx > SHN_HIRESERVE)
|
sec = bfd_abs_section_ptr;
|
|
else if (isym->st_shndx == SHN_COMMON)
|
|
{
|
|
sec = bfd_com_section_ptr;
|
|
/* What ELF calls the size we call the value. What ELF
|
|
calls the value we call the alignment. */
|
|
value = isym->st_size;
|
|
}
|
|
else
|
{
|
{
|
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
if (sec == NULL)
|
if (sec == NULL)
|
sec = bfd_abs_section_ptr;
|
sec = bfd_abs_section_ptr;
|
else if (sec->kept_section)
|
else if (sec->kept_section)
|
Line 3833... |
Line 3927... |
isym->st_shndx = SHN_UNDEF;
|
isym->st_shndx = SHN_UNDEF;
|
}
|
}
|
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
|
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
|
value -= sec->vma;
|
value -= sec->vma;
|
}
|
}
|
else if (isym->st_shndx == SHN_ABS)
|
|
sec = bfd_abs_section_ptr;
|
|
else if (isym->st_shndx == SHN_COMMON)
|
|
{
|
|
sec = bfd_com_section_ptr;
|
|
/* What ELF calls the size we call the value. What ELF
|
|
calls the value we call the alignment. */
|
|
value = isym->st_size;
|
|
}
|
|
else
|
|
{
|
|
/* Leave it up to the processor backend. */
|
|
}
|
|
|
|
name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
|
name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
|
isym->st_name);
|
isym->st_name);
|
if (name == NULL)
|
if (name == NULL)
|
goto error_free_vers;
|
goto error_free_vers;
|
Line 3997... |
Line 4078... |
newlen = namelen + verlen + 2;
|
newlen = namelen + verlen + 2;
|
if ((iver.vs_vers & VERSYM_HIDDEN) == 0
|
if ((iver.vs_vers & VERSYM_HIDDEN) == 0
|
&& isym->st_shndx != SHN_UNDEF)
|
&& isym->st_shndx != SHN_UNDEF)
|
++newlen;
|
++newlen;
|
|
|
newname = bfd_hash_allocate (&htab->root.table, newlen);
|
newname = (char *) bfd_hash_allocate (&htab->root.table, newlen);
|
if (newname == NULL)
|
if (newname == NULL)
|
goto error_free_vers;
|
goto error_free_vers;
|
memcpy (newname, name, namelen);
|
memcpy (newname, name, namelen);
|
p = newname + namelen;
|
p = newname + namelen;
|
*p++ = ELF_VER_CHR;
|
*p++ = ELF_VER_CHR;
|
Line 4069... |
Line 4150... |
|
|
h = *sym_hash;
|
h = *sym_hash;
|
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;
|
|
|
*sym_hash = h;
|
*sym_hash = h;
|
|
h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
|
|
|
new_weakdef = FALSE;
|
new_weakdef = FALSE;
|
if (dynamic
|
if (dynamic
|
&& definition
|
&& definition
|
&& (flags & BSF_WEAK) != 0
|
&& (flags & BSF_WEAK) != 0
|
Line 4208... |
Line 4291... |
h->size = h->root.u.c.size;
|
h->size = h->root.u.c.size;
|
|
|
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
|
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
|
&& (definition || h->type == STT_NOTYPE))
|
&& (definition || h->type == STT_NOTYPE))
|
{
|
{
|
if (h->type != STT_NOTYPE
|
unsigned int type = ELF_ST_TYPE (isym->st_info);
|
&& h->type != ELF_ST_TYPE (isym->st_info)
|
|
&& ! type_change_ok)
|
/* Turn an IFUNC symbol from a DSO into a normal FUNC
|
|
symbol. */
|
|
if (type == STT_GNU_IFUNC
|
|
&& (abfd->flags & DYNAMIC) != 0)
|
|
type = STT_FUNC;
|
|
|
|
if (h->type != type)
|
|
{
|
|
if (h->type != STT_NOTYPE && ! type_change_ok)
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("Warning: type of symbol `%s' changed"
|
(_("Warning: type of symbol `%s' changed"
|
" from %d to %d in %B"),
|
" from %d to %d in %B"),
|
abfd, name, h->type, ELF_ST_TYPE (isym->st_info));
|
abfd, name, h->type, type);
|
|
|
h->type = ELF_ST_TYPE (isym->st_info);
|
h->type = type;
|
}
|
}
|
|
|
/* If st_other has a processor-specific meaning, specific
|
|
code might be needed here. We never merge the visibility
|
|
attribute with the one from a dynamic object. */
|
|
if (bed->elf_backend_merge_symbol_attribute)
|
|
(*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
|
|
dynamic);
|
|
|
|
/* If this symbol has default visibility and the user has requested
|
|
we not re-export it, then mark it as hidden. */
|
|
if (definition && !dynamic
|
|
&& (abfd->no_export
|
|
|| (abfd->my_archive && abfd->my_archive->no_export))
|
|
&& ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
|
|
isym->st_other = (STV_HIDDEN
|
|
| (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
|
|
|
|
if (ELF_ST_VISIBILITY (isym->st_other) != 0 && !dynamic)
|
|
{
|
|
unsigned char hvis, symvis, other, nvis;
|
|
|
|
/* Only merge the visibility. Leave the remainder of the
|
|
st_other field to elf_backend_merge_symbol_attribute. */
|
|
other = h->other & ~ELF_ST_VISIBILITY (-1);
|
|
|
|
/* Combine visibilities, using the most constraining one. */
|
|
hvis = ELF_ST_VISIBILITY (h->other);
|
|
symvis = ELF_ST_VISIBILITY (isym->st_other);
|
|
if (! hvis)
|
|
nvis = symvis;
|
|
else if (! symvis)
|
|
nvis = hvis;
|
|
else
|
|
nvis = hvis < symvis ? hvis : symvis;
|
|
|
|
h->other = other | nvis;
|
|
}
|
}
|
|
|
|
/* Merge st_other field. */
|
|
elf_merge_st_other (abfd, h, isym, definition, dynamic);
|
|
|
/* Set a flag in the hash table entry indicating the type of
|
/* Set a flag in the hash table entry indicating the type of
|
reference or definition we just found. Keep a count of
|
reference or definition we just found. Keep a count of
|
the number of dynamic symbols we find. A dynamic symbol
|
the number of dynamic symbols we find. A dynamic symbol
|
is one which is referenced or defined by both a regular
|
is one which is referenced or defined by both a regular
|
object and a shared object. */
|
object and a shared object. */
|
Line 4271... |
Line 4329... |
h->ref_regular = 1;
|
h->ref_regular = 1;
|
if (bind != STB_WEAK)
|
if (bind != STB_WEAK)
|
h->ref_regular_nonweak = 1;
|
h->ref_regular_nonweak = 1;
|
}
|
}
|
else
|
else
|
|
{
|
h->def_regular = 1;
|
h->def_regular = 1;
|
|
if (h->def_dynamic)
|
|
{
|
|
h->def_dynamic = 0;
|
|
h->ref_dynamic = 1;
|
|
h->dynamic_def = 1;
|
|
}
|
|
}
|
if (! info->executable
|
if (! info->executable
|
|| h->def_dynamic
|
|| h->def_dynamic
|
|| h->ref_dynamic)
|
|| h->ref_dynamic)
|
dynsym = TRUE;
|
dynsym = TRUE;
|
}
|
}
|
Line 4291... |
Line 4357... |
&& ! new_weakdef
|
&& ! new_weakdef
|
&& h->u.weakdef->dynindx != -1))
|
&& h->u.weakdef->dynindx != -1))
|
dynsym = TRUE;
|
dynsym = TRUE;
|
}
|
}
|
|
|
if (definition && (sec->flags & SEC_DEBUGGING))
|
if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
|
{
|
{
|
/* We don't want to make debug symbol dynamic. */
|
/* We don't want to make debug symbol dynamic. */
|
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
|
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
|
dynsym = FALSE;
|
dynsym = FALSE;
|
}
|
}
|
Line 4317... |
Line 4383... |
aliases can be checked. */
|
aliases can be checked. */
|
if (!nondeflt_vers)
|
if (!nondeflt_vers)
|
{
|
{
|
amt = ((isymend - isym + 1)
|
amt = ((isymend - isym + 1)
|
* sizeof (struct elf_link_hash_entry *));
|
* sizeof (struct elf_link_hash_entry *));
|
nondeflt_vers = bfd_malloc (amt);
|
nondeflt_vers =
|
|
(struct elf_link_hash_entry **) bfd_malloc (amt);
|
if (!nondeflt_vers)
|
if (!nondeflt_vers)
|
goto error_free_vers;
|
goto error_free_vers;
|
}
|
}
|
nondeflt_vers[nondeflt_vers_cnt++] = h;
|
nondeflt_vers[nondeflt_vers_cnt++] = h;
|
}
|
}
|
Line 4352... |
Line 4419... |
break;
|
break;
|
}
|
}
|
|
|
if (!add_needed
|
if (!add_needed
|
&& definition
|
&& definition
|
&& dynsym
|
&& ((dynsym
|
&& h->ref_regular)
|
&& h->ref_regular)
|
|
|| (h->ref_dynamic
|
|
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
|
|
&& !on_needed_list (elf_dt_name (abfd), htab->needed))))
|
{
|
{
|
int ret;
|
int ret;
|
const char *soname = elf_dt_name (abfd);
|
const char *soname = elf_dt_name (abfd);
|
|
|
/* A symbol from a library loaded via DT_NEEDED of some
|
/* A symbol from a library loaded via DT_NEEDED of some
|
Line 4371... |
Line 4441... |
abfd, name);
|
abfd, name);
|
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
goto error_free_vers;
|
goto error_free_vers;
|
}
|
}
|
|
|
elf_dyn_lib_class (abfd) &= ~DYN_AS_NEEDED;
|
elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
|
|
(elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
|
|
|
add_needed = TRUE;
|
add_needed = TRUE;
|
ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
|
ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
|
if (ret < 0)
|
if (ret < 0)
|
goto error_free_vers;
|
goto error_free_vers;
|
Line 4477... |
Line 4548... |
|| (h->root.type != bfd_link_hash_defined
|
|| (h->root.type != bfd_link_hash_defined
|
&& h->root.type != bfd_link_hash_defweak))
|
&& h->root.type != bfd_link_hash_defweak))
|
continue;
|
continue;
|
|
|
amt = p - h->root.root.string;
|
amt = p - h->root.root.string;
|
shortname = bfd_malloc (amt + 1);
|
shortname = (char *) bfd_malloc (amt + 1);
|
if (!shortname)
|
if (!shortname)
|
goto error_free_vers;
|
goto error_free_vers;
|
memcpy (shortname, h->root.root.string, amt);
|
memcpy (shortname, h->root.root.string, amt);
|
shortname[amt] = '\0';
|
shortname[amt] = '\0';
|
|
|
Line 4535... |
Line 4606... |
|
|
/* Since we have to search the whole symbol list for each weak
|
/* Since we have to search the whole symbol list for each weak
|
defined symbol, search time for N weak defined symbols will be
|
defined symbol, search time for N weak defined symbols will be
|
O(N^2). Binary search will cut it down to O(NlogN). */
|
O(N^2). Binary search will cut it down to O(NlogN). */
|
amt = extsymcount * sizeof (struct elf_link_hash_entry *);
|
amt = extsymcount * sizeof (struct elf_link_hash_entry *);
|
sorted_sym_hash = bfd_malloc (amt);
|
sorted_sym_hash = (struct elf_link_hash_entry **) bfd_malloc (amt);
|
if (sorted_sym_hash == NULL)
|
if (sorted_sym_hash == NULL)
|
goto error_return;
|
goto error_return;
|
sym_hash = sorted_sym_hash;
|
sym_hash = sorted_sym_hash;
|
hpp = elf_sym_hashes (abfd);
|
hpp = elf_sym_hashes (abfd);
|
hppend = hpp + extsymcount;
|
hppend = hpp + extsymcount;
|
Line 4628... |
Line 4699... |
symbols, make sure the real definition is put
|
symbols, make sure the real definition is put
|
there as well. */
|
there as well. */
|
if (hlook->dynindx != -1 && h->dynindx == -1)
|
if (hlook->dynindx != -1 && h->dynindx == -1)
|
{
|
{
|
if (! bfd_elf_link_record_dynamic_symbol (info, h))
|
if (! bfd_elf_link_record_dynamic_symbol (info, h))
|
|
{
|
|
err_free_sym_hash:
|
|
free (sorted_sym_hash);
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
}
|
|
|
/* If the real definition is in the list of dynamic
|
/* If the real definition is in the list of dynamic
|
symbols, make sure the weak definition is put
|
symbols, make sure the weak definition is put
|
there as well. If we don't do this, then the
|
there as well. If we don't do this, then the
|
dynamic loader might not merge the entries for the
|
dynamic loader might not merge the entries for the
|
real definition and the weak definition. */
|
real definition and the weak definition. */
|
if (h->dynindx != -1 && hlook->dynindx == -1)
|
if (h->dynindx != -1 && hlook->dynindx == -1)
|
{
|
{
|
if (! bfd_elf_link_record_dynamic_symbol (info, hlook))
|
if (! bfd_elf_link_record_dynamic_symbol (info, hlook))
|
goto error_return;
|
goto err_free_sym_hash;
|
}
|
}
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
free (sorted_sym_hash);
|
free (sorted_sym_hash);
|
}
|
}
|
|
|
if (bed->check_directives)
|
if (bed->check_directives
|
(*bed->check_directives) (abfd, info);
|
&& !(*bed->check_directives) (abfd, info))
|
|
return FALSE;
|
|
|
/* If this object is the same format as the output object, and it is
|
/* If this object is the same format as the output object, and it is
|
not a shared library, then let the backend look through the
|
not a shared library, then let the backend look through the
|
relocs.
|
relocs.
|
|
|
Line 4743... |
Line 4819... |
if (is_elf_hash_table (htab) && add_needed)
|
if (is_elf_hash_table (htab) && add_needed)
|
{
|
{
|
/* Add this bfd to the loaded list. */
|
/* Add this bfd to the loaded list. */
|
struct elf_link_loaded_list *n;
|
struct elf_link_loaded_list *n;
|
|
|
n = bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
|
n = (struct elf_link_loaded_list *)
|
|
bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
|
if (n == NULL)
|
if (n == NULL)
|
goto error_return;
|
goto error_return;
|
n->abfd = abfd;
|
n->abfd = abfd;
|
n->next = htab->loaded;
|
n->next = htab->loaded;
|
htab->loaded = n;
|
htab->loaded = n;
|
Line 4794... |
Line 4871... |
if (p == NULL || p[1] != ELF_VER_CHR)
|
if (p == NULL || p[1] != ELF_VER_CHR)
|
return h;
|
return h;
|
|
|
/* First check with only one `@'. */
|
/* First check with only one `@'. */
|
len = strlen (name);
|
len = strlen (name);
|
copy = bfd_alloc (abfd, len);
|
copy = (char *) bfd_alloc (abfd, len);
|
if (copy == NULL)
|
if (copy == NULL)
|
return (struct elf_link_hash_entry *) 0 - 1;
|
return (struct elf_link_hash_entry *) 0 - 1;
|
|
|
first = p - name + 1;
|
first = p - name + 1;
|
memcpy (copy, name, first);
|
memcpy (copy, name, first);
|
Line 4871... |
Line 4948... |
c = bfd_ardata (abfd)->symdef_count;
|
c = bfd_ardata (abfd)->symdef_count;
|
if (c == 0)
|
if (c == 0)
|
return TRUE;
|
return TRUE;
|
amt = c;
|
amt = c;
|
amt *= sizeof (bfd_boolean);
|
amt *= sizeof (bfd_boolean);
|
defined = bfd_zmalloc (amt);
|
defined = (bfd_boolean *) bfd_zmalloc (amt);
|
included = bfd_zmalloc (amt);
|
included = (bfd_boolean *) bfd_zmalloc (amt);
|
if (defined == NULL || included == NULL)
|
if (defined == NULL || included == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
symdefs = bfd_ardata (abfd)->symdefs;
|
symdefs = bfd_ardata (abfd)->symdefs;
|
bed = get_elf_backend_data (abfd);
|
bed = get_elf_backend_data (abfd);
|
Line 5036... |
Line 5113... |
all hash value of the exported symbols in an array. */
|
all hash value of the exported symbols in an array. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
|
elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct hash_codes_info *inf = data;
|
struct hash_codes_info *inf = (struct hash_codes_info *) data;
|
const char *name;
|
const char *name;
|
char *p;
|
char *p;
|
unsigned long ha;
|
unsigned long ha;
|
char *alc = NULL;
|
char *alc = NULL;
|
|
|
Line 5053... |
Line 5130... |
|
|
name = h->root.root.string;
|
name = h->root.root.string;
|
p = strchr (name, ELF_VER_CHR);
|
p = strchr (name, ELF_VER_CHR);
|
if (p != NULL)
|
if (p != NULL)
|
{
|
{
|
alc = bfd_malloc (p - name + 1);
|
alc = (char *) bfd_malloc (p - name + 1);
|
if (alc == NULL)
|
if (alc == NULL)
|
{
|
{
|
inf->error = TRUE;
|
inf->error = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 5107... |
Line 5184... |
all hash value of the exported symbols in an array. */
|
all hash value of the exported symbols in an array. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
|
elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct collect_gnu_hash_codes *s = data;
|
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
|
const char *name;
|
const char *name;
|
char *p;
|
char *p;
|
unsigned long ha;
|
unsigned long ha;
|
char *alc = NULL;
|
char *alc = NULL;
|
|
|
Line 5128... |
Line 5205... |
|
|
name = h->root.root.string;
|
name = h->root.root.string;
|
p = strchr (name, ELF_VER_CHR);
|
p = strchr (name, ELF_VER_CHR);
|
if (p != NULL)
|
if (p != NULL)
|
{
|
{
|
alc = bfd_malloc (p - name + 1);
|
alc = (char *) bfd_malloc (p - name + 1);
|
if (alc == NULL)
|
if (alc == NULL)
|
{
|
{
|
s->error = TRUE;
|
s->error = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
Line 5162... |
Line 5239... |
final dynaminc symbol renumbering. */
|
final dynaminc symbol renumbering. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
|
elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct collect_gnu_hash_codes *s = data;
|
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
|
unsigned long int bucket;
|
unsigned long int bucket;
|
unsigned long int val;
|
unsigned long int val;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
Line 5274... |
Line 5351... |
|
|
/* Create array where we count the collisions in. We must use bfd_malloc
|
/* Create array where we count the collisions in. We must use bfd_malloc
|
since the size could be large. */
|
since the size could be large. */
|
amt = maxsize;
|
amt = maxsize;
|
amt *= sizeof (unsigned long int);
|
amt *= sizeof (unsigned long int);
|
counts = bfd_malloc (amt);
|
counts = (unsigned long int *) bfd_malloc (amt);
|
if (counts == NULL)
|
if (counts == NULL)
|
return 0;
|
return 0;
|
|
|
/* Compute the "optimal" size for the hash table. The criteria is a
|
/* Compute the "optimal" size for the hash table. The criteria is a
|
minimal chain length. The minor criteria is (of course) the size
|
minimal chain length. The minor criteria is (of course) the size
|
Line 5380... |
Line 5457... |
struct bfd_elf_version_tree *verdefs)
|
struct bfd_elf_version_tree *verdefs)
|
{
|
{
|
bfd_size_type soname_indx;
|
bfd_size_type soname_indx;
|
bfd *dynobj;
|
bfd *dynobj;
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
struct elf_assign_sym_version_info asvinfo;
|
struct elf_info_failed asvinfo;
|
|
|
*sinterpptr = NULL;
|
*sinterpptr = NULL;
|
|
|
soname_indx = (bfd_size_type) -1;
|
soname_indx = (bfd_size_type) -1;
|
|
|
Line 5406... |
Line 5483... |
inputobj;
|
inputobj;
|
inputobj = inputobj->link_next)
|
inputobj = inputobj->link_next)
|
{
|
{
|
asection *s;
|
asection *s;
|
|
|
if (inputobj->flags & (DYNAMIC | BFD_LINKER_CREATED))
|
if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
|
continue;
|
continue;
|
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
|
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
|
if (s)
|
if (s)
|
{
|
{
|
if (s->flags & SEC_CODE)
|
if (s->flags & SEC_CODE)
|
Line 5543... |
Line 5620... |
}
|
}
|
|
|
/* Make all global versions with definition. */
|
/* Make all global versions with definition. */
|
for (t = verdefs; t != NULL; t = t->next)
|
for (t = verdefs; t != NULL; t = t->next)
|
for (d = t->globals.list; d != NULL; d = d->next)
|
for (d = t->globals.list; d != NULL; d = d->next)
|
if (!d->symver && d->symbol)
|
if (!d->symver && d->literal)
|
{
|
{
|
const char *verstr, *name;
|
const char *verstr, *name;
|
size_t namelen, verlen, newlen;
|
size_t namelen, verlen, newlen;
|
char *newname, *p;
|
char *newname, *p;
|
struct elf_link_hash_entry *newh;
|
struct elf_link_hash_entry *newh;
|
|
|
name = d->symbol;
|
name = d->pattern;
|
namelen = strlen (name);
|
namelen = strlen (name);
|
verstr = t->name;
|
verstr = t->name;
|
verlen = strlen (verstr);
|
verlen = strlen (verstr);
|
newlen = namelen + verlen + 3;
|
newlen = namelen + verlen + 3;
|
|
|
newname = bfd_malloc (newlen);
|
newname = (char *) bfd_malloc (newlen);
|
if (newname == NULL)
|
if (newname == NULL)
|
return FALSE;
|
return FALSE;
|
memcpy (newname, name, namelen);
|
memcpy (newname, name, namelen);
|
|
|
/* Check the hidden versioned definition. */
|
/* Check the hidden versioned definition. */
|
Line 5591... |
Line 5668... |
|| newh->root.type == bfd_link_hash_defweak))
|
|| newh->root.type == bfd_link_hash_defweak))
|
d->symver = 1;
|
d->symver = 1;
|
}
|
}
|
|
|
/* Attach all the symbols to their version information. */
|
/* Attach all the symbols to their version information. */
|
asvinfo.output_bfd = output_bfd;
|
|
asvinfo.info = info;
|
asvinfo.info = info;
|
asvinfo.verdefs = verdefs;
|
asvinfo.verdefs = verdefs;
|
asvinfo.failed = FALSE;
|
asvinfo.failed = FALSE;
|
|
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_link_hash_traverse (elf_hash_table (info),
|
Line 5608... |
Line 5684... |
{
|
{
|
/* Check if all global versions have a definition. */
|
/* Check if all global versions have a definition. */
|
all_defined = TRUE;
|
all_defined = TRUE;
|
for (t = verdefs; t != NULL; t = t->next)
|
for (t = verdefs; t != NULL; t = t->next)
|
for (d = t->globals.list; d != NULL; d = d->next)
|
for (d = t->globals.list; d != NULL; d = d->next)
|
if (!d->symver && !d->script)
|
if (d->literal && !d->symver && !d->script)
|
{
|
{
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%s: undefined version: %s"),
|
(_("%s: undefined version: %s"),
|
d->pattern, t->name);
|
d->pattern, t->name);
|
all_defined = FALSE;
|
all_defined = FALSE;
|
Line 5795... |
Line 5871... |
for (n = t->deps; n != NULL; n = n->next)
|
for (n = t->deps; n != NULL; n = n->next)
|
size += sizeof (Elf_External_Verdaux);
|
size += sizeof (Elf_External_Verdaux);
|
}
|
}
|
|
|
s->size = size;
|
s->size = size;
|
s->contents = bfd_alloc (output_bfd, s->size);
|
s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
|
if (s->contents == NULL && s->size != 0)
|
if (s->contents == NULL && s->size != 0)
|
return FALSE;
|
return FALSE;
|
|
|
/* Fill in the version definition section. */
|
/* Fill in the version definition section. */
|
|
|
Line 5996... |
Line 6072... |
s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
|
s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
|
BFD_ASSERT (s != NULL);
|
BFD_ASSERT (s != NULL);
|
{
|
{
|
struct elf_find_verdep_info sinfo;
|
struct elf_find_verdep_info sinfo;
|
|
|
sinfo.output_bfd = output_bfd;
|
|
sinfo.info = info;
|
sinfo.info = info;
|
sinfo.vers = elf_tdata (output_bfd)->cverdefs;
|
sinfo.vers = elf_tdata (output_bfd)->cverdefs;
|
if (sinfo.vers == 0)
|
if (sinfo.vers == 0)
|
sinfo.vers = 1;
|
sinfo.vers = 1;
|
sinfo.failed = FALSE;
|
sinfo.failed = FALSE;
|
Line 6034... |
Line 6109... |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
|
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
|
size += sizeof (Elf_External_Vernaux);
|
size += sizeof (Elf_External_Vernaux);
|
}
|
}
|
|
|
s->size = size;
|
s->size = size;
|
s->contents = bfd_alloc (output_bfd, s->size);
|
s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
|
if (s->contents == NULL)
|
if (s->contents == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
p = s->contents;
|
p = s->contents;
|
for (t = elf_tdata (output_bfd)->verref;
|
for (t = elf_tdata (output_bfd)->verref;
|
Line 6134... |
Line 6209... |
void
|
void
|
_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info)
|
_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info)
|
{
|
{
|
asection *s;
|
asection *s;
|
|
|
|
/* Data first, since setting text_index_section changes
|
|
_bfd_elf_link_omit_section_dynsym. */
|
for (s = output_bfd->sections; s != NULL; s = s->next)
|
for (s = output_bfd->sections; s != NULL; s = s->next)
|
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
|
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
|
== (SEC_ALLOC | SEC_READONLY))
|
|
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
|
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
|
{
|
{
|
elf_hash_table (info)->text_index_section = s;
|
elf_hash_table (info)->data_index_section = s;
|
break;
|
break;
|
}
|
}
|
|
|
for (s = output_bfd->sections; s != NULL; s = s->next)
|
for (s = output_bfd->sections; s != NULL; s = s->next)
|
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
|
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
|
|
== (SEC_ALLOC | SEC_READONLY))
|
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
|
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
|
{
|
{
|
elf_hash_table (info)->data_index_section = s;
|
elf_hash_table (info)->text_index_section = s;
|
break;
|
break;
|
}
|
}
|
|
|
if (elf_hash_table (info)->text_index_section == NULL)
|
if (elf_hash_table (info)->text_index_section == NULL)
|
elf_hash_table (info)->text_index_section
|
elf_hash_table (info)->text_index_section
|
Line 6192... |
Line 6269... |
BFD_ASSERT (s != NULL);
|
BFD_ASSERT (s != NULL);
|
if (dynsymcount != 0
|
if (dynsymcount != 0
|
&& (s->flags & SEC_EXCLUDE) == 0)
|
&& (s->flags & SEC_EXCLUDE) == 0)
|
{
|
{
|
s->size = dynsymcount * sizeof (Elf_External_Versym);
|
s->size = dynsymcount * sizeof (Elf_External_Versym);
|
s->contents = bfd_zalloc (output_bfd, s->size);
|
s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
|
if (s->contents == NULL)
|
if (s->contents == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
if (!_bfd_elf_add_dynamic_entry (info, DT_VERSYM, 0))
|
if (!_bfd_elf_add_dynamic_entry (info, DT_VERSYM, 0))
|
return FALSE;
|
return FALSE;
|
Line 6212... |
Line 6289... |
BFD_ASSERT (s != NULL);
|
BFD_ASSERT (s != NULL);
|
s->size = dynsymcount * bed->s->sizeof_sym;
|
s->size = dynsymcount * bed->s->sizeof_sym;
|
|
|
if (dynsymcount != 0)
|
if (dynsymcount != 0)
|
{
|
{
|
s->contents = bfd_alloc (output_bfd, s->size);
|
s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
|
if (s->contents == NULL)
|
if (s->contents == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
/* The first entry in .dynsym is a dummy symbol.
|
/* The first entry in .dynsym is a dummy symbol.
|
Clear all the section syms, in case we don't output them all. */
|
Clear all the section syms, in case we don't output them all. */
|
Line 6239... |
Line 6316... |
|
|
/* Compute the hash values for all exported symbols. At the same
|
/* Compute the hash values for all exported symbols. At the same
|
time store the values in an array so that we could use them for
|
time store the values in an array so that we could use them for
|
optimizations. */
|
optimizations. */
|
amt = dynsymcount * sizeof (unsigned long int);
|
amt = dynsymcount * sizeof (unsigned long int);
|
hashcodes = bfd_malloc (amt);
|
hashcodes = (unsigned long int *) bfd_malloc (amt);
|
if (hashcodes == NULL)
|
if (hashcodes == NULL)
|
return FALSE;
|
return FALSE;
|
hashinf.hashcodes = hashcodes;
|
hashinf.hashcodes = hashcodes;
|
hashinf.error = FALSE;
|
hashinf.error = FALSE;
|
|
|
/* Put all hash values in HASHCODES. */
|
/* Put all hash values in HASHCODES. */
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_collect_hash_codes, &hashinf);
|
elf_collect_hash_codes, &hashinf);
|
if (hashinf.error)
|
if (hashinf.error)
|
|
{
|
|
free (hashcodes);
|
return FALSE;
|
return FALSE;
|
|
}
|
|
|
nsyms = hashinf.hashcodes - hashcodes;
|
nsyms = hashinf.hashcodes - hashcodes;
|
bucketcount
|
bucketcount
|
= compute_bucket_count (info, hashcodes, nsyms, 0);
|
= compute_bucket_count (info, hashcodes, nsyms, 0);
|
free (hashcodes);
|
free (hashcodes);
|
Line 6265... |
Line 6345... |
|
|
s = bfd_get_section_by_name (dynobj, ".hash");
|
s = bfd_get_section_by_name (dynobj, ".hash");
|
BFD_ASSERT (s != NULL);
|
BFD_ASSERT (s != NULL);
|
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
|
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
|
s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
|
s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
|
s->contents = bfd_zalloc (output_bfd, s->size);
|
s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
|
if (s->contents == NULL)
|
if (s->contents == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
|
bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
|
bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
|
bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
|
Line 6288... |
Line 6368... |
|
|
/* Compute the hash values for all exported symbols. At the same
|
/* Compute the hash values for all exported symbols. At the same
|
time store the values in an array so that we could use them for
|
time store the values in an array so that we could use them for
|
optimizations. */
|
optimizations. */
|
amt = dynsymcount * 2 * sizeof (unsigned long int);
|
amt = dynsymcount * 2 * sizeof (unsigned long int);
|
cinfo.hashcodes = bfd_malloc (amt);
|
cinfo.hashcodes = (long unsigned int *) bfd_malloc (amt);
|
if (cinfo.hashcodes == NULL)
|
if (cinfo.hashcodes == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
cinfo.hashval = cinfo.hashcodes + dynsymcount;
|
cinfo.hashval = cinfo.hashcodes + dynsymcount;
|
cinfo.min_dynindx = -1;
|
cinfo.min_dynindx = -1;
|
Line 6301... |
Line 6381... |
|
|
/* Put all hash values in HASHCODES. */
|
/* Put all hash values in HASHCODES. */
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_collect_gnu_hash_codes, &cinfo);
|
elf_collect_gnu_hash_codes, &cinfo);
|
if (cinfo.error)
|
if (cinfo.error)
|
|
{
|
|
free (cinfo.hashcodes);
|
return FALSE;
|
return FALSE;
|
|
}
|
|
|
bucketcount
|
bucketcount
|
= compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1);
|
= compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1);
|
|
|
if (bucketcount == 0)
|
if (bucketcount == 0)
|
Line 6321... |
Line 6404... |
{
|
{
|
/* Empty .gnu.hash section is special. */
|
/* Empty .gnu.hash section is special. */
|
BFD_ASSERT (cinfo.min_dynindx == -1);
|
BFD_ASSERT (cinfo.min_dynindx == -1);
|
free (cinfo.hashcodes);
|
free (cinfo.hashcodes);
|
s->size = 5 * 4 + bed->s->arch_size / 8;
|
s->size = 5 * 4 + bed->s->arch_size / 8;
|
contents = bfd_zalloc (output_bfd, s->size);
|
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
|
if (contents == NULL)
|
if (contents == NULL)
|
return FALSE;
|
return FALSE;
|
s->contents = contents;
|
s->contents = contents;
|
/* 1 empty bucket. */
|
/* 1 empty bucket. */
|
bfd_put_32 (output_bfd, 1, contents);
|
bfd_put_32 (output_bfd, 1, contents);
|
Line 6365... |
Line 6448... |
cinfo.shift2 = maskbitslog2;
|
cinfo.shift2 = maskbitslog2;
|
cinfo.maskbits = 1 << maskbitslog2;
|
cinfo.maskbits = 1 << maskbitslog2;
|
maskwords = 1 << (maskbitslog2 - cinfo.shift1);
|
maskwords = 1 << (maskbitslog2 - cinfo.shift1);
|
amt = bucketcount * sizeof (unsigned long int) * 2;
|
amt = bucketcount * sizeof (unsigned long int) * 2;
|
amt += maskwords * sizeof (bfd_vma);
|
amt += maskwords * sizeof (bfd_vma);
|
cinfo.bitmask = bfd_malloc (amt);
|
cinfo.bitmask = (bfd_vma *) bfd_malloc (amt);
|
if (cinfo.bitmask == NULL)
|
if (cinfo.bitmask == NULL)
|
{
|
{
|
free (cinfo.hashcodes);
|
free (cinfo.hashcodes);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
cinfo.counts = (void *) (cinfo.bitmask + maskwords);
|
cinfo.counts = (long unsigned int *) (cinfo.bitmask + maskwords);
|
cinfo.indx = cinfo.counts + bucketcount;
|
cinfo.indx = cinfo.counts + bucketcount;
|
cinfo.symindx = dynsymcount - cinfo.nsyms;
|
cinfo.symindx = dynsymcount - cinfo.nsyms;
|
memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma));
|
memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma));
|
|
|
/* Determine how often each hash bucket is used. */
|
/* Determine how often each hash bucket is used. */
|
Line 6394... |
Line 6477... |
cinfo.bucketcount = bucketcount;
|
cinfo.bucketcount = bucketcount;
|
cinfo.local_indx = cinfo.min_dynindx;
|
cinfo.local_indx = cinfo.min_dynindx;
|
|
|
s->size = (4 + bucketcount + cinfo.nsyms) * 4;
|
s->size = (4 + bucketcount + cinfo.nsyms) * 4;
|
s->size += cinfo.maskbits / 8;
|
s->size += cinfo.maskbits / 8;
|
contents = bfd_zalloc (output_bfd, s->size);
|
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
|
if (contents == NULL)
|
if (contents == NULL)
|
{
|
{
|
free (cinfo.bitmask);
|
free (cinfo.bitmask);
|
free (cinfo.hashcodes);
|
free (cinfo.hashcodes);
|
return FALSE;
|
return FALSE;
|
Line 6518... |
Line 6601... |
{
|
{
|
/* Allocate the structure if it has not already been allocated by a
|
/* Allocate the structure if it has not already been allocated by a
|
subclass. */
|
subclass. */
|
if (entry == NULL)
|
if (entry == NULL)
|
{
|
{
|
entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
|
entry = (struct bfd_hash_entry *)
|
|
bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
|
if (entry == NULL)
|
if (entry == NULL)
|
return entry;
|
return entry;
|
}
|
}
|
|
|
/* Call the allocation method of the superclass. */
|
/* Call the allocation method of the superclass. */
|
Line 6605... |
Line 6689... |
void
|
void
|
_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
|
_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
|
struct elf_link_hash_entry *h,
|
struct elf_link_hash_entry *h,
|
bfd_boolean force_local)
|
bfd_boolean force_local)
|
{
|
{
|
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
|
if (h->type != STT_GNU_IFUNC)
|
|
{
|
h->plt = elf_hash_table (info)->init_plt_offset;
|
h->plt = elf_hash_table (info)->init_plt_offset;
|
h->needs_plt = 0;
|
h->needs_plt = 0;
|
|
}
|
if (force_local)
|
if (force_local)
|
{
|
{
|
h->forced_local = 1;
|
h->forced_local = 1;
|
if (h->dynindx != -1)
|
if (h->dynindx != -1)
|
{
|
{
|
Line 6655... |
Line 6743... |
_bfd_elf_link_hash_table_create (bfd *abfd)
|
_bfd_elf_link_hash_table_create (bfd *abfd)
|
{
|
{
|
struct elf_link_hash_table *ret;
|
struct elf_link_hash_table *ret;
|
bfd_size_type amt = sizeof (struct elf_link_hash_table);
|
bfd_size_type amt = sizeof (struct elf_link_hash_table);
|
|
|
ret = bfd_malloc (amt);
|
ret = (struct elf_link_hash_table *) bfd_malloc (amt);
|
if (ret == NULL)
|
if (ret == NULL)
|
return NULL;
|
return NULL;
|
|
|
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
|
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
|
sizeof (struct elf_link_hash_entry)))
|
sizeof (struct elf_link_hash_entry)))
|
Line 6747... |
Line 6835... |
bfd_elf_get_bfd_needed_list (bfd *abfd,
|
bfd_elf_get_bfd_needed_list (bfd *abfd,
|
struct bfd_link_needed_list **pneeded)
|
struct bfd_link_needed_list **pneeded)
|
{
|
{
|
asection *s;
|
asection *s;
|
bfd_byte *dynbuf = NULL;
|
bfd_byte *dynbuf = NULL;
|
int elfsec;
|
unsigned int elfsec;
|
unsigned long shlink;
|
unsigned long shlink;
|
bfd_byte *extdyn, *extdynend;
|
bfd_byte *extdyn, *extdynend;
|
size_t extdynsize;
|
size_t extdynsize;
|
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
|
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
|
|
|
Line 6767... |
Line 6855... |
|
|
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
|
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
|
goto error_return;
|
goto error_return;
|
|
|
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
|
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
|
if (elfsec == -1)
|
if (elfsec == SHN_BAD)
|
goto error_return;
|
goto error_return;
|
|
|
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
|
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
|
|
|
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
|
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
|
Line 6798... |
Line 6886... |
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
|
if (string == NULL)
|
if (string == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
amt = sizeof *l;
|
amt = sizeof *l;
|
l = bfd_alloc (abfd, amt);
|
l = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
|
if (l == NULL)
|
if (l == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
l->by = abfd;
|
l->by = abfd;
|
l->name = string;
|
l->name = string;
|
Line 6870... |
Line 6958... |
Elf_Internal_Sym **ind, **indbufend, **indbuf;
|
Elf_Internal_Sym **ind, **indbufend, **indbuf;
|
struct elf_symbuf_symbol *ssym;
|
struct elf_symbuf_symbol *ssym;
|
struct elf_symbuf_head *ssymbuf, *ssymhead;
|
struct elf_symbuf_head *ssymbuf, *ssymhead;
|
bfd_size_type i, shndx_count, total_size;
|
bfd_size_type i, shndx_count, total_size;
|
|
|
indbuf = bfd_malloc2 (symcount, sizeof (*indbuf));
|
indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf));
|
if (indbuf == NULL)
|
if (indbuf == NULL)
|
return NULL;
|
return NULL;
|
|
|
for (ind = indbuf, i = 0; i < symcount; i++)
|
for (ind = indbuf, i = 0; i < symcount; i++)
|
if (isymbuf[i].st_shndx != SHN_UNDEF)
|
if (isymbuf[i].st_shndx != SHN_UNDEF)
|
Line 6890... |
Line 6978... |
if (ind[0]->st_shndx != ind[1]->st_shndx)
|
if (ind[0]->st_shndx != ind[1]->st_shndx)
|
shndx_count++;
|
shndx_count++;
|
|
|
total_size = ((shndx_count + 1) * sizeof (*ssymbuf)
|
total_size = ((shndx_count + 1) * sizeof (*ssymbuf)
|
+ (indbufend - indbuf) * sizeof (*ssym));
|
+ (indbufend - indbuf) * sizeof (*ssym));
|
ssymbuf = bfd_malloc (total_size);
|
ssymbuf = (struct elf_symbuf_head *) bfd_malloc (total_size);
|
if (ssymbuf == NULL)
|
if (ssymbuf == NULL)
|
{
|
{
|
free (indbuf);
|
free (indbuf);
|
return NULL;
|
return NULL;
|
}
|
}
|
Line 6939... |
Line 7027... |
Elf_Internal_Sym *isymbuf1, *isymbuf2;
|
Elf_Internal_Sym *isymbuf1, *isymbuf2;
|
struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
|
struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
|
Elf_Internal_Sym *isym, *isymend;
|
Elf_Internal_Sym *isym, *isymend;
|
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
|
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
|
bfd_size_type count1, count2, i;
|
bfd_size_type count1, count2, i;
|
int shndx1, shndx2;
|
unsigned int shndx1, shndx2;
|
bfd_boolean result;
|
bfd_boolean result;
|
|
|
bfd1 = sec1->owner;
|
bfd1 = sec1->owner;
|
bfd2 = sec2->owner;
|
bfd2 = sec2->owner;
|
|
|
Line 6955... |
Line 7043... |
if (elf_section_type (sec1) != elf_section_type (sec2))
|
if (elf_section_type (sec1) != elf_section_type (sec2))
|
return FALSE;
|
return FALSE;
|
|
|
shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
|
shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
|
shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
|
shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
|
if (shndx1 == -1 || shndx2 == -1)
|
if (shndx1 == SHN_BAD || shndx2 == SHN_BAD)
|
return FALSE;
|
return FALSE;
|
|
|
bed1 = get_elf_backend_data (bfd1);
|
bed1 = get_elf_backend_data (bfd1);
|
bed2 = get_elf_backend_data (bfd2);
|
bed2 = get_elf_backend_data (bfd2);
|
hdr1 = &elf_tdata (bfd1)->symtab_hdr;
|
hdr1 = &elf_tdata (bfd1)->symtab_hdr;
|
Line 6971... |
Line 7059... |
return FALSE;
|
return FALSE;
|
|
|
result = FALSE;
|
result = FALSE;
|
isymbuf1 = NULL;
|
isymbuf1 = NULL;
|
isymbuf2 = NULL;
|
isymbuf2 = NULL;
|
ssymbuf1 = elf_tdata (bfd1)->symbuf;
|
ssymbuf1 = (struct elf_symbuf_head *) elf_tdata (bfd1)->symbuf;
|
ssymbuf2 = elf_tdata (bfd2)->symbuf;
|
ssymbuf2 = (struct elf_symbuf_head *) elf_tdata (bfd2)->symbuf;
|
|
|
if (ssymbuf1 == NULL)
|
if (ssymbuf1 == NULL)
|
{
|
{
|
isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
|
isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
|
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
Line 7012... |
Line 7100... |
ssymbuf1++;
|
ssymbuf1++;
|
count1 = 0;
|
count1 = 0;
|
while (lo < hi)
|
while (lo < hi)
|
{
|
{
|
mid = (lo + hi) / 2;
|
mid = (lo + hi) / 2;
|
if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
|
if (shndx1 < ssymbuf1[mid].st_shndx)
|
hi = mid;
|
hi = mid;
|
else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
|
else if (shndx1 > ssymbuf1[mid].st_shndx)
|
lo = mid + 1;
|
lo = mid + 1;
|
else
|
else
|
{
|
{
|
count1 = ssymbuf1[mid].count;
|
count1 = ssymbuf1[mid].count;
|
ssymbuf1 += mid;
|
ssymbuf1 += mid;
|
Line 7031... |
Line 7119... |
ssymbuf2++;
|
ssymbuf2++;
|
count2 = 0;
|
count2 = 0;
|
while (lo < hi)
|
while (lo < hi)
|
{
|
{
|
mid = (lo + hi) / 2;
|
mid = (lo + hi) / 2;
|
if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
|
if (shndx2 < ssymbuf2[mid].st_shndx)
|
hi = mid;
|
hi = mid;
|
else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
|
else if (shndx2 > ssymbuf2[mid].st_shndx)
|
lo = mid + 1;
|
lo = mid + 1;
|
else
|
else
|
{
|
{
|
count2 = ssymbuf2[mid].count;
|
count2 = ssymbuf2[mid].count;
|
ssymbuf2 += mid;
|
ssymbuf2 += mid;
|
Line 7046... |
Line 7134... |
}
|
}
|
|
|
if (count1 == 0 || count2 == 0 || count1 != count2)
|
if (count1 == 0 || count2 == 0 || count1 != count2)
|
goto done;
|
goto done;
|
|
|
symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
|
symtable1 = (struct elf_symbol *)
|
symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
|
bfd_malloc (count1 * sizeof (struct elf_symbol));
|
|
symtable2 = (struct elf_symbol *)
|
|
bfd_malloc (count2 * sizeof (struct elf_symbol));
|
if (symtable1 == NULL || symtable2 == NULL)
|
if (symtable1 == NULL || symtable2 == NULL)
|
goto done;
|
goto done;
|
|
|
symp = symtable1;
|
symp = symtable1;
|
for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
|
for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
|
Line 7088... |
Line 7178... |
|
|
result = TRUE;
|
result = TRUE;
|
goto done;
|
goto done;
|
}
|
}
|
|
|
symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
|
symtable1 = (struct elf_symbol *)
|
symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
|
bfd_malloc (symcount1 * sizeof (struct elf_symbol));
|
|
symtable2 = (struct elf_symbol *)
|
|
bfd_malloc (symcount2 * sizeof (struct elf_symbol));
|
if (symtable1 == NULL || symtable2 == NULL)
|
if (symtable1 == NULL || symtable2 == NULL)
|
goto done;
|
goto done;
|
|
|
/* Count definitions in the section. */
|
/* Count definitions in the section. */
|
count1 = 0;
|
count1 = 0;
|
for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
|
for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
|
if (isym->st_shndx == (unsigned int) shndx1)
|
if (isym->st_shndx == shndx1)
|
symtable1[count1++].u.isym = isym;
|
symtable1[count1++].u.isym = isym;
|
|
|
count2 = 0;
|
count2 = 0;
|
for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
|
for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
|
if (isym->st_shndx == (unsigned int) shndx2)
|
if (isym->st_shndx == shndx2)
|
symtable2[count2++].u.isym = isym;
|
symtable2[count2++].u.isym = isym;
|
|
|
if (count1 == 0 || count2 == 0 || count1 != count2)
|
if (count1 == 0 || count2 == 0 || count1 != count2)
|
goto done;
|
goto done;
|
|
|
Line 7677... |
Line 7769... |
if (lsb0_p)
|
if (lsb0_p)
|
shift = (start + 1) - len;
|
shift = (start + 1) - len;
|
else
|
else
|
shift = (8 * wordsz) - (start + len);
|
shift = (8 * wordsz) - (start + len);
|
|
|
|
/* FIXME: octets_per_byte. */
|
x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
|
x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
|
|
|
#ifdef DEBUG
|
#ifdef DEBUG
|
printf ("Doing complex reloc: "
|
printf ("Doing complex reloc: "
|
"lsb0? %ld, signed? %ld, trunc? %ld, wordsz %ld, "
|
"lsb0? %ld, signed? %ld, trunc? %ld, wordsz %ld, "
|
Line 7708... |
Line 7801... |
" shifted/masked reloc: %8.8lx\n"
|
" shifted/masked reloc: %8.8lx\n"
|
" result: %8.8lx\n",
|
" result: %8.8lx\n",
|
relocation, (mask << shift),
|
relocation, (mask << shift),
|
((relocation & mask) << shift), x);
|
((relocation & mask) << shift), x);
|
#endif
|
#endif
|
|
/* FIXME: octets_per_byte. */
|
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
|
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
|
return r;
|
return r;
|
}
|
}
|
|
|
/* When performing a relocatable link, the input relocations are
|
/* When performing a relocatable link, the input relocations are
|
Line 7791... |
Line 7885... |
};
|
};
|
|
|
static int
|
static int
|
elf_link_sort_cmp1 (const void *A, const void *B)
|
elf_link_sort_cmp1 (const void *A, const void *B)
|
{
|
{
|
const struct elf_link_sort_rela *a = A;
|
const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A;
|
const struct elf_link_sort_rela *b = B;
|
const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B;
|
int relativea, relativeb;
|
int relativea, relativeb;
|
|
|
relativea = a->type == reloc_class_relative;
|
relativea = a->type == reloc_class_relative;
|
relativeb = b->type == reloc_class_relative;
|
relativeb = b->type == reloc_class_relative;
|
|
|
Line 7816... |
Line 7910... |
}
|
}
|
|
|
static int
|
static int
|
elf_link_sort_cmp2 (const void *A, const void *B)
|
elf_link_sort_cmp2 (const void *A, const void *B)
|
{
|
{
|
const struct elf_link_sort_rela *a = A;
|
const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A;
|
const struct elf_link_sort_rela *b = B;
|
const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B;
|
int copya, copyb;
|
int copya, copyb;
|
|
|
if (a->u.offset < b->u.offset)
|
if (a->u.offset < b->u.offset)
|
return -1;
|
return -1;
|
if (a->u.offset > b->u.offset)
|
if (a->u.offset > b->u.offset)
|
Line 8015... |
Line 8109... |
|
|
sort_elt = (sizeof (struct elf_link_sort_rela)
|
sort_elt = (sizeof (struct elf_link_sort_rela)
|
+ (i2e - 1) * sizeof (Elf_Internal_Rela));
|
+ (i2e - 1) * sizeof (Elf_Internal_Rela));
|
|
|
count = dynamic_relocs->size / ext_size;
|
count = dynamic_relocs->size / ext_size;
|
sort = bfd_zmalloc (sort_elt * count);
|
if (count == 0)
|
|
return 0;
|
|
sort = (bfd_byte *) bfd_zmalloc (sort_elt * count);
|
|
|
if (sort == NULL)
|
if (sort == NULL)
|
{
|
{
|
(*info->callbacks->warning)
|
(*info->callbacks->warning)
|
(info, _("Not enough memory to sort relocations"), 0, abfd, 0, 0);
|
(info, _("Not enough memory to sort relocations"), 0, abfd, 0, 0);
|
Line 8045... |
Line 8141... |
free (sort);
|
free (sort);
|
return 0;
|
return 0;
|
}
|
}
|
erel = o->contents;
|
erel = o->contents;
|
erelend = o->contents + o->size;
|
erelend = o->contents + o->size;
|
|
/* FIXME: octets_per_byte. */
|
p = sort + o->output_offset / ext_size * sort_elt;
|
p = sort + o->output_offset / ext_size * sort_elt;
|
|
|
while (erel < erelend)
|
while (erel < erelend)
|
{
|
{
|
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
|
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
|
Line 8089... |
Line 8186... |
bfd_byte *erel, *erelend;
|
bfd_byte *erel, *erelend;
|
asection *o = lo->u.indirect.section;
|
asection *o = lo->u.indirect.section;
|
|
|
erel = o->contents;
|
erel = o->contents;
|
erelend = o->contents + o->size;
|
erelend = o->contents + o->size;
|
|
/* FIXME: octets_per_byte. */
|
p = sort + o->output_offset / ext_size * sort_elt;
|
p = sort + o->output_offset / ext_size * sort_elt;
|
while (erel < erelend)
|
while (erel < erelend)
|
{
|
{
|
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
|
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
|
(*swap_out) (abfd, s->rela, erel);
|
(*swap_out) (abfd, s->rela, erel);
|
Line 8132... |
Line 8230... |
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Add a symbol to the output symbol table. */
|
/* Add a symbol to the output symbol table. */
|
|
|
static bfd_boolean
|
static int
|
elf_link_output_sym (struct elf_final_link_info *finfo,
|
elf_link_output_sym (struct elf_final_link_info *finfo,
|
const char *name,
|
const char *name,
|
Elf_Internal_Sym *elfsym,
|
Elf_Internal_Sym *elfsym,
|
asection *input_sec,
|
asection *input_sec,
|
struct elf_link_hash_entry *h)
|
struct elf_link_hash_entry *h)
|
{
|
{
|
bfd_byte *dest;
|
bfd_byte *dest;
|
Elf_External_Sym_Shndx *destshndx;
|
Elf_External_Sym_Shndx *destshndx;
|
bfd_boolean (*output_symbol_hook)
|
int (*output_symbol_hook)
|
(struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
|
(struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
|
struct elf_link_hash_entry *);
|
struct elf_link_hash_entry *);
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
|
|
bed = get_elf_backend_data (finfo->output_bfd);
|
bed = get_elf_backend_data (finfo->output_bfd);
|
output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
|
output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
|
if (output_symbol_hook != NULL)
|
if (output_symbol_hook != NULL)
|
{
|
{
|
if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
|
int ret = (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h);
|
return FALSE;
|
if (ret != 1)
|
|
return ret;
|
}
|
}
|
|
|
if (name == NULL || *name == '\0')
|
if (name == NULL || *name == '\0')
|
elfsym->st_name = 0;
|
elfsym->st_name = 0;
|
else if (input_sec->flags & SEC_EXCLUDE)
|
else if (input_sec->flags & SEC_EXCLUDE)
|
Line 8163... |
Line 8262... |
else
|
else
|
{
|
{
|
elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
|
elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
|
name, TRUE, FALSE);
|
name, TRUE, FALSE);
|
if (elfsym->st_name == (unsigned long) -1)
|
if (elfsym->st_name == (unsigned long) -1)
|
return FALSE;
|
return 0;
|
}
|
}
|
|
|
if (finfo->symbuf_count >= finfo->symbuf_size)
|
if (finfo->symbuf_count >= finfo->symbuf_size)
|
{
|
{
|
if (! elf_link_flush_output_syms (finfo, bed))
|
if (! elf_link_flush_output_syms (finfo, bed))
|
return FALSE;
|
return 0;
|
}
|
}
|
|
|
dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym;
|
dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym;
|
destshndx = finfo->symshndxbuf;
|
destshndx = finfo->symshndxbuf;
|
if (destshndx != NULL)
|
if (destshndx != NULL)
|
Line 8181... |
Line 8280... |
if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
|
if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
|
{
|
{
|
bfd_size_type amt;
|
bfd_size_type amt;
|
|
|
amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
|
amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
|
destshndx = bfd_realloc (destshndx, amt * 2);
|
destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
|
|
amt * 2);
|
if (destshndx == NULL)
|
if (destshndx == NULL)
|
return FALSE;
|
return 0;
|
finfo->symshndxbuf = destshndx;
|
finfo->symshndxbuf = destshndx;
|
memset ((char *) destshndx + amt, 0, amt);
|
memset ((char *) destshndx + amt, 0, amt);
|
finfo->shndxbuf_size *= 2;
|
finfo->shndxbuf_size *= 2;
|
}
|
}
|
destshndx += bfd_get_symcount (finfo->output_bfd);
|
destshndx += bfd_get_symcount (finfo->output_bfd);
|
Line 8195... |
Line 8295... |
|
|
bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx);
|
bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx);
|
finfo->symbuf_count += 1;
|
finfo->symbuf_count += 1;
|
bfd_get_symcount (finfo->output_bfd) += 1;
|
bfd_get_symcount (finfo->output_bfd) += 1;
|
|
|
return TRUE;
|
return 1;
|
}
|
}
|
|
|
/* Return TRUE if the dynamic symbol SYM in ABFD is supported. */
|
/* Return TRUE if the dynamic symbol SYM in ABFD is supported. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
check_dynsym (bfd *abfd, Elf_Internal_Sym *sym)
|
check_dynsym (bfd *abfd, Elf_Internal_Sym *sym)
|
{
|
{
|
if (sym->st_shndx > SHN_HIRESERVE)
|
if (sym->st_shndx >= (SHN_LORESERVE & 0xffff)
|
|
&& sym->st_shndx < SHN_LORESERVE)
|
{
|
{
|
/* The gABI doesn't support dynamic symbols in output sections
|
/* The gABI doesn't support dynamic symbols in output sections
|
beyond 64k. */
|
beyond 64k. */
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B: Too many sections: %d (>= %d)"),
|
(_("%B: Too many sections: %d (>= %d)"),
|
abfd, bfd_count_sections (abfd), SHN_LORESERVE);
|
abfd, bfd_count_sections (abfd), SHN_LORESERVE & 0xffff);
|
bfd_set_error (bfd_error_nonrepresentable_section);
|
bfd_set_error (bfd_error_nonrepresentable_section);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
return TRUE;
|
return TRUE;
|
}
|
}
|
Line 8306... |
Line 8407... |
if (isymbuf == NULL)
|
if (isymbuf == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
/* Read in any version definitions. */
|
/* Read in any version definitions. */
|
versymhdr = &elf_tdata (input)->dynversym_hdr;
|
versymhdr = &elf_tdata (input)->dynversym_hdr;
|
extversym = bfd_malloc (versymhdr->sh_size);
|
extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
|
if (extversym == NULL)
|
if (extversym == NULL)
|
goto error_ret;
|
goto error_ret;
|
|
|
if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
|
if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
|
|| (bfd_bread (extversym, versymhdr->sh_size, input)
|
|| (bfd_bread (extversym, versymhdr->sh_size, input)
|
Line 8374... |
Line 8475... |
global symbols. */
|
global symbols. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
|
elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
|
{
|
{
|
struct elf_outext_info *eoinfo = data;
|
struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
|
struct elf_final_link_info *finfo = eoinfo->finfo;
|
struct elf_final_link_info *finfo = eoinfo->finfo;
|
bfd_boolean strip;
|
bfd_boolean strip;
|
Elf_Internal_Sym sym;
|
Elf_Internal_Sym sym;
|
asection *input_sec;
|
asection *input_sec;
|
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
|
long indx;
|
|
int ret;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
if (h->root.type == bfd_link_hash_new)
|
if (h->root.type == bfd_link_hash_new)
|
Line 8493... |
Line 8596... |
sym.st_value = 0;
|
sym.st_value = 0;
|
sym.st_size = h->size;
|
sym.st_size = h->size;
|
sym.st_other = h->other;
|
sym.st_other = h->other;
|
if (h->forced_local)
|
if (h->forced_local)
|
sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
|
sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
|
|
else if (h->unique_global)
|
|
sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type);
|
else if (h->root.type == bfd_link_hash_undefweak
|
else if (h->root.type == bfd_link_hash_undefweak
|
|| h->root.type == bfd_link_hash_defweak)
|
|| h->root.type == bfd_link_hash_defweak)
|
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
|
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
|
else
|
else
|
sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
|
sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
|
Line 8581... |
Line 8686... |
}
|
}
|
|
|
/* Give the processor backend a chance to tweak the symbol value,
|
/* Give the processor backend a chance to tweak the symbol value,
|
and also to finish up anything that needs to be done for this
|
and also to finish up anything that needs to be done for this
|
symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for
|
symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for
|
forced local syms when non-shared is due to a historical quirk. */
|
forced local syms when non-shared is due to a historical quirk.
|
if ((h->dynindx != -1
|
STT_GNU_IFUNC symbol must go through PLT. */
|
|
if ((h->type == STT_GNU_IFUNC
|
|
&& h->def_regular
|
|
&& !finfo->info->relocatable)
|
|
|| ((h->dynindx != -1
|
|| h->forced_local)
|
|| h->forced_local)
|
&& ((finfo->info->shared
|
&& ((finfo->info->shared
|
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
|| h->root.type != bfd_link_hash_undefweak))
|
|| h->root.type != bfd_link_hash_undefweak))
|
|| !h->forced_local)
|
|| !h->forced_local)
|
&& elf_hash_table (finfo->info)->dynamic_sections_created)
|
&& elf_hash_table (finfo->info)->dynamic_sections_created))
|
{
|
{
|
if (! ((*bed->elf_backend_finish_dynamic_symbol)
|
if (! ((*bed->elf_backend_finish_dynamic_symbol)
|
(finfo->output_bfd, finfo->info, h, &sym)))
|
(finfo->output_bfd, finfo->info, h, &sym)))
|
{
|
{
|
eoinfo->failed = TRUE;
|
eoinfo->failed = TRUE;
|
Line 8610... |
Line 8719... |
&& h->ref_regular
|
&& h->ref_regular
|
&& (ELF_ST_BIND (sym.st_info) == STB_GLOBAL
|
&& (ELF_ST_BIND (sym.st_info) == STB_GLOBAL
|
|| ELF_ST_BIND (sym.st_info) == STB_WEAK))
|
|| ELF_ST_BIND (sym.st_info) == STB_WEAK))
|
{
|
{
|
int bindtype;
|
int bindtype;
|
|
unsigned int type = ELF_ST_TYPE (sym.st_info);
|
|
|
|
/* Turn an undefined IFUNC symbol into a normal FUNC symbol. */
|
|
if (type == STT_GNU_IFUNC)
|
|
type = STT_FUNC;
|
|
|
if (h->ref_regular_nonweak)
|
if (h->ref_regular_nonweak)
|
bindtype = STB_GLOBAL;
|
bindtype = STB_GLOBAL;
|
else
|
else
|
bindtype = STB_WEAK;
|
bindtype = STB_WEAK;
|
sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
|
sym.st_info = ELF_ST_INFO (bindtype, type);
|
}
|
}
|
|
|
|
/* If this is a symbol defined in a dynamic library, don't use the
|
|
symbol size from the dynamic library. Relinking an executable
|
|
against a new library may introduce gratuitous changes in the
|
|
executable's symbols if we keep the size. */
|
|
if (sym.st_shndx == SHN_UNDEF
|
|
&& !h->def_regular
|
|
&& h->def_dynamic)
|
|
sym.st_size = 0;
|
|
|
/* If a non-weak symbol with non-default visibility is not defined
|
/* If a non-weak symbol with non-default visibility is not defined
|
locally, it is a fatal error. */
|
locally, it is a fatal error. */
|
if (! finfo->info->relocatable
|
if (! finfo->info->relocatable
|
&& ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
|
&& ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
|
&& ELF_ST_BIND (sym.st_info) != STB_WEAK
|
&& ELF_ST_BIND (sym.st_info) != STB_WEAK
|
Line 8713... |
Line 8836... |
/* If we're stripping it, then it was just a dynamic symbol, and
|
/* If we're stripping it, then it was just a dynamic symbol, and
|
there's nothing else to do. */
|
there's nothing else to do. */
|
if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
|
if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
|
return TRUE;
|
return TRUE;
|
|
|
h->indx = bfd_get_symcount (finfo->output_bfd);
|
indx = bfd_get_symcount (finfo->output_bfd);
|
|
ret = elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h);
|
if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h))
|
if (ret == 0)
|
{
|
{
|
eoinfo->failed = TRUE;
|
eoinfo->failed = TRUE;
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
else if (ret == 1)
|
|
h->indx = indx;
|
|
else if (h->indx == -2)
|
|
abort();
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Return TRUE if special handling is done for relocs in SEC against
|
/* Return TRUE if special handling is done for relocs in SEC against
|
Line 8887... |
Line 9014... |
isym++, pindex++, ppsection++)
|
isym++, pindex++, ppsection++)
|
{
|
{
|
asection *isec;
|
asection *isec;
|
const char *name;
|
const char *name;
|
Elf_Internal_Sym osym;
|
Elf_Internal_Sym osym;
|
|
long indx;
|
|
int ret;
|
|
|
*pindex = -1;
|
*pindex = -1;
|
|
|
if (elf_bad_symtab (input_bfd))
|
if (elf_bad_symtab (input_bfd))
|
{
|
{
|
Line 8901... |
Line 9030... |
}
|
}
|
}
|
}
|
|
|
if (isym->st_shndx == SHN_UNDEF)
|
if (isym->st_shndx == SHN_UNDEF)
|
isec = bfd_und_section_ptr;
|
isec = bfd_und_section_ptr;
|
else if (isym->st_shndx < SHN_LORESERVE
|
|
|| isym->st_shndx > SHN_HIRESERVE)
|
|
{
|
|
isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
|
|
if (isec
|
|
&& isec->sec_info_type == ELF_INFO_TYPE_MERGE
|
|
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION)
|
|
isym->st_value =
|
|
_bfd_merged_section_offset (output_bfd, &isec,
|
|
elf_section_data (isec)->sec_info,
|
|
isym->st_value);
|
|
}
|
|
else if (isym->st_shndx == SHN_ABS)
|
else if (isym->st_shndx == SHN_ABS)
|
isec = bfd_abs_section_ptr;
|
isec = bfd_abs_section_ptr;
|
else if (isym->st_shndx == SHN_COMMON)
|
else if (isym->st_shndx == SHN_COMMON)
|
isec = bfd_com_section_ptr;
|
isec = bfd_com_section_ptr;
|
else
|
else
|
{
|
{
|
|
isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
|
|
if (isec == NULL)
|
|
{
|
/* Don't attempt to output symbols with st_shnx in the
|
/* Don't attempt to output symbols with st_shnx in the
|
reserved range other than SHN_ABS and SHN_COMMON. */
|
reserved range other than SHN_ABS and SHN_COMMON. */
|
*ppsection = NULL;
|
*ppsection = NULL;
|
continue;
|
continue;
|
}
|
}
|
|
else if (isec->sec_info_type == ELF_INFO_TYPE_MERGE
|
|
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION)
|
|
isym->st_value =
|
|
_bfd_merged_section_offset (output_bfd, &isec,
|
|
elf_section_data (isec)->sec_info,
|
|
isym->st_value);
|
|
}
|
|
|
*ppsection = isec;
|
*ppsection = isec;
|
|
|
/* Don't output the first, undefined, symbol. */
|
/* Don't output the first, undefined, symbol. */
|
if (ppsection == finfo->sections)
|
if (ppsection == finfo->sections)
|
Line 8955... |
Line 9082... |
continue;
|
continue;
|
|
|
/* If this symbol is defined in a section which we are
|
/* If this symbol is defined in a section which we are
|
discarding, we don't need to keep it. */
|
discarding, we don't need to keep it. */
|
if (isym->st_shndx != SHN_UNDEF
|
if (isym->st_shndx != SHN_UNDEF
|
&& (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
|
&& isym->st_shndx < SHN_LORESERVE
|
&& (isec == NULL
|
&& bfd_section_removed_from_list (output_bfd,
|
|| bfd_section_removed_from_list (output_bfd,
|
isec->output_section))
|
isec->output_section)))
|
|
continue;
|
continue;
|
|
|
/* Get the name of the symbol. */
|
/* Get the name of the symbol. */
|
name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link,
|
name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link,
|
isym->st_name);
|
isym->st_name);
|
Line 8977... |
Line 9103... |
&& (isec->flags & SEC_MERGE) && ! finfo->info->relocatable)
|
&& (isec->flags & SEC_MERGE) && ! finfo->info->relocatable)
|
|| finfo->info->discard == discard_l)
|
|| finfo->info->discard == discard_l)
|
&& bfd_is_local_label_name (input_bfd, name)))
|
&& bfd_is_local_label_name (input_bfd, name)))
|
continue;
|
continue;
|
|
|
/* If we get here, we are going to output this symbol. */
|
|
|
|
osym = *isym;
|
osym = *isym;
|
|
|
/* Adjust the section index for the output file. */
|
/* Adjust the section index for the output file. */
|
osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
|
osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
|
isec->output_section);
|
isec->output_section);
|
if (osym.st_shndx == SHN_BAD)
|
if (osym.st_shndx == SHN_BAD)
|
return FALSE;
|
return FALSE;
|
|
|
*pindex = bfd_get_symcount (output_bfd);
|
|
|
|
/* ELF symbols in relocatable files are section relative, but
|
/* ELF symbols in relocatable files are section relative, but
|
in executable files they are virtual addresses. Note that
|
in executable files they are virtual addresses. Note that
|
this code assumes that all ELF sections have an associated
|
this code assumes that all ELF sections have an associated
|
BFD section with a reasonable value for output_offset; below
|
BFD section with a reasonable value for output_offset; below
|
we assume that they also have a reasonable value for
|
we assume that they also have a reasonable value for
|
Line 9008... |
Line 9130... |
BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
|
BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
|
osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
|
osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
|
}
|
}
|
}
|
}
|
|
|
if (! elf_link_output_sym (finfo, name, &osym, isec, NULL))
|
indx = bfd_get_symcount (output_bfd);
|
|
ret = elf_link_output_sym (finfo, name, &osym, isec, NULL);
|
|
if (ret == 0)
|
return FALSE;
|
return FALSE;
|
|
else if (ret == 1)
|
|
*pindex = indx;
|
}
|
}
|
|
|
/* Relocate the contents of each section. */
|
/* Relocate the contents of each section. */
|
sym_hashes = elf_sym_hashes (input_bfd);
|
sym_hashes = elf_sym_hashes (input_bfd);
|
for (o = input_bfd->sections; o != NULL; o = o->next)
|
for (o = input_bfd->sections; o != NULL; o = o->next)
|
Line 9024... |
Line 9150... |
{
|
{
|
/* This section was omitted from the link. */
|
/* This section was omitted from the link. */
|
continue;
|
continue;
|
}
|
}
|
|
|
|
if (finfo->info->relocatable
|
|
&& (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
|
|
{
|
|
/* Deal with the group signature symbol. */
|
|
struct bfd_elf_section_data *sec_data = elf_section_data (o);
|
|
unsigned long symndx = sec_data->this_hdr.sh_info;
|
|
asection *osec = o->output_section;
|
|
|
|
if (symndx >= locsymcount
|
|
|| (elf_bad_symtab (input_bfd)
|
|
&& finfo->sections[symndx] == NULL))
|
|
{
|
|
struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff];
|
|
while (h->root.type == bfd_link_hash_indirect
|
|
|| h->root.type == bfd_link_hash_warning)
|
|
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
|
/* Arrange for symbol to be output. */
|
|
h->indx = -2;
|
|
elf_section_data (osec)->this_hdr.sh_info = -2;
|
|
}
|
|
else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION)
|
|
{
|
|
/* We'll use the output section target_index. */
|
|
asection *sec = finfo->sections[symndx]->output_section;
|
|
elf_section_data (osec)->this_hdr.sh_info = sec->target_index;
|
|
}
|
|
else
|
|
{
|
|
if (finfo->indices[symndx] == -1)
|
|
{
|
|
/* Otherwise output the local symbol now. */
|
|
Elf_Internal_Sym sym = isymbuf[symndx];
|
|
asection *sec = finfo->sections[symndx]->output_section;
|
|
const char *name;
|
|
long indx;
|
|
int ret;
|
|
|
|
name = bfd_elf_string_from_elf_section (input_bfd,
|
|
symtab_hdr->sh_link,
|
|
sym.st_name);
|
|
if (name == NULL)
|
|
return FALSE;
|
|
|
|
sym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
|
|
sec);
|
|
if (sym.st_shndx == SHN_BAD)
|
|
return FALSE;
|
|
|
|
sym.st_value += o->output_offset;
|
|
|
|
indx = bfd_get_symcount (output_bfd);
|
|
ret = elf_link_output_sym (finfo, name, &sym, o, NULL);
|
|
if (ret == 0)
|
|
return FALSE;
|
|
else if (ret == 1)
|
|
finfo->indices[symndx] = indx;
|
|
else
|
|
abort ();
|
|
}
|
|
elf_section_data (osec)->this_hdr.sh_info
|
|
= finfo->indices[symndx];
|
|
}
|
|
}
|
|
|
if ((o->flags & SEC_HAS_CONTENTS) == 0
|
if ((o->flags & SEC_HAS_CONTENTS) == 0
|
|| (o->size == 0 && (o->flags & SEC_RELOC) == 0))
|
|| (o->size == 0 && (o->flags & SEC_RELOC) == 0))
|
continue;
|
continue;
|
|
|
if ((o->flags & SEC_LINKER_CREATED) != 0)
|
if ((o->flags & SEC_LINKER_CREATED) != 0)
|
Line 9146... |
Line 9336... |
ps = &finfo->sections[r_symndx];
|
ps = &finfo->sections[r_symndx];
|
sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr,
|
sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr,
|
sym, *ps);
|
sym, *ps);
|
}
|
}
|
|
|
if (s_type == STT_RELC || s_type == STT_SRELC)
|
if ((s_type == STT_RELC || s_type == STT_SRELC)
|
|
&& !finfo->info->relocatable)
|
{
|
{
|
bfd_vma val;
|
bfd_vma val;
|
bfd_vma dot = (rel->r_offset
|
bfd_vma dot = (rel->r_offset
|
+ o->output_offset + o->output_section->vma);
|
+ o->output_offset + o->output_section->vma);
|
#ifdef DEBUG
|
#ifdef DEBUG
|
Line 9407... |
Line 9598... |
if (finfo->indices[r_symndx] == -1)
|
if (finfo->indices[r_symndx] == -1)
|
{
|
{
|
unsigned long shlink;
|
unsigned long shlink;
|
const char *name;
|
const char *name;
|
asection *osec;
|
asection *osec;
|
|
long indx;
|
|
|
if (finfo->info->strip == strip_all)
|
if (finfo->info->strip == strip_all)
|
{
|
{
|
/* You can't do ld -r -s. */
|
/* You can't do ld -r -s. */
|
bfd_set_error (bfd_error_invalid_operation);
|
bfd_set_error (bfd_error_invalid_operation);
|
Line 9446... |
Line 9638... |
sym.st_value -= (elf_hash_table (finfo->info)
|
sym.st_value -= (elf_hash_table (finfo->info)
|
->tls_sec->vma);
|
->tls_sec->vma);
|
}
|
}
|
}
|
}
|
|
|
finfo->indices[r_symndx]
|
indx = bfd_get_symcount (output_bfd);
|
= bfd_get_symcount (output_bfd);
|
ret = elf_link_output_sym (finfo, name, &sym, sec,
|
|
NULL);
|
if (! elf_link_output_sym (finfo, name, &sym, sec,
|
if (ret == 0)
|
NULL))
|
|
return FALSE;
|
return FALSE;
|
|
else if (ret == 1)
|
|
finfo->indices[r_symndx] = indx;
|
|
else
|
|
abort ();
|
}
|
}
|
|
|
r_symndx = finfo->indices[r_symndx];
|
r_symndx = finfo->indices[r_symndx];
|
}
|
}
|
|
|
Line 9514... |
Line 9709... |
return FALSE;
|
return FALSE;
|
}
|
}
|
break;
|
break;
|
default:
|
default:
|
{
|
{
|
|
/* FIXME: octets_per_byte. */
|
if (! (o->flags & SEC_EXCLUDE)
|
if (! (o->flags & SEC_EXCLUDE)
|
&& ! (o->output_section->flags & SEC_NEVER_LOAD)
|
&& ! (o->output_section->flags & SEC_NEVER_LOAD)
|
&& ! bfd_set_section_contents (output_bfd, o->output_section,
|
&& ! bfd_set_section_contents (output_bfd, o->output_section,
|
contents,
|
contents,
|
(file_ptr) o->output_offset,
|
(file_ptr) o->output_offset,
|
Line 9621... |
Line 9817... |
bfd_reloc_status_type rstat;
|
bfd_reloc_status_type rstat;
|
bfd_byte *buf;
|
bfd_byte *buf;
|
bfd_boolean ok;
|
bfd_boolean ok;
|
const char *sym_name;
|
const char *sym_name;
|
|
|
size = bfd_get_reloc_size (howto);
|
size = (bfd_size_type) bfd_get_reloc_size (howto);
|
buf = bfd_zmalloc (size);
|
buf = (bfd_byte *) bfd_zmalloc (size);
|
if (buf == NULL)
|
if (buf == NULL)
|
return FALSE;
|
return FALSE;
|
rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
|
rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
|
switch (rstat)
|
switch (rstat)
|
{
|
{
|
Line 9782... |
Line 9978... |
sub = s->owner;
|
sub = s->owner;
|
if (bfd_get_flavour (sub) == bfd_target_elf_flavour
|
if (bfd_get_flavour (sub) == bfd_target_elf_flavour
|
&& elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass
|
&& elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass
|
&& (elfsec = _bfd_elf_section_from_bfd_section (sub, s))
|
&& (elfsec = _bfd_elf_section_from_bfd_section (sub, s))
|
&& elfsec < elf_numsections (sub)
|
&& elfsec < elf_numsections (sub)
|
&& elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER)
|
&& elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER
|
|
&& elf_elfsections (sub)[elfsec]->sh_link < elf_numsections (sub))
|
{
|
{
|
seen_linkorder++;
|
seen_linkorder++;
|
linkorder_sec = s;
|
linkorder_sec = s;
|
}
|
}
|
else
|
else
|
Line 9836... |
Line 10033... |
{
|
{
|
s = sections[n]->u.indirect.section;
|
s = sections[n]->u.indirect.section;
|
offset &= ~(bfd_vma) 0 << s->alignment_power;
|
offset &= ~(bfd_vma) 0 << s->alignment_power;
|
s->output_offset = offset;
|
s->output_offset = offset;
|
sections[n]->offset = offset;
|
sections[n]->offset = offset;
|
|
/* FIXME: octets_per_byte. */
|
offset += sections[n]->size;
|
offset += sections[n]->size;
|
}
|
}
|
|
|
|
free (sections);
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
|
|
/* Do the final step of an ELF link. */
|
/* Do the final step of an ELF link. */
|
Line 9998... |
Line 10197... |
merged = TRUE;
|
merged = TRUE;
|
|
|
if (info->relocatable || info->emitrelocations)
|
if (info->relocatable || info->emitrelocations)
|
reloc_count = sec->reloc_count;
|
reloc_count = sec->reloc_count;
|
else if (bed->elf_backend_count_relocs)
|
else if (bed->elf_backend_count_relocs)
|
{
|
reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
|
Elf_Internal_Rela * relocs;
|
|
|
|
relocs = _bfd_elf_link_read_relocs (sec->owner, sec,
|
|
NULL, NULL,
|
|
info->keep_memory);
|
|
|
|
if (relocs != NULL)
|
|
{
|
|
reloc_count
|
|
= (*bed->elf_backend_count_relocs) (sec, relocs);
|
|
|
|
if (elf_section_data (sec)->relocs != relocs)
|
|
free (relocs);
|
|
}
|
|
}
|
|
|
|
if (sec->rawsize > max_contents_size)
|
if (sec->rawsize > max_contents_size)
|
max_contents_size = sec->rawsize;
|
max_contents_size = sec->rawsize;
|
if (sec->size > max_contents_size)
|
if (sec->size > max_contents_size)
|
max_contents_size = sec->size;
|
max_contents_size = sec->size;
|
Line 10071... |
Line 10255... |
{
|
{
|
bfd_boolean same_size;
|
bfd_boolean same_size;
|
bfd_size_type entsize1;
|
bfd_size_type entsize1;
|
|
|
entsize1 = esdi->rel_hdr.sh_entsize;
|
entsize1 = esdi->rel_hdr.sh_entsize;
|
|
/* PR 9827: If the header size has not been set yet then
|
|
assume that it will match the output section's reloc type. */
|
|
if (entsize1 == 0)
|
|
entsize1 = o->use_rela_p ? bed->s->sizeof_rela : bed->s->sizeof_rel;
|
|
else
|
BFD_ASSERT (entsize1 == bed->s->sizeof_rel
|
BFD_ASSERT (entsize1 == bed->s->sizeof_rel
|
|| entsize1 == bed->s->sizeof_rela);
|
|| entsize1 == bed->s->sizeof_rela);
|
same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_rel);
|
same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_rel);
|
|
|
if (!same_size)
|
if (!same_size)
|
Line 10170... |
Line 10359... |
/* sh_flags, sh_addr and sh_size all start off zero. */
|
/* sh_flags, sh_addr and sh_size all start off zero. */
|
symtab_hdr->sh_entsize = bed->s->sizeof_sym;
|
symtab_hdr->sh_entsize = bed->s->sizeof_sym;
|
/* sh_link is set in assign_section_numbers. */
|
/* sh_link is set in assign_section_numbers. */
|
/* sh_info is set below. */
|
/* sh_info is set below. */
|
/* sh_offset is set just below. */
|
/* sh_offset is set just below. */
|
symtab_hdr->sh_addralign = 1 << bed->s->log_file_align;
|
symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
|
|
|
off = elf_tdata (abfd)->next_file_pos;
|
off = elf_tdata (abfd)->next_file_pos;
|
off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
|
off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
|
|
|
/* Note that at this point elf_tdata (abfd)->next_file_pos is
|
/* Note that at this point elf_tdata (abfd)->next_file_pos is
|
Line 10187... |
Line 10376... |
finfo.symbuf_size = 20;
|
finfo.symbuf_size = 20;
|
else
|
else
|
finfo.symbuf_size = max_sym_count;
|
finfo.symbuf_size = max_sym_count;
|
amt = finfo.symbuf_size;
|
amt = finfo.symbuf_size;
|
amt *= bed->s->sizeof_sym;
|
amt *= bed->s->sizeof_sym;
|
finfo.symbuf = bfd_malloc (amt);
|
finfo.symbuf = (bfd_byte *) bfd_malloc (amt);
|
if (finfo.symbuf == NULL)
|
if (finfo.symbuf == NULL)
|
goto error_return;
|
goto error_return;
|
if (elf_numsections (abfd) > SHN_LORESERVE)
|
if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
|
{
|
{
|
/* Wild guess at number of output symbols. realloc'd as needed. */
|
/* Wild guess at number of output symbols. realloc'd as needed. */
|
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
|
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
|
finfo.shndxbuf_size = amt;
|
finfo.shndxbuf_size = amt;
|
amt *= sizeof (Elf_External_Sym_Shndx);
|
amt *= sizeof (Elf_External_Sym_Shndx);
|
finfo.symshndxbuf = bfd_zmalloc (amt);
|
finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
|
if (finfo.symshndxbuf == NULL)
|
if (finfo.symshndxbuf == NULL)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
/* Start writing out the symbol table. The first symbol is always a
|
/* Start writing out the symbol table. The first symbol is always a
|
Line 10211... |
Line 10400... |
elfsym.st_value = 0;
|
elfsym.st_value = 0;
|
elfsym.st_size = 0;
|
elfsym.st_size = 0;
|
elfsym.st_info = 0;
|
elfsym.st_info = 0;
|
elfsym.st_other = 0;
|
elfsym.st_other = 0;
|
elfsym.st_shndx = SHN_UNDEF;
|
elfsym.st_shndx = SHN_UNDEF;
|
if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
|
if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
|
NULL))
|
NULL) != 1)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
/* Output a symbol for each section. We output these even if we are
|
/* Output a symbol for each section. We output these even if we are
|
discarding local symbols, since they are used for relocs. These
|
discarding local symbols, since they are used for relocs. These
|
Line 10237... |
Line 10426... |
{
|
{
|
o->target_index = bfd_get_symcount (abfd);
|
o->target_index = bfd_get_symcount (abfd);
|
elfsym.st_shndx = i;
|
elfsym.st_shndx = i;
|
if (!info->relocatable)
|
if (!info->relocatable)
|
elfsym.st_value = o->vma;
|
elfsym.st_value = o->vma;
|
if (!elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
|
if (elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL) != 1)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
if (i == SHN_LORESERVE - 1)
|
|
i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
|
|
}
|
}
|
}
|
}
|
|
|
/* Allocate some memory to hold information read in from the input
|
/* Allocate some memory to hold information read in from the input
|
files. */
|
files. */
|
if (max_contents_size != 0)
|
if (max_contents_size != 0)
|
{
|
{
|
finfo.contents = bfd_malloc (max_contents_size);
|
finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
|
if (finfo.contents == NULL)
|
if (finfo.contents == NULL)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
if (max_external_reloc_size != 0)
|
if (max_external_reloc_size != 0)
|
Line 10265... |
Line 10452... |
|
|
if (max_internal_reloc_count != 0)
|
if (max_internal_reloc_count != 0)
|
{
|
{
|
amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
|
amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
|
amt *= sizeof (Elf_Internal_Rela);
|
amt *= sizeof (Elf_Internal_Rela);
|
finfo.internal_relocs = bfd_malloc (amt);
|
finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
|
if (finfo.internal_relocs == NULL)
|
if (finfo.internal_relocs == NULL)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
if (max_sym_count != 0)
|
if (max_sym_count != 0)
|
{
|
{
|
amt = max_sym_count * bed->s->sizeof_sym;
|
amt = max_sym_count * bed->s->sizeof_sym;
|
finfo.external_syms = bfd_malloc (amt);
|
finfo.external_syms = (bfd_byte *) bfd_malloc (amt);
|
if (finfo.external_syms == NULL)
|
if (finfo.external_syms == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
amt = max_sym_count * sizeof (Elf_Internal_Sym);
|
amt = max_sym_count * sizeof (Elf_Internal_Sym);
|
finfo.internal_syms = bfd_malloc (amt);
|
finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
|
if (finfo.internal_syms == NULL)
|
if (finfo.internal_syms == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
amt = max_sym_count * sizeof (long);
|
amt = max_sym_count * sizeof (long);
|
finfo.indices = bfd_malloc (amt);
|
finfo.indices = (long int *) bfd_malloc (amt);
|
if (finfo.indices == NULL)
|
if (finfo.indices == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
amt = max_sym_count * sizeof (asection *);
|
amt = max_sym_count * sizeof (asection *);
|
finfo.sections = bfd_malloc (amt);
|
finfo.sections = (asection **) bfd_malloc (amt);
|
if (finfo.sections == NULL)
|
if (finfo.sections == NULL)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
if (max_sym_shndx_count != 0)
|
if (max_sym_shndx_count != 0)
|
{
|
{
|
amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
|
amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
|
finfo.locsym_shndx = bfd_malloc (amt);
|
finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
|
if (finfo.locsym_shndx == NULL)
|
if (finfo.locsym_shndx == NULL)
|
goto error_return;
|
goto error_return;
|
}
|
}
|
|
|
if (elf_hash_table (info)->tls_sec)
|
if (elf_hash_table (info)->tls_sec)
|
Line 10415... |
Line 10602... |
|
|
/* If backend needs to output some local symbols not present in the hash
|
/* If backend needs to output some local symbols not present in the hash
|
table, do it now. */
|
table, do it now. */
|
if (bed->elf_backend_output_arch_local_syms)
|
if (bed->elf_backend_output_arch_local_syms)
|
{
|
{
|
typedef bfd_boolean (*out_sym_func)
|
typedef int (*out_sym_func)
|
(void *, const char *, Elf_Internal_Sym *, asection *,
|
(void *, const char *, Elf_Internal_Sym *, asection *,
|
struct elf_link_hash_entry *);
|
struct elf_link_hash_entry *);
|
|
|
if (! ((*bed->elf_backend_output_arch_local_syms)
|
if (! ((*bed->elf_backend_output_arch_local_syms)
|
(abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
|
(abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
|
Line 10488... |
Line 10675... |
/* Copy the internal symbol as is.
|
/* Copy the internal symbol as is.
|
Note that we saved a word of storage and overwrote
|
Note that we saved a word of storage and overwrote
|
the original st_name with the dynstr_index. */
|
the original st_name with the dynstr_index. */
|
sym = e->isym;
|
sym = e->isym;
|
|
|
if (e->isym.st_shndx != SHN_UNDEF
|
|
&& (e->isym.st_shndx < SHN_LORESERVE
|
|
|| e->isym.st_shndx > SHN_HIRESERVE))
|
|
{
|
|
s = bfd_section_from_elf_index (e->input_bfd,
|
s = bfd_section_from_elf_index (e->input_bfd,
|
e->isym.st_shndx);
|
e->isym.st_shndx);
|
|
if (s != NULL)
|
|
{
|
sym.st_shndx =
|
sym.st_shndx =
|
elf_section_data (s->output_section)->this_idx;
|
elf_section_data (s->output_section)->this_idx;
|
if (! check_dynsym (abfd, &sym))
|
if (! check_dynsym (abfd, &sym))
|
return FALSE;
|
return FALSE;
|
sym.st_value = (s->output_section->vma
|
sym.st_value = (s->output_section->vma
|
Line 10529... |
Line 10713... |
|
|
/* If backend needs to output some symbols not present in the hash
|
/* If backend needs to output some symbols not present in the hash
|
table, do it now. */
|
table, do it now. */
|
if (bed->elf_backend_output_arch_syms)
|
if (bed->elf_backend_output_arch_syms)
|
{
|
{
|
typedef bfd_boolean (*out_sym_func)
|
typedef int (*out_sym_func)
|
(void *, const char *, Elf_Internal_Sym *, asection *,
|
(void *, const char *, Elf_Internal_Sym *, asection *,
|
struct elf_link_hash_entry *);
|
struct elf_link_hash_entry *);
|
|
|
if (! ((*bed->elf_backend_output_arch_syms)
|
if (! ((*bed->elf_backend_output_arch_syms)
|
(abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
|
(abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
|
Line 10664... |
Line 10848... |
FALSE, FALSE, TRUE);
|
FALSE, FALSE, TRUE);
|
if (h != NULL
|
if (h != NULL
|
&& (h->root.type == bfd_link_hash_defined
|
&& (h->root.type == bfd_link_hash_defined
|
|| h->root.type == bfd_link_hash_defweak))
|
|| h->root.type == bfd_link_hash_defweak))
|
{
|
{
|
dyn.d_un.d_val = h->root.u.def.value;
|
dyn.d_un.d_ptr = h->root.u.def.value;
|
o = h->root.u.def.section;
|
o = h->root.u.def.section;
|
if (o->output_section != NULL)
|
if (o->output_section != NULL)
|
dyn.d_un.d_val += (o->output_section->vma
|
dyn.d_un.d_ptr += (o->output_section->vma
|
+ o->output_offset);
|
+ o->output_offset);
|
else
|
else
|
{
|
{
|
/* The symbol is imported from another shared
|
/* The symbol is imported from another shared
|
library and does not apply to this one. */
|
library and does not apply to this one. */
|
dyn.d_un.d_val = 0;
|
dyn.d_un.d_ptr = 0;
|
}
|
}
|
break;
|
break;
|
}
|
}
|
}
|
}
|
continue;
|
continue;
|
Line 10752... |
Line 10936... |
if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ)
|
if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ)
|
type = SHT_REL;
|
type = SHT_REL;
|
else
|
else
|
type = SHT_RELA;
|
type = SHT_RELA;
|
dyn.d_un.d_val = 0;
|
dyn.d_un.d_val = 0;
|
|
dyn.d_un.d_ptr = 0;
|
for (i = 1; i < elf_numsections (abfd); i++)
|
for (i = 1; i < elf_numsections (abfd); i++)
|
{
|
{
|
Elf_Internal_Shdr *hdr;
|
Elf_Internal_Shdr *hdr;
|
|
|
hdr = elf_elfsections (abfd)[i];
|
hdr = elf_elfsections (abfd)[i];
|
Line 10764... |
Line 10949... |
{
|
{
|
if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
|
if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
|
dyn.d_un.d_val += hdr->sh_size;
|
dyn.d_un.d_val += hdr->sh_size;
|
else
|
else
|
{
|
{
|
if (dyn.d_un.d_val == 0
|
if (dyn.d_un.d_ptr == 0
|
|| hdr->sh_addr < dyn.d_un.d_val)
|
|| hdr->sh_addr < dyn.d_un.d_ptr)
|
dyn.d_un.d_val = hdr->sh_addr;
|
dyn.d_un.d_ptr = hdr->sh_addr;
|
}
|
}
|
}
|
}
|
}
|
}
|
break;
|
break;
|
}
|
}
|
Line 10828... |
Line 11013... |
continue;
|
continue;
|
if ((elf_section_data (o->output_section)->this_hdr.sh_type
|
if ((elf_section_data (o->output_section)->this_hdr.sh_type
|
!= SHT_STRTAB)
|
!= SHT_STRTAB)
|
|| strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
|
|| strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
|
{
|
{
|
|
/* FIXME: octets_per_byte. */
|
if (! bfd_set_section_contents (abfd, o->output_section,
|
if (! bfd_set_section_contents (abfd, o->output_section,
|
o->contents,
|
o->contents,
|
(file_ptr) o->output_offset,
|
(file_ptr) o->output_offset,
|
o->size))
|
o->size))
|
goto error_return;
|
goto error_return;
|
Line 10902... |
Line 11088... |
|
|
elf_tdata (abfd)->linker = TRUE;
|
elf_tdata (abfd)->linker = TRUE;
|
|
|
if (attr_section)
|
if (attr_section)
|
{
|
{
|
bfd_byte *contents = bfd_malloc (attr_size);
|
bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
|
if (contents == NULL)
|
if (contents == NULL)
|
return FALSE; /* Bail out and fail. */
|
return FALSE; /* Bail out and fail. */
|
bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
|
bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
|
bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
|
bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
|
free (contents);
|
free (contents);
|
Line 11244... |
Line 11430... |
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)
|
&& !h->root.u.def.section->gc_mark
|
&& !h->root.u.def.section->gc_mark
|
&& !(h->root.u.def.section->owner->flags & DYNAMIC))
|
&& !(h->root.u.def.section->owner->flags & DYNAMIC))
|
{
|
{
|
struct elf_gc_sweep_symbol_info *inf = data;
|
struct elf_gc_sweep_symbol_info *inf =
|
|
(struct elf_gc_sweep_symbol_info *) data;
|
(*inf->hide_symbol) (inf->info, h, TRUE);
|
(*inf->hide_symbol) (inf->info, h, TRUE);
|
}
|
}
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
Line 11274... |
Line 11461... |
if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
|
if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
|
continue;
|
continue;
|
|
|
for (o = sub->sections; o != NULL; o = o->next)
|
for (o = sub->sections; o != NULL; o = o->next)
|
{
|
{
|
/* Keep debug and special sections. */
|
/* When any section in a section group is kept, we keep all
|
if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
|
sections in the section group. If the first member of
|
|
the section group is excluded, we will also exclude the
|
|
group section. */
|
|
if (o->flags & SEC_GROUP)
|
|
{
|
|
asection *first = elf_next_in_group (o);
|
|
o->gc_mark = first->gc_mark;
|
|
}
|
|
else if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
|
|| (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
|
|| (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
|
|
{
|
|
/* Keep debug and special sections. */
|
o->gc_mark = 1;
|
o->gc_mark = 1;
|
|
}
|
|
|
if (o->gc_mark)
|
if (o->gc_mark)
|
continue;
|
continue;
|
|
|
/* Skip sweeping sections already excluded. */
|
/* Skip sweeping sections already excluded. */
|
Line 11614... |
Line 11812... |
return FALSE;
|
return FALSE;
|
|
|
win:
|
win:
|
if (!child->vtable)
|
if (!child->vtable)
|
{
|
{
|
child->vtable = bfd_zalloc (abfd, sizeof (*child->vtable));
|
child->vtable = (struct elf_link_virtual_table_entry *)
|
|
bfd_zalloc (abfd, sizeof (*child->vtable));
|
if (!child->vtable)
|
if (!child->vtable)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
if (!h)
|
if (!h)
|
{
|
{
|
Line 11646... |
Line 11845... |
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
unsigned int log_file_align = bed->s->log_file_align;
|
unsigned int log_file_align = bed->s->log_file_align;
|
|
|
if (!h->vtable)
|
if (!h->vtable)
|
{
|
{
|
h->vtable = bfd_zalloc (abfd, sizeof (*h->vtable));
|
h->vtable = (struct elf_link_virtual_table_entry *)
|
|
bfd_zalloc (abfd, sizeof (*h->vtable));
|
if (!h->vtable)
|
if (!h->vtable)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
if (addend >= h->vtable->size)
|
if (addend >= h->vtable->size)
|
Line 11679... |
Line 11879... |
consolidation pass. */
|
consolidation pass. */
|
bytes = ((size >> log_file_align) + 1) * sizeof (bfd_boolean);
|
bytes = ((size >> log_file_align) + 1) * sizeof (bfd_boolean);
|
|
|
if (ptr)
|
if (ptr)
|
{
|
{
|
ptr = bfd_realloc (ptr - 1, bytes);
|
ptr = (bfd_boolean *) bfd_realloc (ptr - 1, bytes);
|
|
|
if (ptr != NULL)
|
if (ptr != NULL)
|
{
|
{
|
size_t oldbytes;
|
size_t oldbytes;
|
|
|
Line 11691... |
Line 11891... |
* sizeof (bfd_boolean));
|
* sizeof (bfd_boolean));
|
memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes);
|
memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes);
|
}
|
}
|
}
|
}
|
else
|
else
|
ptr = bfd_zmalloc (bytes);
|
ptr = (bfd_boolean *) bfd_zmalloc (bytes);
|
|
|
if (ptr == NULL)
|
if (ptr == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
/* And arrange for that done flag to be at index -1. */
|
/* And arrange for that done flag to be at index -1. */
|
Line 11708... |
Line 11908... |
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
struct alloc_got_off_arg {
|
struct alloc_got_off_arg {
|
bfd_vma gotoff;
|
bfd_vma gotoff;
|
unsigned int got_elt_size;
|
struct bfd_link_info *info;
|
};
|
};
|
|
|
/* We need a special top-level link routine to convert got reference counts
|
/* We need a special top-level link routine to convert got reference counts
|
to real got offsets. */
|
to real got offsets. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
|
elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
|
{
|
{
|
struct alloc_got_off_arg *gofarg = arg;
|
struct alloc_got_off_arg *gofarg = (struct alloc_got_off_arg *) arg;
|
|
bfd *obfd = gofarg->info->output_bfd;
|
|
const struct elf_backend_data *bed = get_elf_backend_data (obfd);
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
|
|
if (h->got.refcount > 0)
|
if (h->got.refcount > 0)
|
{
|
{
|
h->got.offset = gofarg->gotoff;
|
h->got.offset = gofarg->gotoff;
|
gofarg->gotoff += gofarg->got_elt_size;
|
gofarg->gotoff += bed->got_elt_size (obfd, gofarg->info, h, NULL, 0);
|
}
|
}
|
else
|
else
|
h->got.offset = (bfd_vma) -1;
|
h->got.offset = (bfd_vma) -1;
|
|
|
return TRUE;
|
return TRUE;
|
Line 11743... |
Line 11945... |
struct bfd_link_info *info)
|
struct bfd_link_info *info)
|
{
|
{
|
bfd *i;
|
bfd *i;
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
bfd_vma gotoff;
|
bfd_vma gotoff;
|
unsigned int got_elt_size = bed->s->arch_size / 8;
|
|
struct alloc_got_off_arg gofarg;
|
struct alloc_got_off_arg gofarg;
|
|
|
|
BFD_ASSERT (abfd == info->output_bfd);
|
|
|
if (! is_elf_hash_table (info->hash))
|
if (! is_elf_hash_table (info->hash))
|
return FALSE;
|
return FALSE;
|
|
|
/* The GOT offset is relative to the .got section, but the GOT header is
|
/* The GOT offset is relative to the .got section, but the GOT header is
|
put into the .got.plt section, if the backend uses it. */
|
put into the .got.plt section, if the backend uses it. */
|
Line 11781... |
Line 11984... |
for (j = 0; j < locsymcount; ++j)
|
for (j = 0; j < locsymcount; ++j)
|
{
|
{
|
if (local_got[j] > 0)
|
if (local_got[j] > 0)
|
{
|
{
|
local_got[j] = gotoff;
|
local_got[j] = gotoff;
|
gotoff += got_elt_size;
|
gotoff += bed->got_elt_size (abfd, info, NULL, i, j);
|
}
|
}
|
else
|
else
|
local_got[j] = (bfd_vma) -1;
|
local_got[j] = (bfd_vma) -1;
|
}
|
}
|
}
|
}
|
|
|
/* Then the global .got entries. .plt refcounts are handled by
|
/* Then the global .got entries. .plt refcounts are handled by
|
adjust_dynamic_symbol */
|
adjust_dynamic_symbol */
|
gofarg.gotoff = gotoff;
|
gofarg.gotoff = gotoff;
|
gofarg.got_elt_size = got_elt_size;
|
gofarg.info = info;
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_link_hash_traverse (elf_hash_table (info),
|
elf_gc_allocate_got_offsets,
|
elf_gc_allocate_got_offsets,
|
&gofarg);
|
&gofarg);
|
return TRUE;
|
return TRUE;
|
}
|
}
|
Line 11814... |
Line 12017... |
}
|
}
|
|
|
bfd_boolean
|
bfd_boolean
|
bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
|
bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
|
{
|
{
|
struct elf_reloc_cookie *rcookie = cookie;
|
struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *) cookie;
|
|
|
if (rcookie->bad_symtab)
|
if (rcookie->bad_symtab)
|
rcookie->rel = rcookie->rels;
|
rcookie->rel = rcookie->rels;
|
|
|
for (; rcookie->rel < rcookie->relend; rcookie->rel++)
|
for (; rcookie->rel < rcookie->relend; rcookie->rel++)
|
Line 11861... |
Line 12064... |
asection *isec;
|
asection *isec;
|
Elf_Internal_Sym *isym;
|
Elf_Internal_Sym *isym;
|
|
|
/* Need to: get the symbol; get the section. */
|
/* Need to: get the symbol; get the section. */
|
isym = &rcookie->locsyms[r_symndx];
|
isym = &rcookie->locsyms[r_symndx];
|
if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
|
|
{
|
|
isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
|
isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
|
if (isec != NULL && elf_discarded_section (isec))
|
if (isec != NULL && elf_discarded_section (isec))
|
return TRUE;
|
return TRUE;
|
}
|
}
|
}
|
|
return FALSE;
|
return FALSE;
|
}
|
}
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
Line 11966... |
Line 12166... |
ret = TRUE;
|
ret = TRUE;
|
|
|
return ret;
|
return ret;
|
}
|
}
|
|
|
|
/* For a SHT_GROUP section, return the group signature. For other
|
|
sections, return the normal section name. */
|
|
|
|
static const char *
|
|
section_signature (asection *sec)
|
|
{
|
|
if ((sec->flags & SEC_GROUP) != 0
|
|
&& elf_next_in_group (sec) != NULL
|
|
&& elf_group_name (elf_next_in_group (sec)) != NULL)
|
|
return elf_group_name (elf_next_in_group (sec));
|
|
return sec->name;
|
|
}
|
|
|
void
|
void
|
_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section *sec,
|
_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
struct bfd_link_info *info)
|
struct bfd_link_info *info)
|
{
|
{
|
flagword flags;
|
flagword flags;
|
const char *name, *p;
|
const char *name, *p;
|
struct bfd_section_already_linked *l;
|
struct bfd_section_already_linked *l;
|
Line 12007... |
Line 12220... |
|
|
Also, not merging link once sections in a relocatable link
|
Also, not merging link once sections in a relocatable link
|
causes trouble for MIPS ELF, which relies on link once semantics
|
causes trouble for MIPS ELF, which relies on link once semantics
|
to handle the .reginfo section correctly. */
|
to handle the .reginfo section correctly. */
|
|
|
name = bfd_get_section_name (abfd, sec);
|
name = section_signature (sec);
|
|
|
if (CONST_STRNEQ (name, ".gnu.linkonce.")
|
if (CONST_STRNEQ (name, ".gnu.linkonce.")
|
&& (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
|
&& (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
|
p++;
|
p++;
|
else
|
else
|
Line 12022... |
Line 12235... |
for (l = already_linked_list->entry; l != NULL; l = l->next)
|
for (l = already_linked_list->entry; l != NULL; l = l->next)
|
{
|
{
|
/* We may have 2 different types of sections on the list: group
|
/* We may have 2 different types of sections on the list: group
|
sections and linkonce sections. Match like sections. */
|
sections and linkonce sections. Match like sections. */
|
if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
|
if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
|
&& strcmp (name, l->sec->name) == 0
|
&& strcmp (name, section_signature (l->sec)) == 0
|
&& bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
|
&& bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
|
{
|
{
|
/* The section has already been linked. See if we should
|
/* The section has already been linked. See if we should
|
issue a warning. */
|
issue a warning. */
|
switch (flags & SEC_LINK_DUPLICATES)
|
switch (flags & SEC_LINK_DUPLICATES)
|
Line 12145... |
Line 12358... |
sec->kept_section = first;
|
sec->kept_section = first;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
|
/* Do not complain on unresolved relocations in `.gnu.linkonce.r.F'
|
|
referencing its discarded `.gnu.linkonce.t.F' counterpart - g++-3.4
|
|
specific as g++-4.x is using COMDAT groups (without the `.gnu.linkonce'
|
|
prefix) instead. `.gnu.linkonce.r.*' were the `.rodata' part of its
|
|
matching `.gnu.linkonce.t.*'. If `.gnu.linkonce.r.F' is not discarded
|
|
but its `.gnu.linkonce.t.F' is discarded means we chose one-only
|
|
`.gnu.linkonce.t.F' section from a different bfd not requiring any
|
|
`.gnu.linkonce.r.F'. Thus `.gnu.linkonce.r.F' should be discarded.
|
|
The reverse order cannot happen as there is never a bfd with only the
|
|
`.gnu.linkonce.r.F' section. The order of sections in a bfd does not
|
|
matter as here were are looking only for cross-bfd sections. */
|
|
|
|
if ((flags & SEC_GROUP) == 0 && CONST_STRNEQ (name, ".gnu.linkonce.r."))
|
|
for (l = already_linked_list->entry; l != NULL; l = l->next)
|
|
if ((l->sec->flags & SEC_GROUP) == 0
|
|
&& CONST_STRNEQ (l->sec->name, ".gnu.linkonce.t."))
|
|
{
|
|
if (abfd != l->sec->owner)
|
|
sec->output_section = bfd_abs_section_ptr;
|
|
break;
|
|
}
|
|
|
/* This is the first section with this name. Record it. */
|
/* This is the first section with this name. Record it. */
|
if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
|
if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
|
info->callbacks->einfo (_("%F%P: already_linked_table: %E"));
|
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
|
}
|
}
|
|
|
bfd_boolean
|
bfd_boolean
|
_bfd_elf_common_definition (Elf_Internal_Sym *sym)
|
_bfd_elf_common_definition (Elf_Internal_Sym *sym)
|
{
|
{
|
Line 12168... |
Line 12403... |
_bfd_elf_common_section (asection *sec ATTRIBUTE_UNUSED)
|
_bfd_elf_common_section (asection *sec ATTRIBUTE_UNUSED)
|
{
|
{
|
return bfd_com_section_ptr;
|
return bfd_com_section_ptr;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
bfd_vma
|
|
_bfd_elf_default_got_elt_size (bfd *abfd,
|
|
struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
|
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
|
|
bfd *ibfd ATTRIBUTE_UNUSED,
|
|
unsigned long symndx ATTRIBUTE_UNUSED)
|
|
{
|
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
|
return bed->s->arch_size / 8;
|
|
}
|
|
|
|
/* Routines to support the creation of dynamic relocs. */
|
|
|
|
/* Return true if NAME is a name of a relocation
|
|
section associated with section S. */
|
|
|
|
static bfd_boolean
|
|
is_reloc_section (bfd_boolean rela, const char * name, asection * s)
|
|
{
|
|
if (rela)
|
|
return CONST_STRNEQ (name, ".rela")
|
|
&& strcmp (bfd_get_section_name (NULL, s), name + 5) == 0;
|
|
|
|
return CONST_STRNEQ (name, ".rel")
|
|
&& strcmp (bfd_get_section_name (NULL, s), name + 4) == 0;
|
|
}
|
|
|
|
/* Returns the name of the dynamic reloc section associated with SEC. */
|
|
|
|
static const char *
|
|
get_dynamic_reloc_section_name (bfd * abfd,
|
|
asection * sec,
|
|
bfd_boolean is_rela)
|
|
{
|
|
const char * name;
|
|
unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
|
|
unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
|
|
|
|
name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
|
|
if (name == NULL)
|
|
return NULL;
|
|
|
|
if (! is_reloc_section (is_rela, name, sec))
|
|
{
|
|
static bfd_boolean complained = FALSE;
|
|
|
|
if (! complained)
|
|
{
|
|
(*_bfd_error_handler)
|
|
(_("%B: bad relocation section name `%s\'"), abfd, name);
|
|
complained = TRUE;
|
|
}
|
|
name = NULL;
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
/* Returns the dynamic reloc section associated with SEC.
|
|
If necessary compute the name of the dynamic reloc section based
|
|
on SEC's name (looked up in ABFD's string table) and the setting
|
|
of IS_RELA. */
|
|
|
|
asection *
|
|
_bfd_elf_get_dynamic_reloc_section (bfd * abfd,
|
|
asection * sec,
|
|
bfd_boolean is_rela)
|
|
{
|
|
asection * reloc_sec = elf_section_data (sec)->sreloc;
|
|
|
|
if (reloc_sec == NULL)
|
|
{
|
|
const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela);
|
|
|
|
if (name != NULL)
|
|
{
|
|
reloc_sec = bfd_get_section_by_name (abfd, name);
|
|
|
|
if (reloc_sec != NULL)
|
|
elf_section_data (sec)->sreloc = reloc_sec;
|
|
}
|
|
}
|
|
|
|
return reloc_sec;
|
|
}
|
|
|
|
/* Returns the dynamic reloc section associated with SEC. If the
|
|
section does not exist it is created and attached to the DYNOBJ
|
|
bfd and stored in the SRELOC field of SEC's elf_section_data
|
|
structure.
|
|
|
|
ALIGNMENT is the alignment for the newly created section and
|
|
IS_RELA defines whether the name should be .rela.<SEC's name>
|
|
or .rel.<SEC's name>. The section name is looked up in the
|
|
string table associated with ABFD. */
|
|
|
|
asection *
|
|
_bfd_elf_make_dynamic_reloc_section (asection * sec,
|
|
bfd * dynobj,
|
|
unsigned int alignment,
|
|
bfd * abfd,
|
|
bfd_boolean is_rela)
|
|
{
|
|
asection * reloc_sec = elf_section_data (sec)->sreloc;
|
|
|
|
if (reloc_sec == NULL)
|
|
{
|
|
const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela);
|
|
|
|
if (name == NULL)
|
|
return NULL;
|
|
|
|
reloc_sec = bfd_get_section_by_name (dynobj, name);
|
|
|
|
if (reloc_sec == NULL)
|
|
{
|
|
flagword flags;
|
|
|
|
flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
|
if ((sec->flags & SEC_ALLOC) != 0)
|
|
flags |= SEC_ALLOC | SEC_LOAD;
|
|
|
|
reloc_sec = bfd_make_section_with_flags (dynobj, name, flags);
|
|
if (reloc_sec != NULL)
|
|
{
|
|
if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
|
|
reloc_sec = NULL;
|
|
}
|
|
}
|
|
|
|
elf_section_data (sec)->sreloc = reloc_sec;
|
|
}
|
|
|
|
return reloc_sec;
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|