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