/* ELF linking support for BFD.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
}
s = bfd_make_section_with_flags (abfd,
- (bed->default_use_rela_p
+ (bed->rela_plts_and_copies_p
? ".rela.plt" : ".rel.plt"),
flags | SEC_READONLY);
if (s == NULL
if (! info->shared)
{
s = bfd_make_section_with_flags (abfd,
- (bed->default_use_rela_p
+ (bed->rela_plts_and_copies_p
? ".rela.bss" : ".rel.bss"),
flags | SEC_READONLY);
if (s == NULL
&& (h->type == STT_OBJECT
|| (sym != NULL
&& ELF_ST_TYPE (sym->st_info) == STT_OBJECT)))
- || (d != NULL
+ || (d != NULL
&& h->root.type == bfd_link_hash_new
&& (*d->match) (&d->head, NULL, h->root.root.string)))
h->dynamic = 1;
break;
case bfd_link_hash_indirect:
/* We had a versioned symbol in a dynamic library. We make the
- the versioned symbol point to this one. */
+ the versioned symbol point to this one. */
bed = get_elf_backend_data (output_bfd);
hv = h;
while (hv->root.type == bfd_link_hash_indirect
}
if (entry->isym.st_shndx != SHN_UNDEF
- && (entry->isym.st_shndx < SHN_LORESERVE
- || entry->isym.st_shndx > SHN_HIRESERVE))
+ && entry->isym.st_shndx < SHN_LORESERVE)
{
asection *s;
int bind;
bfd *oldbfd;
bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
- bfd_boolean newweak, oldweak;
+ bfd_boolean newweak, oldweak, newfunc, oldfunc;
const struct elf_backend_data *bed;
*skip = FALSE;
return FALSE;
*sym_hash = h;
+ bed = get_elf_backend_data (abfd);
+
/* This code is for coping with dynamic objects, and is only useful
if we are doing an ELF link. */
- if (info->hash->creator != abfd->xvec)
+ if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
return TRUE;
/* For merging, we only care about real symbols. */
&& h->root.type != bfd_link_hash_undefweak
&& 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
definition with the default version, we skip it if its type and
the type of existing regular definition mismatch. We only do it
&& ELF_ST_TYPE (sym->st_info) != h->type
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
&& h->type != STT_NOTYPE
- && !(bed->is_function_type (ELF_ST_TYPE (sym->st_info))
- && bed->is_function_type (h->type)))
+ && !(newfunc && oldfunc))
{
*skip = TRUE;
return TRUE;
oldweak = FALSE;
/* Allow changes between different types of funciton symbol. */
- if (bed->is_function_type (ELF_ST_TYPE (sym->st_info))
- && bed->is_function_type (h->type))
+ if (newfunc && oldfunc)
*type_change_ok = TRUE;
/* It's OK to change the type if either the existing symbol or the
&& (sec->flags & SEC_ALLOC) != 0
&& (sec->flags & SEC_LOAD) == 0
&& sym->st_size > 0
- && !bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
+ && !newfunc)
newdyncommon = TRUE;
else
newdyncommon = FALSE;
&& (h->root.u.def.section->flags & SEC_ALLOC) != 0
&& (h->root.u.def.section->flags & SEC_LOAD) == 0
&& h->size > 0
- && !bed->is_function_type (h->type))
+ && !oldfunc)
olddyncommon = TRUE;
else
olddyncommon = FALSE;
&& newdef
&& (olddef
|| (h->root.type == bfd_link_hash_common
- && (newweak
- || bed->is_function_type (ELF_ST_TYPE (sym->st_info))))))
+ && (newweak || newfunc))))
{
*override = TRUE;
newdef = FALSE;
if (!newdyn
&& (newdef
|| (bfd_is_com_section (sec)
- && (oldweak
- || bed->is_function_type (h->type))))
+ && (oldweak || oldfunc)))
&& olddyn
&& olddef
&& h->def_dynamic)
overriding a function. */
if (bfd_is_com_section (sec))
- *type_change_ok = TRUE;
+ {
+ 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;
+ }
if ((*sym_hash)->root.type == bfd_link_hash_indirect)
flip = *sym_hash;
size = o->reloc_count;
size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
if (keep_memory)
- internal_relocs = bfd_alloc (abfd, size);
+ internal_relocs = alloc2 = bfd_alloc (abfd, size);
else
internal_relocs = alloc2 = bfd_malloc (size);
if (internal_relocs == NULL)
if (alloc1 != NULL)
free (alloc1);
if (alloc2 != NULL)
- free (alloc2);
+ {
+ if (keep_memory)
+ bfd_release (abfd, alloc2);
+ else
+ free (alloc2);
+ }
return NULL;
}
(*_bfd_error_handler)
(_("%B: relocation size mismatch in %B section %A"),
output_bfd, input_section->owner, input_section);
- bfd_set_error (bfd_error_wrong_object_format);
+ bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
if (h == NULL)
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
flag set, so test it first, and don't bail out. */
if (ELF_COMMON_DEF_P (h))
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
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);
if (!is_elf_hash_table (hash_table))
return TRUE;
return TRUE;
}
\f
+/* Return TRUE iff relocations for INPUT are compatible with OUTPUT.
+ The default is to only match when the INPUT and OUTPUT are exactly
+ the same target. */
+
+bfd_boolean
+_bfd_elf_default_relocs_compatible (const bfd_target *input,
+ const bfd_target *output)
+{
+ return input == output;
+}
+
+/* Return TRUE iff relocations for INPUT are compatible with OUTPUT.
+ This version is used when different targets for the same architecture
+ are virtually identical. */
+
+bfd_boolean
+_bfd_elf_relocs_compatible (const bfd_target *input,
+ const bfd_target *output)
+{
+ const struct elf_backend_data *obed, *ibed;
+
+ if (input == output)
+ return TRUE;
+
+ ibed = xvec_get_elf_backend_data (input);
+ obed = xvec_get_elf_backend_data (output);
+
+ if (ibed->arch != obed->arch)
+ return FALSE;
+
+ /* If both backends are using this function, deem them compatible. */
+ return ibed->relocs_compatible == obed->relocs_compatible;
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bfd_boolean
the format of the output file. */
if (info->relocatable
|| !is_elf_hash_table (htab)
- || htab->root.creator != abfd->xvec)
+ || info->output_bfd->xvec != abfd->xvec)
{
if (info->relocatable)
bfd_set_error (bfd_error_invalid_operation);
format as the output, we can't make a shared library. */
if (info->shared
&& is_elf_hash_table (htab)
- && htab->root.creator == abfd->xvec
+ && info->output_bfd->xvec == abfd->xvec
&& !htab->dynamic_sections_created)
{
if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
{
bfd_byte *dynbuf;
bfd_byte *extdyn;
- int elfsec;
+ unsigned int elfsec;
unsigned long shlink;
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
goto error_free_dyn;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
- if (elfsec == -1)
+ if (elfsec == SHN_BAD)
goto error_free_dyn;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
if (isym->st_shndx == SHN_UNDEF)
sec = bfd_und_section_ptr;
- else if (isym->st_shndx < SHN_LORESERVE
- || isym->st_shndx > SHN_HIRESERVE)
+ 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
{
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (sec == NULL)
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
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,
isym->st_name);
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. */
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
if (hlook->dynindx != -1 && h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- goto error_return;
+ {
+ err_free_sym_hash:
+ free (sorted_sym_hash);
+ goto error_return;
+ }
}
/* If the real definition is in the list of dynamic
if (h->dynindx != -1 && hlook->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, hlook))
- goto error_return;
+ goto err_free_sym_hash;
}
break;
}
different format. It probably can't be done. */
if (! dynamic
&& is_elf_hash_table (htab)
- && htab->root.creator == abfd->xvec
- && bed->check_relocs != NULL)
+ && bed->check_relocs != NULL
+ && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
asection *o;
unsigned long *hashcodes;
bfd_boolean error;
};
-
+
/* This function will be called though elf_link_hash_traverse to store
all hash value of the exported symbols in an array. */
Therefore the result is always a good payoff between few collisions
(= short chain lengths) and table size. */
static size_t
-compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes,
- unsigned long int nsyms, int gnu_hash)
+compute_bucket_count (struct bfd_link_info *info,
+ unsigned long int *hashcodes ATTRIBUTE_UNUSED,
+ unsigned long int nsyms,
+ int gnu_hash)
{
- size_t dynsymcount = elf_hash_table (info)->dynsymcount;
size_t best_size = 0;
unsigned long int i;
- bfd_size_type amt;
/* We have a problem here. The following code to optimize the table
size requires an integer type with more the 32 bits. If
size_t maxsize;
BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
bfd *dynobj = elf_hash_table (info)->dynobj;
+ size_t dynsymcount = elf_hash_table (info)->dynsymcount;
const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
unsigned long int *counts;
+ bfd_size_type amt;
/* Possible optimization parameters: if we have NSYMS symbols we say
that the hashing table must at least have NSYMS/4 and at most
{
asection *s;
- if (inputobj->flags & (DYNAMIC | BFD_LINKER_CREATED))
+ if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
continue;
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
if (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)
- if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
- == (SEC_ALLOC | SEC_READONLY))
+ if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
&& !_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;
}
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))
{
- elf_hash_table (info)->data_index_section = s;
+ elf_hash_table (info)->text_index_section = s;
break;
}
elf_link_hash_traverse (elf_hash_table (info),
elf_collect_hash_codes, &hashinf);
if (hashinf.error)
- return FALSE;
+ {
+ free (hashcodes);
+ return FALSE;
+ }
nsyms = hashinf.hashcodes - hashcodes;
bucketcount
elf_link_hash_traverse (elf_hash_table (info),
elf_collect_gnu_hash_codes, &cinfo);
if (cinfo.error)
- return FALSE;
+ {
+ free (cinfo.hashcodes);
+ return FALSE;
+ }
bucketcount
= compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1);
{
asection *s;
bfd_byte *dynbuf = NULL;
- int elfsec;
+ unsigned int elfsec;
unsigned long shlink;
bfd_byte *extdyn, *extdynend;
size_t extdynsize;
goto error_return;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
- if (elfsec == -1)
+ if (elfsec == SHN_BAD)
goto error_return;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
Elf_Internal_Sym **ind, **indbufend, **indbuf;
struct elf_symbuf_symbol *ssym;
struct elf_symbuf_head *ssymbuf, *ssymhead;
- bfd_size_type i, shndx_count;
+ bfd_size_type i, shndx_count, total_size;
indbuf = bfd_malloc2 (symcount, sizeof (*indbuf));
if (indbuf == NULL)
if (ind[0]->st_shndx != ind[1]->st_shndx)
shndx_count++;
- ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
- + (indbufend - indbuf) * sizeof (*ssymbuf));
+ total_size = ((shndx_count + 1) * sizeof (*ssymbuf)
+ + (indbufend - indbuf) * sizeof (*ssym));
+ ssymbuf = bfd_malloc (total_size);
if (ssymbuf == NULL)
{
free (indbuf);
return NULL;
}
- ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
+ ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count + 1);
ssymbuf->ssym = NULL;
ssymbuf->count = shndx_count;
ssymbuf->st_shndx = 0;
ssym->st_other = (*ind)->st_other;
ssymhead->count++;
}
- BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
+ BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count
+ && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
+ == total_size));
free (indbuf);
return ssymbuf;
/* Check if 2 sections define the same set of local and global
symbols. */
-bfd_boolean
+static bfd_boolean
bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
struct bfd_link_info *info)
{
Elf_Internal_Sym *isym, *isymend;
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
bfd_size_type count1, count2, i;
- int shndx1, shndx2;
+ unsigned int shndx1, shndx2;
bfd_boolean result;
bfd1 = sec1->owner;
bfd2 = sec2->owner;
- /* If both are .gnu.linkonce sections, they have to have the same
- section name. */
- if (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
- && CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
- return strcmp (sec1->name + sizeof ".gnu.linkonce",
- sec2->name + sizeof ".gnu.linkonce") == 0;
-
/* Both sections have to be in ELF. */
if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
|| bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
if (elf_section_type (sec1) != elf_section_type (sec2))
return FALSE;
- if ((elf_section_flags (sec1) & SHF_GROUP) != 0
- && (elf_section_flags (sec2) & SHF_GROUP) != 0)
- {
- /* If both are members of section groups, they have to have the
- same group name. */
- if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
- return FALSE;
- }
-
shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
- if (shndx1 == -1 || shndx2 == -1)
+ if (shndx1 == SHN_BAD || shndx2 == SHN_BAD)
return FALSE;
bed1 = get_elf_backend_data (bfd1);
while (lo < hi)
{
mid = (lo + hi) / 2;
- if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
+ if (shndx1 < ssymbuf1[mid].st_shndx)
hi = mid;
- else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
+ else if (shndx1 > ssymbuf1[mid].st_shndx)
lo = mid + 1;
else
{
while (lo < hi)
{
mid = (lo + hi) / 2;
- if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
+ if (shndx2 < ssymbuf2[mid].st_shndx)
hi = mid;
- else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
+ else if (shndx2 > ssymbuf2[mid].st_shndx)
lo = mid + 1;
else
{
/* Count definitions in the section. */
count1 = 0;
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;
count2 = 0;
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;
if (count1 == 0 || count2 == 0 || count1 != count2)
Complex relocations are generalized, self-describing relocations. The
implementation of them consists of two parts: complex symbols, and the
- relocations themselves.
+ relocations themselves.
The relocations are use a reserved elf-wide relocation type code (R_RELC
external / BFD_RELOC_RELC internal) and an encoding of relocation field
<unary-operator> := as in C, plus "0-" for unambiguous negation. */
static void
-set_symbol_value (bfd * bfd_with_globals,
- Elf_Internal_Sym * isymbuf,
- size_t locsymcount,
- size_t symidx,
- bfd_vma val)
+set_symbol_value (bfd *bfd_with_globals,
+ Elf_Internal_Sym *isymbuf,
+ size_t locsymcount,
+ size_t symidx,
+ bfd_vma val)
{
struct elf_link_hash_entry **sym_hashes;
struct elf_link_hash_entry *h;
h->root.u.def.section = bfd_abs_section_ptr;
}
-static bfd_boolean
-resolve_symbol (const char * name,
- bfd * input_bfd,
- struct elf_final_link_info * finfo,
- bfd_vma * result,
- Elf_Internal_Sym * isymbuf,
- size_t locsymcount)
-{
- Elf_Internal_Sym * sym;
- struct bfd_link_hash_entry * global_entry;
- const char * candidate = NULL;
- Elf_Internal_Shdr * symtab_hdr;
- size_t i;
-
+static bfd_boolean
+resolve_symbol (const char *name,
+ bfd *input_bfd,
+ struct elf_final_link_info *finfo,
+ bfd_vma *result,
+ Elf_Internal_Sym *isymbuf,
+ size_t locsymcount)
+{
+ Elf_Internal_Sym *sym;
+ struct bfd_link_hash_entry *global_entry;
+ const char *candidate = NULL;
+ Elf_Internal_Shdr *symtab_hdr;
+ size_t i;
+
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
for (i = 0; i < locsymcount; ++ i)
}
/* Hmm, haven't found it yet. perhaps it is a global. */
- global_entry = bfd_link_hash_lookup (finfo->info->hash, name, FALSE, FALSE, TRUE);
+ global_entry = bfd_link_hash_lookup (finfo->info->hash, name,
+ FALSE, FALSE, TRUE);
if (!global_entry)
return FALSE;
-
+
if (global_entry->type == bfd_link_hash_defined
|| global_entry->type == bfd_link_hash_defweak)
{
- * result = global_entry->u.def.value
- + global_entry->u.def.section->output_section->vma
- + global_entry->u.def.section->output_offset;
+ *result = (global_entry->u.def.value
+ + global_entry->u.def.section->output_section->vma
+ + global_entry->u.def.section->output_offset);
#ifdef DEBUG
printf ("Found GLOBAL symbol '%s' with value %8.8lx\n",
global_entry->root.string, (unsigned long) *result);
#endif
return TRUE;
- }
+ }
return FALSE;
}
static bfd_boolean
-resolve_section (const char * name,
- asection * sections,
- bfd_vma * result)
+resolve_section (const char *name,
+ asection *sections,
+ bfd_vma *result)
{
- asection * curr;
- unsigned int len;
+ asection *curr;
+ unsigned int len;
- for (curr = sections; curr; curr = curr->next)
+ for (curr = sections; curr; curr = curr->next)
if (strcmp (curr->name, name) == 0)
{
*result = curr->vma;
}
/* Hmm. still haven't found it. try pseudo-section names. */
- for (curr = sections; curr; curr = curr->next)
+ for (curr = sections; curr; curr = curr->next)
{
len = strlen (curr->name);
- if (len > strlen (name))
+ if (len > strlen (name))
continue;
if (strncmp (curr->name, name, len) == 0)
/* Insert more pseudo-section names here, if you like. */
}
}
-
+
return FALSE;
}
static void
-undefined_reference (const char * reftype,
- const char * name)
+undefined_reference (const char *reftype, const char *name)
{
- _bfd_error_handler (_("undefined %s reference in complex symbol: %s"), reftype, name);
+ _bfd_error_handler (_("undefined %s reference in complex symbol: %s"),
+ reftype, name);
}
static bfd_boolean
-eval_symbol (bfd_vma * result,
- const char ** symp,
- bfd * input_bfd,
- struct elf_final_link_info * finfo,
- bfd_vma dot,
- Elf_Internal_Sym * isymbuf,
- size_t locsymcount,
- int signed_p)
-{
- int len;
- int symlen;
- bfd_vma a;
- bfd_vma b;
- const int bufsz = 4096;
- char symbuf [bufsz];
+eval_symbol (bfd_vma *result,
+ const char **symp,
+ bfd *input_bfd,
+ struct elf_final_link_info *finfo,
+ bfd_vma dot,
+ Elf_Internal_Sym *isymbuf,
+ size_t locsymcount,
+ int signed_p)
+{
+ size_t len;
+ size_t symlen;
+ bfd_vma a;
+ bfd_vma b;
+ char symbuf[4096];
const char *sym = *symp;
- const char * symend;
- bfd_boolean symbol_is_section = FALSE;
+ const char *symend;
+ bfd_boolean symbol_is_section = FALSE;
len = strlen (sym);
symend = sym + len;
- if (len < 1 || len > bufsz)
+ if (len < 1 || len > sizeof (symbuf))
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
-
+
switch (* sym)
{
case '.':
case 'S':
symbol_is_section = TRUE;
- case 's':
+ case 's':
++sym;
symlen = strtol (sym, (char **) symp, 10);
sym = *symp + 1; /* Skip the trailing ':'. */
- if ((symend < sym) || ((symlen + 1) > bufsz))
+ if (symend < sym || symlen + 1 > sizeof (symbuf))
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
memcpy (symbuf, sym, symlen);
- symbuf [symlen] = '\0';
+ symbuf[symlen] = '\0';
*symp = sym + symlen;
-
- /* Is it always possible, with complex symbols, that gas "mis-guessed"
+
+ /* Is it always possible, with complex symbols, that gas "mis-guessed"
the symbol as a section, or vice-versa. so we're pretty liberal in our
interpretation here; section means "try section first", not "must be a
section", and likewise with symbol. */
- if (symbol_is_section)
+ if (symbol_is_section)
{
if (!resolve_section (symbuf, finfo->output_bfd->sections, result)
&& !resolve_symbol (symbuf, input_bfd, finfo, result,
undefined_reference ("section", symbuf);
return FALSE;
}
- }
- else
+ }
+ else
{
if (!resolve_symbol (symbuf, input_bfd, finfo, result,
isymbuf, locsymcount)
}
return TRUE;
-
+
/* All that remains are operators. */
#define UNARY_OP(op) \
if (strncmp (sym, #op, strlen (#op)) == 0) \
{ \
sym += strlen (#op); \
- if (* sym == ':') \
- ++ sym; \
+ if (*sym == ':') \
+ ++sym; \
*symp = sym; \
if (!eval_symbol (&a, symp, input_bfd, finfo, dot, \
isymbuf, locsymcount, signed_p)) \
- return FALSE; \
- if (signed_p) \
+ return FALSE; \
+ if (signed_p) \
*result = op ((bfd_signed_vma) a); \
- else \
- * result = op a; \
+ else \
+ *result = op a; \
return TRUE; \
}
if (strncmp (sym, #op, strlen (#op)) == 0) \
{ \
sym += strlen (#op); \
- if (* sym == ':') \
- ++ sym; \
+ if (*sym == ':') \
+ ++sym; \
*symp = sym; \
if (!eval_symbol (&a, symp, input_bfd, finfo, dot, \
isymbuf, locsymcount, signed_p)) \
- return FALSE; \
+ return FALSE; \
++*symp; \
if (!eval_symbol (&b, symp, input_bfd, finfo, dot, \
isymbuf, locsymcount, signed_p)) \
- return FALSE; \
- if (signed_p) \
+ return FALSE; \
+ if (signed_p) \
*result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \
- else \
- * result = a op b; \
+ else \
+ *result = a op b; \
return TRUE; \
}
}
static void
-put_value (bfd_vma size,
- unsigned long chunksz,
- bfd * input_bfd,
- bfd_vma x,
- bfd_byte * location)
+put_value (bfd_vma size,
+ unsigned long chunksz,
+ bfd *input_bfd,
+ bfd_vma x,
+ bfd_byte *location)
{
location += (size - chunksz);
- for (; size; size -= chunksz, location -= chunksz, x >>= (chunksz * 8))
+ for (; size; size -= chunksz, location -= chunksz, x >>= (chunksz * 8))
{
switch (chunksz)
{
}
}
-static bfd_vma
-get_value (bfd_vma size,
- unsigned long chunksz,
- bfd * input_bfd,
- bfd_byte * location)
+static bfd_vma
+get_value (bfd_vma size,
+ unsigned long chunksz,
+ bfd *input_bfd,
+ bfd_byte *location)
{
bfd_vma x = 0;
- for (; size; size -= chunksz, location += chunksz)
+ for (; size; size -= chunksz, location += chunksz)
{
switch (chunksz)
{
return x;
}
-static void
-decode_complex_addend
- (unsigned long * start, /* in bits */
- unsigned long * oplen, /* in bits */
- unsigned long * len, /* in bits */
- unsigned long * wordsz, /* in bytes */
- unsigned long * chunksz, /* in bytes */
- unsigned long * lsb0_p,
- unsigned long * signed_p,
- unsigned long * trunc_p,
- unsigned long encoded)
+static void
+decode_complex_addend (unsigned long *start, /* in bits */
+ unsigned long *oplen, /* in bits */
+ unsigned long *len, /* in bits */
+ unsigned long *wordsz, /* in bytes */
+ unsigned long *chunksz, /* in bytes */
+ unsigned long *lsb0_p,
+ unsigned long *signed_p,
+ unsigned long *trunc_p,
+ unsigned long encoded)
{
* start = encoded & 0x3F;
* len = (encoded >> 6) & 0x3F;
* trunc_p = (encoded >> 29) & 1;
}
-void
+bfd_reloc_status_type
bfd_elf_perform_complex_relocation (bfd *input_bfd,
- asection *input_section,
+ asection *input_section ATTRIBUTE_UNUSED,
bfd_byte *contents,
Elf_Internal_Rela *rel,
bfd_vma relocation)
{
bfd_vma shift, x, mask;
unsigned long start, oplen, len, wordsz, chunksz, lsb0_p, signed_p, trunc_p;
+ bfd_reloc_status_type r;
/* Perform this reloc, since it is complex.
(this is not to say that it necessarily refers to a complex
symbol; merely that it is a self-describing CGEN based reloc.
i.e. the addend has the complete reloc information (bit start, end,
- word size, etc) encoded within it.). */
+ word size, etc) encoded within it.). */
- decode_complex_addend (& start, & oplen, & len, & wordsz,
- & chunksz, & lsb0_p, & signed_p,
- & trunc_p, rel->r_addend);
+ decode_complex_addend (&start, &oplen, &len, &wordsz,
+ &chunksz, &lsb0_p, &signed_p,
+ &trunc_p, rel->r_addend);
mask = (((1L << (len - 1)) - 1) << 1) | 1;
else
shift = (8 * wordsz) - (start + len);
- x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
+ x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
#ifdef DEBUG
printf ("Doing complex reloc: "
oplen, x, mask, relocation);
#endif
+ r = bfd_reloc_ok;
if (! trunc_p)
- {
- /* Now do an overflow check. */
- if (bfd_check_overflow ((signed_p ?
- complain_overflow_signed :
- complain_overflow_unsigned),
- len, 0, (8 * wordsz),
- relocation) == bfd_reloc_overflow)
- (*_bfd_error_handler)
- ("%s (%s + 0x%lx): relocation overflow: 0x%lx %sdoes not fit "
- "within 0x%lx",
- input_bfd->filename, input_section->name, rel->r_offset,
- relocation, (signed_p ? "(signed) " : ""), mask);
- }
-
+ /* Now do an overflow check. */
+ r = bfd_check_overflow ((signed_p
+ ? complain_overflow_signed
+ : complain_overflow_unsigned),
+ len, 0, (8 * wordsz),
+ relocation);
+
/* Do the deed. */
x = (x & ~(mask << shift)) | ((relocation & mask) << shift);
" shifted mask: %8.8lx\n"
" shifted/masked reloc: %8.8lx\n"
" result: %8.8lx\n",
- relocation, (mask << shift),
+ relocation, (mask << shift),
((relocation & mask) << shift), x);
#endif
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
+ return r;
}
/* When performing a relocatable link, the input relocations are
bfd_size_type amt;
amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
- finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2);
+ destshndx = bfd_realloc (destshndx, amt * 2);
if (destshndx == NULL)
return FALSE;
+ finfo->symshndxbuf = destshndx;
memset ((char *) destshndx + amt, 0, amt);
finfo->shndxbuf_size *= 2;
}
static bfd_boolean
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
- beyond 64k. */
+ beyond 64k. */
(*_bfd_error_handler)
(_("%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);
return FALSE;
}
sym.st_value += input_sec->output_section->vma;
if (h->type == STT_TLS)
{
- /* STT_TLS symbols are relative to PT_TLS segment
- base. */
- BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
- sym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
+ asection *tls_sec = elf_hash_table (finfo->info)->tls_sec;
+ if (tls_sec != NULL)
+ sym.st_value -= tls_sec->vma;
+ else
+ {
+ /* The TLS section may have been garbage collected. */
+ BFD_ASSERT (finfo->info->gc_sections
+ && !input_sec->gc_mark);
+ }
}
}
}
sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
}
+ /* 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
locally, it is a fatal error. */
if (! finfo->info->relocatable
{
if ((kept->flags & SEC_GROUP) != 0)
kept = match_group_member (sec, kept, info);
- if (kept != NULL && sec->size != kept->size)
+ if (kept != NULL
+ && ((sec->rawsize != 0 ? sec->rawsize : sec->size)
+ != (kept->rawsize != 0 ? kept->rawsize : kept->size)))
kept = NULL;
sec->kept_section = kept;
}
if (isym->st_shndx == SHN_UNDEF)
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)
isec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
isec = bfd_com_section_ptr;
else
{
- /* Don't attempt to output symbols with st_shnx in the
- reserved range other than SHN_ABS and SHN_COMMON. */
- *ppsection = NULL;
- continue;
+ 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
+ reserved range other than SHN_ABS and SHN_COMMON. */
+ *ppsection = NULL;
+ 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;
/* If this symbol is defined in a section which we are
discarding, we don't need to keep it. */
if (isym->st_shndx != SHN_UNDEF
- && (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
- && (isec == NULL
- || bfd_section_removed_from_list (output_bfd,
- isec->output_section)))
+ && isym->st_shndx < SHN_LORESERVE
+ && bfd_section_removed_from_list (output_bfd,
+ isec->output_section))
continue;
/* Get the name of the symbol. */
default:
{
if (! (o->flags & SEC_EXCLUDE)
+ && ! (o->output_section->flags & SEC_NEVER_LOAD)
&& ! bfd_set_section_contents (output_bfd, o->output_section,
contents,
(file_ptr) o->output_offset,
&& elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass
&& (elfsec = _bfd_elf_section_from_bfd_section (sub, s))
&& 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++;
linkorder_sec = s;
offset += sections[n]->size;
}
+ free (sections);
return TRUE;
}
elf_link_input_bfd ignores this section. */
input_section->flags &= ~SEC_HAS_CONTENTS;
}
-
+
attr_size = bfd_elf_obj_attr_size (abfd);
if (attr_size)
{
/* sh_link is set in assign_section_numbers. */
/* sh_info is set 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 = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
finfo.symbuf = bfd_malloc (amt);
if (finfo.symbuf == NULL)
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. */
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
if (!elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
goto error_return;
}
- if (i == SHN_LORESERVE - 1)
- i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
}
}
the original st_name with the dynstr_index. */
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,
+ e->isym.st_shndx);
+ if (s != NULL)
{
- s = bfd_section_from_elf_index (e->input_bfd,
- e->isym.st_shndx);
-
sym.st_shndx =
elf_section_data (s->output_section)->this_idx;
if (! check_dynsym (abfd, &sym))
if (dyn.d_tag == DT_TEXTREL)
{
- info->callbacks->einfo
+ info->callbacks->einfo
(_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
break;
}
return FALSE;
}
\f
+/* Initialize COOKIE for input bfd ABFD. */
+
+static bfd_boolean
+init_reloc_cookie (struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info, bfd *abfd)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ const struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (abfd);
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ cookie->abfd = abfd;
+ cookie->sym_hashes = elf_sym_hashes (abfd);
+ cookie->bad_symtab = elf_bad_symtab (abfd);
+ if (cookie->bad_symtab)
+ {
+ cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
+ cookie->extsymoff = 0;
+ }
+ else
+ {
+ cookie->locsymcount = symtab_hdr->sh_info;
+ cookie->extsymoff = symtab_hdr->sh_info;
+ }
+
+ if (bed->s->arch_size == 32)
+ cookie->r_sym_shift = 8;
+ else
+ cookie->r_sym_shift = 32;
+
+ cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (cookie->locsyms == NULL && cookie->locsymcount != 0)
+ {
+ cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ cookie->locsymcount, 0,
+ NULL, NULL, NULL);
+ if (cookie->locsyms == NULL)
+ {
+ info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
+ return FALSE;
+ }
+ if (info->keep_memory)
+ symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+ }
+ return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie, if appropriate. */
+
+static void
+fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (cookie->locsyms != NULL
+ && symtab_hdr->contents != (unsigned char *) cookie->locsyms)
+ free (cookie->locsyms);
+}
+
+/* Initialize the relocation information in COOKIE for input section SEC
+ of input bfd ABFD. */
+
+static bfd_boolean
+init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info, bfd *abfd,
+ asection *sec)
+{
+ const struct elf_backend_data *bed;
+
+ if (sec->reloc_count == 0)
+ {
+ cookie->rels = NULL;
+ cookie->relend = NULL;
+ }
+ else
+ {
+ bed = get_elf_backend_data (abfd);
+
+ cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+ info->keep_memory);
+ if (cookie->rels == NULL)
+ return FALSE;
+ cookie->rel = cookie->rels;
+ cookie->relend = (cookie->rels
+ + sec->reloc_count * bed->s->int_rels_per_ext_rel);
+ }
+ cookie->rel = cookie->rels;
+ return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_rels,
+ if appropriate. */
+
+static void
+fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+ asection *sec)
+{
+ if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
+ free (cookie->rels);
+}
+
+/* Initialize the whole of COOKIE for input section SEC. */
+
+static bfd_boolean
+init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info,
+ asection *sec)
+{
+ if (!init_reloc_cookie (cookie, info, sec->owner))
+ goto error1;
+ if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec))
+ goto error2;
+ return TRUE;
+
+ error2:
+ fini_reloc_cookie (cookie, sec->owner);
+ error1:
+ return FALSE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_for_section,
+ if appropriate. */
+
+static void
+fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+ asection *sec)
+{
+ fini_reloc_cookie_rels (cookie, sec);
+ fini_reloc_cookie (cookie, sec->owner);
+}
+\f
/* Garbage collect unused sections. */
/* Default gc_mark_hook. */
return NULL;
}
+/* COOKIE->rel describes a relocation against section SEC, which is
+ a section we've decided to keep. Return the section that contains
+ the relocation symbol, or NULL if no section contains it. */
+
+asection *
+_bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
+ elf_gc_mark_hook_fn gc_mark_hook,
+ struct elf_reloc_cookie *cookie)
+{
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
+ if (r_symndx == 0)
+ return NULL;
+
+ if (r_symndx >= cookie->locsymcount
+ || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
+ {
+ h = cookie->sym_hashes[r_symndx - cookie->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;
+ return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
+ }
+
+ return (*gc_mark_hook) (sec, info, cookie->rel, NULL,
+ &cookie->locsyms[r_symndx]);
+}
+
+/* COOKIE->rel describes a relocation against section SEC, which is
+ a section we've decided to keep. Mark the section that contains
+ the relocation symbol. */
+
+bfd_boolean
+_bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
+ asection *sec,
+ elf_gc_mark_hook_fn gc_mark_hook,
+ struct elf_reloc_cookie *cookie)
+{
+ asection *rsec;
+
+ rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+ if (rsec && !rsec->gc_mark)
+ {
+ if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+ rsec->gc_mark = 1;
+ else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+ return FALSE;
+ }
+ return TRUE;
+}
+
/* The mark phase of garbage collection. For a given section, mark
it and any sections in this section's group, and all the sections
which define symbols to which it refers. */
elf_gc_mark_hook_fn gc_mark_hook)
{
bfd_boolean ret;
- bfd_boolean is_eh;
- asection *group_sec;
+ asection *group_sec, *eh_frame;
sec->gc_mark = 1;
/* Look through the section relocs. */
ret = TRUE;
- is_eh = strcmp (sec->name, ".eh_frame") == 0;
- if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
+ eh_frame = elf_eh_frame_section (sec->owner);
+ if ((sec->flags & SEC_RELOC) != 0
+ && sec->reloc_count > 0
+ && sec != eh_frame)
{
- Elf_Internal_Rela *relstart, *rel, *relend;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- size_t nlocsyms;
- size_t extsymoff;
- bfd *input_bfd = sec->owner;
- const struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
- Elf_Internal_Sym *isym = NULL;
- int r_sym_shift;
-
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (input_bfd);
-
- /* Read the local symbols. */
- if (elf_bad_symtab (input_bfd))
- {
- nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym;
- extsymoff = 0;
- }
- else
- extsymoff = nlocsyms = symtab_hdr->sh_info;
+ struct elf_reloc_cookie cookie;
- isym = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (isym == NULL && nlocsyms != 0)
+ if (!init_reloc_cookie_for_section (&cookie, info, sec))
+ ret = FALSE;
+ else
{
- isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0,
- NULL, NULL, NULL);
- if (isym == NULL)
- return FALSE;
+ for (; cookie.rel < cookie.relend; cookie.rel++)
+ if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
+ {
+ ret = FALSE;
+ break;
+ }
+ fini_reloc_cookie_for_section (&cookie, sec);
}
+ }
- /* Read the relocations. */
- relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL,
- info->keep_memory);
- if (relstart == NULL)
- {
- ret = FALSE;
- goto out1;
- }
- relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+ if (ret && eh_frame && elf_fde_list (sec))
+ {
+ struct elf_reloc_cookie cookie;
- if (bed->s->arch_size == 32)
- r_sym_shift = 8;
+ if (!init_reloc_cookie_for_section (&cookie, info, eh_frame))
+ ret = FALSE;
else
- r_sym_shift = 32;
-
- for (rel = relstart; rel < relend; rel++)
- {
- unsigned long r_symndx;
- asection *rsec;
- struct elf_link_hash_entry *h;
-
- r_symndx = rel->r_info >> r_sym_shift;
- if (r_symndx == 0)
- continue;
-
- if (r_symndx >= nlocsyms
- || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
- {
- h = sym_hashes[r_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;
- rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
- }
- else
- {
- rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
- }
-
- if (rsec && !rsec->gc_mark)
- {
- if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
- rsec->gc_mark = 1;
- else if (is_eh)
- rsec->gc_mark_from_eh = 1;
- else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
- {
- ret = FALSE;
- goto out2;
- }
- }
- }
-
- out2:
- if (elf_section_data (sec)->relocs != relstart)
- free (relstart);
- out1:
- if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
{
- if (! info->keep_memory)
- free (isym);
- else
- symtab_hdr->contents = (unsigned char *) isym;
+ if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame,
+ gc_mark_hook, &cookie))
+ ret = FALSE;
+ fini_reloc_cookie_for_section (&cookie, eh_frame);
}
}
return TRUE;
}
+/* Keep all sections containing symbols undefined on the command-line,
+ and the section containing the entry symbol. */
+
+void
+_bfd_elf_gc_keep (struct bfd_link_info *info)
+{
+ struct bfd_sym_chain *sym;
+
+ for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
+ {
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (elf_hash_table (info), sym->name,
+ FALSE, FALSE, FALSE);
+
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !bfd_is_abs_section (h->root.u.def.section))
+ h->root.u.def.section->flags |= SEC_KEEP;
+ }
+}
+
/* Do mark and sweep of unused sections. */
bfd_boolean
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (!bed->can_gc_sections
- || info->relocatable
- || info->emitrelocations
|| !is_elf_hash_table (info->hash))
{
(*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
return TRUE;
}
+ bed->gc_keep (info);
+
+ /* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section
+ at the .eh_frame section if we can mark the FDEs individually. */
+ _bfd_elf_begin_eh_frame_parsing (info);
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ {
+ asection *sec;
+ struct elf_reloc_cookie cookie;
+
+ sec = bfd_get_section_by_name (sub, ".eh_frame");
+ if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+ {
+ _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
+ if (elf_section_data (sec)->sec_info)
+ elf_eh_frame_section (sub) = sec;
+ fini_reloc_cookie_for_section (&cookie, sec);
+ }
+ }
+ _bfd_elf_end_eh_frame_parsing (info);
+
/* Apply transitive closure to the vtable entry usage info. */
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_propagate_vtable_entries_used,
/* Allow the backend to mark additional target specific sections. */
if (bed->gc_mark_extra_sections)
- bed->gc_mark_extra_sections(info, gc_mark_hook);
-
- /* ... again for sections marked from eh_frame. */
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
- {
- asection *o;
-
- if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
- continue;
-
- /* Keep .gcc_except_table.* if the associated .text.* (or the
- associated .gnu.linkonce.t.* if .text.* doesn't exist) is
- marked. This isn't very nice, but the proper solution,
- splitting .eh_frame up and using comdat doesn't pan out
- easily due to needing special relocs to handle the
- difference of two symbols in separate sections.
- Don't keep code sections referenced by .eh_frame. */
-#define TEXT_PREFIX ".text."
-#define TEXT_PREFIX2 ".gnu.linkonce.t."
-#define GCC_EXCEPT_TABLE_PREFIX ".gcc_except_table."
- for (o = sub->sections; o != NULL; o = o->next)
- if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
- {
- if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX))
- {
- char *fn_name;
- const char *sec_name;
- asection *fn_text;
- unsigned o_name_prefix_len , fn_name_prefix_len, tmp;
-
- o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
- sec_name = o->name + o_name_prefix_len;
- fn_name_prefix_len = strlen (TEXT_PREFIX);
- tmp = strlen (TEXT_PREFIX2);
- if (tmp > fn_name_prefix_len)
- fn_name_prefix_len = tmp;
- fn_name
- = bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1);
- if (fn_name == NULL)
- return FALSE;
-
- /* Try the first prefix. */
- sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
- fn_text = bfd_get_section_by_name (sub, fn_name);
-
- /* Try the second prefix. */
- if (fn_text == NULL)
- {
- sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name);
- fn_text = bfd_get_section_by_name (sub, fn_name);
- }
-
- free (fn_name);
- if (fn_text == NULL || !fn_text->gc_mark)
- continue;
- }
-
- /* If not using specially named exception table section,
- then keep whatever we are using. */
- if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
- return FALSE;
- }
- }
+ bed->gc_mark_extra_sections (info, gc_mark_hook);
/* ... and mark SEC_EXCLUDE for those that go. */
return elf_gc_sweep (abfd, info);
/* Need to: get the symbol; get the section. */
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);
- if (isec != NULL && elf_discarded_section (isec))
- return TRUE;
- }
+ isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
+ if (isec != NULL && elf_discarded_section (isec))
+ return TRUE;
}
return FALSE;
}
{
struct elf_reloc_cookie cookie;
asection *stab, *eh;
- Elf_Internal_Shdr *symtab_hdr;
const struct elf_backend_data *bed;
bfd *abfd;
- unsigned int count;
bfd_boolean ret = FALSE;
if (info->traditional_format
|| !is_elf_hash_table (info->hash))
return FALSE;
+ _bfd_elf_begin_eh_frame_parsing (info);
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
{
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
&& bed->elf_backend_discard_info == NULL)
continue;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- cookie.abfd = abfd;
- cookie.sym_hashes = elf_sym_hashes (abfd);
- cookie.bad_symtab = elf_bad_symtab (abfd);
- if (cookie.bad_symtab)
- {
- cookie.locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
- cookie.extsymoff = 0;
- }
- else
- {
- cookie.locsymcount = symtab_hdr->sh_info;
- cookie.extsymoff = symtab_hdr->sh_info;
- }
-
- if (bed->s->arch_size == 32)
- cookie.r_sym_shift = 8;
- else
- cookie.r_sym_shift = 32;
-
- cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (cookie.locsyms == NULL && cookie.locsymcount != 0)
- {
- cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- cookie.locsymcount, 0,
- NULL, NULL, NULL);
- if (cookie.locsyms == NULL)
- {
- info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
- return FALSE;
- }
- }
+ if (!init_reloc_cookie (&cookie, info, abfd))
+ return FALSE;
- if (stab != NULL)
+ if (stab != NULL
+ && stab->reloc_count > 0
+ && init_reloc_cookie_rels (&cookie, info, abfd, stab))
{
- cookie.rels = NULL;
- count = stab->reloc_count;
- if (count != 0)
- cookie.rels = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL,
- info->keep_memory);
- if (cookie.rels != NULL)
- {
- cookie.rel = cookie.rels;
- cookie.relend = cookie.rels;
- cookie.relend += count * bed->s->int_rels_per_ext_rel;
- if (_bfd_discard_section_stabs (abfd, stab,
- elf_section_data (stab)->sec_info,
- bfd_elf_reloc_symbol_deleted_p,
- &cookie))
- ret = TRUE;
- if (elf_section_data (stab)->relocs != cookie.rels)
- free (cookie.rels);
- }
+ if (_bfd_discard_section_stabs (abfd, stab,
+ elf_section_data (stab)->sec_info,
+ bfd_elf_reloc_symbol_deleted_p,
+ &cookie))
+ ret = TRUE;
+ fini_reloc_cookie_rels (&cookie, stab);
}
- if (eh != NULL)
+ if (eh != NULL
+ && init_reloc_cookie_rels (&cookie, info, abfd, eh))
{
- cookie.rels = NULL;
- count = eh->reloc_count;
- if (count != 0)
- cookie.rels = _bfd_elf_link_read_relocs (abfd, eh, NULL, NULL,
- info->keep_memory);
- cookie.rel = cookie.rels;
- cookie.relend = cookie.rels;
- if (cookie.rels != NULL)
- cookie.relend += count * bed->s->int_rels_per_ext_rel;
-
+ _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
bfd_elf_reloc_symbol_deleted_p,
&cookie))
ret = TRUE;
-
- if (cookie.rels != NULL
- && elf_section_data (eh)->relocs != cookie.rels)
- free (cookie.rels);
+ fini_reloc_cookie_rels (&cookie, eh);
}
if (bed->elf_backend_discard_info != NULL
&& (*bed->elf_backend_discard_info) (abfd, &cookie, info))
ret = TRUE;
- if (cookie.locsyms != NULL
- && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
- {
- if (! info->keep_memory)
- free (cookie.locsyms);
- else
- symtab_hdr->contents = (unsigned char *) cookie.locsyms;
- }
+ fini_reloc_cookie (&cookie, abfd);
}
+ _bfd_elf_end_eh_frame_parsing (info);
if (info->eh_frame_hdr
&& !info->relocatable
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
-_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)
{
flagword flags;
causes trouble for MIPS ELF, which relies on link once semantics
to handle the .reginfo section correctly. */
- name = bfd_get_section_name (abfd, sec);
+ name = section_signature (sec);
if (CONST_STRNEQ (name, ".gnu.linkonce.")
&& (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
/* We may have 2 different types of sections on the list: group
sections and linkonce sections. Match like sections. */
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)
{
/* The section has already been linked. See if we should