/* linker.c -- BFD linker routines
- Copyright 1993 Free Software Foundation, Inc.
+ Copyright (C) 1993, 94 Free Software Foundation, Inc.
Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
-This file is part of BFD
+This file is part of BFD, the Binary File Descriptor library.
-GLD 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
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
-GLD is distributed in the hope that it will be useful,
+This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GLD; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "bfd.h"
#include "sysdep.h"
<<bfdlink.h>>). These structures describe how to create the
contents of the output section in terms of the contents of
various input sections, fill constants, and, eventually, other
- types of information.
+ types of information. They also describe relocs that must be
+ created by the BFD backend, but do not correspond to any input
+ file; this is used to support -Ur, which builds constructors
+ while generating a relocateable object file.
INODE
Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link
static struct bfd_hash_entry *generic_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
const char *));
+static boolean generic_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *, boolean collect));
static boolean generic_link_add_object_symbols
- PARAMS ((bfd *, struct bfd_link_info *));
-static boolean generic_link_check_archive_element
+ PARAMS ((bfd *, struct bfd_link_info *, boolean collect));
+static boolean generic_link_check_archive_element_no_collect
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean generic_link_check_archive_element_collect
PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean generic_link_check_archive_element
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded, boolean collect));
static boolean generic_link_add_symbol_list
- PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **));
+ PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
+ boolean collect));
static boolean generic_add_output_symbol
PARAMS ((bfd *, size_t *psymalloc, asymbol *));
static boolean default_fill_link_order
if (ret == (struct bfd_link_hash_entry *) NULL)
ret = ((struct bfd_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry)));
+ if (ret == (struct bfd_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
/* Call the allocation method of the superclass. */
ret = ((struct bfd_link_hash_entry *)
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
- /* Initialize the local fields. */
- ret->type = bfd_link_hash_new;
- ret->written = false;
- ret->next = NULL;
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->type = bfd_link_hash_new;
+ ret->written = false;
+ ret->next = NULL;
+ }
return (struct bfd_hash_entry *) ret;
}
if (ret == (struct generic_link_hash_entry *) NULL)
ret = ((struct generic_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry)));
+ if (ret == (struct generic_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
/* Call the allocation method of the superclass. */
ret = ((struct generic_link_hash_entry *)
_bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
- /* Set local fields. */
- ret->sym = NULL;
+ if (ret)
+ {
+ /* Set local fields. */
+ ret->sym = NULL;
+ }
return (struct bfd_hash_entry *) ret;
}
struct generic_link_hash_table *ret;
ret = ((struct generic_link_hash_table *)
- bfd_xmalloc (sizeof (struct generic_link_hash_table)));
+ malloc (sizeof (struct generic_link_hash_table)));
+ if (!ret)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_link_hash_table *) NULL;
+ }
if (! _bfd_link_hash_table_init (&ret->root, abfd,
generic_link_hash_newfunc))
{
return &ret->root;
}
\f
-/* Generic function to add symbols from an object file to the global
- hash table. */
+/* Generic function to add symbols to from an object file to the
+ global hash table. This version does not automatically collect
+ constructors by name. */
boolean
_bfd_generic_link_add_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
+{
+ return generic_link_add_symbols (abfd, info, false);
+}
+
+/* Generic function to add symbols from an object file to the global
+ hash table. This version automatically collects constructors by
+ name, as the collect2 program does. It should be used for any
+ target which does not provide some other mechanism for setting up
+ constructors and destructors; these are approximately those targets
+ for which gcc uses collect2 and do not support stabs. */
+
+boolean
+_bfd_generic_link_add_symbols_collect (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ return generic_link_add_symbols (abfd, info, true);
+}
+
+/* Add symbols from an object file to the global hash table. */
+
+static boolean
+generic_link_add_symbols (abfd, info, collect)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean collect;
{
boolean ret;
switch (bfd_get_format (abfd))
{
case bfd_object:
- ret = generic_link_add_object_symbols (abfd, info);
+ ret = generic_link_add_object_symbols (abfd, info, collect);
break;
case bfd_archive:
- ret = _bfd_generic_link_add_archive_symbols
- (abfd, info, generic_link_check_archive_element);
+ ret = (_bfd_generic_link_add_archive_symbols
+ (abfd, info,
+ (collect
+ ? generic_link_check_archive_element_collect
+ : generic_link_check_archive_element_no_collect)));
break;
default:
- bfd_error = wrong_format;
+ bfd_set_error (bfd_error_wrong_format);
ret = false;
}
- /* If we might be using the C based alloca function, make sure we
- have dumped the symbol tables we just allocated. */
-#ifndef __GNUC__
-#ifndef alloca
- alloca (0);
-#endif
-#endif
-
return ret;
}
/* Add symbols from an object file to the global hash table. */
static boolean
-generic_link_add_object_symbols (abfd, info)
+generic_link_add_object_symbols (abfd, info, collect)
bfd *abfd;
struct bfd_link_info *info;
+ boolean collect;
{
size_t symsize;
asymbol **symbols;
bfd_size_type symbol_count;
+ boolean result;
symsize = get_symtab_upper_bound (abfd);
- symbols = (asymbol **) alloca (symsize);
+ symbols = (asymbol **) malloc (symsize);
+ if (symbols == NULL && symsize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
symbol_count = bfd_canonicalize_symtab (abfd, symbols);
- return generic_link_add_symbol_list (abfd, info, symbol_count, symbols);
+ result = generic_link_add_symbol_list (abfd, info, symbol_count, symbols,
+ collect);
+ free (symbols);
+ return result;
}
\f
/* We build a hash table of all symbols defined in an archive. */
if (ret == (struct archive_hash_entry *) NULL)
ret = ((struct archive_hash_entry *)
bfd_hash_allocate (table, sizeof (struct archive_hash_entry)));
+ if (ret == (struct archive_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
/* Call the allocation method of the superclass. */
ret = ((struct archive_hash_entry *)
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
- /* Initialize the local fields. */
- ret->defs = (struct archive_list *) NULL;
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->defs = (struct archive_list *) NULL;
+ }
return (struct bfd_hash_entry *) ret;
}
if (! bfd_has_map (abfd))
{
- bfd_error = no_symbols;
+ bfd_set_error (bfd_error_no_symbols);
return false;
}
for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
{
struct archive_hash_entry *arh;
- struct archive_list *l;
+ struct archive_list *l, **pp;
arh = archive_hash_lookup (&arsym_hash, arsym->name, true, false);
if (arh == (struct archive_hash_entry *) NULL)
- return false;
- l = (struct archive_list *) alloca (sizeof (struct archive_list));
- l->next = arh->defs;
- arh->defs = l;
+ goto error_return;
+ l = (struct archive_list *)
+ obstack_alloc (&(&(&arsym_hash)->table)->memory,
+ sizeof (struct archive_list));
+ if (l == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
l->indx = indx;
+ for (pp = &arh->defs;
+ *pp != (struct archive_list *) NULL;
+ pp = &(*pp)->next)
+ ;
+ *pp = l;
+ l->next = NULL;
}
pass = 1;
element = bfd_get_elt_at_index (abfd, l->indx);
if (element == (bfd *) NULL)
- return false;
+ goto error_return;
/* If we've already included this element, or if we've
already checked it on this pass, continue. */
/* CHECKFN will see if this element should be included, and
go ahead and include it if appropriate. */
if (! (*checkfn) (element, info, &needed))
- return false;
+ goto error_return;
if (! needed)
element->archive_pass = pass;
archive_hash_table_free (&arsym_hash);
return true;
+
+ error_return:
+ archive_hash_table_free (&arsym_hash);
+ return false;
}
\f
-/* See if we should include an archive element. */
+/* See if we should include an archive element. This version is used
+ when we do not want to automatically collect constructors based on
+ the symbol name, presumably because we have some other mechanism
+ for finding them. */
+
+static boolean
+generic_link_check_archive_element_no_collect (abfd, info, pneeded)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+{
+ return generic_link_check_archive_element (abfd, info, pneeded, false);
+}
+
+/* See if we should include an archive element. This version is used
+ when we want to automatically collect constructors based on the
+ symbol name, as collect2 does. */
static boolean
-generic_link_check_archive_element (abfd, info, pneeded)
+generic_link_check_archive_element_collect (abfd, info, pneeded)
bfd *abfd;
struct bfd_link_info *info;
boolean *pneeded;
+{
+ return generic_link_check_archive_element (abfd, info, pneeded, true);
+}
+
+/* See if we should include an archive element. Optionally collect
+ constructors. */
+
+static boolean
+generic_link_check_archive_element (abfd, info, pneeded, collect)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+ boolean collect;
{
size_t symsize;
- asymbol **symbols;
+ asymbol **symbols = NULL;
bfd_size_type symbol_count;
asymbol **pp, **ppend;
*pneeded = false;
symsize = get_symtab_upper_bound (abfd);
- symbols = (asymbol **) alloca (symsize);
+ symbols = (asymbol **) malloc (symsize);
+ if (symbols == NULL && symsize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
symbol_count = bfd_canonicalize_symtab (abfd, symbols);
pp = symbols;
/* This object file defines this symbol, so pull it in. */
if (! (*info->callbacks->add_archive_element) (info, abfd,
bfd_asymbol_name (p)))
- return false;
+ goto error_return;
if (! generic_link_add_symbol_list (abfd, info, symbol_count,
- symbols))
- return false;
+ symbols, collect))
+ goto error_return;
*pneeded = true;
- return true;
+ goto successful_return;
}
/* P is a common symbol. */
file. This is for the -u option in the linker. */
if (! (*info->callbacks->add_archive_element)
(info, abfd, bfd_asymbol_name (p)))
- return false;
+ goto error_return;
*pneeded = true;
- return true;
+ goto successful_return;
}
/* Turn the symbol into a common symbol but do not link in
}
/* This archive element is not needed. */
+
+ successful_return:
+ if (symbols != NULL)
+ free (symbols);
return true;
+
+ error_return:
+ if (symbols != NULL)
+ free (symbols);
+ return false;
}
-/* Add the symbol from an object file to the global hash table. */
+/* Add the symbols from an object file to the global hash table. ABFD
+ is the object file. INFO is the linker information. SYMBOL_COUNT
+ is the number of symbols. SYMBOLS is the list of symbols. COLLECT
+ is true if constructors should be automatically collected by name
+ as is done by collect2. */
static boolean
-generic_link_add_symbol_list (abfd, info, symbol_count, symbols)
+generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
bfd *abfd;
struct bfd_link_info *info;
bfd_size_type symbol_count;
asymbol **symbols;
+ boolean collect;
{
asymbol **pp, **ppend;
else
string = NULL;
- /* We pass the constructor argument as false, for
- compatibility. As backends are converted they can
- arrange to pass the right value (the right value is the
- size of a function pointer if gcc uses collect2 for the
- object file format, zero if it does not).
- FIXME: We pass the bitsize as 32, which is just plain
- wrong, but actually doesn't matter very much. */
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name, p->flags, bfd_get_section (p),
- p->value, string, false, 0, 32,
+ p->value, string, false, collect,
(struct bfd_link_hash_entry **) &h)))
return false;
which case it is the warning string.
COPY is true if NAME or STRING must be copied into locally
allocated memory if they need to be saved.
- CONSTRUCTOR is true if we should automatically collect gcc
- constructor or destructor names.
- BITSIZE is the number of bits in constructor or set entries.
+ COLLECT is true if we should automatically collect gcc constructor
+ or destructor names as collect2 does.
HASHP, if not NULL, is a place to store the created hash table
entry. */
boolean
_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
- string, copy, constructor, bitsize, hashp)
+ string, copy, collect, hashp)
struct bfd_link_info *info;
bfd *abfd;
const char *name;
bfd_vma value;
const char *string;
boolean copy;
- boolean constructor;
- unsigned int bitsize;
+ boolean collect;
struct bfd_link_hash_entry **hashp;
{
enum link_row row;
and destructors and pass them up in a callback. We only
do this for certain object file types, since many object
file types can handle this automatically. */
- if (constructor && name[0] == '_')
+ if (collect && name[0] == '_')
{
const char *s;
{
if (! ((*info->callbacks->constructor)
(info,
- c == 'I' ? true : false, bitsize,
+ c == 'I' ? true : false,
name, abfd, section, value)))
return false;
}
}
break;
case SET:
- if (! (*info->callbacks->add_to_set) (info, h, bitsize, abfd,
- section, value))
+ if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR,
+ abfd, section, value))
return false;
break;
case WARN:
sub = ((struct bfd_link_hash_entry *)
bfd_hash_allocate (&info->hash->table,
sizeof (struct bfd_link_hash_entry)));
+ if (!sub)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
*sub = *h;
h->type = bfd_link_hash_warning;
h->u.i.link = sub;
return false;
/* Accumulate the global symbols. */
+ wginfo.info = info;
wginfo.output_bfd = abfd;
wginfo.psymalloc = &outsymalloc;
_bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
p != (struct bfd_link_order *) NULL;
p = p->next)
{
- if (p->type == bfd_indirect_link_order)
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ ++o->reloc_count;
+ else if (p->type == bfd_indirect_link_order)
{
asection *input_section;
bfd *input_bfd;
input_bfd = input_section->owner;
relsize = bfd_get_reloc_upper_bound (input_bfd,
input_section);
- relocs = (arelent **) bfd_xmalloc (relsize);
+ relocs = (arelent **) malloc ((size_t) relsize);
+ if (!relocs && relsize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
reloc_count =
bfd_canonicalize_reloc (input_bfd, input_section,
relocs,
bfd_alloc (abfd,
(o->reloc_count
* sizeof (arelent *))));
+ if (!o->orelocation)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ o->flags |= SEC_RELOC;
/* Reset the count so that it can be used as an index
when putting in the output relocs. */
o->reloc_count = 0;
p != (struct bfd_link_order *) NULL;
p = p->next)
{
- if (! _bfd_default_link_order (abfd, info, o, p))
- return false;
+ switch (p->type)
+ {
+ case bfd_section_reloc_link_order:
+ case bfd_symbol_reloc_link_order:
+ if (! _bfd_generic_reloc_link_order (abfd, info, o, p))
+ return false;
+ break;
+ default:
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ return false;
+ break;
+ }
}
}
*psymalloc * sizeof (asymbol *));
if (newsyms == (asymbol **) NULL)
{
- bfd_error = no_memory;
+ bfd_set_error (bfd_error_no_memory);
return false;
}
output_bfd->outsymbols = newsyms;
asymbol **sym_ptr;
asymbol **sym_end;
- symsize = get_symtab_upper_bound (input_bfd);
- input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
- input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
- input_bfd->outsymbols);
+ /* Do not clobber outsymbols if they have already been created. */
+ if (input_bfd->outsymbols == NULL)
+ {
+ symsize = get_symtab_upper_bound (input_bfd);
+ input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
+ if (!input_bfd->outsymbols)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
+ input_bfd->outsymbols);
+ }
/* Create a filename symbol if we are supposed to. */
if (info->create_object_symbols_section != (asection *) NULL)
asymbol *newsym;
newsym = bfd_make_empty_symbol (input_bfd);
+ if (!newsym)
+ return false;
newsym->name = input_bfd->filename;
newsym->value = 0;
newsym->flags = BSF_LOCAL | BSF_FILE;
case bfd_link_hash_common:
sym->value = h->root.u.c.size;
sym->flags |= BSF_GLOBAL;
+ if (! bfd_is_com_section (sym->section))
+ {
+ BFD_ASSERT (sym->section == &bfd_und_section);
+ sym->section = &bfd_com_section;
+ }
/* We do not set the section of the symbol to
- c.section. c.section is saved so that we know
- where to allocate the symbol if we define it. In
- this case the type is still bfd_link_hash_common,
- so we did not define it, so we do not want to use
- that section. */
- BFD_ASSERT (bfd_is_com_section (sym->section));
+ h->root.u.c.section. That value was saved so
+ that we would know where to allocate the symbol
+ if it was defined. In this case the type is
+ still bfd_link_hash_common, so we did not define
+ it, so we do not want to use that section. */
break;
}
}
if (h->root.written)
return true;
+ h->root.written = true;
+
+ if (wginfo->info->strip == strip_all
+ || (wginfo->info->strip == strip_some
+ && bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string,
+ false, false) == NULL))
+ return true;
+
if (h->sym != (asymbol *) NULL)
{
sym = h->sym;
else
{
sym = bfd_make_empty_symbol (wginfo->output_bfd);
+ if (!sym)
+ return false;
sym->name = h->root.root.string;
sym->flags = 0;
}
sym->section = &bfd_und_section;
sym->value = 0;
sym->flags |= BSF_WEAK;
+ break;
case bfd_link_hash_defined:
sym->section = h->root.u.def.section;
sym->value = h->root.u.def.value;
break;
case bfd_link_hash_common:
sym->value = h->root.u.c.size;
+ if (! bfd_is_com_section (sym->section))
+ {
+ BFD_ASSERT (sym->section == &bfd_und_section);
+ sym->section = &bfd_com_section;
+ }
/* Do not set the section; see _bfd_generic_link_output_symbols. */
- BFD_ASSERT (bfd_is_com_section (sym->section));
break;
case bfd_link_hash_indirect:
case bfd_link_hash_warning:
abort ();
}
- h->root.written = true;
+ return true;
+}
+
+/* Create a relocation. */
+
+boolean
+_bfd_generic_reloc_link_order (abfd, info, sec, link_order)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ struct bfd_link_order *link_order;
+{
+ arelent *r;
+
+ if (! info->relocateable)
+ abort ();
+ if (sec->orelocation == (arelent **) NULL)
+ abort ();
+
+ r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
+ if (r == (arelent *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ r->address = link_order->offset;
+ r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
+ if (r->howto == (const reloc_howto_type *) NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* Get the symbol to use for the relocation. */
+ if (link_order->type == bfd_section_reloc_link_order)
+ r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+ else
+ {
+ struct generic_link_hash_entry *h;
+
+ h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
+ link_order->u.reloc.p->u.name,
+ false, false, true);
+ if (h == (struct generic_link_hash_entry *) NULL
+ || ! h->root.written)
+ {
+ if (! ((*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name,
+ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ return false;
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ r->sym_ptr_ptr = &h->sym;
+ }
+
+ /* If this is an inplace reloc, write the addend to the object file.
+ Otherwise, store it in the reloc addend. */
+ if (! r->howto->partial_inplace)
+ r->addend = link_order->u.reloc.p->addend;
+ else
+ {
+ bfd_size_type size;
+ bfd_reloc_status_type rstat;
+ bfd_byte *buf;
+ boolean ok;
+
+ size = bfd_get_reloc_size (r->howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
+ if (buf == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ rstat = _bfd_relocate_contents (r->howto, abfd,
+ link_order->u.reloc.p->addend, buf);
+ switch (rstat)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ if (! ((*info->callbacks->reloc_overflow)
+ (info,
+ (link_order->type == bfd_section_reloc_link_order
+ ? bfd_section_name (abfd, link_order->u.reloc.p->u.section)
+ : link_order->u.reloc.p->u.name),
+ r->howto->name, link_order->u.reloc.p->addend,
+ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ {
+ free (buf);
+ return false;
+ }
+ break;
+ }
+ ok = bfd_set_section_contents (abfd, sec, (PTR) buf,
+ (file_ptr) link_order->offset, size);
+ free (buf);
+ if (! ok)
+ return false;
+
+ r->addend = 0;
+ }
+
+ sec->orelocation[sec->reloc_count] = r;
+ ++sec->reloc_count;
return true;
}
new = ((struct bfd_link_order *)
bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order)));
+ if (!new)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
new->type = bfd_undefined_link_order;
new->offset = 0;
return new;
}
-/* Default link order processing routine. */
+/* Default link order processing routine. Note that we can not handle
+ the reloc_link_order types here, since they depend upon the details
+ of how the particular backends generates relocs. */
boolean
_bfd_default_link_order (abfd, info, sec, link_order)
switch (link_order->type)
{
case bfd_undefined_link_order:
+ case bfd_section_reloc_link_order:
+ case bfd_symbol_reloc_link_order:
default:
abort ();
case bfd_indirect_link_order:
return default_indirect_link_order (abfd, info, sec, link_order);
case bfd_fill_link_order:
return default_fill_link_order (abfd, info, sec, link_order);
+ case bfd_data_link_order:
+ return bfd_set_section_contents (abfd, sec,
+ (PTR) link_order->u.data.contents,
+ (file_ptr) link_order->offset,
+ link_order->size);
}
}
char *space;
size_t i;
int fill;
+ boolean result;
BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0);
size = (size_t) link_order->size;
- space = (char *) alloca (size);
+ space = (char *) malloc (size);
+ if (space == NULL && size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
fill = link_order->u.fill.value;
for (i = 0; i < size; i += 2)
space[i] = fill >> 8;
for (i = 1; i < size; i += 2)
space[i] = fill;
- return bfd_set_section_contents (abfd, sec, space,
- (file_ptr) link_order->offset,
- link_order->size);
+ result = bfd_set_section_contents (abfd, sec, space,
+ (file_ptr) link_order->offset,
+ link_order->size);
+ free (space);
+ return result;
}
/* Default routine to handle a bfd_indirect_link_order. */
{
asection *input_section;
bfd *input_bfd;
- bfd_byte *contents;
+ bfd_byte *contents = NULL;
+ bfd_byte *new_contents;
BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
BFD_ASSERT (input_section->output_section == output_section);
BFD_ASSERT (input_section->output_offset == link_order->offset);
- BFD_ASSERT (bfd_section_size (input_bfd, input_section) == link_order->size);
+ BFD_ASSERT (input_section->_cooked_size == link_order->size);
if (info->relocateable
&& input_section->reloc_count > 0
symsize = get_symtab_upper_bound (input_bfd);
input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
+ if (!input_bfd->outsymbols)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
input_bfd->outsymbols);
}
/* Get and relocate the section contents. */
- contents = (bfd_byte *) alloca (bfd_section_size (input_bfd, input_section));
- contents = (bfd_get_relocated_section_contents
- (output_bfd, info, link_order, contents, info->relocateable,
- bfd_get_outsymbols (input_bfd)));
+ contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section));
+ if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ new_contents = (bfd_get_relocated_section_contents
+ (output_bfd, info, link_order, contents, info->relocateable,
+ bfd_get_outsymbols (input_bfd)));
+ if (!new_contents)
+ goto error_return;
/* Output the section contents. */
- if (! bfd_set_section_contents (output_bfd, output_section, (PTR) contents,
+ if (! bfd_set_section_contents (output_bfd, output_section,
+ (PTR) new_contents,
link_order->offset, link_order->size))
- return false;
+ goto error_return;
+ if (contents != NULL)
+ free (contents);
return true;
+
+ error_return:
+ if (contents != NULL)
+ free (contents);
+ return false;
+}
+
+/* A little routine to count the number of relocs in a link_order
+ list. */
+
+unsigned int
+_bfd_count_link_order_relocs (link_order)
+ struct bfd_link_order *link_order;
+{
+ register unsigned int c;
+ register struct bfd_link_order *l;
+
+ c = 0;
+ for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next)
+ {
+ if (l->type == bfd_section_reloc_link_order
+ || l->type == bfd_symbol_reloc_link_order)
+ ++c;
+ }
+
+ return c;
}