1 /* 8 and 16 bit COFF relocation functions, for BFD.
2 Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by Cygnus Support.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
22 Most of this hacked by Steve Chamberlain,
26 /* These routines are used by coff-h8300 and coff-z8k to do
34 #include "coff/internal.h"
37 extern bfd_error_vector_type bfd_error_vector
;
40 DEFUN(bfd_coff_reloc16_get_value
,(reloc
, seclet
),
42 bfd_seclet_type
*seclet
)
45 asymbol
*symbol
= *(reloc
->sym_ptr_ptr
);
46 /* A symbol holds a pointer to a section, and an offset from the
47 base of the section. To relocate, we find where the section will
48 live in the output and add that in */
50 if (symbol
->section
== &bfd_und_section
)
52 /* Ouch, this is an undefined symbol.. */
53 bfd_error_vector
.undefined_symbol(reloc
, seclet
);
54 value
= symbol
->value
;
58 value
= symbol
->value
+
59 symbol
->section
->output_offset
+
60 symbol
->section
->output_section
->vma
;
64 /* Add the value contained in the relocation */
65 value
+= reloc
->addend
;
71 DEFUN(perform_slip
,(s
, slip
, input_section
, value
),
74 asection
*input_section AND
78 /* Find all symbols past this point, and make them know
83 if (p
->section
== input_section
)
85 /* This was pointing into this section, so mangle it */
96 DEFUN(movb1
,(input_section
, symbols
, r
, shrink
),
97 asection
*input_section AND
102 bfd_vma value
= bfd_coff_reloc16_get_value(r
,0);
107 /* Change the reloc type from 16bit, possible 8 to 8bit
109 r
->howto
= r
->howto
+ 1;
110 /* The place to relc moves back by one */
113 /* This will be two bytes smaller in the long run */
115 perform_slip(symbols
, 2, input_section
, r
->address
- shrink
+1);
123 DEFUN(jmp1
,(input_section
, symbols
, r
, shrink
),
124 asection
*input_section AND
125 asymbol
**symbols AND
131 bfd_vma value
= bfd_coff_reloc16_get_value(r
, 0);
133 bfd_vma dot
= input_section
->output_section
->vma
+
134 input_section
->output_offset
+ r
->address
;
137 /* See if the address we're looking at within 127 bytes of where
138 we are, if so then we can use a small branch rather than the
139 jump we were going to */
141 gap
= value
- (dot
- shrink
);
144 if (-120 < (long)gap
&& (long)gap
< 120 )
147 /* Change the reloc type from 16bit, possible 8 to 8bit
149 r
->howto
= r
->howto
+ 1;
150 /* The place to relc moves back by one */
153 /* This will be two bytes smaller in the long run */
155 perform_slip(symbols
, 2, input_section
, r
->address
-shrink
+1);
163 DEFUN(bfd_coff_reloc16_relax_section
,(abfd
, i
, symbols
),
169 /* Get enough memory to hold the stuff */
170 bfd
*input_bfd
= i
->owner
;
171 asection
*input_section
= i
;
175 bfd_size_type reloc_size
= bfd_get_reloc_upper_bound(input_bfd
,
177 arelent
**reloc_vector
= (arelent
**)bfd_xmalloc(reloc_size
);
179 /* Get the relocs and think about them */
180 if (bfd_canonicalize_reloc(input_bfd
,
186 for (parent
= reloc_vector
; *parent
; parent
++)
188 arelent
*r
= *parent
;
189 switch (r
->howto
->type
) {
197 shrink
= movb1(input_section
, symbols
, r
, shrink
);
202 shrink
= jmp1(input_section
, symbols
, r
, shrink
);
210 input_section
->_cooked_size
-= shrink
;
211 free((char *)reloc_vector
);
216 DEFUN(bfd_coff_reloc16_get_relocated_section_contents
,(in_abfd
, seclet
, data
),
218 bfd_seclet_type
*seclet AND
222 /* Get enough memory to hold the stuff */
223 bfd
*input_bfd
= seclet
->u
.indirect
.section
->owner
;
224 asection
*input_section
= seclet
->u
.indirect
.section
;
225 bfd_size_type reloc_size
= bfd_get_reloc_upper_bound(input_bfd
,
227 arelent
**reloc_vector
= (arelent
**)bfd_xmalloc(reloc_size
);
229 /* read in the section */
230 bfd_get_section_contents(input_bfd
,
234 input_section
->_raw_size
);
237 if (bfd_canonicalize_reloc(input_bfd
,
240 seclet
->u
.indirect
.symbols
) )
242 arelent
**parent
= reloc_vector
;
247 unsigned int dst_address
= 0;
248 unsigned int src_address
= 0;
252 /* Find how long a run we can do */
253 while (dst_address
< seclet
->size
)
259 /* Note that the relaxing didn't tie up the addresses in the
260 relocation, so we use the original address to work out the
261 run of non-relocated data */
262 run
= reloc
->address
- src_address
;
268 run
= seclet
->size
- dst_address
;
271 for (idx
= 0; idx
< run
; idx
++)
273 data
[dst_address
++] = data
[src_address
++];
276 /* Now do the relocation */
280 switch (reloc
->howto
->type
)
283 /* Speciial relaxed type */
285 bfd_vma dot
= seclet
->offset
+ dst_address
+ seclet
->u
.indirect
.section
->output_section
->vma
;
286 int gap
= bfd_coff_reloc16_get_value(reloc
,seclet
)-dot
-1;
287 if ((gap
& ~0xff ) != 0 &&((gap
& 0xff00)!= 0xff00)) abort();
289 bfd_put_8(in_abfd
,gap
, data
+dst_address
);
291 switch (data
[dst_address
-1])
296 bfd_put_8(in_abfd
, 0x55, data
+dst_address
-1);
300 bfd_put_8(in_abfd
, 0x40, data
+dst_address
-1);
319 /* Special relaxed type, there will be a gap between where we
320 get stuff from and where we put stuff to now
322 for a mov.b @aa:16 -> mov.b @aa:8
323 opcode 0x6a 0x0y offset
326 if (data
[dst_address
-1] != 0x6a)
328 switch (data
[src_address
] & 0xf0)
332 data
[dst_address
-1] = (data
[src_address
] & 0xf) | 0x20;
336 data
[dst_address
-1] = (data
[src_address
] & 0xf) | 0x30;
342 /* the offset must fit ! after all, what was all the relaxing
345 bfd_put_8(in_abfd
, bfd_coff_reloc16_get_value(reloc
, seclet
),
348 /* Note the magic - src goes up by two bytes, but dst by only
357 bfd_vma dot
= seclet
->offset
+ dst_address
+ seclet
->u
.indirect
.section
->output_section
->vma
;
358 int gap
= bfd_coff_reloc16_get_value(reloc
,seclet
)-dot
;
359 if (gap
> 127 || gap
< -128)
361 bfd_error_vector
.reloc_value_truncated(reloc
, seclet
);
364 bfd_put_8(in_abfd
,gap
, data
+dst_address
);
373 unsigned int gap
=bfd_coff_reloc16_get_value(reloc
,seclet
);
374 if (gap
> 0xff && gap
< ~0xff)
376 bfd_error_vector
.reloc_value_truncated(reloc
, seclet
);
379 bfd_put_8(in_abfd
, gap
, data
+dst_address
);
387 /* A relword which would have like to have been a pcrel */
389 /* A relword which would like to have been modified but
392 bfd_put_16(in_abfd
, bfd_coff_reloc16_get_value(reloc
,seclet
),
398 bfd_coff_reloc16_extra_cases (in_abfd
, seclet
, reloc
, data
,
399 &src_address
, &dst_address
);
405 free((char *)reloc_vector
);