/* 8 and 16 bit COFF relocation functions, for BFD.
- Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+ Free Software Foundation, Inc.
Written by Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
Most of this hacked by Steve Chamberlain,
*/
/* These routines are used by coff-h8300 and coff-z8k to do
- relocation. */
+ relocation.
+
+ FIXME: This code should be rewritten to support the new COFF
+ linker. Basically, they need to deal with COFF relocs rather than
+ BFD generic relocs. They should store the relocs in some location
+ where coff_link_input_bfd can find them (and coff_link_input_bfd
+ should be changed to use this location rather than rereading the
+ file) (unless info->keep_memory is false, in which case they should
+ free up the relocs after dealing with them). */
#include "bfd.h"
#include "sysdep.h"
-#include "obstack.h"
#include "libbfd.h"
#include "bfdlink.h"
+#include "genlink.h"
#include "coff/internal.h"
#include "libcoff.h"
base of the section. To relocate, we find where the section will
live in the output and add that in */
- if (symbol->section == &bfd_und_section)
+ if (bfd_is_und_section (symbol->section)
+ || bfd_is_com_section (symbol->section))
{
struct bfd_link_hash_entry *h;
we convert this stuff to use a specific final_link function
and change the interface to bfd_relax_section to not require
the generic symbols. */
- h = bfd_link_hash_lookup (link_info->hash, bfd_asymbol_name (symbol),
- false, false, true);
+ h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
+ bfd_asymbol_name (symbol),
+ false, false, true);
if (h != (struct bfd_link_hash_entry *) NULL
- && h->type == bfd_link_hash_defined)
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
value = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
}
void
-bfd_perform_slip(s, slip, input_section, value)
- asymbol **s;
+bfd_perform_slip(abfd, slip, input_section, value)
+ bfd *abfd;
unsigned int slip;
asection *input_section;
bfd_vma value;
{
+ asymbol **s;
+
+ s = _bfd_generic_link_get_symbols (abfd);
+ BFD_ASSERT (s != (asymbol **) NULL);
+
/* Find all symbols past this point, and make them know
what's happened */
while (*s)
if (p->value > value)
{
p->value -= slip;
+ if (p->udata.p != NULL)
+ {
+ struct generic_link_hash_entry *h;
+
+ h = (struct generic_link_hash_entry *) p->udata.p;
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak);
+ h->root.u.def.value -= slip;
+ BFD_ASSERT (h->root.u.def.value == p->value);
+ }
}
}
s++;
}
boolean
-bfd_coff_reloc16_relax_section (abfd, i, link_info, symbols)
+bfd_coff_reloc16_relax_section (abfd, i, link_info, again)
bfd *abfd;
asection *i;
struct bfd_link_info *link_info;
- asymbol **symbols;
+ boolean *again;
{
/* Get enough memory to hold the stuff */
bfd *input_bfd = i->owner;
asection *input_section = i;
- int shrink = 0 ;
- boolean new = false;
-
- bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd,
- input_section);
- arelent **reloc_vector = (arelent **)bfd_xmalloc(reloc_size);
+ int *shrinks;
+ int shrink = 0;
+ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+ arelent **reloc_vector = NULL;
+ long reloc_count;
+
+ /* We only do global relaxation once. It is not safe to do it multiple
+ times (see discussion of the "shrinks" array below). */
+ *again = false;
+
+ if (reloc_size < 0)
+ return false;
+
+ reloc_vector = (arelent **) bfd_malloc (reloc_size);
+ if (!reloc_vector && reloc_size > 0)
+ return false;
/* Get the relocs and think about them */
- if (bfd_canonicalize_reloc(input_bfd,
- input_section,
- reloc_vector,
- symbols))
+ reloc_count =
+ bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
+ _bfd_generic_link_get_symbols (input_bfd));
+ if (reloc_count < 0)
{
- arelent **parent;
- for (parent = reloc_vector; *parent; parent++)
- {
- shrink = bfd_coff_reloc16_estimate (abfd, input_section, symbols,
- *parent, shrink, link_info);
- }
+ free (reloc_vector);
+ return false;
+ }
+
+ /* The reloc16.c and related relaxing code is very simple, the price
+ for that simplicity is we can only call this function once for
+ each section.
+
+ So, to get the best results within that limitation, we do multiple
+ relaxing passes over each section here. That involves keeping track
+ of the "shrink" at each reloc in the section. This allows us to
+ accurately determine the relative location of two relocs within
+ this section.
+
+ In theory, if we kept the "shrinks" array for each section for the
+ entire link, we could use the generic relaxing code in the linker
+ and get better results, particularly for jsr->bsr and 24->16 bit
+ memory reference relaxations. */
+
+ if (reloc_count > 0)
+ {
+ int another_pass = 0;
+
+ /* Allocate and initialize the shrinks array for this section. */
+ shrinks = (int *) bfd_malloc (reloc_count * sizeof (int));
+ memset (shrinks, 0, reloc_count * sizeof (int));
+
+ /* Loop until nothing changes in this section. */
+ do {
+ arelent **parent;
+ unsigned int i;
+ long j;
+
+ another_pass = 0;
+
+ for (i = 0, parent = reloc_vector; *parent; parent++, i++)
+ {
+ /* Let the target/machine dependent code examine each reloc
+ in this section and attempt to shrink it. */
+ shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
+ shrinks[i], link_info);
+
+ /* If it shrunk, note it in the shrinks array and set up for
+ another pass. */
+ if (shrink != shrinks[i])
+ {
+ another_pass = 1;
+ for (j = i + 1; j < reloc_count; j++)
+ shrinks[j] += shrink - shrinks[i];
+ }
+ }
+
+ } while (another_pass);
+
+ free((char *)shrinks);
}
input_section->_cooked_size -= shrink;
free((char *)reloc_vector);
- return new;
+ return true;
}
bfd_byte *
/* Get enough memory to hold the stuff */
bfd *input_bfd = link_order->u.indirect.section->owner;
asection *input_section = link_order->u.indirect.section;
- bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd,
- input_section);
- arelent **reloc_vector = (arelent **)bfd_xmalloc(reloc_size);
-
+ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+ arelent **reloc_vector;
+ long reloc_count;
+
+ if (reloc_size < 0)
+ return NULL;
+
/* If producing relocateable output, don't bother to relax. */
if (relocateable)
return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
symbols);
/* read in the section */
- bfd_get_section_contents(input_bfd,
- input_section,
- data,
- 0,
- input_section->_raw_size);
+ if (! bfd_get_section_contents(input_bfd,
+ input_section,
+ data,
+ 0,
+ input_section->_raw_size))
+ return NULL;
+
+ reloc_vector = (arelent **) bfd_malloc((size_t) reloc_size);
+ if (!reloc_vector && reloc_size != 0)
+ return NULL;
- if (bfd_canonicalize_reloc(input_bfd,
- input_section,
- reloc_vector,
- symbols) )
+ reloc_count = bfd_canonicalize_reloc (input_bfd,
+ input_section,
+ reloc_vector,
+ symbols);
+ if (reloc_count < 0)
+ {
+ free (reloc_vector);
+ return NULL;
+ }
+
+ if (reloc_count > 0)
{
arelent **parent = reloc_vector;
arelent *reloc ;
-
-
-
unsigned int dst_address = 0;
unsigned int src_address = 0;
unsigned int run;
/* Find how long a run we can do */
while (dst_address < link_order->size)
{
-
reloc = *parent;
if (reloc)
{
run of non-relocated data */
run = reloc->address - src_address;
parent++;
-
}
else
{
if (reloc)
{
- bfd_coff_reloc16_extra_cases (in_abfd, link_info, link_order,
+ bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
reloc, data, &src_address,
&dst_address);
}