xref: /netbsd-src/external/gpl3/gdb/dist/bfd/reloc16.c (revision d11b170b9000ada93db553723522a63d5deac310)
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@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