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, | |
01b49cb3 C |
49 | R_V850_max |
50 | }; | |
51 | ||
52 | static reloc_howto_type elf_v850_howto_table[] = | |
53 | { | |
54 | /* This reloc does nothing. */ | |
55 | HOWTO (R_V850_NONE, /* type */ | |
56 | 0, /* rightshift */ | |
57 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
58 | 32, /* bitsize */ | |
59 | false, /* pc_relative */ | |
60 | 0, /* bitpos */ | |
61 | complain_overflow_bitfield, /* complain_on_overflow */ | |
62 | bfd_elf_generic_reloc, /* special_function */ | |
63 | "R_V850_NONE", /* name */ | |
64 | false, /* partial_inplace */ | |
65 | 0, /* src_mask */ | |
66 | 0, /* dst_mask */ | |
67 | false), /* pcrel_offset */ | |
68 | ||
69 | /* A PC relative 9 bit branch. */ | |
70 | HOWTO (R_V850_9_PCREL, /* type */ | |
71 | 2, /* rightshift */ | |
72 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
73 | 26, /* bitsize */ | |
74 | true, /* pc_relative */ | |
75 | 0, /* bitpos */ | |
76 | complain_overflow_bitfield, /* complain_on_overflow */ | |
e73b6ae6 | 77 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
78 | "R_V850_9_PCREL", /* name */ |
79 | false, /* partial_inplace */ | |
80 | 0x00ffffff, /* src_mask */ | |
81 | 0x00ffffff, /* dst_mask */ | |
82 | true), /* pcrel_offset */ | |
83 | ||
84 | /* A PC relative 22 bit branch. */ | |
85 | HOWTO (R_V850_22_PCREL, /* type */ | |
86 | 2, /* rightshift */ | |
87 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
88 | 22, /* bitsize */ | |
89 | true, /* pc_relative */ | |
90 | 7, /* bitpos */ | |
91 | complain_overflow_signed, /* complain_on_overflow */ | |
e73b6ae6 | 92 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
93 | "R_V850_22_PCREL", /* name */ |
94 | false, /* partial_inplace */ | |
95 | 0x07ffff80, /* src_mask */ | |
96 | 0x07ffff80, /* dst_mask */ | |
97 | true), /* pcrel_offset */ | |
98 | ||
99 | /* High 16 bits of symbol value. */ | |
100 | HOWTO (R_V850_HI16_S, /* type */ | |
101 | 0, /* rightshift */ | |
102 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
103 | 16, /* bitsize */ | |
104 | false, /* pc_relative */ | |
e73b6ae6 | 105 | 0, /* bitpos */ |
01b49cb3 | 106 | complain_overflow_dont,/* complain_on_overflow */ |
e73b6ae6 | 107 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
108 | "R_V850_HI16_S", /* name */ |
109 | true, /* partial_inplace */ | |
110 | 0xffff, /* src_mask */ | |
111 | 0xffff, /* dst_mask */ | |
112 | false), /* pcrel_offset */ | |
113 | ||
114 | /* High 16 bits of symbol value. */ | |
115 | HOWTO (R_V850_HI16, /* type */ | |
116 | 0, /* rightshift */ | |
117 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
118 | 16, /* bitsize */ | |
119 | false, /* pc_relative */ | |
e73b6ae6 | 120 | 0, /* bitpos */ |
01b49cb3 | 121 | complain_overflow_dont,/* complain_on_overflow */ |
e73b6ae6 | 122 | bfd_elf32_v850_reloc, /* special_function */ |
01b49cb3 C |
123 | "R_V850_HI16", /* name */ |
124 | true, /* partial_inplace */ | |
125 | 0xffff, /* src_mask */ | |
126 | 0xffff, /* dst_mask */ | |
127 | false), /* pcrel_offset */ | |
128 | ||
129 | /* Low 16 bits of symbol value. */ | |
130 | HOWTO (R_V850_LO16, /* type */ | |
131 | 0, /* rightshift */ | |
132 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
133 | 16, /* bitsize */ | |
134 | false, /* pc_relative */ | |
e73b6ae6 | 135 | 0, /* bitpos */ |
01b49cb3 C |
136 | complain_overflow_dont,/* complain_on_overflow */ |
137 | bfd_elf_generic_reloc, /* special_function */ | |
138 | "R_V850_LO16", /* name */ | |
139 | true, /* partial_inplace */ | |
140 | 0xffff, /* src_mask */ | |
141 | 0xffff, /* dst_mask */ | |
142 | false), /* pcrel_offset */ | |
237b5c4c JL |
143 | |
144 | /* Simple 32bit reloc. */ | |
145 | HOWTO (R_V850_32, /* type */ | |
146 | 0, /* rightshift */ | |
147 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
148 | 32, /* bitsize */ | |
149 | false, /* pc_relative */ | |
150 | 0, /* bitpos */ | |
151 | complain_overflow_dont,/* complain_on_overflow */ | |
152 | bfd_elf_generic_reloc, /* special_function */ | |
153 | "R_V850_32", /* name */ | |
e73b6ae6 JL |
154 | true, /* partial_inplace */ |
155 | 0xffffffff, /* src_mask */ | |
237b5c4c JL |
156 | 0xffffffff, /* dst_mask */ |
157 | false), /* pcrel_offset */ | |
158 | ||
159 | /* Simple 16bit reloc. */ | |
160 | HOWTO (R_V850_16, /* type */ | |
161 | 0, /* rightshift */ | |
162 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
163 | 16, /* bitsize */ | |
164 | false, /* pc_relative */ | |
165 | 0, /* bitpos */ | |
166 | complain_overflow_dont,/* complain_on_overflow */ | |
167 | bfd_elf_generic_reloc, /* special_function */ | |
168 | "R_V850_16", /* name */ | |
e73b6ae6 JL |
169 | true, /* partial_inplace */ |
170 | 0xffff, /* src_mask */ | |
237b5c4c JL |
171 | 0xffff, /* dst_mask */ |
172 | false), /* pcrel_offset */ | |
173 | ||
174 | /* Simple 8bit reloc. */ | |
175 | HOWTO (R_V850_8, /* type */ | |
176 | 0, /* rightshift */ | |
177 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
178 | 8, /* bitsize */ | |
179 | false, /* pc_relative */ | |
180 | 0, /* bitpos */ | |
181 | complain_overflow_dont,/* complain_on_overflow */ | |
182 | bfd_elf_generic_reloc, /* special_function */ | |
183 | "R_V850_8", /* name */ | |
e73b6ae6 JL |
184 | true, /* partial_inplace */ |
185 | 0xff, /* src_mask */ | |
237b5c4c JL |
186 | 0xff, /* dst_mask */ |
187 | false), /* pcrel_offset */ | |
01b49cb3 C |
188 | }; |
189 | ||
190 | /* Map BFD reloc types to V850 ELF reloc types. */ | |
191 | ||
192 | struct v850_reloc_map | |
193 | { | |
194 | unsigned char bfd_reloc_val; | |
195 | unsigned char elf_reloc_val; | |
196 | }; | |
197 | ||
198 | static const struct v850_reloc_map v850_reloc_map[] = | |
199 | { | |
200 | { BFD_RELOC_NONE, R_V850_NONE, }, | |
201 | { BFD_RELOC_V850_9_PCREL, R_V850_9_PCREL, }, | |
202 | { BFD_RELOC_V850_22_PCREL, R_V850_22_PCREL, }, | |
203 | { BFD_RELOC_HI16_S, R_V850_HI16_S, }, | |
204 | { BFD_RELOC_HI16, R_V850_HI16, }, | |
205 | { BFD_RELOC_LO16, R_V850_LO16, }, | |
237b5c4c JL |
206 | { BFD_RELOC_32, R_V850_32, }, |
207 | { BFD_RELOC_16, R_V850_16, }, | |
208 | { BFD_RELOC_8, R_V850_8, }, | |
01b49cb3 C |
209 | }; |
210 | ||
211 | static reloc_howto_type * | |
212 | bfd_elf32_bfd_reloc_type_lookup (abfd, code) | |
213 | bfd *abfd; | |
214 | bfd_reloc_code_real_type code; | |
215 | { | |
216 | unsigned int i; | |
217 | ||
218 | for (i = 0; | |
219 | i < sizeof (v850_reloc_map) / sizeof (struct v850_reloc_map); | |
220 | i++) | |
221 | { | |
222 | if (v850_reloc_map[i].bfd_reloc_val == code) | |
223 | return &elf_v850_howto_table[v850_reloc_map[i].elf_reloc_val]; | |
224 | } | |
225 | ||
226 | return NULL; | |
227 | } | |
228 | ||
229 | /* Set the howto pointer for an V850 ELF reloc. */ | |
230 | ||
231 | static void | |
232 | v850_info_to_howto_rel (abfd, cache_ptr, dst) | |
233 | bfd *abfd; | |
234 | arelent *cache_ptr; | |
235 | Elf32_Internal_Rel *dst; | |
236 | { | |
237 | unsigned int r_type; | |
238 | ||
239 | r_type = ELF32_R_TYPE (dst->r_info); | |
240 | BFD_ASSERT (r_type < (unsigned int) R_V850_max); | |
241 | cache_ptr->howto = &elf_v850_howto_table[r_type]; | |
242 | } | |
243 | ||
e73b6ae6 JL |
244 | static bfd_reloc_status_type |
245 | bfd_elf32_v850_reloc (abfd, reloc, symbol, data, isection, obfd, err) | |
246 | bfd *abfd; | |
247 | arelent *reloc; | |
248 | asymbol *symbol; | |
249 | PTR data; | |
250 | asection *isection; | |
251 | bfd *obfd; | |
252 | char **err; | |
253 | { | |
254 | if (obfd != (bfd *) NULL | |
255 | && (symbol->flags & BSF_SECTION_SYM) == 0 | |
256 | && (! reloc->howto->partial_inplace | |
257 | || reloc->addend == 0)) | |
258 | { | |
259 | reloc->address += isection->output_offset; | |
260 | return bfd_reloc_ok; | |
261 | } | |
262 | else if (obfd != NULL) | |
263 | { | |
264 | return bfd_reloc_continue; | |
265 | } | |
266 | ||
267 | /* We handle final linking of some relocs ourselves. */ | |
268 | { | |
269 | long relocation, insn; | |
270 | ||
271 | /* Is the address of the relocation really within the section? */ | |
272 | if (reloc->address > isection->_cooked_size) | |
273 | return bfd_reloc_outofrange; | |
274 | ||
275 | /* Work out which section the relocation is targetted at and the | |
276 | initial relocation command value. */ | |
277 | ||
278 | /* Get symbol value. (Common symbols are special.) */ | |
279 | if (bfd_is_com_section (symbol->section)) | |
280 | relocation = 0; | |
281 | else | |
282 | relocation = symbol->value; | |
283 | ||
284 | /* Convert input-section-relative symbol value to absolute + addend. */ | |
285 | relocation += symbol->section->output_section->vma; | |
286 | relocation += symbol->section->output_offset; | |
287 | relocation += reloc->addend; | |
288 | ||
289 | if (reloc->howto->pc_relative == true) | |
290 | { | |
291 | /* Here the variable relocation holds the final address of the | |
292 | symbol we are relocating against, plus any addend. */ | |
293 | relocation -= isection->output_section->vma + isection->output_offset; | |
294 | ||
295 | /* Deal with pcrel_offset */ | |
296 | relocation -= reloc->address; | |
297 | } | |
298 | ||
299 | /* I've got no clue... */ | |
300 | reloc->addend = 0; | |
301 | ||
302 | if (reloc->howto->type == R_V850_22_PCREL) | |
303 | { | |
304 | if (relocation > 0x1ffff || relocation < -0x200000) | |
305 | return bfd_reloc_overflow; | |
306 | ||
307 | if ((relocation % 2) != 0) | |
308 | return bfd_reloc_dangerous; | |
309 | ||
310 | insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc->address); | |
311 | insn |= (((relocation & 0xfffe) << 16) | |
312 | | ((relocation & 0x3f0000) >> 16)); | |
313 | bfd_put_32 (abfd, insn, (bfd_byte *)data + reloc->address); | |
314 | return bfd_reloc_ok; | |
315 | } | |
316 | else if (reloc->howto->type == R_V850_9_PCREL) | |
317 | { | |
318 | if (relocation > 0xff || relocation < -0x100) | |
319 | return bfd_reloc_overflow; | |
320 | ||
321 | if ((relocation % 2) != 0) | |
322 | return bfd_reloc_dangerous; | |
323 | ||
324 | insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address); | |
325 | insn |= ((relocation & 0x1f0) << 7) | ((relocation & 0x0e) << 3); | |
326 | bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address); | |
327 | return bfd_reloc_ok; | |
328 | } | |
329 | else if (reloc->howto->type == R_V850_HI16_S) | |
330 | { | |
1336da39 | 331 | relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address); |
e73b6ae6 JL |
332 | relocation = (relocation >> 16) + ((relocation & 0x8000) != 0); |
333 | bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address); | |
334 | return bfd_reloc_ok; | |
335 | } | |
336 | else if (reloc->howto->type == R_V850_HI16) | |
337 | { | |
1336da39 | 338 | relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address); |
e73b6ae6 JL |
339 | relocation = (relocation >> 16); |
340 | bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address); | |
341 | return bfd_reloc_ok; | |
342 | } | |
343 | } | |
344 | ||
345 | return bfd_reloc_continue; | |
346 | } | |
347 | ||
1336da39 SG |
348 | static boolean bfd_elf32_v850_is_local_label PARAMS ((bfd *, asymbol *)); |
349 | ||
350 | /*ARGSUSED*/ | |
351 | static boolean | |
352 | bfd_elf32_v850_is_local_label (abfd, symbol) | |
353 | bfd *abfd; | |
354 | asymbol *symbol; | |
355 | { | |
356 | return ((symbol->name[0] == '.' && (symbol->name[1] == 'L' || symbol->name[1] == '.')) | |
357 | || (symbol->name[0] == '_' && symbol->name[1] == '.' && symbol->name[2] == 'L' | |
358 | && symbol->name[3] == '_')); | |
359 | } | |
360 | ||
361 | #define bfd_elf32_bfd_is_local_label bfd_elf32_v850_is_local_label | |
362 | ||
e73b6ae6 JL |
363 | #define TARGET_LITTLE_SYM bfd_elf32_v850_vec |
364 | #define TARGET_LITTLE_NAME "elf32-v850" | |
01b49cb3 C |
365 | #define ELF_ARCH bfd_arch_v850 |
366 | #define ELF_MACHINE_CODE EM_CYGNUS_V850 | |
367 | #define ELF_MAXPAGESIZE 0x1000 | |
368 | ||
369 | #define elf_info_to_howto 0 | |
370 | #define elf_info_to_howto_rel v850_info_to_howto_rel | |
371 | ||
1336da39 SG |
372 | #define elf_symbol_leading_char '_' |
373 | ||
01b49cb3 | 374 | #include "elf32-target.h" |