/* COFF specific linker code.
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
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
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
/* This file contains the COFF backend linker code. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "coff/internal.h"
/* Set local fields. */
ret->indx = -1;
ret->type = T_NULL;
- ret->class = C_NULL;
+ ret->symbol_class = C_NULL;
ret->numaux = 0;
ret->auxbfd = NULL;
ret->aux = NULL;
bfd *abfd,
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
struct bfd_hash_table *,
- const char *))
+ const char *),
+ unsigned int entsize)
{
memset (&table->stab_info, 0, sizeof (table->stab_info));
- return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+ return _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
}
/* Create a COFF linker hash table. */
struct coff_link_hash_table *ret;
bfd_size_type amt = sizeof (struct coff_link_hash_table);
- ret = bfd_malloc (amt);
+ ret = (struct coff_link_hash_table *) bfd_malloc (amt);
if (ret == NULL)
return NULL;
if (! _bfd_coff_link_hash_table_init (ret, abfd,
- _bfd_coff_link_hash_newfunc))
+ _bfd_coff_link_hash_newfunc,
+ sizeof (struct coff_link_hash_entry)))
{
free (ret);
return (struct bfd_link_hash_table *) NULL;
static bfd_boolean
coff_link_check_ar_symbols (bfd *abfd,
struct bfd_link_info *info,
- bfd_boolean *pneeded)
+ bfd_boolean *pneeded,
+ bfd **subsbfd)
{
bfd_size_type symesz;
bfd_byte *esym;
/* Auto import. */
if (!h
&& info->pei386_auto_import
- && !strncmp (name,"__imp_", 6))
+ && CONST_STRNEQ (name, "__imp_"))
h = bfd_link_hash_lookup (info->hash, name + 6, FALSE, FALSE, TRUE);
/* We are only interested in symbols that are currently
if (h != (struct bfd_link_hash_entry *) NULL
&& h->type == bfd_link_hash_undefined)
{
- if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+ if (!(*info->callbacks
+ ->add_archive_element) (info, abfd, name, subsbfd))
return FALSE;
*pneeded = TRUE;
return TRUE;
struct bfd_link_info *info,
bfd_boolean *pneeded)
{
- if (! _bfd_coff_get_external_symbols (abfd))
- return FALSE;
+ bfd *oldbfd;
+ bfd_boolean needed;
- if (! coff_link_check_ar_symbols (abfd, info, pneeded))
+ if (!_bfd_coff_get_external_symbols (abfd))
return FALSE;
- if (*pneeded
- && ! coff_link_add_symbols (abfd, info))
+ oldbfd = abfd;
+ if (!coff_link_check_ar_symbols (abfd, info, pneeded, &abfd))
return FALSE;
- if ((! info->keep_memory || ! *pneeded)
- && ! _bfd_coff_free_symbols (abfd))
- return FALSE;
+ needed = *pneeded;
+ if (needed)
+ {
+ /* Potentially, the add_archive_element hook may have set a
+ substitute BFD for us. */
+ if (abfd != oldbfd)
+ {
+ if (!info->keep_memory
+ && !_bfd_coff_free_symbols (oldbfd))
+ return FALSE;
+ if (!_bfd_coff_get_external_symbols (abfd))
+ return FALSE;
+ }
+ if (!coff_link_add_symbols (abfd, info))
+ return FALSE;
+ }
+ if (!info->keep_memory || !needed)
+ {
+ if (!_bfd_coff_free_symbols (abfd))
+ return FALSE;
+ }
return TRUE;
}
bfd_byte *esym_end;
bfd_size_type amt;
+ symcount = obj_raw_syment_count (abfd);
+
+ if (symcount == 0)
+ return TRUE; /* Nothing to do. */
+
/* Keep the symbols during this function, in case the linker needs
to read the generic symbols in order to report an error message. */
keep_syms = obj_coff_keep_syms (abfd);
else
default_copy = TRUE;
- symcount = obj_raw_syment_count (abfd);
-
/* We keep a list of the linker hash table entries that correspond
to particular symbols. */
amt = symcount * sizeof (struct coff_link_hash_entry *);
- sym_hash = bfd_zalloc (abfd, amt);
- if (sym_hash == NULL && symcount != 0)
+ sym_hash = (struct coff_link_hash_entry **) bfd_zalloc (abfd, amt);
+ if (sym_hash == NULL)
goto error_return;
obj_coff_sym_hashes (abfd) = sym_hash;
if (obj_pe (abfd)
&& (classification == COFF_SYMBOL_GLOBAL
|| classification == COFF_SYMBOL_PE_SECTION)
+ && coff_section_data (abfd, section) != NULL
&& coff_section_data (abfd, section)->comdat != NULL
- && strncmp (name, "??_", 3) == 0
+ && CONST_STRNEQ (name, "??_")
&& strcmp (name, coff_section_data (abfd, section)->comdat->name) == 0)
{
if (*sym_hash == NULL)
(*sym_hash)->root.u.c.p->alignment_power
= bfd_coff_default_section_alignment_power (abfd);
- if (info->hash->creator->flavour == bfd_get_flavour (abfd))
+ if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd))
{
/* If we don't have any symbol information currently in
the hash table, or if we are looking at a symbol
definition, then update the symbol class and type in
the hash table. */
- if (((*sym_hash)->class == C_NULL
+ if (((*sym_hash)->symbol_class == C_NULL
&& (*sym_hash)->type == T_NULL)
|| sym.n_scnum != 0
|| (sym.n_value != 0
&& (*sym_hash)->root.type != bfd_link_hash_defined
&& (*sym_hash)->root.type != bfd_link_hash_defweak))
{
- (*sym_hash)->class = sym.n_sclass;
+ (*sym_hash)->symbol_class = sym.n_sclass;
if (sym.n_type != T_NULL)
{
/* We want to warn if the type changed, but not
&& (BTYPE ((*sym_hash)->type) == T_NULL
|| BTYPE (sym.n_type) == T_NULL)))
(*_bfd_error_handler)
- (_("Warning: type of symbol `%s' changed from %d to %d in %s"),
- name, (*sym_hash)->type, sym.n_type,
- bfd_archive_filename (abfd));
+ (_("Warning: type of symbol `%s' changed from %d to %d in %B"),
+ abfd, name, (*sym_hash)->type, sym.n_type);
/* We don't want to change from a meaningful
base type to a null one, but if we know
optimize the handling of any .stab/.stabstr sections. */
if (! info->relocatable
&& ! info->traditional_format
- && info->hash->creator->flavour == bfd_get_flavour (abfd)
+ && bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)
&& (info->strip != strip_all && info->strip != strip_debugger))
{
asection *stabstr;
asection *stab;
for (stab = abfd->sections; stab; stab = stab->next)
- if (strncmp (".stab", stab->name, 5) == 0
+ if (CONST_STRNEQ (stab->name, ".stab")
&& (!stab->name[5]
|| (stab->name[5] == '.' && ISDIGIT (stab->name[6]))))
{
{
o->reloc_count = 0;
o->lineno_count = 0;
- for (p = o->link_order_head; p != NULL; p = p->next)
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
{
if (p->type == bfd_indirect_link_order)
{
the target_index fields are 1 based. */
amt = abfd->section_count + 1;
amt *= sizeof (struct coff_link_section_info);
- finfo.section_info = bfd_malloc (amt);
+ finfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
if (finfo.section_info == NULL)
goto error_return;
for (i = 0; i <= abfd->section_count; i++)
BFD_ASSERT (info->relocatable);
amt = o->reloc_count;
amt *= sizeof (struct internal_reloc);
- finfo.section_info[o->target_index].relocs = bfd_malloc (amt);
+ finfo.section_info[o->target_index].relocs =
+ (struct internal_reloc *) bfd_malloc (amt);
amt = o->reloc_count;
amt *= sizeof (struct coff_link_hash_entry *);
- finfo.section_info[o->target_index].rel_hashes = bfd_malloc (amt);
+ finfo.section_info[o->target_index].rel_hashes =
+ (struct coff_link_hash_entry **) bfd_malloc (amt);
if (finfo.section_info[o->target_index].relocs == NULL
|| finfo.section_info[o->target_index].rel_hashes == NULL)
goto error_return;
/* Allocate some buffers used while linking. */
amt = max_sym_count * sizeof (struct internal_syment);
- finfo.internal_syms = bfd_malloc (amt);
+ finfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
amt = max_sym_count * sizeof (asection *);
- finfo.sec_ptrs = bfd_malloc (amt);
+ finfo.sec_ptrs = (asection **) bfd_malloc (amt);
amt = max_sym_count * sizeof (long);
- finfo.sym_indices = bfd_malloc (amt);
- finfo.outsyms = bfd_malloc ((max_sym_count + 1) * symesz);
+ finfo.sym_indices = (long int *) bfd_malloc (amt);
+ finfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz);
amt = max_lineno_count * bfd_coff_linesz (abfd);
- finfo.linenos = bfd_malloc (amt);
- finfo.contents = bfd_malloc (max_contents_size);
+ finfo.linenos = (bfd_byte *) bfd_malloc (amt);
+ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
amt = max_reloc_count * relsz;
- finfo.external_relocs = bfd_malloc (amt);
+ finfo.external_relocs = (bfd_byte *) bfd_malloc (amt);
if (! info->relocatable)
{
amt = max_reloc_count * sizeof (struct internal_reloc);
- finfo.internal_relocs = bfd_malloc (amt);
+ finfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
}
if ((finfo.internal_syms == NULL && max_sym_count > 0)
|| (finfo.sec_ptrs == NULL && max_sym_count > 0)
for (o = abfd->sections; o != NULL; o = o->next)
{
- for (p = o->link_order_head; p != NULL; p = p->next)
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
{
if (p->type == bfd_indirect_link_order
&& bfd_family_coff (p->u.indirect.section->owner))
the symbol indices to use for relocs against them, and we can
finally write out the relocs. */
amt = max_output_reloc_count * relsz;
- external_relocs = bfd_malloc (amt);
+ external_relocs = (bfd_byte *) bfd_malloc (amt);
if (external_relocs == NULL)
goto error_return;
free (copy);
return 0;
}
- e = copy + sec->size;
+ e = (char *) copy + sec->size;
- for (s = copy; s < e ; )
+ for (s = (char *) copy; s < e ; )
{
- if (s[0]!= '-')
+ if (s[0] != '-')
{
s++;
continue;
}
- if (strncmp (s,"-attr", 5) == 0)
+ if (CONST_STRNEQ (s, "-attr"))
{
char *name;
char *attribs;
asection *asec;
int loop = 1;
int had_write = 0;
- int had_read = 0;
int had_exec= 0;
- int had_shared= 0;
s += 5;
s = get_name (s, &name);
had_write = 1;
break;
case 'R':
- had_read = 1;
break;
case 'S':
- had_shared = 1;
break;
case 'X':
had_exec = 1;
asec->flags |= SEC_READONLY;
}
}
- else if (strncmp (s,"-heap", 5) == 0)
- s = dores_com (s+5, output_bfd, 1);
+ else if (CONST_STRNEQ (s, "-heap"))
+ s = dores_com (s + 5, output_bfd, 1);
- else if (strncmp (s,"-stack", 6) == 0)
- s = dores_com (s+6, output_bfd, 0);
+ else if (CONST_STRNEQ (s, "-stack"))
+ s = dores_com (s + 6, output_bfd, 0);
+
+ /* GNU extension for aligned commons. */
+ else if (CONST_STRNEQ (s, "-aligncomm:"))
+ {
+ /* Common symbols must be aligned on reading, as it
+ is too late to do anything here, after they have
+ already been allocated, so just skip the directive. */
+ s += 11;
+ }
else
s++;
{
unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask;
unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft;
-#if 0
- unsigned int n_btmask = coff_data (input_bfd)->local_n_btmask;
-#endif
bfd_boolean (*adjust_symndx)
(bfd *, struct bfd_link_info *, bfd *, asection *,
struct internal_reloc *, bfd_boolean *);
/* Skip section symbols for sections which are not going to be
emitted. */
if (!skip
- && dont_skip_symbol == 0
+ && !dont_skip_symbol
&& isym.n_sclass == C_STAT
&& isym.n_type == T_NULL
- && isym.n_numaux > 0
- && (*secpp)->output_section == bfd_abs_section_ptr)
+ && isym.n_numaux > 0
+ && ((*secpp)->output_section == bfd_abs_section_ptr
+ || bfd_section_removed_from_list (output_bfd,
+ (*secpp)->output_section)))
skip = TRUE;
#endif
out to be a duplicate, we pass this address to
bfd_release. */
amt = sizeof (struct coff_debug_merge_type);
- mt = bfd_alloc (input_bfd, amt);
+ mt = (struct coff_debug_merge_type *) bfd_alloc (input_bfd, amt);
if (mt == NULL)
return FALSE;
- mt->class = isym.n_sclass;
+ mt->type_class = isym.n_sclass;
/* Pick up the aux entry, which points to the end of the tag
entries. */
bfd_coff_swap_sym_in (input_bfd, esl, islp);
amt = sizeof (struct coff_debug_merge_element);
- *epp = bfd_alloc (input_bfd, amt);
+ *epp = (struct coff_debug_merge_element *)
+ bfd_alloc (input_bfd, amt);
if (*epp == NULL)
return FALSE;
return FALSE;
amt = strlen (elename) + 1;
- name_copy = bfd_alloc (input_bfd, amt);
+ name_copy = (char *) bfd_alloc (input_bfd, amt);
if (name_copy == NULL)
return FALSE;
strcpy (name_copy, elename);
{
struct coff_debug_merge_element *me, *mel;
- if (mtl->class != mt->class)
+ if (mtl->type_class != mt->type_class)
continue;
for (me = mt->elements, mel = mtl->elements;
generate two symbols with the same name, but only one
will have aux entries. */
BFD_ASSERT (isymp->n_numaux == 0
+ || h->numaux == 0
|| h->numaux == isymp->n_numaux);
}
union internal_auxent aux;
union internal_auxent *auxp;
- if (h != NULL)
+ if (h != NULL && h->aux != NULL && (h->numaux > i))
auxp = h->aux + i;
else
{
auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx;
}
}
- else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
+ else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
+ && isymp->n_sclass != C_NT_WEAK)
{
unsigned long indx;
if ((o->flags & SEC_RELOC) != 0
&& o->reloc_count != 0)
{
- ((*_bfd_error_handler)
- (_("%s: relocs in section `%s', but it has no contents"),
- bfd_archive_filename (input_bfd),
- bfd_get_section_name (input_bfd, o)));
+ (*_bfd_error_handler)
+ (_("%B: relocs in section `%A', but it has no contents"),
+ input_bfd, o);
bfd_set_error (bfd_error_no_contents);
return FALSE;
}
isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
}
- isym.n_sclass = h->class;
+ isym.n_sclass = h->symbol_class;
isym.n_type = h->type;
if (isym.n_sclass == C_NULL)
file_ptr loc;
size = bfd_get_reloc_size (howto);
- buf = bfd_zmalloc (size);
+ buf = (bfd_byte *) bfd_zmalloc (size);
if (buf == NULL)
return FALSE;
abort ();
case bfd_reloc_overflow:
if (! ((*finfo->info->callbacks->reloc_overflow)
- (finfo->info,
+ (finfo->info, NULL,
(link_order->type == bfd_section_reloc_link_order
? bfd_section_name (output_bfd,
link_order->u.reloc.p->u.section)
|| (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
{
(*_bfd_error_handler)
- ("%s: illegal symbol index %ld in relocs",
- bfd_archive_filename (input_bfd), symndx);
+ ("%B: illegal symbol index %ld in relocs", input_bfd, symndx);
return FALSE;
}
else
else if (h->root.type == bfd_link_hash_undefweak)
{
- if (h->class == C_NT_WEAK && h->numaux == 1)
+ if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
{
/* See _Microsoft Portable Executable and Common Object
- * File Format Specification_, section 5.5.3.
- * Note that weak symbols without aux records are a GNU
- * extension.
- * FIXME: All weak externals are treated as having
- * characteristics IMAGE_WEAK_EXTERN_SEARCH_LIBRARY (2).
- * There are no known uses of the other two types of
- * weak externals.
- */
+ File Format Specification_, section 5.5.3.
+ Note that weak symbols without aux records are a GNU
+ extension.
+ FIXME: All weak externals are treated as having
+ characteristic IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY (1).
+ These behave as per SVR4 ABI: A library member
+ will resolve a weak external only if a normal
+ external causes the library member to be linked.
+ See also linker.c: generic_link_check_archive_element. */
asection *sec;
struct coff_link_hash_entry *h2 =
- input_bfd->tdata.coff_obj_data->sym_hashes[
+ h->auxbfd->tdata.coff_obj_data->sym_hashes[
h->aux->x_sym.x_tagndx.l];
- sec = h2->root.u.def.section;
- val = h2->root.u.def.value + sec->output_section->vma
- + sec->output_offset;
+ if (!h2 || h2->root.type == bfd_link_hash_undefined)
+ {
+ sec = bfd_abs_section_ptr;
+ val = 0;
+ }
+ else
+ {
+ sec = h2->root.u.def.section;
+ val = h2->root.u.def.value
+ + sec->output_section->vma + sec->output_offset;
+ }
}
else
- /* This is a GNU extension. */
+ /* This is a GNU extension. */
val = 0;
}
absolute. We output the address here to a file.
This file is then read by dlltool when generating the
reloc section. Note that the base file is not
- portable between systems. We write out a long here,
- and dlltool reads in a long. */
- long addr = (rel->r_vaddr
+ portable between systems. We write out a bfd_vma here,
+ and dlltool reads in a bfd_vma. */
+ bfd_vma addr = (rel->r_vaddr
- input_section->vma
+ input_section->output_offset
+ input_section->output_section->vma);
if (coff_data (output_bfd)->pe)
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
- if (fwrite (&addr, 1, sizeof (long), (FILE *) info->base_file)
- != sizeof (long))
+ if (fwrite (&addr, 1, sizeof (bfd_vma), (FILE *) info->base_file)
+ != sizeof (bfd_vma))
{
bfd_set_error (bfd_error_system_call);
return FALSE;
break;
case bfd_reloc_outofrange:
(*_bfd_error_handler)
- (_("%s: bad reloc address 0x%lx in section `%s'"),
- bfd_archive_filename (input_bfd),
- (unsigned long) rel->r_vaddr,
- bfd_get_section_name (input_bfd, input_section));
+ (_("%B: bad reloc address 0x%lx in section `%A'"),
+ input_bfd, input_section, (unsigned long) rel->r_vaddr);
return FALSE;
case bfd_reloc_overflow:
{
if (symndx == -1)
name = "*ABS*";
else if (h != NULL)
- name = h->root.root.string;
+ name = NULL;
else
{
name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
}
if (! ((*info->callbacks->reloc_overflow)
- (info, name, howto->name, (bfd_vma) 0, input_bfd,
- input_section, rel->r_vaddr - input_section->vma)))
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section,
+ rel->r_vaddr - input_section->vma)))
return FALSE;
}
}