Commit | Line | Data |
---|---|---|
e98e6ec1 SC |
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 | } |