reloc16.c revision 60484
1/* 8 and 16 bit COFF relocation functions, for BFD.
2   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
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/*
23Most of this hacked by  Steve Chamberlain,
24			sac@cygnus.com
25*/
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 "bfd.h"
39#include "sysdep.h"
40#include "libbfd.h"
41#include "bfdlink.h"
42#include "genlink.h"
43#include "coff/internal.h"
44#include "libcoff.h"
45
46bfd_vma
47bfd_coff_reloc16_get_value (reloc, link_info, input_section)
48     arelent *reloc;
49     struct bfd_link_info *link_info;
50     asection *input_section;
51{
52  bfd_vma value;
53  asymbol *symbol = *(reloc->sym_ptr_ptr);
54  /* A symbol holds a pointer to a section, and an offset from the
55     base of the section.  To relocate, we find where the section will
56     live in the output and add that in */
57
58  if (bfd_is_und_section (symbol->section)
59      || bfd_is_com_section (symbol->section))
60    {
61      struct bfd_link_hash_entry *h;
62
63      /* The symbol is undefined in this BFD.  Look it up in the
64	 global linker hash table.  FIXME: This should be changed when
65	 we convert this stuff to use a specific final_link function
66	 and change the interface to bfd_relax_section to not require
67	 the generic symbols.  */
68      h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
69					bfd_asymbol_name (symbol),
70					false, false, true);
71      if (h != (struct bfd_link_hash_entry *) NULL
72	  && (h->type == bfd_link_hash_defined
73	      || h->type == bfd_link_hash_defweak))
74	value = (h->u.def.value
75		 + h->u.def.section->output_section->vma
76		 + h->u.def.section->output_offset);
77      else if (h != (struct bfd_link_hash_entry *) NULL
78	       && h->type == bfd_link_hash_common)
79	value = h->u.c.size;
80      else
81	{
82	  if (! ((*link_info->callbacks->undefined_symbol)
83		 (link_info, bfd_asymbol_name (symbol),
84		  input_section->owner, input_section, reloc->address,
85		  true)))
86	    abort ();
87	  value = 0;
88	}
89    }
90  else
91    {
92      value = symbol->value +
93	symbol->section->output_offset +
94	  symbol->section->output_section->vma;
95    }
96
97  /* Add the value contained in the relocation */
98  value += reloc->addend;
99
100  return value;
101}
102
103void
104bfd_perform_slip(abfd, slip, input_section, value)
105     bfd *abfd;
106     unsigned int slip;
107     asection *input_section;
108     bfd_vma value;
109{
110  asymbol **s;
111
112  s = _bfd_generic_link_get_symbols (abfd);
113  BFD_ASSERT (s != (asymbol **) NULL);
114
115  /* Find all symbols past this point, and make them know
116     what's happened */
117  while (*s)
118    {
119      asymbol *p = *s;
120      if (p->section == input_section)
121	{
122	  /* This was pointing into this section, so mangle it */
123	  if (p->value > value)
124	    {
125	      p->value -= slip;
126	      if (p->udata.p != NULL)
127		{
128		  struct generic_link_hash_entry *h;
129
130		  h = (struct generic_link_hash_entry *) p->udata.p;
131		  BFD_ASSERT (h->root.type == bfd_link_hash_defined
132			      || h->root.type == bfd_link_hash_defweak);
133		  h->root.u.def.value -= slip;
134		  BFD_ASSERT (h->root.u.def.value == p->value);
135		}
136	    }
137	}
138      s++;
139    }
140}
141
142boolean
143bfd_coff_reloc16_relax_section (abfd, i, link_info, again)
144     bfd *abfd;
145     asection *i;
146     struct bfd_link_info *link_info;
147     boolean *again;
148{
149  /* Get enough memory to hold the stuff */
150  bfd *input_bfd = i->owner;
151  asection *input_section = i;
152  int *shrinks;
153  int 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  /* We only do global relaxation once.  It is not safe to do it multiple
159     times (see discussion of the "shrinks" array below).  */
160  *again = false;
161
162  if (reloc_size < 0)
163    return false;
164
165  reloc_vector = (arelent **) bfd_malloc (reloc_size);
166  if (!reloc_vector && reloc_size > 0)
167    return false;
168
169  /* Get the relocs and think about them */
170  reloc_count =
171    bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
172			    _bfd_generic_link_get_symbols (input_bfd));
173  if (reloc_count < 0)
174    {
175      free (reloc_vector);
176      return false;
177    }
178
179  /* The reloc16.c and related relaxing code is very simple, the price
180     for that simplicity is we can only call this function once for
181     each section.
182
183     So, to get the best results within that limitation, we do multiple
184     relaxing passes over each section here.  That involves keeping track
185     of the "shrink" at each reloc in the section.  This allows us to
186     accurately determine the relative location of two relocs within
187     this section.
188
189     In theory, if we kept the "shrinks" array for each section for the
190     entire link, we could use the generic relaxing code in the linker
191     and get better results, particularly for jsr->bsr and 24->16 bit
192     memory reference relaxations.  */
193
194  if (reloc_count > 0)
195    {
196      int another_pass = 0;
197
198      /* Allocate and initialize the shrinks array for this section.
199         The last element is used as an accumlator of shrinks.  */
200      shrinks = (int *) bfd_malloc ((reloc_count + 1) * sizeof (int));
201      memset (shrinks, 0, (reloc_count + 1) * sizeof (int));
202
203      /* Loop until nothing changes in this section.  */
204      do {
205	arelent **parent;
206	unsigned int i;
207	long j;
208
209	another_pass = 0;
210
211	for (i = 0, parent = reloc_vector; *parent; parent++, i++)
212	  {
213	    /* Let the target/machine dependent code examine each reloc
214	       in this section and attempt to shrink it.  */
215	    shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
216						shrinks[i], link_info);
217
218	    /* If it shrunk, note it in the shrinks array and set up for
219	       another pass.  */
220	    if (shrink != shrinks[i])
221	      {
222	        another_pass = 1;
223		for (j = i + 1; j <= reloc_count; j++)
224		  shrinks[j] += shrink - shrinks[i];
225	      }
226	  }
227
228      } while (another_pass);
229
230      shrink = shrinks[reloc_count];
231      free((char *)shrinks);
232    }
233
234  input_section->_cooked_size -= shrink;
235  free((char *)reloc_vector);
236  return true;
237}
238
239bfd_byte *
240bfd_coff_reloc16_get_relocated_section_contents(in_abfd,
241						link_info,
242						link_order,
243						data,
244						relocateable,
245						symbols)
246     bfd *in_abfd;
247     struct bfd_link_info *link_info;
248     struct bfd_link_order *link_order;
249     bfd_byte *data;
250     boolean relocateable;
251     asymbol **symbols;
252{
253  /* Get enough memory to hold the stuff */
254  bfd *input_bfd = link_order->u.indirect.section->owner;
255  asection *input_section = link_order->u.indirect.section;
256  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
257  arelent **reloc_vector;
258  long reloc_count;
259
260  if (reloc_size < 0)
261    return NULL;
262
263  /* If producing relocateable output, don't bother to relax.  */
264  if (relocateable)
265    return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
266						       link_order,
267						       data, relocateable,
268						       symbols);
269
270  /* read in the section */
271  if (! bfd_get_section_contents(input_bfd,
272				 input_section,
273				 data,
274				 0,
275				 input_section->_raw_size))
276    return NULL;
277
278
279  reloc_vector = (arelent **) bfd_malloc((size_t) 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	  /* Copy the bytes */
319	  for (idx = 0; idx < run; idx++)
320	    {
321	      data[dst_address++] = data[src_address++];
322	    }
323
324	  /* Now do the relocation */
325
326	  if (reloc)
327	    {
328	      bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
329					    reloc, data, &src_address,
330					    &dst_address);
331	    }
332	}
333    }
334  free((char *)reloc_vector);
335  return data;
336}
337
338