Commit | Line | Data |
---|---|---|
01b49cb3 C |
1 | /* V850-specific support for 32-bit ELF |
2 | Copyright (C) 1994, 1995 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of BFD, the Binary File Descriptor library. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #include "bfd.h" | |
21 | #include "sysdep.h" | |
22 | #include "libbfd.h" | |
23 | #include "elf-bfd.h" | |
24 | ||
25 | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup | |
26 | PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); | |
27 | static void v850_info_to_howto_rel | |
28 | PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); | |
e73b6ae6 JL |
29 | static bfd_reloc_status_type bfd_elf32_v850_reloc |
30 | PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); | |
31 | ||
01b49cb3 C |
32 | |
33 | ||
34 | /* Try to minimize the amount of space occupied by relocation tables | |
35 | on the ROM (not that the ROM won't be swamped by other ELF overhead). */ | |
36 | #define USE_REL | |
37 | ||
38 | enum reloc_type | |
39 | { | |
40 | R_V850_NONE = 0, | |
41 | R_V850_9_PCREL, | |
42 | R_V850_22_PCREL, | |
43 | R_V850_HI16_S, | |
44 | R_V850_HI16, | |
45 | R_V850_LO16, | |
237b5c4c JL |
46 | R_V850_32, |
47 | R_V850_16, | |
48 | R_V850_8, | |
b6d08fce JL |
49 | R_V850_SDA_OFFSET, |
50 | R_V850_ZDA_OFFSET, | |
51 | R_V850_TDA_OFFSET, | |
01b49cb3 C |
52 | R_V850_max |
53 | }; | |
54 | ||
55 | static reloc_howto_type elf_v850_howto_table[] = | |
56 | { | |
57 | /* This reloc does nothing. */ | |
58 | HOWTO (R_V850_NONE, /* type */ | |
59 | 0, /* rightshift */ | |
60 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
61 | 32, /* bitsize */ | |
62 | false, /* pc_relative */ | |
63 | 0, /* bitpos */ | |
64 | complain_overflow_bitfield, /* complain_on_overflow */ | |
65 | bfd_elf_generic_reloc, /* special_function */ | |
66 | "R_V850_NONE", /* name */ | |
67 | false, /* partial_inplace */ | |
68 | 0, /* src_mask */ | |
69 | 0, /* dst_mask */ | |
70 | false), /* pcrel_offset */ | |
71 | ||
72 | /* A PC relative 9 bit branch. */ | |
73 | HOWTO (R_V850_9_PCREL, /* type */ | |
74 | 2, /* rightshift */ | |
75 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
76 | 26, /* bitsize */ | |
77 | true, /* pc_relative */ | |
78 | 0, /* bitpos */ | |
79 | complain_overflow_bitfield, /* complain_on_overflow */ | |
e73b6ae6 | 80 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
81 | "R_V850_9_PCREL", /* name */ |
82 | false, /* partial_inplace */ | |
83 | 0x00ffffff, /* src_mask */ | |
84 | 0x00ffffff, /* dst_mask */ | |
85 | true), /* pcrel_offset */ | |
86 | ||
87 | /* A PC relative 22 bit branch. */ | |
88 | HOWTO (R_V850_22_PCREL, /* type */ | |
89 | 2, /* rightshift */ | |
90 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
91 | 22, /* bitsize */ | |
92 | true, /* pc_relative */ | |
93 | 7, /* bitpos */ | |
94 | complain_overflow_signed, /* complain_on_overflow */ | |
e73b6ae6 | 95 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
96 | "R_V850_22_PCREL", /* name */ |
97 | false, /* partial_inplace */ | |
98 | 0x07ffff80, /* src_mask */ | |
99 | 0x07ffff80, /* dst_mask */ | |
100 | true), /* pcrel_offset */ | |
101 | ||
102 | /* High 16 bits of symbol value. */ | |
103 | HOWTO (R_V850_HI16_S, /* type */ | |
104 | 0, /* rightshift */ | |
105 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
106 | 16, /* bitsize */ | |
107 | false, /* pc_relative */ | |
e73b6ae6 | 108 | 0, /* bitpos */ |
01b49cb3 | 109 | complain_overflow_dont,/* complain_on_overflow */ |
e73b6ae6 | 110 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
111 | "R_V850_HI16_S", /* name */ |
112 | true, /* partial_inplace */ | |
113 | 0xffff, /* src_mask */ | |
114 | 0xffff, /* dst_mask */ | |
115 | false), /* pcrel_offset */ | |
116 | ||
117 | /* High 16 bits of symbol value. */ | |
118 | HOWTO (R_V850_HI16, /* type */ | |
119 | 0, /* rightshift */ | |
120 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
121 | 16, /* bitsize */ | |
122 | false, /* pc_relative */ | |
e73b6ae6 | 123 | 0, /* bitpos */ |
01b49cb3 | 124 | complain_overflow_dont,/* complain_on_overflow */ |
e73b6ae6 | 125 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
126 | "R_V850_HI16", /* name */ |
127 | true, /* partial_inplace */ | |
128 | 0xffff, /* src_mask */ | |
129 | 0xffff, /* dst_mask */ | |
130 | false), /* pcrel_offset */ | |
131 | ||
132 | /* Low 16 bits of symbol value. */ | |
133 | HOWTO (R_V850_LO16, /* type */ | |
134 | 0, /* rightshift */ | |
135 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
136 | 16, /* bitsize */ | |
137 | false, /* pc_relative */ | |
e73b6ae6 | 138 | 0, /* bitpos */ |
01b49cb3 C |
139 | complain_overflow_dont,/* complain_on_overflow */ |
140 | bfd_elf_generic_reloc, /* special_function */ | |
141 | "R_V850_LO16", /* name */ | |
142 | true, /* partial_inplace */ | |
143 | 0xffff, /* src_mask */ | |
144 | 0xffff, /* dst_mask */ | |
145 | false), /* pcrel_offset */ | |
237b5c4c JL |
146 | |
147 | /* Simple 32bit reloc. */ | |
148 | HOWTO (R_V850_32, /* type */ | |
149 | 0, /* rightshift */ | |
150 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
151 | 32, /* bitsize */ | |
152 | false, /* pc_relative */ | |
153 | 0, /* bitpos */ | |
154 | complain_overflow_dont,/* complain_on_overflow */ | |
155 | bfd_elf_generic_reloc, /* special_function */ | |
156 | "R_V850_32", /* name */ | |
e73b6ae6 JL |
157 | true, /* partial_inplace */ |
158 | 0xffffffff, /* src_mask */ | |
237b5c4c JL |
159 | 0xffffffff, /* dst_mask */ |
160 | false), /* pcrel_offset */ | |
161 | ||
162 | /* Simple 16bit reloc. */ | |
163 | HOWTO (R_V850_16, /* type */ | |
164 | 0, /* rightshift */ | |
165 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
166 | 16, /* bitsize */ | |
167 | false, /* pc_relative */ | |
168 | 0, /* bitpos */ | |
169 | complain_overflow_dont,/* complain_on_overflow */ | |
170 | bfd_elf_generic_reloc, /* special_function */ | |
171 | "R_V850_16", /* name */ | |
e73b6ae6 JL |
172 | true, /* partial_inplace */ |
173 | 0xffff, /* src_mask */ | |
237b5c4c JL |
174 | 0xffff, /* dst_mask */ |
175 | false), /* pcrel_offset */ | |
176 | ||
177 | /* Simple 8bit reloc. */ | |
178 | HOWTO (R_V850_8, /* type */ | |
179 | 0, /* rightshift */ | |
180 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
181 | 8, /* bitsize */ | |
182 | false, /* pc_relative */ | |
183 | 0, /* bitpos */ | |
184 | complain_overflow_dont,/* complain_on_overflow */ | |
185 | bfd_elf_generic_reloc, /* special_function */ | |
186 | "R_V850_8", /* name */ | |
e73b6ae6 JL |
187 | true, /* partial_inplace */ |
188 | 0xff, /* src_mask */ | |
237b5c4c JL |
189 | 0xff, /* dst_mask */ |
190 | false), /* pcrel_offset */ | |
b6d08fce JL |
191 | |
192 | /* Offset from the short data area pointer. */ | |
193 | HOWTO (R_V850_SDA_OFFSET, /* type */ | |
194 | 0, /* rightshift */ | |
195 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
196 | 16, /* bitsize */ | |
197 | false, /* pc_relative */ | |
198 | 0, /* bitpos */ | |
199 | complain_overflow_dont,/* complain_on_overflow */ | |
200 | bfd_elf_generic_reloc, /* special_function */ | |
201 | "R_V850_SDA_OFFSET", /* name */ | |
202 | true, /* partial_inplace */ | |
203 | 0xffff, /* src_mask */ | |
204 | 0xffff, /* dst_mask */ | |
205 | false), /* pcrel_offset */ | |
206 | ||
207 | /* Offset from the tiny data area pointer. */ | |
208 | HOWTO (R_V850_TDA_OFFSET, /* type */ | |
209 | 0, /* rightshift */ | |
210 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
211 | 16, /* bitsize */ | |
212 | false, /* pc_relative */ | |
213 | 0, /* bitpos */ | |
214 | complain_overflow_dont,/* complain_on_overflow */ | |
215 | bfd_elf_generic_reloc, /* special_function */ | |
216 | "R_V850_TDA_OFFSET", /* name */ | |
217 | true, /* partial_inplace */ | |
218 | 0xffff, /* src_mask */ | |
219 | 0xffff, /* dst_mask */ | |
220 | false), /* pcrel_offset */ | |
221 | ||
222 | /* Offset from the zero data area pointer. */ | |
223 | HOWTO (R_V850_ZDA_OFFSET, /* type */ | |
224 | 0, /* rightshift */ | |
225 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
226 | 16, /* bitsize */ | |
227 | false, /* pc_relative */ | |
228 | 0, /* bitpos */ | |
229 | complain_overflow_dont,/* complain_on_overflow */ | |
230 | bfd_elf_generic_reloc, /* special_function */ | |
231 | "R_V850_ZDA_OFFSET", /* name */ | |
232 | true, /* partial_inplace */ | |
233 | 0xffff, /* src_mask */ | |
234 | 0xffff, /* dst_mask */ | |
235 | false), /* pcrel_offset */ | |
236 | ||
01b49cb3 C |
237 | }; |
238 | ||
239 | /* Map BFD reloc types to V850 ELF reloc types. */ | |
240 | ||
241 | struct v850_reloc_map | |
242 | { | |
243 | unsigned char bfd_reloc_val; | |
244 | unsigned char elf_reloc_val; | |
245 | }; | |
246 | ||
247 | static const struct v850_reloc_map v850_reloc_map[] = | |
248 | { | |
249 | { BFD_RELOC_NONE, R_V850_NONE, }, | |
250 | { BFD_RELOC_V850_9_PCREL, R_V850_9_PCREL, }, | |
251 | { BFD_RELOC_V850_22_PCREL, R_V850_22_PCREL, }, | |
252 | { BFD_RELOC_HI16_S, R_V850_HI16_S, }, | |
253 | { BFD_RELOC_HI16, R_V850_HI16, }, | |
254 | { BFD_RELOC_LO16, R_V850_LO16, }, | |
237b5c4c JL |
255 | { BFD_RELOC_32, R_V850_32, }, |
256 | { BFD_RELOC_16, R_V850_16, }, | |
257 | { BFD_RELOC_8, R_V850_8, }, | |
b6d08fce JL |
258 | { BFD_RELOC_V850_TDA_OFFSET, R_V850_TDA_OFFSET, }, |
259 | { BFD_RELOC_V850_SDA_OFFSET, R_V850_SDA_OFFSET, }, | |
260 | { BFD_RELOC_V850_ZDA_OFFSET, R_V850_ZDA_OFFSET, }, | |
01b49cb3 C |
261 | }; |
262 | ||
263 | static reloc_howto_type * | |
264 | bfd_elf32_bfd_reloc_type_lookup (abfd, code) | |
265 | bfd *abfd; | |
266 | bfd_reloc_code_real_type code; | |
267 | { | |
268 | unsigned int i; | |
269 | ||
270 | for (i = 0; | |
271 | i < sizeof (v850_reloc_map) / sizeof (struct v850_reloc_map); | |
272 | i++) | |
273 | { | |
274 | if (v850_reloc_map[i].bfd_reloc_val == code) | |
275 | return &elf_v850_howto_table[v850_reloc_map[i].elf_reloc_val]; | |
276 | } | |
277 | ||
278 | return NULL; | |
279 | } | |
280 | ||
281 | /* Set the howto pointer for an V850 ELF reloc. */ | |
282 | ||
283 | static void | |
284 | v850_info_to_howto_rel (abfd, cache_ptr, dst) | |
285 | bfd *abfd; | |
286 | arelent *cache_ptr; | |
287 | Elf32_Internal_Rel *dst; | |
288 | { | |
289 | unsigned int r_type; | |
290 | ||
291 | r_type = ELF32_R_TYPE (dst->r_info); | |
292 | BFD_ASSERT (r_type < (unsigned int) R_V850_max); | |
293 | cache_ptr->howto = &elf_v850_howto_table[r_type]; | |
294 | } | |
295 | ||
e73b6ae6 JL |
296 | static bfd_reloc_status_type |
297 | bfd_elf32_v850_reloc (abfd, reloc, symbol, data, isection, obfd, err) | |
298 | bfd *abfd; | |
299 | arelent *reloc; | |
300 | asymbol *symbol; | |
301 | PTR data; | |
302 | asection *isection; | |
303 | bfd *obfd; | |
304 | char **err; | |
305 | { | |
306 | if (obfd != (bfd *) NULL | |
307 | && (symbol->flags & BSF_SECTION_SYM) == 0 | |
308 | && (! reloc->howto->partial_inplace | |
309 | || reloc->addend == 0)) | |
310 | { | |
311 | reloc->address += isection->output_offset; | |
312 | return bfd_reloc_ok; | |
313 | } | |
314 | else if (obfd != NULL) | |
315 | { | |
316 | return bfd_reloc_continue; | |
317 | } | |
318 | ||
05f1baaa JL |
319 | /* Catch relocs involving undefined symbols. */ |
320 | if (bfd_is_und_section (symbol->section) | |
321 | && (symbol->flags & BSF_WEAK) == 0 | |
322 | && obfd == NULL) | |
323 | return bfd_reloc_undefined; | |
324 | ||
e73b6ae6 JL |
325 | /* We handle final linking of some relocs ourselves. */ |
326 | { | |
327 | long relocation, insn; | |
328 | ||
329 | /* Is the address of the relocation really within the section? */ | |
330 | if (reloc->address > isection->_cooked_size) | |
331 | return bfd_reloc_outofrange; | |
332 | ||
333 | /* Work out which section the relocation is targetted at and the | |
334 | initial relocation command value. */ | |
335 | ||
336 | /* Get symbol value. (Common symbols are special.) */ | |
337 | if (bfd_is_com_section (symbol->section)) | |
338 | relocation = 0; | |
339 | else | |
340 | relocation = symbol->value; | |
341 | ||
342 | /* Convert input-section-relative symbol value to absolute + addend. */ | |
343 | relocation += symbol->section->output_section->vma; | |
344 | relocation += symbol->section->output_offset; | |
345 | relocation += reloc->addend; | |
346 | ||
347 | if (reloc->howto->pc_relative == true) | |
348 | { | |
349 | /* Here the variable relocation holds the final address of the | |
350 | symbol we are relocating against, plus any addend. */ | |
351 | relocation -= isection->output_section->vma + isection->output_offset; | |
352 | ||
353 | /* Deal with pcrel_offset */ | |
354 | relocation -= reloc->address; | |
355 | } | |
356 | ||
357 | /* I've got no clue... */ | |
358 | reloc->addend = 0; | |
359 | ||
360 | if (reloc->howto->type == R_V850_22_PCREL) | |
361 | { | |
362 | if (relocation > 0x1ffff || relocation < -0x200000) | |
363 | return bfd_reloc_overflow; | |
364 | ||
365 | if ((relocation % 2) != 0) | |
366 | return bfd_reloc_dangerous; | |
367 | ||
368 | insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc->address); | |
e1d98a0a | 369 | insn &= ~0xfffe003f; |
e73b6ae6 JL |
370 | insn |= (((relocation & 0xfffe) << 16) |
371 | | ((relocation & 0x3f0000) >> 16)); | |
372 | bfd_put_32 (abfd, insn, (bfd_byte *)data + reloc->address); | |
373 | return bfd_reloc_ok; | |
374 | } | |
375 | else if (reloc->howto->type == R_V850_9_PCREL) | |
376 | { | |
377 | if (relocation > 0xff || relocation < -0x100) | |
378 | return bfd_reloc_overflow; | |
379 | ||
380 | if ((relocation % 2) != 0) | |
381 | return bfd_reloc_dangerous; | |
382 | ||
383 | insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address); | |
e1d98a0a | 384 | insn &= 0xf870; |
e73b6ae6 JL |
385 | insn |= ((relocation & 0x1f0) << 7) | ((relocation & 0x0e) << 3); |
386 | bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address); | |
387 | return bfd_reloc_ok; | |
388 | } | |
389 | else if (reloc->howto->type == R_V850_HI16_S) | |
390 | { | |
1336da39 | 391 | relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address); |
e73b6ae6 JL |
392 | relocation = (relocation >> 16) + ((relocation & 0x8000) != 0); |
393 | bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address); | |
394 | return bfd_reloc_ok; | |
395 | } | |
396 | else if (reloc->howto->type == R_V850_HI16) | |
397 | { | |
1336da39 | 398 | relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address); |
e73b6ae6 JL |
399 | relocation = (relocation >> 16); |
400 | bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address); | |
401 | return bfd_reloc_ok; | |
402 | } | |
403 | } | |
404 | ||
405 | return bfd_reloc_continue; | |
406 | } | |
407 | ||
1336da39 SG |
408 | static boolean bfd_elf32_v850_is_local_label PARAMS ((bfd *, asymbol *)); |
409 | ||
410 | /*ARGSUSED*/ | |
411 | static boolean | |
412 | bfd_elf32_v850_is_local_label (abfd, symbol) | |
413 | bfd *abfd; | |
414 | asymbol *symbol; | |
415 | { | |
416 | return ((symbol->name[0] == '.' && (symbol->name[1] == 'L' || symbol->name[1] == '.')) | |
417 | || (symbol->name[0] == '_' && symbol->name[1] == '.' && symbol->name[2] == 'L' | |
418 | && symbol->name[3] == '_')); | |
419 | } | |
420 | ||
421 | #define bfd_elf32_bfd_is_local_label bfd_elf32_v850_is_local_label | |
422 | ||
e73b6ae6 JL |
423 | #define TARGET_LITTLE_SYM bfd_elf32_v850_vec |
424 | #define TARGET_LITTLE_NAME "elf32-v850" | |
01b49cb3 C |
425 | #define ELF_ARCH bfd_arch_v850 |
426 | #define ELF_MACHINE_CODE EM_CYGNUS_V850 | |
427 | #define ELF_MAXPAGESIZE 0x1000 | |
428 | ||
429 | #define elf_info_to_howto 0 | |
430 | #define elf_info_to_howto_rel v850_info_to_howto_rel | |
431 | ||
1336da39 SG |
432 | #define elf_symbol_leading_char '_' |
433 | ||
01b49cb3 | 434 | #include "elf32-target.h" |