4088f0eb9ba482f411535789c99cea9bc6e6baa6
[binutils-gdb.git] / bfd / seclet.c
1 /* This module is part of BFD */
2
3
4 /* The intention is that one day, all the code which uses sections
5 will change and use seclets instead - maybe seglet would have been
6 a better name..
7
8 Anyway, a seclet contains enough info to be able to describe an
9 area of output memory in one go.
10
11 The only description so far catered for is that of the
12 <<bfd_indirect_seclet>>, which is a select which points to a
13 <<section>> and the <<asymbols>> associated with the section, so
14 that relocation can be done when needed.
15
16 One day there will be more types - they will at least migrate from
17 the linker's data structures - also there could be extra stuff,
18 like a bss seclet, which descibes a lump of memory as containing
19 zeros compactly, without the horrible SEC_* flag cruft.
20
21
22 */
23
24 #include "bfd.h"
25 #include "sysdep.h"
26 #include "libbfd.h"
27 #include "seclet.h"
28 #include "coff/internal.h"
29 bfd_seclet_type *
30 DEFUN(bfd_new_seclet,(abfd, section),
31 bfd *abfd AND
32 asection *section)
33 {
34 bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type));
35 if (section->seclets_tail != (bfd_seclet_type *)NULL) {
36 section->seclets_tail->next = n;
37 }
38 else
39 {
40 section->seclets_head = n;
41 }
42 section->seclets_tail = n;
43
44 return n;
45
46 }
47
48
49
50
51 #define MAX_ERRORS_IN_A_ROW 10
52 extern bfd_error_vector_type bfd_error_vector;
53 bfd_vma
54 DEFUN(get_value,(reloc, seclet),
55 arelent *reloc AND
56 bfd_seclet_type *seclet)
57 {
58 bfd_vma value;
59 if (reloc->sym_ptr_ptr)
60 {
61 asymbol *symbol = *(reloc->sym_ptr_ptr);
62
63
64 /* A symbol holds a pointer to a section, and an offset from the
65 base of the section. To relocate, we find where the section will
66 live in the output and add that in */
67
68 if (symbol->section == (asection *)NULL)
69 {
70 /* Ouch, this is an undefined symbol.. */
71 bfd_error_vector.undefined_symbol(reloc, seclet);
72 value = symbol->value;
73 }
74 else
75 {
76 value = symbol->value +
77 symbol->section->output_offset +
78 symbol->section->output_section->vma;
79 }
80 }
81
82 else
83 {
84 value = 0;
85 }
86
87 /* Add the value contained in the relocation */
88 value += (short)((reloc->addend) & 0xffff);
89
90 return value;
91
92
93 }
94
95 static char *
96 DEFUN(foo_bfd_get_relocated_section_contents,(seclet),
97 bfd_seclet_type *seclet)
98
99 {
100 asymbol **symbols = 0;
101 extern bfd *output_bfd;
102 bfd *abfd;
103
104 /* Get enough memory to hold the stuff */
105 bfd *input_bfd = seclet->u.indirect.section->owner;
106 asection *input_section = seclet->u.indirect.section;
107
108 char *data = malloc(input_section->_raw_size);
109 char *dst = data;
110 char *prev_dst = data;
111 unsigned int gap = 0;
112
113 bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd,
114 input_section);
115 arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
116 abfd = output_bfd;
117
118 /* read in the section */
119 bfd_get_section_contents(input_bfd,
120 input_section,
121 data,
122 0,
123 input_section->_raw_size);
124
125
126 if (bfd_canonicalize_reloc(input_bfd,
127 input_section,
128 reloc_vector,
129 seclet->u.indirect.symbols) )
130 {
131 arelent **parent = reloc_vector;
132 arelent *reloc ;
133
134
135
136 unsigned int dst_address = 0;
137 unsigned int src_address = 0;
138 unsigned int run;
139 unsigned int idx;
140
141 /* Find how long a run we can do */
142 while (dst_address < seclet->size)
143 {
144
145 reloc = *parent;
146 if (reloc)
147 {
148 /* Note that the relaxing didn't tie up the addresses in the
149 relocation, so we use the original address to work out the
150 run of non-relocated data */
151 run = reloc->address - src_address;
152 parent++;
153
154 }
155 else
156 {
157 run = seclet->size - dst_address;
158 }
159 /* Copy the bytes */
160 for (idx = 0; idx < run; idx++)
161 {
162 data[dst_address++] = data[src_address++];
163 }
164
165 /* Now do the relocation */
166
167 if (reloc)
168 {
169 switch (reloc->howto->type)
170 {
171 case R_JMP2:
172 /* Speciial relaxed type */
173 {
174 bfd_vma dot = seclet->offset + dst_address + seclet->u.indirect.section->output_section->vma;
175 int gap = get_value(reloc,seclet)-dot-1;
176 if ((gap & ~0xff ) != 0 &&((gap & 0xff00)!= 0xff00)) abort();
177
178 bfd_put_8(abfd,gap, data+dst_address);
179
180 switch (data[dst_address-1])
181 {
182
183 case 0x5e:
184 /* jsr -> bsr */
185 bfd_put_8(abfd, 0x55, data+dst_address-1);
186 break;
187 case 0x5a:
188 /* jmp ->bra */
189 bfd_put_8(abfd, 0x40, data+dst_address-1);
190 break;
191
192 default:
193 abort();
194
195 }
196
197
198
199
200 dst_address++;
201 src_address+=3;
202
203 break;
204 }
205
206
207 case R_MOVB2:
208 /* Special relaxed type, there will be a gap between where we
209 get stuff from and where we put stuff to now
210
211 for a mov.b @aa:16 -> mov.b @aa:8
212 opcode 0x6a 0x0y offset
213 -> 0x2y off
214 */
215 if (data[dst_address-1] != 0x6a)
216 abort();
217 switch (data[dst_address] & 0xf0)
218 {
219 case 0x00:
220 /* Src is memory */
221 data[dst_address-1] = (data[src_address] & 0xf) | 0x20;
222 break;
223 case 0x80:
224 /* Src is reg */
225 data[dst_address-1] = (data[src_address] & 0xf) | 0x30;
226 break;
227 default:
228 abort();
229 }
230
231 /* the offset must fit ! after all, what was all the relaxing
232 about ? */
233
234 bfd_put_8(abfd, get_value(reloc, seclet), data + dst_address);
235
236 /* Note the magic - src goes up by two bytes, but dst by only
237 one */
238 dst_address+=1;
239 src_address+=3;
240
241 break;
242 /* PCrel 8 bits */
243 case R_PCRBYTE:
244 {
245 bfd_vma dot = seclet->offset + dst_address + seclet->u.indirect.section->output_section->vma;
246 int gap = get_value(reloc,seclet)-dot;
247 if (gap > 127 || gap < -128)
248 {
249 bfd_error_vector.reloc_value_truncated(reloc, seclet);
250 }
251
252 bfd_put_8(abfd,gap, data+dst_address);
253 dst_address++;
254 src_address++;
255
256 break;
257 }
258
259 case R_RELBYTE:
260 {
261 unsigned int gap =get_value(reloc,seclet);
262 if (gap > 256)
263 {
264 bfd_error_vector.reloc_value_truncated(reloc, seclet);
265 }
266
267 bfd_put_8(abfd, gap, data+dst_address);
268 dst_address+=1;
269 src_address+=1;
270
271
272 }
273 break;
274 case R_JMP1:
275 /* A relword which would have like to have been a pcrel */
276 case R_MOVB1:
277 /* A relword which would like to have been modified but
278 didn't make it */
279 case R_RELWORD:
280 bfd_put_16(abfd, get_value(reloc,seclet), data+dst_address);
281 dst_address+=2;
282 src_address+=2;
283 break;
284
285 default:
286 abort();
287 }
288 }
289 }
290 }
291 free((char *)reloc_vector);
292 return data;
293
294 }
295
296 void
297 DEFUN(rel,(abfd, seclet, output_section),
298 bfd *abfd AND
299 bfd_seclet_type *seclet AND
300 asection *output_section)
301 {
302 bfd_byte *data;
303 if (output_section->flags & SEC_HAS_CONTENTS )
304 {
305
306 data = bfd_get_relocated_section_contents(abfd, seclet);
307
308 if(bfd_set_section_contents(abfd,
309 output_section,
310 data,
311 seclet->offset,
312 seclet->size) == false)
313 {
314 abort();
315 }
316
317 }
318
319
320
321
322
323 }
324
325 void
326 DEFUN(seclet_dump_seclet,(abfd, seclet, section),
327 bfd *abfd AND
328 bfd_seclet_type *seclet AND
329 asection *section)
330 {
331 switch (seclet->type)
332 {
333
334 case bfd_indirect_seclet:
335 /* The contents of this section come from another one somewhere
336 else */
337 rel(abfd, seclet, section);
338
339
340 break;
341
342 default:
343 abort();
344 }
345
346
347
348 }
349
350 void
351 DEFUN(seclet_dump,(abfd),
352 bfd *abfd)
353 {
354 /* Write all the seclets on the bfd out, relocate etc according to the
355 rules */
356
357 asection *o = abfd->sections;
358 while (o != (asection *)NULL)
359 {
360 bfd_seclet_type *p = o->seclets_head;
361 while (p != (bfd_seclet_type *)NULL)
362 {
363 seclet_dump_seclet(abfd, p, o);
364 p = p ->next;
365 }
366
367 o = o->next;
368 }
369
370 }