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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [ld/] [ldwrite.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
/* ldwrite.c -- write out the linked file
/* ldwrite.c -- write out the linked file
   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002,
   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002,
   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   Written by Steve Chamberlain sac@cygnus.com
   Written by Steve Chamberlain sac@cygnus.com
 
 
   This file is part of the GNU Binutils.
   This file is part of the GNU Binutils.
 
 
   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.  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "bfdlink.h"
#include "bfdlink.h"
#include "libiberty.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
 
 
#include "ld.h"
#include "ld.h"
#include "ldexp.h"
#include "ldexp.h"
#include "ldlang.h"
#include "ldlang.h"
#include "ldwrite.h"
#include "ldwrite.h"
#include "ldmisc.h"
#include "ldmisc.h"
#include <ldgram.h>
#include <ldgram.h>
#include "ldmain.h"
#include "ldmain.h"
 
 
/* Build link_order structures for the BFD linker.  */
/* Build link_order structures for the BFD linker.  */
 
 
static void
static void
build_link_order (lang_statement_union_type *statement)
build_link_order (lang_statement_union_type *statement)
{
{
  switch (statement->header.type)
  switch (statement->header.type)
    {
    {
    case lang_data_statement_enum:
    case lang_data_statement_enum:
      {
      {
        asection *output_section;
        asection *output_section;
        struct bfd_link_order *link_order;
        struct bfd_link_order *link_order;
        bfd_vma value;
        bfd_vma value;
        bfd_boolean big_endian = FALSE;
        bfd_boolean big_endian = FALSE;
 
 
        output_section = statement->data_statement.output_section;
        output_section = statement->data_statement.output_section;
        ASSERT (output_section->owner == link_info.output_bfd);
        ASSERT (output_section->owner == link_info.output_bfd);
 
 
        link_order = bfd_new_link_order (link_info.output_bfd, output_section);
        link_order = bfd_new_link_order (link_info.output_bfd, output_section);
        if (link_order == NULL)
        if (link_order == NULL)
          einfo (_("%P%F: bfd_new_link_order failed\n"));
          einfo (_("%P%F: bfd_new_link_order failed\n"));
 
 
        link_order->type = bfd_data_link_order;
        link_order->type = bfd_data_link_order;
        link_order->offset = statement->data_statement.output_offset;
        link_order->offset = statement->data_statement.output_offset;
        link_order->u.data.contents = xmalloc (QUAD_SIZE);
        link_order->u.data.contents = xmalloc (QUAD_SIZE);
 
 
        value = statement->data_statement.value;
        value = statement->data_statement.value;
 
 
        /* If the endianness of the output BFD is not known, then we
        /* If the endianness of the output BFD is not known, then we
           base the endianness of the data on the first input file.
           base the endianness of the data on the first input file.
           By convention, the bfd_put routines for an unknown
           By convention, the bfd_put routines for an unknown
           endianness are big endian, so we must swap here if the
           endianness are big endian, so we must swap here if the
           input file is little endian.  */
           input file is little endian.  */
        if (bfd_big_endian (link_info.output_bfd))
        if (bfd_big_endian (link_info.output_bfd))
          big_endian = TRUE;
          big_endian = TRUE;
        else if (bfd_little_endian (link_info.output_bfd))
        else if (bfd_little_endian (link_info.output_bfd))
          big_endian = FALSE;
          big_endian = FALSE;
        else
        else
          {
          {
            bfd_boolean swap;
            bfd_boolean swap;
 
 
            swap = FALSE;
            swap = FALSE;
            if (command_line.endian == ENDIAN_BIG)
            if (command_line.endian == ENDIAN_BIG)
              big_endian = TRUE;
              big_endian = TRUE;
            else if (command_line.endian == ENDIAN_LITTLE)
            else if (command_line.endian == ENDIAN_LITTLE)
              {
              {
                big_endian = FALSE;
                big_endian = FALSE;
                swap = TRUE;
                swap = TRUE;
              }
              }
            else if (command_line.endian == ENDIAN_UNSET)
            else if (command_line.endian == ENDIAN_UNSET)
              {
              {
                big_endian = TRUE;
                big_endian = TRUE;
                {
                {
                  LANG_FOR_EACH_INPUT_STATEMENT (s)
                  LANG_FOR_EACH_INPUT_STATEMENT (s)
                    {
                    {
                      if (s->the_bfd != NULL)
                      if (s->the_bfd != NULL)
                        {
                        {
                          if (bfd_little_endian (s->the_bfd))
                          if (bfd_little_endian (s->the_bfd))
                            {
                            {
                              big_endian = FALSE;
                              big_endian = FALSE;
                              swap = TRUE;
                              swap = TRUE;
                            }
                            }
                          break;
                          break;
                        }
                        }
                    }
                    }
                }
                }
              }
              }
 
 
            if (swap)
            if (swap)
              {
              {
                bfd_byte buffer[8];
                bfd_byte buffer[8];
 
 
                switch (statement->data_statement.type)
                switch (statement->data_statement.type)
                  {
                  {
                  case QUAD:
                  case QUAD:
                  case SQUAD:
                  case SQUAD:
                    if (sizeof (bfd_vma) >= QUAD_SIZE)
                    if (sizeof (bfd_vma) >= QUAD_SIZE)
                      {
                      {
                        bfd_putl64 (value, buffer);
                        bfd_putl64 (value, buffer);
                        value = bfd_getb64 (buffer);
                        value = bfd_getb64 (buffer);
                        break;
                        break;
                      }
                      }
                    /* Fall through.  */
                    /* Fall through.  */
                  case LONG:
                  case LONG:
                    bfd_putl32 (value, buffer);
                    bfd_putl32 (value, buffer);
                    value = bfd_getb32 (buffer);
                    value = bfd_getb32 (buffer);
                    break;
                    break;
                  case SHORT:
                  case SHORT:
                    bfd_putl16 (value, buffer);
                    bfd_putl16 (value, buffer);
                    value = bfd_getb16 (buffer);
                    value = bfd_getb16 (buffer);
                    break;
                    break;
                  case BYTE:
                  case BYTE:
                    break;
                    break;
                  default:
                  default:
                    abort ();
                    abort ();
                  }
                  }
              }
              }
          }
          }
 
 
        ASSERT (output_section->owner == link_info.output_bfd);
        ASSERT (output_section->owner == link_info.output_bfd);
        switch (statement->data_statement.type)
        switch (statement->data_statement.type)
          {
          {
          case QUAD:
          case QUAD:
          case SQUAD:
          case SQUAD:
            if (sizeof (bfd_vma) >= QUAD_SIZE)
            if (sizeof (bfd_vma) >= QUAD_SIZE)
              bfd_put_64 (link_info.output_bfd, value,
              bfd_put_64 (link_info.output_bfd, value,
                          link_order->u.data.contents);
                          link_order->u.data.contents);
            else
            else
              {
              {
                bfd_vma high;
                bfd_vma high;
 
 
                if (statement->data_statement.type == QUAD)
                if (statement->data_statement.type == QUAD)
                  high = 0;
                  high = 0;
                else if ((value & 0x80000000) == 0)
                else if ((value & 0x80000000) == 0)
                  high = 0;
                  high = 0;
                else
                else
                  high = (bfd_vma) -1;
                  high = (bfd_vma) -1;
                bfd_put_32 (link_info.output_bfd, high,
                bfd_put_32 (link_info.output_bfd, high,
                            (link_order->u.data.contents
                            (link_order->u.data.contents
                             + (big_endian ? 0 : 4)));
                             + (big_endian ? 0 : 4)));
                bfd_put_32 (link_info.output_bfd, value,
                bfd_put_32 (link_info.output_bfd, value,
                            (link_order->u.data.contents
                            (link_order->u.data.contents
                             + (big_endian ? 4 : 0)));
                             + (big_endian ? 4 : 0)));
              }
              }
            link_order->size = QUAD_SIZE;
            link_order->size = QUAD_SIZE;
            break;
            break;
          case LONG:
          case LONG:
            bfd_put_32 (link_info.output_bfd, value,
            bfd_put_32 (link_info.output_bfd, value,
                        link_order->u.data.contents);
                        link_order->u.data.contents);
            link_order->size = LONG_SIZE;
            link_order->size = LONG_SIZE;
            break;
            break;
          case SHORT:
          case SHORT:
            bfd_put_16 (link_info.output_bfd, value,
            bfd_put_16 (link_info.output_bfd, value,
                        link_order->u.data.contents);
                        link_order->u.data.contents);
            link_order->size = SHORT_SIZE;
            link_order->size = SHORT_SIZE;
            break;
            break;
          case BYTE:
          case BYTE:
            bfd_put_8 (link_info.output_bfd, value,
            bfd_put_8 (link_info.output_bfd, value,
                       link_order->u.data.contents);
                       link_order->u.data.contents);
            link_order->size = BYTE_SIZE;
            link_order->size = BYTE_SIZE;
            break;
            break;
          default:
          default:
            abort ();
            abort ();
          }
          }
      }
      }
      break;
      break;
 
 
    case lang_reloc_statement_enum:
    case lang_reloc_statement_enum:
      {
      {
        lang_reloc_statement_type *rs;
        lang_reloc_statement_type *rs;
        asection *output_section;
        asection *output_section;
        struct bfd_link_order *link_order;
        struct bfd_link_order *link_order;
 
 
        rs = &statement->reloc_statement;
        rs = &statement->reloc_statement;
 
 
        output_section = rs->output_section;
        output_section = rs->output_section;
        ASSERT (output_section->owner == link_info.output_bfd);
        ASSERT (output_section->owner == link_info.output_bfd);
 
 
        link_order = bfd_new_link_order (link_info.output_bfd, output_section);
        link_order = bfd_new_link_order (link_info.output_bfd, output_section);
        if (link_order == NULL)
        if (link_order == NULL)
          einfo (_("%P%F: bfd_new_link_order failed\n"));
          einfo (_("%P%F: bfd_new_link_order failed\n"));
 
 
        link_order->offset = rs->output_offset;
        link_order->offset = rs->output_offset;
        link_order->size = bfd_get_reloc_size (rs->howto);
        link_order->size = bfd_get_reloc_size (rs->howto);
 
 
        link_order->u.reloc.p = xmalloc (sizeof (struct bfd_link_order_reloc));
        link_order->u.reloc.p = xmalloc (sizeof (struct bfd_link_order_reloc));
 
 
        link_order->u.reloc.p->reloc = rs->reloc;
        link_order->u.reloc.p->reloc = rs->reloc;
        link_order->u.reloc.p->addend = rs->addend_value;
        link_order->u.reloc.p->addend = rs->addend_value;
 
 
        if (rs->name == NULL)
        if (rs->name == NULL)
          {
          {
            link_order->type = bfd_section_reloc_link_order;
            link_order->type = bfd_section_reloc_link_order;
            if (rs->section->owner == link_info.output_bfd)
            if (rs->section->owner == link_info.output_bfd)
              link_order->u.reloc.p->u.section = rs->section;
              link_order->u.reloc.p->u.section = rs->section;
            else
            else
              {
              {
                link_order->u.reloc.p->u.section = rs->section->output_section;
                link_order->u.reloc.p->u.section = rs->section->output_section;
                link_order->u.reloc.p->addend += rs->section->output_offset;
                link_order->u.reloc.p->addend += rs->section->output_offset;
              }
              }
          }
          }
        else
        else
          {
          {
            link_order->type = bfd_symbol_reloc_link_order;
            link_order->type = bfd_symbol_reloc_link_order;
            link_order->u.reloc.p->u.name = rs->name;
            link_order->u.reloc.p->u.name = rs->name;
          }
          }
      }
      }
      break;
      break;
 
 
    case lang_input_section_enum:
    case lang_input_section_enum:
      {
      {
        /* Create a new link_order in the output section with this
        /* Create a new link_order in the output section with this
           attached */
           attached */
        asection *i = statement->input_section.section;
        asection *i = statement->input_section.section;
 
 
        if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag
        if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag
            && (i->flags & SEC_EXCLUDE) == 0)
            && (i->flags & SEC_EXCLUDE) == 0)
          {
          {
            asection *output_section = i->output_section;
            asection *output_section = i->output_section;
 
 
            ASSERT (output_section->owner == link_info.output_bfd);
            ASSERT (output_section->owner == link_info.output_bfd);
 
 
            if ((output_section->flags & SEC_HAS_CONTENTS) != 0
            if ((output_section->flags & SEC_HAS_CONTENTS) != 0
                || ((output_section->flags & SEC_LOAD) != 0
                || ((output_section->flags & SEC_LOAD) != 0
                    && (output_section->flags & SEC_THREAD_LOCAL)))
                    && (output_section->flags & SEC_THREAD_LOCAL)))
              {
              {
                struct bfd_link_order *link_order;
                struct bfd_link_order *link_order;
 
 
                link_order = bfd_new_link_order (link_info.output_bfd,
                link_order = bfd_new_link_order (link_info.output_bfd,
                                                 output_section);
                                                 output_section);
 
 
                if (i->flags & SEC_NEVER_LOAD)
                if (i->flags & SEC_NEVER_LOAD)
                  {
                  {
                    /* We've got a never load section inside one which
                    /* We've got a never load section inside one which
                       is going to be output, we'll change it into a
                       is going to be output, we'll change it into a
                       fill.  */
                       fill.  */
                    link_order->type = bfd_data_link_order;
                    link_order->type = bfd_data_link_order;
                    link_order->u.data.contents = (unsigned char *) "";
                    link_order->u.data.contents = (unsigned char *) "";
                    link_order->u.data.size = 1;
                    link_order->u.data.size = 1;
                  }
                  }
                else
                else
                  {
                  {
                    link_order->type = bfd_indirect_link_order;
                    link_order->type = bfd_indirect_link_order;
                    link_order->u.indirect.section = i;
                    link_order->u.indirect.section = i;
                    ASSERT (i->output_section == output_section);
                    ASSERT (i->output_section == output_section);
                  }
                  }
                link_order->size = i->size;
                link_order->size = i->size;
                link_order->offset = i->output_offset;
                link_order->offset = i->output_offset;
              }
              }
          }
          }
      }
      }
      break;
      break;
 
 
    case lang_padding_statement_enum:
    case lang_padding_statement_enum:
      /* Make a new link_order with the right filler */
      /* Make a new link_order with the right filler */
      {
      {
        asection *output_section;
        asection *output_section;
        struct bfd_link_order *link_order;
        struct bfd_link_order *link_order;
 
 
        output_section = statement->padding_statement.output_section;
        output_section = statement->padding_statement.output_section;
        ASSERT (statement->padding_statement.output_section->owner
        ASSERT (statement->padding_statement.output_section->owner
                == link_info.output_bfd);
                == link_info.output_bfd);
        if (((output_section->flags & SEC_HAS_CONTENTS) != 0
        if (((output_section->flags & SEC_HAS_CONTENTS) != 0
             || ((output_section->flags & SEC_LOAD) != 0
             || ((output_section->flags & SEC_LOAD) != 0
                 && (output_section->flags & SEC_THREAD_LOCAL)))
                 && (output_section->flags & SEC_THREAD_LOCAL)))
            && (output_section->flags & SEC_NEVER_LOAD) == 0)
            && (output_section->flags & SEC_NEVER_LOAD) == 0)
          {
          {
            link_order = bfd_new_link_order (link_info.output_bfd,
            link_order = bfd_new_link_order (link_info.output_bfd,
                                             output_section);
                                             output_section);
            link_order->type = bfd_data_link_order;
            link_order->type = bfd_data_link_order;
            link_order->size = statement->padding_statement.size;
            link_order->size = statement->padding_statement.size;
            link_order->offset = statement->padding_statement.output_offset;
            link_order->offset = statement->padding_statement.output_offset;
            link_order->u.data.contents = statement->padding_statement.fill->data;
            link_order->u.data.contents = statement->padding_statement.fill->data;
            link_order->u.data.size = statement->padding_statement.fill->size;
            link_order->u.data.size = statement->padding_statement.fill->size;
          }
          }
      }
      }
      break;
      break;
 
 
    default:
    default:
      /* All the other ones fall through */
      /* All the other ones fall through */
      break;
      break;
    }
    }
}
}
 
 
/* Return true if NAME is the name of an unsplittable section. These
/* Return true if NAME is the name of an unsplittable section. These
   are the stabs strings, dwarf strings.  */
   are the stabs strings, dwarf strings.  */
 
 
static bfd_boolean
static bfd_boolean
unsplittable_name (const char *name)
unsplittable_name (const char *name)
{
{
  if (CONST_STRNEQ (name, ".stab"))
  if (CONST_STRNEQ (name, ".stab"))
    {
    {
      /* There are several stab like string sections. We pattern match on
      /* There are several stab like string sections. We pattern match on
         ".stab...str"  */
         ".stab...str"  */
      unsigned len = strlen (name);
      unsigned len = strlen (name);
      if (strcmp (&name[len-3], "str") == 0)
      if (strcmp (&name[len-3], "str") == 0)
        return TRUE;
        return TRUE;
    }
    }
  else if (strcmp (name, "$GDB_STRINGS$") == 0)
  else if (strcmp (name, "$GDB_STRINGS$") == 0)
    return TRUE;
    return TRUE;
  return FALSE;
  return FALSE;
}
}
 
 
/* Wander around the input sections, make sure that
/* Wander around the input sections, make sure that
   we'll never try and create an output section with more relocs
   we'll never try and create an output section with more relocs
   than will fit.. Do this by always assuming the worst case, and
   than will fit.. Do this by always assuming the worst case, and
   creating new output sections with all the right bits.  */
   creating new output sections with all the right bits.  */
#define TESTIT 1
#define TESTIT 1
static asection *
static asection *
clone_section (bfd *abfd, asection *s, const char *name, int *count)
clone_section (bfd *abfd, asection *s, const char *name, int *count)
{
{
  char *tname;
  char *tname;
  char *sname;
  char *sname;
  unsigned int len;
  unsigned int len;
  asection *n;
  asection *n;
  struct bfd_link_hash_entry *h;
  struct bfd_link_hash_entry *h;
 
 
  /* Invent a section name from the section name and a dotted numeric
  /* Invent a section name from the section name and a dotted numeric
     suffix.   */
     suffix.   */
  len = strlen (name);
  len = strlen (name);
  tname = xmalloc (len + 1);
  tname = xmalloc (len + 1);
  memcpy (tname, name, len + 1);
  memcpy (tname, name, len + 1);
  /* Remove a dotted number suffix, from a previous split link. */
  /* Remove a dotted number suffix, from a previous split link. */
  while (len && ISDIGIT (tname[len-1]))
  while (len && ISDIGIT (tname[len-1]))
    len--;
    len--;
  if (len > 1 && tname[len-1] == '.')
  if (len > 1 && tname[len-1] == '.')
    /* It was a dotted number. */
    /* It was a dotted number. */
    tname[len-1] = 0;
    tname[len-1] = 0;
 
 
  /* We want to use the whole of the original section name for the
  /* We want to use the whole of the original section name for the
     split name, but coff can be restricted to 8 character names.  */
     split name, but coff can be restricted to 8 character names.  */
  if (bfd_family_coff (abfd) && strlen (tname) > 5)
  if (bfd_family_coff (abfd) && strlen (tname) > 5)
    {
    {
      /* Some section names cannot be truncated, as the name is
      /* Some section names cannot be truncated, as the name is
         used to locate some other section.  */
         used to locate some other section.  */
      if (CONST_STRNEQ (name, ".stab")
      if (CONST_STRNEQ (name, ".stab")
          || strcmp (name, "$GDB_SYMBOLS$") == 0)
          || strcmp (name, "$GDB_SYMBOLS$") == 0)
        {
        {
          einfo (_ ("%F%P: cannot create split section name for %s\n"), name);
          einfo (_ ("%F%P: cannot create split section name for %s\n"), name);
          /* Silence gcc warnings.  einfo exits, so we never reach here.  */
          /* Silence gcc warnings.  einfo exits, so we never reach here.  */
          return NULL;
          return NULL;
        }
        }
      tname[5] = 0;
      tname[5] = 0;
    }
    }
 
 
  if ((sname = bfd_get_unique_section_name (abfd, tname, count)) == NULL
  if ((sname = bfd_get_unique_section_name (abfd, tname, count)) == NULL
      || (n = bfd_make_section_anyway (abfd, sname)) == NULL
      || (n = bfd_make_section_anyway (abfd, sname)) == NULL
      || (h = bfd_link_hash_lookup (link_info.hash,
      || (h = bfd_link_hash_lookup (link_info.hash,
                                    sname, TRUE, TRUE, FALSE)) == NULL)
                                    sname, TRUE, TRUE, FALSE)) == NULL)
    {
    {
      einfo (_("%F%P: clone section failed: %E\n"));
      einfo (_("%F%P: clone section failed: %E\n"));
      /* Silence gcc warnings.  einfo exits, so we never reach here.  */
      /* Silence gcc warnings.  einfo exits, so we never reach here.  */
      return NULL;
      return NULL;
    }
    }
  free (tname);
  free (tname);
 
 
  /* Set up section symbol.  */
  /* Set up section symbol.  */
  h->type = bfd_link_hash_defined;
  h->type = bfd_link_hash_defined;
  h->u.def.value = 0;
  h->u.def.value = 0;
  h->u.def.section = n;
  h->u.def.section = n;
 
 
  n->flags = s->flags;
  n->flags = s->flags;
  n->vma = s->vma;
  n->vma = s->vma;
  n->user_set_vma = s->user_set_vma;
  n->user_set_vma = s->user_set_vma;
  n->lma = s->lma;
  n->lma = s->lma;
  n->size = 0;
  n->size = 0;
  n->output_offset = s->output_offset;
  n->output_offset = s->output_offset;
  n->output_section = n;
  n->output_section = n;
  n->orelocation = 0;
  n->orelocation = 0;
  n->reloc_count = 0;
  n->reloc_count = 0;
  n->alignment_power = s->alignment_power;
  n->alignment_power = s->alignment_power;
  return n;
  return n;
}
}
 
 
#if TESTING
#if TESTING
static void
static void
ds (asection *s)
ds (asection *s)
{
{
  struct bfd_link_order *l = s->map_head.link_order;
  struct bfd_link_order *l = s->map_head.link_order;
  printf ("vma %x size %x\n", s->vma, s->size);
  printf ("vma %x size %x\n", s->vma, s->size);
  while (l)
  while (l)
    {
    {
      if (l->type == bfd_indirect_link_order)
      if (l->type == bfd_indirect_link_order)
        {
        {
          printf ("%8x %s\n", l->offset, l->u.indirect.section->owner->filename);
          printf ("%8x %s\n", l->offset, l->u.indirect.section->owner->filename);
        }
        }
      else
      else
        {
        {
          printf (_("%8x something else\n"), l->offset);
          printf (_("%8x something else\n"), l->offset);
        }
        }
      l = l->next;
      l = l->next;
    }
    }
  printf ("\n");
  printf ("\n");
}
}
 
 
dump (char *s, asection *a1, asection *a2)
dump (char *s, asection *a1, asection *a2)
{
{
  printf ("%s\n", s);
  printf ("%s\n", s);
  ds (a1);
  ds (a1);
  ds (a2);
  ds (a2);
}
}
 
 
static void
static void
sanity_check (bfd *abfd)
sanity_check (bfd *abfd)
{
{
  asection *s;
  asection *s;
  for (s = abfd->sections; s; s = s->next)
  for (s = abfd->sections; s; s = s->next)
    {
    {
      struct bfd_link_order *p;
      struct bfd_link_order *p;
      bfd_vma prev = 0;
      bfd_vma prev = 0;
      for (p = s->map_head.link_order; p; p = p->next)
      for (p = s->map_head.link_order; p; p = p->next)
        {
        {
          if (p->offset > 100000)
          if (p->offset > 100000)
            abort ();
            abort ();
          if (p->offset < prev)
          if (p->offset < prev)
            abort ();
            abort ();
          prev = p->offset;
          prev = p->offset;
        }
        }
    }
    }
}
}
#else
#else
#define sanity_check(a)
#define sanity_check(a)
#define dump(a, b, c)
#define dump(a, b, c)
#endif
#endif
 
 
static void
static void
split_sections (bfd *abfd, struct bfd_link_info *info)
split_sections (bfd *abfd, struct bfd_link_info *info)
{
{
  asection *original_sec;
  asection *original_sec;
  int nsecs = abfd->section_count;
  int nsecs = abfd->section_count;
  sanity_check (abfd);
  sanity_check (abfd);
  /* Look through all the original sections.  */
  /* Look through all the original sections.  */
  for (original_sec = abfd->sections;
  for (original_sec = abfd->sections;
       original_sec && nsecs;
       original_sec && nsecs;
       original_sec = original_sec->next, nsecs--)
       original_sec = original_sec->next, nsecs--)
    {
    {
      int count = 0;
      int count = 0;
      unsigned int lines = 0;
      unsigned int lines = 0;
      unsigned int relocs = 0;
      unsigned int relocs = 0;
      bfd_size_type sec_size = 0;
      bfd_size_type sec_size = 0;
      struct bfd_link_order *l;
      struct bfd_link_order *l;
      struct bfd_link_order *p;
      struct bfd_link_order *p;
      bfd_vma vma = original_sec->vma;
      bfd_vma vma = original_sec->vma;
      asection *cursor = original_sec;
      asection *cursor = original_sec;
 
 
      /* Count up the relocations and line entries to see if anything
      /* Count up the relocations and line entries to see if anything
         would be too big to fit.  Accumulate section size too.  */
         would be too big to fit.  Accumulate section size too.  */
      for (l = NULL, p = cursor->map_head.link_order; p != NULL; p = l->next)
      for (l = NULL, p = cursor->map_head.link_order; p != NULL; p = l->next)
        {
        {
          unsigned int thislines = 0;
          unsigned int thislines = 0;
          unsigned int thisrelocs = 0;
          unsigned int thisrelocs = 0;
          bfd_size_type thissize = 0;
          bfd_size_type thissize = 0;
          if (p->type == bfd_indirect_link_order)
          if (p->type == bfd_indirect_link_order)
            {
            {
              asection *sec;
              asection *sec;
 
 
              sec = p->u.indirect.section;
              sec = p->u.indirect.section;
 
 
              if (info->strip == strip_none
              if (info->strip == strip_none
                  || info->strip == strip_some)
                  || info->strip == strip_some)
                thislines = sec->lineno_count;
                thislines = sec->lineno_count;
 
 
              if (info->relocatable)
              if (info->relocatable)
                thisrelocs = sec->reloc_count;
                thisrelocs = sec->reloc_count;
 
 
              thissize = sec->size;
              thissize = sec->size;
 
 
            }
            }
          else if (info->relocatable
          else if (info->relocatable
                   && (p->type == bfd_section_reloc_link_order
                   && (p->type == bfd_section_reloc_link_order
                       || p->type == bfd_symbol_reloc_link_order))
                       || p->type == bfd_symbol_reloc_link_order))
            thisrelocs++;
            thisrelocs++;
 
 
          if (l != NULL
          if (l != NULL
              && (thisrelocs + relocs >= config.split_by_reloc
              && (thisrelocs + relocs >= config.split_by_reloc
                  || thislines + lines >= config.split_by_reloc
                  || thislines + lines >= config.split_by_reloc
                  || (thissize + sec_size >= config.split_by_file))
                  || (thissize + sec_size >= config.split_by_file))
              && !unsplittable_name (cursor->name))
              && !unsplittable_name (cursor->name))
            {
            {
              /* Create a new section and put this link order and the
              /* Create a new section and put this link order and the
                 following link orders into it.  */
                 following link orders into it.  */
              bfd_vma shift_offset;
              bfd_vma shift_offset;
              asection *n;
              asection *n;
 
 
              n = clone_section (abfd, cursor, original_sec->name, &count);
              n = clone_section (abfd, cursor, original_sec->name, &count);
 
 
              /* Attach the link orders to the new section and snip
              /* Attach the link orders to the new section and snip
                 them off from the old section.  */
                 them off from the old section.  */
              n->map_head.link_order = p;
              n->map_head.link_order = p;
              n->map_tail.link_order = cursor->map_tail.link_order;
              n->map_tail.link_order = cursor->map_tail.link_order;
              cursor->map_tail.link_order = l;
              cursor->map_tail.link_order = l;
              l->next = NULL;
              l->next = NULL;
              l = p;
              l = p;
 
 
              /* Change the size of the original section and
              /* Change the size of the original section and
                 update the vma of the new one.  */
                 update the vma of the new one.  */
 
 
              dump ("before snip", cursor, n);
              dump ("before snip", cursor, n);
 
 
              shift_offset = p->offset;
              shift_offset = p->offset;
              n->size = cursor->size - shift_offset;
              n->size = cursor->size - shift_offset;
              cursor->size = shift_offset;
              cursor->size = shift_offset;
 
 
              vma += shift_offset;
              vma += shift_offset;
              n->lma = n->vma = vma;
              n->lma = n->vma = vma;
 
 
              /* Run down the chain and change the output section to
              /* Run down the chain and change the output section to
                 the right one, update the offsets too.  */
                 the right one, update the offsets too.  */
              do
              do
                {
                {
                  p->offset -= shift_offset;
                  p->offset -= shift_offset;
                  if (p->type == bfd_indirect_link_order)
                  if (p->type == bfd_indirect_link_order)
                    {
                    {
                      p->u.indirect.section->output_section = n;
                      p->u.indirect.section->output_section = n;
                      p->u.indirect.section->output_offset = p->offset;
                      p->u.indirect.section->output_offset = p->offset;
                    }
                    }
                  p = p->next;
                  p = p->next;
                }
                }
              while (p);
              while (p);
 
 
              dump ("after snip", cursor, n);
              dump ("after snip", cursor, n);
              cursor = n;
              cursor = n;
              relocs = thisrelocs;
              relocs = thisrelocs;
              lines = thislines;
              lines = thislines;
              sec_size = thissize;
              sec_size = thissize;
            }
            }
          else
          else
            {
            {
              l = p;
              l = p;
              relocs += thisrelocs;
              relocs += thisrelocs;
              lines += thislines;
              lines += thislines;
              sec_size += thissize;
              sec_size += thissize;
            }
            }
        }
        }
    }
    }
  sanity_check (abfd);
  sanity_check (abfd);
}
}
 
 
/* Call BFD to write out the linked file.  */
/* Call BFD to write out the linked file.  */
 
 
void
void
ldwrite (void)
ldwrite (void)
{
{
  /* Reset error indicator, which can typically something like invalid
  /* Reset error indicator, which can typically something like invalid
     format from opening up the .o files.  */
     format from opening up the .o files.  */
  bfd_set_error (bfd_error_no_error);
  bfd_set_error (bfd_error_no_error);
  lang_for_each_statement (build_link_order);
  lang_for_each_statement (build_link_order);
 
 
  if (config.split_by_reloc != (unsigned) -1
  if (config.split_by_reloc != (unsigned) -1
      || config.split_by_file != (bfd_size_type) -1)
      || config.split_by_file != (bfd_size_type) -1)
    split_sections (link_info.output_bfd, &link_info);
    split_sections (link_info.output_bfd, &link_info);
  if (!bfd_final_link (link_info.output_bfd, &link_info))
  if (!bfd_final_link (link_info.output_bfd, &link_info))
    {
    {
      /* If there was an error recorded, print it out.  Otherwise assume
      /* If there was an error recorded, print it out.  Otherwise assume
         an appropriate error message like unknown symbol was printed
         an appropriate error message like unknown symbol was printed
         out.  */
         out.  */
 
 
      if (bfd_get_error () != bfd_error_no_error)
      if (bfd_get_error () != bfd_error_no_error)
        einfo (_("%F%P: final link failed: %E\n"));
        einfo (_("%F%P: final link failed: %E\n"));
      else
      else
        xexit (1);
        xexit (1);
    }
    }
}
}
 
 

powered by: WebSVN 2.1.0

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