Line 1... |
Line 1... |
/* COFF specific linker code.
|
/* COFF specific linker code.
|
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
|
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
|
2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
Written by Ian Lance Taylor, Cygnus Support.
|
Written by Ian Lance Taylor, Cygnus Support.
|
|
|
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
|
Line 77... |
Line 77... |
if (ret != (struct coff_link_hash_entry *) NULL)
|
if (ret != (struct coff_link_hash_entry *) NULL)
|
{
|
{
|
/* Set local fields. */
|
/* Set local fields. */
|
ret->indx = -1;
|
ret->indx = -1;
|
ret->type = T_NULL;
|
ret->type = T_NULL;
|
ret->class = C_NULL;
|
ret->symbol_class = C_NULL;
|
ret->numaux = 0;
|
ret->numaux = 0;
|
ret->auxbfd = NULL;
|
ret->auxbfd = NULL;
|
ret->aux = NULL;
|
ret->aux = NULL;
|
}
|
}
|
|
|
Line 108... |
Line 108... |
_bfd_coff_link_hash_table_create (bfd *abfd)
|
_bfd_coff_link_hash_table_create (bfd *abfd)
|
{
|
{
|
struct coff_link_hash_table *ret;
|
struct coff_link_hash_table *ret;
|
bfd_size_type amt = sizeof (struct coff_link_hash_table);
|
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)
|
if (ret == NULL)
|
return NULL;
|
return NULL;
|
|
|
if (! _bfd_coff_link_hash_table_init (ret, abfd,
|
if (! _bfd_coff_link_hash_table_init (ret, abfd,
|
_bfd_coff_link_hash_newfunc,
|
_bfd_coff_link_hash_newfunc,
|
Line 318... |
Line 318... |
default_copy = TRUE;
|
default_copy = TRUE;
|
|
|
/* We keep a list of the linker hash table entries that correspond
|
/* We keep a list of the linker hash table entries that correspond
|
to particular symbols. */
|
to particular symbols. */
|
amt = symcount * sizeof (struct coff_link_hash_entry *);
|
amt = symcount * sizeof (struct coff_link_hash_entry *);
|
sym_hash = bfd_zalloc (abfd, amt);
|
sym_hash = (struct coff_link_hash_entry **) bfd_zalloc (abfd, amt);
|
if (sym_hash == NULL)
|
if (sym_hash == NULL)
|
goto error_return;
|
goto error_return;
|
obj_coff_sym_hashes (abfd) = sym_hash;
|
obj_coff_sym_hashes (abfd) = sym_hash;
|
|
|
symesz = bfd_coff_symesz (abfd);
|
symesz = bfd_coff_symesz (abfd);
|
Line 486... |
Line 486... |
{
|
{
|
/* If we don't have any symbol information currently in
|
/* If we don't have any symbol information currently in
|
the hash table, or if we are looking at a symbol
|
the hash table, or if we are looking at a symbol
|
definition, then update the symbol class and type in
|
definition, then update the symbol class and type in
|
the hash table. */
|
the hash table. */
|
if (((*sym_hash)->class == C_NULL
|
if (((*sym_hash)->symbol_class == C_NULL
|
&& (*sym_hash)->type == T_NULL)
|
&& (*sym_hash)->type == T_NULL)
|
|| sym.n_scnum != 0
|
|| sym.n_scnum != 0
|
|| (sym.n_value != 0
|
|| (sym.n_value != 0
|
&& (*sym_hash)->root.type != bfd_link_hash_defined
|
&& (*sym_hash)->root.type != bfd_link_hash_defined
|
&& (*sym_hash)->root.type != bfd_link_hash_defweak))
|
&& (*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)
|
if (sym.n_type != T_NULL)
|
{
|
{
|
/* We want to warn if the type changed, but not
|
/* We want to warn if the type changed, but not
|
if it changed from an unspecified type.
|
if it changed from an unspecified type.
|
Testing the whole type byte may work, but the
|
Testing the whole type byte may work, but the
|
Line 770... |
Line 770... |
|
|
/* We use section_count + 1, rather than section_count, because
|
/* We use section_count + 1, rather than section_count, because
|
the target_index fields are 1 based. */
|
the target_index fields are 1 based. */
|
amt = abfd->section_count + 1;
|
amt = abfd->section_count + 1;
|
amt *= sizeof (struct coff_link_section_info);
|
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)
|
if (finfo.section_info == NULL)
|
goto error_return;
|
goto error_return;
|
for (i = 0; i <= abfd->section_count; i++)
|
for (i = 0; i <= abfd->section_count; i++)
|
{
|
{
|
finfo.section_info[i].relocs = NULL;
|
finfo.section_info[i].relocs = NULL;
|
Line 813... |
Line 813... |
but only when doing a relocatable link, which is not the
|
but only when doing a relocatable link, which is not the
|
common case. */
|
common case. */
|
BFD_ASSERT (info->relocatable);
|
BFD_ASSERT (info->relocatable);
|
amt = o->reloc_count;
|
amt = o->reloc_count;
|
amt *= sizeof (struct internal_reloc);
|
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 = o->reloc_count;
|
amt *= sizeof (struct coff_link_hash_entry *);
|
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
|
if (finfo.section_info[o->target_index].relocs == NULL
|
|| finfo.section_info[o->target_index].rel_hashes == NULL)
|
|| finfo.section_info[o->target_index].rel_hashes == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
if (o->reloc_count > max_output_reloc_count)
|
if (o->reloc_count > max_output_reloc_count)
|
Line 849... |
Line 851... |
max_sym_count = sz;
|
max_sym_count = sz;
|
}
|
}
|
|
|
/* Allocate some buffers used while linking. */
|
/* Allocate some buffers used while linking. */
|
amt = max_sym_count * sizeof (struct internal_syment);
|
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 *);
|
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);
|
amt = max_sym_count * sizeof (long);
|
finfo.sym_indices = bfd_malloc (amt);
|
finfo.sym_indices = (long int *) bfd_malloc (amt);
|
finfo.outsyms = bfd_malloc ((max_sym_count + 1) * symesz);
|
finfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz);
|
amt = max_lineno_count * bfd_coff_linesz (abfd);
|
amt = max_lineno_count * bfd_coff_linesz (abfd);
|
finfo.linenos = bfd_malloc (amt);
|
finfo.linenos = (bfd_byte *) bfd_malloc (amt);
|
finfo.contents = bfd_malloc (max_contents_size);
|
finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
|
amt = max_reloc_count * relsz;
|
amt = max_reloc_count * relsz;
|
finfo.external_relocs = bfd_malloc (amt);
|
finfo.external_relocs = (bfd_byte *) bfd_malloc (amt);
|
if (! info->relocatable)
|
if (! info->relocatable)
|
{
|
{
|
amt = max_reloc_count * sizeof (struct internal_reloc);
|
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)
|
if ((finfo.internal_syms == NULL && max_sym_count > 0)
|
|| (finfo.sec_ptrs == NULL && max_sym_count > 0)
|
|| (finfo.sec_ptrs == NULL && max_sym_count > 0)
|
|| (finfo.sym_indices == NULL && max_sym_count > 0)
|
|| (finfo.sym_indices == NULL && max_sym_count > 0)
|
|| finfo.outsyms == NULL
|
|| finfo.outsyms == NULL
|
Line 1013... |
Line 1015... |
{
|
{
|
/* Now that we have written out all the global symbols, we know
|
/* Now that we have written out all the global symbols, we know
|
the symbol indices to use for relocs against them, and we can
|
the symbol indices to use for relocs against them, and we can
|
finally write out the relocs. */
|
finally write out the relocs. */
|
amt = max_output_reloc_count * relsz;
|
amt = max_output_reloc_count * relsz;
|
external_relocs = bfd_malloc (amt);
|
external_relocs = (bfd_byte *) bfd_malloc (amt);
|
if (external_relocs == NULL)
|
if (external_relocs == NULL)
|
goto error_return;
|
goto error_return;
|
|
|
for (o = abfd->sections; o != NULL; o = o->next)
|
for (o = abfd->sections; o != NULL; o = o->next)
|
{
|
{
|
Line 1280... |
Line 1282... |
s = dores_com (s + 5, output_bfd, 1);
|
s = dores_com (s + 5, output_bfd, 1);
|
|
|
else if (CONST_STRNEQ (s, "-stack"))
|
else if (CONST_STRNEQ (s, "-stack"))
|
s = dores_com (s + 6, output_bfd, 0);
|
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
|
else
|
s++;
|
s++;
|
}
|
}
|
free (copy);
|
free (copy);
|
return 1;
|
return 1;
|
Line 1591... |
Line 1602... |
|
|
/* Allocate memory to hold type information. If this turns
|
/* Allocate memory to hold type information. If this turns
|
out to be a duplicate, we pass this address to
|
out to be a duplicate, we pass this address to
|
bfd_release. */
|
bfd_release. */
|
amt = sizeof (struct coff_debug_merge_type);
|
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)
|
if (mt == NULL)
|
return FALSE;
|
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
|
/* Pick up the aux entry, which points to the end of the tag
|
entries. */
|
entries. */
|
bfd_coff_swap_aux_in (input_bfd, (esym + isymesz),
|
bfd_coff_swap_aux_in (input_bfd, (esym + isymesz),
|
isym.n_type, isym.n_sclass, 0, isym.n_numaux,
|
isym.n_type, isym.n_sclass, 0, isym.n_numaux,
|
Line 1618... |
Line 1629... |
char *name_copy;
|
char *name_copy;
|
|
|
bfd_coff_swap_sym_in (input_bfd, esl, islp);
|
bfd_coff_swap_sym_in (input_bfd, esl, islp);
|
|
|
amt = sizeof (struct coff_debug_merge_element);
|
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)
|
if (*epp == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
elename = _bfd_coff_internal_syment_name (input_bfd, islp,
|
elename = _bfd_coff_internal_syment_name (input_bfd, islp,
|
elebuf);
|
elebuf);
|
if (elename == NULL)
|
if (elename == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
amt = strlen (elename) + 1;
|
amt = strlen (elename) + 1;
|
name_copy = bfd_alloc (input_bfd, amt);
|
name_copy = (char *) bfd_alloc (input_bfd, amt);
|
if (name_copy == NULL)
|
if (name_copy == NULL)
|
return FALSE;
|
return FALSE;
|
strcpy (name_copy, elename);
|
strcpy (name_copy, elename);
|
|
|
(*epp)->name = name_copy;
|
(*epp)->name = name_copy;
|
Line 1683... |
Line 1695... |
|
|
for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
|
for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
|
{
|
{
|
struct coff_debug_merge_element *me, *mel;
|
struct coff_debug_merge_element *me, *mel;
|
|
|
if (mtl->class != mt->class)
|
if (mtl->type_class != mt->type_class)
|
continue;
|
continue;
|
|
|
for (me = mt->elements, mel = mtl->elements;
|
for (me = mt->elements, mel = mtl->elements;
|
me != NULL && mel != NULL;
|
me != NULL && mel != NULL;
|
me = me->next, mel = mel->next)
|
me = me->next, mel = mel->next)
|
Line 2545... |
Line 2557... |
}
|
}
|
isym._n._n_n._n_zeroes = 0;
|
isym._n._n_n._n_zeroes = 0;
|
isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
|
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;
|
isym.n_type = h->type;
|
|
|
if (isym.n_sclass == C_NULL)
|
if (isym.n_sclass == C_NULL)
|
isym.n_sclass = C_EXT;
|
isym.n_sclass = C_EXT;
|
|
|
Line 2718... |
Line 2730... |
bfd_reloc_status_type rstat;
|
bfd_reloc_status_type rstat;
|
bfd_boolean ok;
|
bfd_boolean ok;
|
file_ptr loc;
|
file_ptr loc;
|
|
|
size = bfd_get_reloc_size (howto);
|
size = 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,
|
rstat = _bfd_relocate_contents (howto, output_bfd,
|
(bfd_vma) link_order->u.reloc.p->addend,\
|
(bfd_vma) link_order->u.reloc.p->addend,\
|
Line 2931... |
Line 2943... |
+ sec->output_offset);
|
+ sec->output_offset);
|
}
|
}
|
|
|
else if (h->root.type == bfd_link_hash_undefweak)
|
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
|
/* See _Microsoft Portable Executable and Common Object
|
File Format Specification_, section 5.5.3.
|
File Format Specification_, section 5.5.3.
|
Note that weak symbols without aux records are a GNU
|
Note that weak symbols without aux records are a GNU
|
extension.
|
extension.
|
Line 2945... |
Line 2957... |
will resolve a weak external only if a normal
|
will resolve a weak external only if a normal
|
external causes the library member to be linked.
|
external causes the library member to be linked.
|
See also linker.c: generic_link_check_archive_element. */
|
See also linker.c: generic_link_check_archive_element. */
|
asection *sec;
|
asection *sec;
|
struct coff_link_hash_entry *h2 =
|
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];
|
h->aux->x_sym.x_tagndx.l];
|
|
|
if (!h2 || h2->root.type == bfd_link_hash_undefined)
|
if (!h2 || h2->root.type == bfd_link_hash_undefined)
|
{
|
{
|
sec = bfd_abs_section_ptr;
|
sec = bfd_abs_section_ptr;
|
Line 2983... |
Line 2995... |
{
|
{
|
/* Relocation to a symbol in a section which isn't
|
/* Relocation to a symbol in a section which isn't
|
absolute. We output the address here to a file.
|
absolute. We output the address here to a file.
|
This file is then read by dlltool when generating the
|
This file is then read by dlltool when generating the
|
reloc section. Note that the base file is not
|
reloc section. Note that the base file is not
|
portable between systems. We write out a long here,
|
portable between systems. We write out a bfd_vma here,
|
and dlltool reads in a long. */
|
and dlltool reads in a bfd_vma. */
|
long addr = (rel->r_vaddr
|
bfd_vma addr = (rel->r_vaddr
|
- input_section->vma
|
- input_section->vma
|
+ input_section->output_offset
|
+ input_section->output_offset
|
+ input_section->output_section->vma);
|
+ input_section->output_section->vma);
|
if (coff_data (output_bfd)->pe)
|
if (coff_data (output_bfd)->pe)
|
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
|
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
|
if (fwrite (&addr, 1, sizeof (long), (FILE *) info->base_file)
|
if (fwrite (&addr, 1, sizeof (bfd_vma), (FILE *) info->base_file)
|
!= sizeof (long))
|
!= sizeof (bfd_vma))
|
{
|
{
|
bfd_set_error (bfd_error_system_call);
|
bfd_set_error (bfd_error_system_call);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
}
|
}
|