OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [bfd/] [reloc16.c] - Diff between revs 156 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 156 Rev 816
/* 8 and 16 bit COFF relocation functions, for BFD.
/* 8 and 16 bit COFF relocation functions, for BFD.
   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
   2002, 2003, 2004, 2007 Free Software Foundation, Inc.
   2002, 2003, 2004, 2007 Free Software Foundation, Inc.
   Written by Cygnus Support.
   Written by 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
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program 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
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
 
 
/* Most of this hacked by Steve Chamberlain <sac@cygnus.com>.  */
/* Most of this hacked by Steve Chamberlain <sac@cygnus.com>.  */
 
 
/* These routines are used by coff-h8300 and coff-z8k to do
/* 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
   FIXME: This code should be rewritten to support the new COFF
   linker.  Basically, they need to deal with COFF relocs rather than
   linker.  Basically, they need to deal with COFF relocs rather than
   BFD generic relocs.  They should store the relocs in some location
   BFD generic relocs.  They should store the relocs in some location
   where coff_link_input_bfd can find them (and coff_link_input_bfd
   where coff_link_input_bfd can find them (and coff_link_input_bfd
   should be changed to use this location rather than rereading the
   should be changed to use this location rather than rereading the
   file) (unless info->keep_memory is FALSE, in which case they should
   file) (unless info->keep_memory is FALSE, in which case they should
   free up the relocs after dealing with them).  */
   free up the relocs after dealing with them).  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "libbfd.h"
#include "libbfd.h"
#include "bfdlink.h"
#include "bfdlink.h"
#include "genlink.h"
#include "genlink.h"
#include "coff/internal.h"
#include "coff/internal.h"
#include "libcoff.h"
#include "libcoff.h"
 
 
bfd_vma
bfd_vma
bfd_coff_reloc16_get_value (reloc, link_info, input_section)
bfd_coff_reloc16_get_value (reloc, link_info, input_section)
     arelent *reloc;
     arelent *reloc;
     struct bfd_link_info *link_info;
     struct bfd_link_info *link_info;
     asection *input_section;
     asection *input_section;
{
{
  bfd_vma value;
  bfd_vma value;
  asymbol *symbol = *(reloc->sym_ptr_ptr);
  asymbol *symbol = *(reloc->sym_ptr_ptr);
  /* A symbol holds a pointer to a section, and an offset from the
  /* A symbol holds a pointer to a section, and an offset from the
     base of the section.  To relocate, we find where the section will
     base of the section.  To relocate, we find where the section will
     live in the output and add that in.  */
     live in the output and add that in.  */
 
 
  if (bfd_is_und_section (symbol->section)
  if (bfd_is_und_section (symbol->section)
      || bfd_is_com_section (symbol->section))
      || bfd_is_com_section (symbol->section))
    {
    {
      struct bfd_link_hash_entry *h;
      struct bfd_link_hash_entry *h;
 
 
      /* The symbol is undefined in this BFD.  Look it up in the
      /* The symbol is undefined in this BFD.  Look it up in the
         global linker hash table.  FIXME: This should be changed when
         global linker hash table.  FIXME: This should be changed when
         we convert this stuff to use a specific final_link function
         we convert this stuff to use a specific final_link function
         and change the interface to bfd_relax_section to not require
         and change the interface to bfd_relax_section to not require
         the generic symbols.  */
         the generic symbols.  */
      h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
      h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
                                        bfd_asymbol_name (symbol),
                                        bfd_asymbol_name (symbol),
                                        FALSE, FALSE, TRUE);
                                        FALSE, FALSE, TRUE);
      if (h != (struct bfd_link_hash_entry *) NULL
      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))
              || h->type == bfd_link_hash_defweak))
        value = (h->u.def.value
        value = (h->u.def.value
                 + h->u.def.section->output_section->vma
                 + h->u.def.section->output_section->vma
                 + h->u.def.section->output_offset);
                 + h->u.def.section->output_offset);
      else if (h != (struct bfd_link_hash_entry *) NULL
      else if (h != (struct bfd_link_hash_entry *) NULL
               && h->type == bfd_link_hash_common)
               && h->type == bfd_link_hash_common)
        value = h->u.c.size;
        value = h->u.c.size;
      else if (h != (struct bfd_link_hash_entry *) NULL
      else if (h != (struct bfd_link_hash_entry *) NULL
               && h->type == bfd_link_hash_undefweak)
               && h->type == bfd_link_hash_undefweak)
        /* This is a GNU extension.  */
        /* This is a GNU extension.  */
        value = 0;
        value = 0;
      else
      else
        {
        {
          if (!((*link_info->callbacks->undefined_symbol)
          if (!((*link_info->callbacks->undefined_symbol)
                (link_info, bfd_asymbol_name (symbol),
                (link_info, bfd_asymbol_name (symbol),
                 input_section->owner, input_section, reloc->address,
                 input_section->owner, input_section, reloc->address,
                 TRUE)))
                 TRUE)))
            abort ();
            abort ();
          value = 0;
          value = 0;
        }
        }
    }
    }
  else
  else
    {
    {
      value = symbol->value
      value = symbol->value
        + symbol->section->output_offset
        + symbol->section->output_offset
        + symbol->section->output_section->vma;
        + symbol->section->output_section->vma;
    }
    }
 
 
  /* Add the value contained in the relocation.  */
  /* Add the value contained in the relocation.  */
  value += reloc->addend;
  value += reloc->addend;
 
 
  return value;
  return value;
}
}
 
 
void
void
bfd_perform_slip (abfd, slip, input_section, value)
bfd_perform_slip (abfd, slip, input_section, value)
     bfd *abfd;
     bfd *abfd;
     unsigned int slip;
     unsigned int slip;
     asection *input_section;
     asection *input_section;
     bfd_vma value;
     bfd_vma value;
{
{
  asymbol **s;
  asymbol **s;
 
 
  s = _bfd_generic_link_get_symbols (abfd);
  s = _bfd_generic_link_get_symbols (abfd);
  BFD_ASSERT (s != (asymbol **) NULL);
  BFD_ASSERT (s != (asymbol **) NULL);
 
 
  /* Find all symbols past this point, and make them know
  /* Find all symbols past this point, and make them know
     what's happened.  */
     what's happened.  */
  while (*s)
  while (*s)
    {
    {
      asymbol *p = *s;
      asymbol *p = *s;
      if (p->section == input_section)
      if (p->section == input_section)
        {
        {
          /* This was pointing into this section, so mangle it.  */
          /* This was pointing into this section, so mangle it.  */
          if (p->value > value)
          if (p->value > value)
            {
            {
              p->value -= slip;
              p->value -= slip;
              if (p->udata.p != NULL)
              if (p->udata.p != NULL)
                {
                {
                  struct generic_link_hash_entry *h;
                  struct generic_link_hash_entry *h;
 
 
                  h = (struct generic_link_hash_entry *) p->udata.p;
                  h = (struct generic_link_hash_entry *) p->udata.p;
                  BFD_ASSERT (h->root.type == bfd_link_hash_defined
                  BFD_ASSERT (h->root.type == bfd_link_hash_defined
                              || h->root.type == bfd_link_hash_defweak);
                              || h->root.type == bfd_link_hash_defweak);
                  h->root.u.def.value -= slip;
                  h->root.u.def.value -= slip;
                  BFD_ASSERT (h->root.u.def.value == p->value);
                  BFD_ASSERT (h->root.u.def.value == p->value);
                }
                }
            }
            }
        }
        }
      s++;
      s++;
    }
    }
}
}
 
 
bfd_boolean
bfd_boolean
bfd_coff_reloc16_relax_section (abfd, input_section, link_info, again)
bfd_coff_reloc16_relax_section (abfd, input_section, link_info, again)
     bfd *abfd;
     bfd *abfd;
     asection *input_section;
     asection *input_section;
     struct bfd_link_info *link_info;
     struct bfd_link_info *link_info;
     bfd_boolean *again;
     bfd_boolean *again;
{
{
  /* Get enough memory to hold the stuff.  */
  /* Get enough memory to hold the stuff.  */
  bfd *input_bfd = input_section->owner;
  bfd *input_bfd = input_section->owner;
  unsigned *shrinks;
  unsigned *shrinks;
  unsigned shrink = 0;
  unsigned shrink = 0;
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  arelent **reloc_vector = NULL;
  arelent **reloc_vector = NULL;
  long reloc_count;
  long reloc_count;
 
 
  /* We only do global relaxation once.  It is not safe to do it multiple
  /* We only do global relaxation once.  It is not safe to do it multiple
     times (see discussion of the "shrinks" array below).  */
     times (see discussion of the "shrinks" array below).  */
  *again = FALSE;
  *again = FALSE;
 
 
  if (reloc_size < 0)
  if (reloc_size < 0)
    return FALSE;
    return FALSE;
 
 
  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  if (!reloc_vector && reloc_size > 0)
  if (!reloc_vector && reloc_size > 0)
    return FALSE;
    return FALSE;
 
 
  /* Get the relocs and think about them.  */
  /* Get the relocs and think about them.  */
  reloc_count =
  reloc_count =
    bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
    bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
                            _bfd_generic_link_get_symbols (input_bfd));
                            _bfd_generic_link_get_symbols (input_bfd));
  if (reloc_count < 0)
  if (reloc_count < 0)
    {
    {
      free (reloc_vector);
      free (reloc_vector);
      return FALSE;
      return FALSE;
    }
    }
 
 
  /* The reloc16.c and related relaxing code is very simple, the price
  /* The reloc16.c and related relaxing code is very simple, the price
     for that simplicity is we can only call this function once for
     for that simplicity is we can only call this function once for
     each section.
     each section.
 
 
     So, to get the best results within that limitation, we do multiple
     So, to get the best results within that limitation, we do multiple
     relaxing passes over each section here.  That involves keeping track
     relaxing passes over each section here.  That involves keeping track
     of the "shrink" at each reloc in the section.  This allows us to
     of the "shrink" at each reloc in the section.  This allows us to
     accurately determine the relative location of two relocs within
     accurately determine the relative location of two relocs within
     this section.
     this section.
 
 
     In theory, if we kept the "shrinks" array for each section for the
     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
     entire link, we could use the generic relaxing code in the linker
     and get better results, particularly for jsr->bsr and 24->16 bit
     and get better results, particularly for jsr->bsr and 24->16 bit
     memory reference relaxations.  */
     memory reference relaxations.  */
 
 
  if (reloc_count > 0)
  if (reloc_count > 0)
    {
    {
      int another_pass = 0;
      int another_pass = 0;
      bfd_size_type amt;
      bfd_size_type amt;
 
 
      /* Allocate and initialize the shrinks array for this section.
      /* Allocate and initialize the shrinks array for this section.
         The last element is used as an accumulator of shrinks.  */
         The last element is used as an accumulator of shrinks.  */
      amt = reloc_count + 1;
      amt = reloc_count + 1;
      amt *= sizeof (unsigned);
      amt *= sizeof (unsigned);
      shrinks = (unsigned *) bfd_zmalloc (amt);
      shrinks = (unsigned *) bfd_zmalloc (amt);
 
 
      /* Loop until nothing changes in this section.  */
      /* Loop until nothing changes in this section.  */
      do
      do
        {
        {
          arelent **parent;
          arelent **parent;
          unsigned int i;
          unsigned int i;
          long j;
          long j;
 
 
          another_pass = 0;
          another_pass = 0;
 
 
          for (i = 0, parent = reloc_vector; *parent; parent++, i++)
          for (i = 0, parent = reloc_vector; *parent; parent++, i++)
            {
            {
              /* Let the target/machine dependent code examine each reloc
              /* Let the target/machine dependent code examine each reloc
                 in this section and attempt to shrink it.  */
                 in this section and attempt to shrink it.  */
              shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
              shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
                                                  shrinks[i], link_info);
                                                  shrinks[i], link_info);
 
 
              /* If it shrunk, note it in the shrinks array and set up for
              /* If it shrunk, note it in the shrinks array and set up for
                 another pass.  */
                 another pass.  */
              if (shrink != shrinks[i])
              if (shrink != shrinks[i])
                {
                {
                  another_pass = 1;
                  another_pass = 1;
                  for (j = i + 1; j <= reloc_count; j++)
                  for (j = i + 1; j <= reloc_count; j++)
                    shrinks[j] += shrink - shrinks[i];
                    shrinks[j] += shrink - shrinks[i];
                }
                }
            }
            }
        }
        }
      while (another_pass);
      while (another_pass);
 
 
      shrink = shrinks[reloc_count];
      shrink = shrinks[reloc_count];
      free ((char *) shrinks);
      free ((char *) shrinks);
    }
    }
 
 
  input_section->rawsize = input_section->size;
  input_section->rawsize = input_section->size;
  input_section->size -= shrink;
  input_section->size -= shrink;
  free ((char *) reloc_vector);
  free ((char *) reloc_vector);
  return TRUE;
  return TRUE;
}
}
 
 
bfd_byte *
bfd_byte *
bfd_coff_reloc16_get_relocated_section_contents (in_abfd,
bfd_coff_reloc16_get_relocated_section_contents (in_abfd,
                                                 link_info,
                                                 link_info,
                                                 link_order,
                                                 link_order,
                                                 data,
                                                 data,
                                                 relocatable,
                                                 relocatable,
                                                 symbols)
                                                 symbols)
     bfd *in_abfd;
     bfd *in_abfd;
     struct bfd_link_info *link_info;
     struct bfd_link_info *link_info;
     struct bfd_link_order *link_order;
     struct bfd_link_order *link_order;
     bfd_byte *data;
     bfd_byte *data;
     bfd_boolean relocatable;
     bfd_boolean relocatable;
     asymbol **symbols;
     asymbol **symbols;
{
{
  /* Get enough memory to hold the stuff.  */
  /* Get enough memory to hold the stuff.  */
  bfd *input_bfd = link_order->u.indirect.section->owner;
  bfd *input_bfd = link_order->u.indirect.section->owner;
  asection *input_section = link_order->u.indirect.section;
  asection *input_section = link_order->u.indirect.section;
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  arelent **reloc_vector;
  arelent **reloc_vector;
  long reloc_count;
  long reloc_count;
  bfd_size_type sz;
  bfd_size_type sz;
 
 
  if (reloc_size < 0)
  if (reloc_size < 0)
    return NULL;
    return NULL;
 
 
  /* If producing relocatable output, don't bother to relax.  */
  /* If producing relocatable output, don't bother to relax.  */
  if (relocatable)
  if (relocatable)
    return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
    return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
                                                       link_order,
                                                       link_order,
                                                       data, relocatable,
                                                       data, relocatable,
                                                       symbols);
                                                       symbols);
 
 
  /* Read in the section.  */
  /* Read in the section.  */
  sz = input_section->rawsize ? input_section->rawsize : input_section->size;
  sz = input_section->rawsize ? input_section->rawsize : input_section->size;
  if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz))
  if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz))
    return NULL;
    return NULL;
 
 
  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  if (!reloc_vector && reloc_size != 0)
  if (!reloc_vector && reloc_size != 0)
    return NULL;
    return NULL;
 
 
  reloc_count = bfd_canonicalize_reloc (input_bfd,
  reloc_count = bfd_canonicalize_reloc (input_bfd,
                                        input_section,
                                        input_section,
                                        reloc_vector,
                                        reloc_vector,
                                        symbols);
                                        symbols);
  if (reloc_count < 0)
  if (reloc_count < 0)
    {
    {
      free (reloc_vector);
      free (reloc_vector);
      return NULL;
      return NULL;
    }
    }
 
 
  if (reloc_count > 0)
  if (reloc_count > 0)
    {
    {
      arelent **parent = reloc_vector;
      arelent **parent = reloc_vector;
      arelent *reloc;
      arelent *reloc;
      unsigned int dst_address = 0;
      unsigned int dst_address = 0;
      unsigned int src_address = 0;
      unsigned int src_address = 0;
      unsigned int run;
      unsigned int run;
      unsigned int idx;
      unsigned int idx;
 
 
      /* Find how long a run we can do.  */
      /* Find how long a run we can do.  */
      while (dst_address < link_order->size)
      while (dst_address < link_order->size)
        {
        {
          reloc = *parent;
          reloc = *parent;
          if (reloc)
          if (reloc)
            {
            {
              /* Note that the relaxing didn't tie up the addresses in the
              /* Note that the relaxing didn't tie up the addresses in the
                 relocation, so we use the original address to work out the
                 relocation, so we use the original address to work out the
                 run of non-relocated data.  */
                 run of non-relocated data.  */
              run = reloc->address - src_address;
              run = reloc->address - src_address;
              parent++;
              parent++;
            }
            }
          else
          else
            {
            {
              run = link_order->size - dst_address;
              run = link_order->size - dst_address;
            }
            }
 
 
          /* Copy the bytes.  */
          /* Copy the bytes.  */
          for (idx = 0; idx < run; idx++)
          for (idx = 0; idx < run; idx++)
            data[dst_address++] = data[src_address++];
            data[dst_address++] = data[src_address++];
 
 
          /* Now do the relocation.  */
          /* Now do the relocation.  */
          if (reloc)
          if (reloc)
            {
            {
              bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
              bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
                                            reloc, data, &src_address,
                                            reloc, data, &src_address,
                                            &dst_address);
                                            &dst_address);
            }
            }
        }
        }
    }
    }
  free ((char *) reloc_vector);
  free ((char *) reloc_vector);
  return data;
  return data;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.