Back to index

cell-binutils  2.17cvs20070401
reloc16.c
Go to the documentation of this file.
00001 /* 8 and 16 bit COFF relocation functions, for BFD.
00002    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
00003    2002, 2003, 2004 Free Software Foundation, Inc.
00004    Written by Cygnus Support.
00005 
00006 This file is part of BFD, the Binary File Descriptor library.
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 /* Most of this hacked by Steve Chamberlain <sac@cygnus.com>.  */
00023 
00024 /* These routines are used by coff-h8300 and coff-z8k to do
00025    relocation.
00026 
00027    FIXME: This code should be rewritten to support the new COFF
00028    linker.  Basically, they need to deal with COFF relocs rather than
00029    BFD generic relocs.  They should store the relocs in some location
00030    where coff_link_input_bfd can find them (and coff_link_input_bfd
00031    should be changed to use this location rather than rereading the
00032    file) (unless info->keep_memory is FALSE, in which case they should
00033    free up the relocs after dealing with them).  */
00034 
00035 #include "bfd.h"
00036 #include "sysdep.h"
00037 #include "libbfd.h"
00038 #include "bfdlink.h"
00039 #include "genlink.h"
00040 #include "coff/internal.h"
00041 #include "libcoff.h"
00042 
00043 bfd_vma
00044 bfd_coff_reloc16_get_value (reloc, link_info, input_section)
00045      arelent *reloc;
00046      struct bfd_link_info *link_info;
00047      asection *input_section;
00048 {
00049   bfd_vma value;
00050   asymbol *symbol = *(reloc->sym_ptr_ptr);
00051   /* A symbol holds a pointer to a section, and an offset from the
00052      base of the section.  To relocate, we find where the section will
00053      live in the output and add that in.  */
00054 
00055   if (bfd_is_und_section (symbol->section)
00056       || bfd_is_com_section (symbol->section))
00057     {
00058       struct bfd_link_hash_entry *h;
00059 
00060       /* The symbol is undefined in this BFD.  Look it up in the
00061         global linker hash table.  FIXME: This should be changed when
00062         we convert this stuff to use a specific final_link function
00063         and change the interface to bfd_relax_section to not require
00064         the generic symbols.  */
00065       h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
00066                                    bfd_asymbol_name (symbol),
00067                                    FALSE, FALSE, TRUE);
00068       if (h != (struct bfd_link_hash_entry *) NULL
00069          && (h->type == bfd_link_hash_defined
00070              || h->type == bfd_link_hash_defweak))
00071        value = (h->u.def.value
00072                + h->u.def.section->output_section->vma
00073                + h->u.def.section->output_offset);
00074       else if (h != (struct bfd_link_hash_entry *) NULL
00075               && h->type == bfd_link_hash_common)
00076        value = h->u.c.size;
00077       else
00078        {
00079          if (!((*link_info->callbacks->undefined_symbol)
00080               (link_info, bfd_asymbol_name (symbol),
00081                input_section->owner, input_section, reloc->address,
00082                TRUE)))
00083            abort ();
00084          value = 0;
00085        }
00086     }
00087   else
00088     {
00089       value = symbol->value
00090        + symbol->section->output_offset
00091        + symbol->section->output_section->vma;
00092     }
00093 
00094   /* Add the value contained in the relocation.  */
00095   value += reloc->addend;
00096 
00097   return value;
00098 }
00099 
00100 void
00101 bfd_perform_slip (abfd, slip, input_section, value)
00102      bfd *abfd;
00103      unsigned int slip;
00104      asection *input_section;
00105      bfd_vma value;
00106 {
00107   asymbol **s;
00108 
00109   s = _bfd_generic_link_get_symbols (abfd);
00110   BFD_ASSERT (s != (asymbol **) NULL);
00111 
00112   /* Find all symbols past this point, and make them know
00113      what's happened.  */
00114   while (*s)
00115     {
00116       asymbol *p = *s;
00117       if (p->section == input_section)
00118        {
00119          /* This was pointing into this section, so mangle it.  */
00120          if (p->value > value)
00121            {
00122              p->value -= slip;
00123              if (p->udata.p != NULL)
00124               {
00125                 struct generic_link_hash_entry *h;
00126 
00127                 h = (struct generic_link_hash_entry *) p->udata.p;
00128                 BFD_ASSERT (h->root.type == bfd_link_hash_defined
00129                            || h->root.type == bfd_link_hash_defweak);
00130                 h->root.u.def.value -= slip;
00131                 BFD_ASSERT (h->root.u.def.value == p->value);
00132               }
00133            }
00134        }
00135       s++;
00136     }
00137 }
00138 
00139 bfd_boolean
00140 bfd_coff_reloc16_relax_section (abfd, input_section, link_info, again)
00141      bfd *abfd;
00142      asection *input_section;
00143      struct bfd_link_info *link_info;
00144      bfd_boolean *again;
00145 {
00146   /* Get enough memory to hold the stuff.  */
00147   bfd *input_bfd = input_section->owner;
00148   unsigned *shrinks;
00149   unsigned shrink = 0;
00150   long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
00151   arelent **reloc_vector = NULL;
00152   long reloc_count;
00153 
00154   /* We only do global relaxation once.  It is not safe to do it multiple
00155      times (see discussion of the "shrinks" array below).  */
00156   *again = FALSE;
00157 
00158   if (reloc_size < 0)
00159     return FALSE;
00160 
00161   reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
00162   if (!reloc_vector && reloc_size > 0)
00163     return FALSE;
00164 
00165   /* Get the relocs and think about them.  */
00166   reloc_count =
00167     bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
00168                          _bfd_generic_link_get_symbols (input_bfd));
00169   if (reloc_count < 0)
00170     {
00171       free (reloc_vector);
00172       return FALSE;
00173     }
00174 
00175   /* The reloc16.c and related relaxing code is very simple, the price
00176      for that simplicity is we can only call this function once for
00177      each section.
00178 
00179      So, to get the best results within that limitation, we do multiple
00180      relaxing passes over each section here.  That involves keeping track
00181      of the "shrink" at each reloc in the section.  This allows us to
00182      accurately determine the relative location of two relocs within
00183      this section.
00184 
00185      In theory, if we kept the "shrinks" array for each section for the
00186      entire link, we could use the generic relaxing code in the linker
00187      and get better results, particularly for jsr->bsr and 24->16 bit
00188      memory reference relaxations.  */
00189 
00190   if (reloc_count > 0)
00191     {
00192       int another_pass = 0;
00193       bfd_size_type amt;
00194 
00195       /* Allocate and initialize the shrinks array for this section.
00196         The last element is used as an accumulator of shrinks.  */
00197       amt = reloc_count + 1;
00198       amt *= sizeof (unsigned);
00199       shrinks = (unsigned *) bfd_zmalloc (amt);
00200 
00201       /* Loop until nothing changes in this section.  */
00202       do
00203        {
00204          arelent **parent;
00205          unsigned int i;
00206          long j;
00207 
00208          another_pass = 0;
00209 
00210          for (i = 0, parent = reloc_vector; *parent; parent++, i++)
00211            {
00212              /* Let the target/machine dependent code examine each reloc
00213                in this section and attempt to shrink it.  */
00214              shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
00215                                             shrinks[i], link_info);
00216 
00217              /* If it shrunk, note it in the shrinks array and set up for
00218                another pass.  */
00219              if (shrink != shrinks[i])
00220               {
00221                 another_pass = 1;
00222                 for (j = i + 1; j <= reloc_count; j++)
00223                   shrinks[j] += shrink - shrinks[i];
00224               }
00225            }
00226        }
00227       while (another_pass);
00228 
00229       shrink = shrinks[reloc_count];
00230       free ((char *) shrinks);
00231     }
00232 
00233   input_section->rawsize = input_section->size;
00234   input_section->size -= shrink;
00235   free ((char *) reloc_vector);
00236   return TRUE;
00237 }
00238 
00239 bfd_byte *
00240 bfd_coff_reloc16_get_relocated_section_contents (in_abfd,
00241                                            link_info,
00242                                            link_order,
00243                                            data,
00244                                            relocatable,
00245                                            symbols)
00246      bfd *in_abfd;
00247      struct bfd_link_info *link_info;
00248      struct bfd_link_order *link_order;
00249      bfd_byte *data;
00250      bfd_boolean relocatable;
00251      asymbol **symbols;
00252 {
00253   /* Get enough memory to hold the stuff.  */
00254   bfd *input_bfd = link_order->u.indirect.section->owner;
00255   asection *input_section = link_order->u.indirect.section;
00256   long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
00257   arelent **reloc_vector;
00258   long reloc_count;
00259   bfd_size_type sz;
00260 
00261   if (reloc_size < 0)
00262     return NULL;
00263 
00264   /* If producing relocatable output, don't bother to relax.  */
00265   if (relocatable)
00266     return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
00267                                                  link_order,
00268                                                  data, relocatable,
00269                                                  symbols);
00270 
00271   /* Read in the section.  */
00272   sz = input_section->rawsize ? input_section->rawsize : input_section->size;
00273   if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz))
00274     return NULL;
00275 
00276   reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
00277   if (!reloc_vector && reloc_size != 0)
00278     return NULL;
00279 
00280   reloc_count = bfd_canonicalize_reloc (input_bfd,
00281                                    input_section,
00282                                    reloc_vector,
00283                                    symbols);
00284   if (reloc_count < 0)
00285     {
00286       free (reloc_vector);
00287       return NULL;
00288     }
00289 
00290   if (reloc_count > 0)
00291     {
00292       arelent **parent = reloc_vector;
00293       arelent *reloc;
00294       unsigned int dst_address = 0;
00295       unsigned int src_address = 0;
00296       unsigned int run;
00297       unsigned int idx;
00298 
00299       /* Find how long a run we can do.  */
00300       while (dst_address < link_order->size)
00301        {
00302          reloc = *parent;
00303          if (reloc)
00304            {
00305              /* Note that the relaxing didn't tie up the addresses in the
00306                relocation, so we use the original address to work out the
00307                run of non-relocated data.  */
00308              run = reloc->address - src_address;
00309              parent++;
00310            }
00311          else
00312            {
00313              run = link_order->size - dst_address;
00314            }
00315 
00316          /* Copy the bytes.  */
00317          for (idx = 0; idx < run; idx++)
00318            data[dst_address++] = data[src_address++];
00319 
00320          /* Now do the relocation.  */
00321          if (reloc)
00322            {
00323              bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
00324                                        reloc, data, &src_address,
00325                                        &dst_address);
00326            }
00327        }
00328     }
00329   free ((char *) reloc_vector);
00330   return data;
00331 }