Home | History | Annotate | Line # | Download | only in bfd
reloc16.c revision 1.1.1.1
      1 /* 8 and 16 bit COFF relocation functions, for BFD.
      2    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
      3    2002, 2003, 2004, 2005, 2007, 2008, 2009, 2012
      4    Free Software Foundation, Inc.
      5    Written by Cygnus Support.
      6 
      7    This file is part of BFD, the Binary File Descriptor library.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     22    MA 02110-1301, USA.  */
     23 
     24 
     25 /* Most of this hacked by Steve Chamberlain <sac (at) cygnus.com>.  */
     26 
     27 /* These routines are used by coff-h8300 and coff-z8k to do
     28    relocation.
     29 
     30    FIXME: This code should be rewritten to support the new COFF
     31    linker.  Basically, they need to deal with COFF relocs rather than
     32    BFD generic relocs.  They should store the relocs in some location
     33    where coff_link_input_bfd can find them (and coff_link_input_bfd
     34    should be changed to use this location rather than rereading the
     35    file) (unless info->keep_memory is FALSE, in which case they should
     36    free up the relocs after dealing with them).  */
     37 
     38 #include "sysdep.h"
     39 #include "bfd.h"
     40 #include "libbfd.h"
     41 #include "bfdlink.h"
     42 #include "genlink.h"
     43 #include "coff/internal.h"
     44 #include "libcoff.h"
     45 
     46 bfd_vma
     47 bfd_coff_reloc16_get_value (arelent *reloc,
     48 			    struct bfd_link_info *link_info,
     49 			    asection *input_section)
     50 {
     51   bfd_vma value;
     52   asymbol *symbol = *(reloc->sym_ptr_ptr);
     53   /* A symbol holds a pointer to a section, and an offset from the
     54      base of the section.  To relocate, we find where the section will
     55      live in the output and add that in.  */
     56 
     57   if (bfd_is_und_section (symbol->section)
     58       || bfd_is_com_section (symbol->section))
     59     {
     60       struct bfd_link_hash_entry *h;
     61 
     62       /* The symbol is undefined in this BFD.  Look it up in the
     63 	 global linker hash table.  FIXME: This should be changed when
     64 	 we convert this stuff to use a specific final_link function
     65 	 and change the interface to bfd_relax_section to not require
     66 	 the generic symbols.  */
     67       h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
     68 					bfd_asymbol_name (symbol),
     69 					FALSE, FALSE, TRUE);
     70       if (h != (struct bfd_link_hash_entry *) NULL
     71 	  && (h->type == bfd_link_hash_defined
     72 	      || h->type == bfd_link_hash_defweak))
     73 	value = (h->u.def.value
     74 		 + h->u.def.section->output_section->vma
     75 		 + h->u.def.section->output_offset);
     76       else if (h != (struct bfd_link_hash_entry *) NULL
     77 	       && h->type == bfd_link_hash_common)
     78 	value = h->u.c.size;
     79       else if (h != (struct bfd_link_hash_entry *) NULL
     80 	       && h->type == bfd_link_hash_undefweak)
     81 	/* This is a GNU extension.  */
     82 	value = 0;
     83       else
     84 	{
     85 	  if (!((*link_info->callbacks->undefined_symbol)
     86 		(link_info, bfd_asymbol_name (symbol),
     87 		 input_section->owner, input_section, reloc->address,
     88 		 TRUE)))
     89 	    abort ();
     90 	  value = 0;
     91 	}
     92     }
     93   else
     94     {
     95       value = symbol->value
     96 	+ symbol->section->output_offset
     97 	+ symbol->section->output_section->vma;
     98     }
     99 
    100   /* Add the value contained in the relocation.  */
    101   value += reloc->addend;
    102 
    103   return value;
    104 }
    105 
    106 void
    107 bfd_perform_slip (bfd *abfd,
    108 		  unsigned int slip,
    109 		  asection *input_section,
    110 		  bfd_vma value)
    111 {
    112   asymbol **s;
    113 
    114   s = _bfd_generic_link_get_symbols (abfd);
    115   BFD_ASSERT (s != (asymbol **) NULL);
    116 
    117   /* Find all symbols past this point, and make them know
    118      what's happened.  */
    119   while (*s)
    120     {
    121       asymbol *p = *s;
    122       if (p->section == input_section)
    123 	{
    124 	  /* This was pointing into this section, so mangle it.  */
    125 	  if (p->value > value)
    126 	    {
    127 	      p->value -= slip;
    128 	      if (p->udata.p != NULL)
    129 		{
    130 		  struct generic_link_hash_entry *h;
    131 
    132 		  h = (struct generic_link_hash_entry *) p->udata.p;
    133 		  BFD_ASSERT (h->root.type == bfd_link_hash_defined
    134 			      || h->root.type == bfd_link_hash_defweak);
    135 		  h->root.u.def.value -= slip;
    136 		  BFD_ASSERT (h->root.u.def.value == p->value);
    137 		}
    138 	    }
    139 	}
    140       s++;
    141     }
    142 }
    143 
    144 bfd_boolean
    145 bfd_coff_reloc16_relax_section (bfd *abfd,
    146 				asection *input_section,
    147 				struct bfd_link_info *link_info,
    148 				bfd_boolean *again)
    149 {
    150   /* Get enough memory to hold the stuff.  */
    151   bfd *input_bfd = input_section->owner;
    152   unsigned *shrinks;
    153   unsigned shrink = 0;
    154   long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
    155   arelent **reloc_vector = NULL;
    156   long reloc_count;
    157 
    158   if (link_info->relocatable)
    159     (*link_info->callbacks->einfo)
    160       (_("%P%F: --relax and -r may not be used together\n"));
    161 
    162   /* We only do global relaxation once.  It is not safe to do it multiple
    163      times (see discussion of the "shrinks" array below).  */
    164   *again = FALSE;
    165 
    166   if (reloc_size < 0)
    167     return FALSE;
    168 
    169   reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
    170   if (!reloc_vector && reloc_size > 0)
    171     return FALSE;
    172 
    173   /* Get the relocs and think about them.  */
    174   reloc_count =
    175     bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
    176 			    _bfd_generic_link_get_symbols (input_bfd));
    177   if (reloc_count < 0)
    178     {
    179       free (reloc_vector);
    180       return FALSE;
    181     }
    182 
    183   /* The reloc16.c and related relaxing code is very simple, the price
    184      for that simplicity is we can only call this function once for
    185      each section.
    186 
    187      So, to get the best results within that limitation, we do multiple
    188      relaxing passes over each section here.  That involves keeping track
    189      of the "shrink" at each reloc in the section.  This allows us to
    190      accurately determine the relative location of two relocs within
    191      this section.
    192 
    193      In theory, if we kept the "shrinks" array for each section for the
    194      entire link, we could use the generic relaxing code in the linker
    195      and get better results, particularly for jsr->bsr and 24->16 bit
    196      memory reference relaxations.  */
    197 
    198   if (reloc_count > 0)
    199     {
    200       int another_pass = 0;
    201       bfd_size_type amt;
    202 
    203       /* Allocate and initialize the shrinks array for this section.
    204 	 The last element is used as an accumulator of shrinks.  */
    205       amt = reloc_count + 1;
    206       amt *= sizeof (unsigned);
    207       shrinks = (unsigned *) bfd_zmalloc (amt);
    208 
    209       /* Loop until nothing changes in this section.  */
    210       do
    211 	{
    212 	  arelent **parent;
    213 	  unsigned int i;
    214 	  long j;
    215 
    216 	  another_pass = 0;
    217 
    218 	  for (i = 0, parent = reloc_vector; *parent; parent++, i++)
    219 	    {
    220 	      /* Let the target/machine dependent code examine each reloc
    221 		 in this section and attempt to shrink it.  */
    222 	      shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
    223 						  shrinks[i], link_info);
    224 
    225 	      /* If it shrunk, note it in the shrinks array and set up for
    226 		 another pass.  */
    227 	      if (shrink != shrinks[i])
    228 		{
    229 		  another_pass = 1;
    230 		  for (j = i + 1; j <= reloc_count; j++)
    231 		    shrinks[j] += shrink - shrinks[i];
    232 		}
    233 	    }
    234 	}
    235       while (another_pass);
    236 
    237       shrink = shrinks[reloc_count];
    238       free ((char *) shrinks);
    239     }
    240 
    241   input_section->rawsize = input_section->size;
    242   input_section->size -= shrink;
    243   free ((char *) reloc_vector);
    244   return TRUE;
    245 }
    246 
    247 bfd_byte *
    248 bfd_coff_reloc16_get_relocated_section_contents
    249   (bfd *in_abfd,
    250    struct bfd_link_info *link_info,
    251    struct bfd_link_order *link_order,
    252    bfd_byte *data,
    253    bfd_boolean relocatable,
    254    asymbol **symbols)
    255 {
    256   /* Get enough memory to hold the stuff.  */
    257   bfd *input_bfd = link_order->u.indirect.section->owner;
    258   asection *input_section = link_order->u.indirect.section;
    259   long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
    260   arelent **reloc_vector;
    261   long reloc_count;
    262   bfd_size_type sz;
    263 
    264   if (reloc_size < 0)
    265     return NULL;
    266 
    267   /* If producing relocatable output, don't bother to relax.  */
    268   if (relocatable)
    269     return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
    270 						       link_order,
    271 						       data, relocatable,
    272 						       symbols);
    273 
    274   /* Read in the section.  */
    275   sz = input_section->rawsize ? input_section->rawsize : input_section->size;
    276   if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz))
    277     return NULL;
    278 
    279   reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
    280   if (!reloc_vector && reloc_size != 0)
    281     return NULL;
    282 
    283   reloc_count = bfd_canonicalize_reloc (input_bfd,
    284 					input_section,
    285 					reloc_vector,
    286 					symbols);
    287   if (reloc_count < 0)
    288     {
    289       free (reloc_vector);
    290       return NULL;
    291     }
    292 
    293   if (reloc_count > 0)
    294     {
    295       arelent **parent = reloc_vector;
    296       arelent *reloc;
    297       unsigned int dst_address = 0;
    298       unsigned int src_address = 0;
    299       unsigned int run;
    300       unsigned int idx;
    301 
    302       /* Find how long a run we can do.  */
    303       while (dst_address < link_order->size)
    304 	{
    305 	  reloc = *parent;
    306 	  if (reloc)
    307 	    {
    308 	      /* Note that the relaxing didn't tie up the addresses in the
    309 		 relocation, so we use the original address to work out the
    310 		 run of non-relocated data.  */
    311 	      run = reloc->address - src_address;
    312 	      parent++;
    313 	    }
    314 	  else
    315 	    {
    316 	      run = link_order->size - dst_address;
    317 	    }
    318 
    319 	  /* Copy the bytes.  */
    320 	  for (idx = 0; idx < run; idx++)
    321 	    data[dst_address++] = data[src_address++];
    322 
    323 	  /* Now do the relocation.  */
    324 	  if (reloc)
    325 	    {
    326 	      bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
    327 					    reloc, data, &src_address,
    328 					    &dst_address);
    329 	    }
    330 	}
    331     }
    332   free ((char *) reloc_vector);
    333   return data;
    334 }
    335