This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / bfd / reloc16.c
1 /* 8 and 16 bit COFF relocation functions, for BFD.
2    Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3    Written by Cygnus Support.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* 
22 Most of this hacked by  Steve Chamberlain,
23                         sac@cygnus.com 
24 */
25
26 /* These routines are used by coff-h8300 and coff-z8k to do
27    relocation.  */
28
29 #include "bfd.h"
30 #include "sysdep.h"
31 #include "obstack.h"
32 #include "libbfd.h"
33 #include "bfdlink.h"
34 #include "coff/internal.h"
35 #include "libcoff.h"
36
37 bfd_vma
38 bfd_coff_reloc16_get_value (reloc, link_info, input_section)
39      arelent *reloc;
40      struct bfd_link_info *link_info;
41      asection *input_section;
42 {
43   bfd_vma value;
44   asymbol *symbol = *(reloc->sym_ptr_ptr);
45   /* A symbol holds a pointer to a section, and an offset from the
46      base of the section.  To relocate, we find where the section will
47      live in the output and add that in */
48
49   if (symbol->section == &bfd_und_section)
50     {
51       struct bfd_link_hash_entry *h;
52
53       /* The symbol is undefined in this BFD.  Look it up in the
54          global linker hash table.  FIXME: This should be changed when
55          we convert this stuff to use a specific final_link function
56          and change the interface to bfd_relax_section to not require
57          the generic symbols.  */
58       h = bfd_link_hash_lookup (link_info->hash, bfd_asymbol_name (symbol),
59                                 false, false, true);
60       if (h != (struct bfd_link_hash_entry *) NULL
61           && h->type == bfd_link_hash_defined)
62         value = (h->u.def.value
63                  + h->u.def.section->output_section->vma
64                  + h->u.def.section->output_offset);
65       else if (h != (struct bfd_link_hash_entry *) NULL
66                && h->type == bfd_link_hash_common)
67         value = h->u.c.size;
68       else
69         {
70           if (! ((*link_info->callbacks->undefined_symbol)
71                  (link_info, bfd_asymbol_name (symbol),
72                   input_section->owner, input_section, reloc->address)))
73             abort ();
74           value = 0;
75         }
76     }
77   else 
78     {
79       value = symbol->value +
80         symbol->section->output_offset +
81           symbol->section->output_section->vma;
82     }
83   
84   /* Add the value contained in the relocation */
85   value += reloc->addend;
86   
87   return value;
88 }
89
90 void
91 bfd_perform_slip(s, slip, input_section, value)
92      asymbol **s;
93      unsigned int slip;
94      asection *input_section;
95      bfd_vma value;
96 {
97   /* Find all symbols past this point, and make them know
98      what's happened */
99   while (*s) 
100     {
101       asymbol *p = *s;
102       if (p->section == input_section) 
103         {
104           /* This was pointing into this section, so mangle it */
105           if (p->value > value)
106             {
107               p->value -= slip;
108             }
109         }
110       s++;
111     }    
112 }
113
114 boolean 
115 bfd_coff_reloc16_relax_section (abfd, i, link_info, symbols)
116      bfd *abfd;
117      asection *i;
118      struct bfd_link_info *link_info;
119      asymbol **symbols;
120 {
121   /* Get enough memory to hold the stuff */
122   bfd *input_bfd = i->owner;
123   asection *input_section = i;
124   int shrink = 0 ;
125   boolean new = false;
126   
127   bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd,
128                                                        input_section);
129   arelent **reloc_vector = (arelent **)bfd_xmalloc(reloc_size);
130
131   /* Get the relocs and think about them */
132   if (bfd_canonicalize_reloc(input_bfd, 
133                              input_section,
134                              reloc_vector,
135                              symbols))
136     {
137       arelent **parent;
138       for (parent = reloc_vector; *parent; parent++) 
139         {
140           shrink = bfd_coff_reloc16_estimate (abfd, input_section, symbols,
141                                               *parent, shrink, link_info);
142         }
143     }
144
145   input_section->_cooked_size -= shrink;  
146   free((char *)reloc_vector);
147   return new;
148 }
149
150 bfd_byte *
151 bfd_coff_reloc16_get_relocated_section_contents(in_abfd,
152                                                 link_info,
153                                                 link_order,
154                                                 data,
155                                                 relocateable,
156                                                 symbols)
157      bfd *in_abfd;
158      struct bfd_link_info *link_info;
159      struct bfd_link_order *link_order;
160      bfd_byte *data;
161      boolean relocateable;
162      asymbol **symbols;
163 {
164   /* Get enough memory to hold the stuff */
165   bfd *input_bfd = link_order->u.indirect.section->owner;
166   asection *input_section = link_order->u.indirect.section;
167   bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd,
168                                                        input_section);
169   arelent **reloc_vector = (arelent **)bfd_xmalloc(reloc_size);
170   
171   /* If producing relocateable output, don't bother to relax.  */
172   if (relocateable)
173     return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
174                                                        link_order,
175                                                        data, relocateable,
176                                                        symbols);
177
178   /* read in the section */
179   bfd_get_section_contents(input_bfd,
180                            input_section,
181                            data,
182                            0,
183                            input_section->_raw_size);
184   
185   
186   if (bfd_canonicalize_reloc(input_bfd, 
187                              input_section,
188                              reloc_vector,
189                              symbols) )
190     {
191       arelent **parent = reloc_vector;
192       arelent *reloc ;
193     
194
195
196       unsigned int dst_address = 0;
197       unsigned int src_address = 0;
198       unsigned int run;
199       unsigned int idx;
200     
201       /* Find how long a run we can do */
202       while (dst_address < link_order->size) 
203         {
204       
205           reloc = *parent;
206           if (reloc) 
207             {
208               /* Note that the relaxing didn't tie up the addresses in the
209                  relocation, so we use the original address to work out the
210                  run of non-relocated data */
211               run = reloc->address - src_address;
212               parent++;
213         
214             }
215           else 
216             {
217               run = link_order->size - dst_address;
218             }
219           /* Copy the bytes */
220           for (idx = 0; idx < run; idx++)
221             {
222               data[dst_address++] = data[src_address++];
223             }
224     
225           /* Now do the relocation */
226     
227           if (reloc) 
228             {
229               bfd_coff_reloc16_extra_cases (in_abfd, link_info, link_order,
230                                             reloc, data, &src_address,
231                                             &dst_address);
232             }    
233         }
234     }
235   free((char *)reloc_vector);
236   return data;
237 }
238