]>
Commit | Line | Data |
---|---|---|
1d5c6cfd DE |
1 | /* M32R-specific support for 32-bit ELF. |
2 | Copyright (C) 1996, 1997 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 | #include "elf/m32r.h" | |
25 | ||
26 | static bfd_reloc_status_type m32r_elf_10_pcrel_reloc | |
27 | PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); | |
28 | static bfd_reloc_status_type m32r_elf_hi16_slo_reloc | |
29 | PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); | |
30 | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup | |
31 | PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); | |
32 | static void m32r_info_to_howto_rel | |
33 | PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); | |
34 | ||
35 | /* Use REL instead of RELA to save space. */ | |
36 | #define USE_REL | |
37 | ||
38 | static reloc_howto_type elf_m32r_howto_table[] = | |
39 | { | |
40 | /* This reloc does nothing. */ | |
41 | HOWTO (R_M32R_NONE, /* type */ | |
42 | 0, /* rightshift */ | |
43 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
44 | 32, /* bitsize */ | |
45 | false, /* pc_relative */ | |
46 | 0, /* bitpos */ | |
47 | complain_overflow_bitfield, /* complain_on_overflow */ | |
48 | bfd_elf_generic_reloc, /* special_function */ | |
49 | "R_M32R_NONE", /* name */ | |
50 | false, /* partial_inplace */ | |
51 | 0, /* src_mask */ | |
52 | 0, /* dst_mask */ | |
53 | false), /* pcrel_offset */ | |
54 | ||
55 | /* A 16 bit absolute relocation. */ | |
56 | HOWTO (R_M32R_16, /* type */ | |
57 | 0, /* rightshift */ | |
58 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
59 | 16, /* bitsize */ | |
60 | false, /* pc_relative */ | |
61 | 0, /* bitpos */ | |
62 | complain_overflow_bitfield, /* complain_on_overflow */ | |
63 | bfd_elf_generic_reloc, /* special_function */ | |
64 | "R_M32R_16", /* name */ | |
b9c5ee68 | 65 | true, /* partial_inplace */ |
1d5c6cfd DE |
66 | 0xffff, /* src_mask */ |
67 | 0xffff, /* dst_mask */ | |
68 | false), /* pcrel_offset */ | |
69 | ||
70 | /* A 32 bit absolute relocation. */ | |
71 | HOWTO (R_M32R_32, /* type */ | |
72 | 0, /* rightshift */ | |
73 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
74 | 32, /* bitsize */ | |
75 | false, /* pc_relative */ | |
76 | 0, /* bitpos */ | |
77 | complain_overflow_bitfield, /* complain_on_overflow */ | |
78 | bfd_elf_generic_reloc, /* special_function */ | |
79 | "R_M32R_32", /* name */ | |
b9c5ee68 | 80 | true, /* partial_inplace */ |
1d5c6cfd DE |
81 | 0xffffffff, /* src_mask */ |
82 | 0xffffffff, /* dst_mask */ | |
83 | false), /* pcrel_offset */ | |
84 | ||
85 | /* A 24 bit address. */ | |
86 | HOWTO (R_M32R_24, /* type */ | |
87 | 0, /* rightshift */ | |
88 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
89 | 24, /* bitsize */ | |
90 | false, /* pc_relative */ | |
91 | 0, /* bitpos */ | |
92 | complain_overflow_unsigned, /* complain_on_overflow */ | |
93 | bfd_elf_generic_reloc, /* special_function */ | |
94 | "R_M32R_24", /* name */ | |
b9c5ee68 | 95 | true, /* partial_inplace */ |
1d5c6cfd DE |
96 | 0xffffff, /* src_mask */ |
97 | 0xffffff, /* dst_mask */ | |
98 | false), /* pcrel_offset */ | |
99 | ||
100 | /* An PC Relative 10-bit relocation, shifted by 2. | |
101 | This reloc is complicated because relocations are relative to pc & -4. | |
102 | i.e. branches in the right insn slot use the address of the left insn | |
103 | slot for pc. */ | |
104 | HOWTO (R_M32R_10_PCREL, /* type */ | |
105 | 2, /* rightshift */ | |
106 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
107 | 10, /* bitsize */ | |
108 | true, /* pc_relative */ | |
109 | 0, /* bitpos */ | |
110 | complain_overflow_signed, /* complain_on_overflow */ | |
111 | m32r_elf_10_pcrel_reloc, /* special_function */ | |
112 | "R_M32R_10_PCREL", /* name */ | |
113 | false, /* partial_inplace */ | |
114 | 0xff, /* src_mask */ | |
115 | 0xff, /* dst_mask */ | |
116 | true), /* pcrel_offset */ | |
117 | ||
118 | /* A relative 18 bit relocation, right shifted by 2. */ | |
119 | HOWTO (R_M32R_18_PCREL, /* type */ | |
120 | 2, /* rightshift */ | |
121 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
122 | 18, /* bitsize */ | |
123 | true, /* pc_relative */ | |
124 | 0, /* bitpos */ | |
125 | complain_overflow_signed, /* complain_on_overflow */ | |
126 | bfd_elf_generic_reloc, /* special_function */ | |
127 | "R_M32R_18_PCREL", /* name */ | |
128 | false, /* partial_inplace */ | |
129 | 0xffff, /* src_mask */ | |
130 | 0xffff, /* dst_mask */ | |
131 | true), /* pcrel_offset */ | |
132 | ||
133 | /* A relative 26 bit relocation, right shifted by 2. */ | |
134 | HOWTO (R_M32R_26_PCREL, /* type */ | |
135 | 2, /* rightshift */ | |
136 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
137 | 26, /* bitsize */ | |
138 | true, /* pc_relative */ | |
139 | 0, /* bitpos */ | |
140 | complain_overflow_signed, /* complain_on_overflow */ | |
141 | bfd_elf_generic_reloc, /* special_function */ | |
142 | "R_M32R_26_PCREL", /* name */ | |
143 | false, /* partial_inplace */ | |
144 | 0xffffff, /* src_mask */ | |
145 | 0xffffff, /* dst_mask */ | |
146 | true), /* pcrel_offset */ | |
147 | ||
148 | /* High 16 bits of address when lower 16 is or'd in. */ | |
149 | HOWTO (R_M32R_HI16_ULO, /* type */ | |
150 | 16, /* rightshift */ | |
151 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
152 | 16, /* bitsize */ | |
153 | false, /* pc_relative */ | |
154 | 0, /* bitpos */ | |
155 | complain_overflow_dont, /* complain_on_overflow */ | |
156 | bfd_elf_generic_reloc, /* special_function */ | |
157 | "R_M32R_HI16_ULO", /* name */ | |
b9c5ee68 | 158 | true, /* partial_inplace */ |
1d5c6cfd DE |
159 | 0x0000ffff, /* src_mask */ |
160 | 0x0000ffff, /* dst_mask */ | |
161 | false), /* pcrel_offset */ | |
162 | ||
163 | /* High 16 bits of address when lower 16 is added in. */ | |
164 | HOWTO (R_M32R_HI16_SLO, /* type */ | |
165 | 16, /* rightshift */ | |
166 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
167 | 16, /* bitsize */ | |
168 | false, /* pc_relative */ | |
169 | 0, /* bitpos */ | |
170 | complain_overflow_dont, /* complain_on_overflow */ | |
171 | m32r_elf_hi16_slo_reloc, /* special_function */ | |
172 | "R_M32R_HI16_SLO", /* name */ | |
b9c5ee68 | 173 | true, /* partial_inplace */ |
1d5c6cfd DE |
174 | 0x0000ffff, /* src_mask */ |
175 | 0x0000ffff, /* dst_mask */ | |
176 | false), /* pcrel_offset */ | |
177 | ||
178 | /* Lower 16 bits of address. */ | |
179 | HOWTO (R_M32R_LO16, /* type */ | |
180 | 0, /* rightshift */ | |
181 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
182 | 16, /* bitsize */ | |
183 | false, /* pc_relative */ | |
184 | 0, /* bitpos */ | |
185 | complain_overflow_dont, /* complain_on_overflow */ | |
186 | bfd_elf_generic_reloc, /* special_function */ | |
187 | "R_M32R_LO16", /* name */ | |
b9c5ee68 | 188 | true, /* partial_inplace */ |
1d5c6cfd DE |
189 | 0x0000ffff, /* src_mask */ |
190 | 0x0000ffff, /* dst_mask */ | |
191 | false), /* pcrel_offset */ | |
192 | }; | |
193 | ||
194 | /* Handle the R_M32R_10_PCREL reloc. */ | |
195 | ||
196 | static bfd_reloc_status_type | |
197 | m32r_elf_10_pcrel_reloc (abfd, reloc_entry, symbol, data, | |
198 | input_section, output_bfd, error_message) | |
199 | bfd *abfd; | |
200 | arelent *reloc_entry; | |
201 | asymbol *symbol; | |
202 | PTR data; | |
203 | asection *input_section; | |
204 | bfd *output_bfd; | |
205 | char **error_message; | |
206 | { | |
207 | bfd_vma relocation; | |
208 | bfd_vma x; | |
209 | reloc_howto_type *howto; | |
210 | ||
211 | /* This part if from bfd_elf_generic_reloc. */ | |
212 | if (output_bfd != (bfd *) NULL | |
213 | && (symbol->flags & BSF_SECTION_SYM) == 0 | |
214 | && (! reloc_entry->howto->partial_inplace | |
215 | || reloc_entry->addend == 0)) | |
216 | { | |
217 | reloc_entry->address += input_section->output_offset; | |
218 | return bfd_reloc_ok; | |
219 | } | |
220 | ||
221 | if (output_bfd != NULL) | |
222 | { | |
223 | /* FIXME: See bfd_perform_relocation. Is this right? */ | |
224 | return bfd_reloc_continue; | |
225 | } | |
226 | ||
227 | /* The rest is copied from bfd_perform_relocation, modified to suit us. */ | |
228 | ||
229 | if (reloc_entry->address > input_section->_cooked_size) | |
230 | return bfd_reloc_outofrange; | |
231 | ||
232 | relocation = (symbol->value | |
233 | + symbol->section->output_section->vma | |
234 | + symbol->section->output_offset); | |
235 | relocation += reloc_entry->addend; | |
236 | relocation -= (input_section->output_section->vma | |
237 | + input_section->output_offset); | |
238 | relocation -= (reloc_entry->address & -4L); | |
239 | ||
240 | howto = reloc_entry->howto; | |
241 | x = bfd_get_16 (abfd, (char *) data + reloc_entry->address); | |
242 | relocation >>= howto->rightshift; | |
243 | relocation <<= howto->bitpos; | |
244 | x = (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask); | |
245 | bfd_put_16 (abfd, x, (char *) data + reloc_entry->address); | |
246 | ||
247 | if ((bfd_signed_vma) relocation < - 0x80 | |
248 | || (bfd_signed_vma) relocation > 0x7f) | |
249 | return bfd_reloc_overflow; | |
250 | else | |
251 | return bfd_reloc_ok; | |
252 | } | |
253 | ||
254 | /* Handle the R_M32R_HI16_SLO reloc. | |
255 | This reloc is used in load/store with displacement instructions. | |
256 | The lower 16 bits are sign extended when added to the high 16 bytes | |
257 | so if the lower 16 bits are negative (bit 15 == 1) then we must add one | |
258 | to the high 16 bytes (which will get subtracted off when the low 16 bits | |
259 | are added. */ | |
260 | ||
261 | static bfd_reloc_status_type | |
262 | m32r_elf_hi16_slo_reloc (abfd, reloc_entry, symbol, data, | |
263 | input_section, output_bfd, error_message) | |
264 | bfd *abfd; | |
265 | arelent *reloc_entry; | |
266 | asymbol *symbol; | |
267 | PTR data; | |
268 | asection *input_section; | |
269 | bfd *output_bfd; | |
270 | char **error_message; | |
271 | { | |
272 | bfd_vma relocation; | |
273 | unsigned long x; | |
274 | int bit15; | |
275 | reloc_howto_type *howto; | |
276 | ||
277 | /* This part if from bfd_elf_generic_reloc. */ | |
278 | if (output_bfd != (bfd *) NULL | |
279 | && (symbol->flags & BSF_SECTION_SYM) == 0 | |
280 | && (! reloc_entry->howto->partial_inplace | |
281 | || reloc_entry->addend == 0)) | |
282 | { | |
283 | reloc_entry->address += input_section->output_offset; | |
284 | return bfd_reloc_ok; | |
285 | } | |
286 | ||
287 | if (output_bfd != NULL) | |
288 | { | |
289 | /* FIXME: See bfd_perform_relocation. Is this right? */ | |
290 | return bfd_reloc_continue; | |
291 | } | |
292 | ||
293 | /* The rest is copied from bfd_perform_relocation, modified to suit us. */ | |
294 | ||
295 | if (reloc_entry->address > input_section->_cooked_size) | |
296 | return bfd_reloc_outofrange; | |
297 | ||
298 | relocation = (symbol->value | |
299 | + symbol->section->output_section->vma | |
300 | + symbol->section->output_offset); | |
301 | relocation += reloc_entry->addend; | |
302 | ||
303 | howto = reloc_entry->howto; | |
304 | x = bfd_get_32 (abfd, (char *) data + reloc_entry->address); | |
305 | bit15 = relocation & 0x8000; | |
306 | relocation >>= howto->rightshift; | |
307 | if (bit15) | |
308 | relocation += 1; | |
309 | relocation <<= howto->bitpos; | |
310 | x = (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask); | |
311 | bfd_put_32 (abfd, x, (char *) data + reloc_entry->address); | |
312 | ||
313 | return bfd_reloc_ok; | |
314 | } | |
315 | ||
316 | /* Map BFD reloc types to M32R ELF reloc types. */ | |
317 | ||
318 | struct m32r_reloc_map | |
319 | { | |
320 | unsigned char bfd_reloc_val; | |
321 | unsigned char elf_reloc_val; | |
322 | }; | |
323 | ||
324 | static const struct m32r_reloc_map m32r_reloc_map[] = | |
325 | { | |
326 | { BFD_RELOC_NONE, R_M32R_NONE }, | |
327 | { BFD_RELOC_16, R_M32R_16 }, | |
328 | { BFD_RELOC_32, R_M32R_32 }, | |
329 | { BFD_RELOC_M32R_24, R_M32R_24 }, | |
330 | { BFD_RELOC_M32R_10_PCREL, R_M32R_10_PCREL }, | |
331 | { BFD_RELOC_M32R_18_PCREL, R_M32R_18_PCREL }, | |
332 | { BFD_RELOC_M32R_26_PCREL, R_M32R_26_PCREL }, | |
333 | { BFD_RELOC_M32R_HI16_ULO, R_M32R_HI16_ULO }, | |
334 | { BFD_RELOC_M32R_HI16_SLO, R_M32R_HI16_SLO }, | |
335 | { BFD_RELOC_M32R_LO16, R_M32R_LO16 }, | |
336 | }; | |
337 | ||
338 | static reloc_howto_type * | |
339 | bfd_elf32_bfd_reloc_type_lookup (abfd, code) | |
340 | bfd *abfd; | |
341 | bfd_reloc_code_real_type code; | |
342 | { | |
343 | unsigned int i; | |
344 | ||
345 | for (i = 0; | |
346 | i < sizeof (m32r_reloc_map) / sizeof (struct m32r_reloc_map); | |
347 | i++) | |
348 | { | |
349 | if (m32r_reloc_map[i].bfd_reloc_val == code) | |
350 | return &elf_m32r_howto_table[m32r_reloc_map[i].elf_reloc_val]; | |
351 | } | |
352 | ||
353 | return NULL; | |
354 | } | |
355 | ||
356 | /* Set the howto pointer for an M32R ELF reloc. */ | |
357 | ||
358 | static void | |
359 | m32r_info_to_howto_rel (abfd, cache_ptr, dst) | |
360 | bfd *abfd; | |
361 | arelent *cache_ptr; | |
362 | Elf32_Internal_Rel *dst; | |
363 | { | |
364 | unsigned int r_type; | |
365 | ||
366 | r_type = ELF32_R_TYPE (dst->r_info); | |
367 | BFD_ASSERT (r_type < (unsigned int) R_M32R_max); | |
368 | cache_ptr->howto = &elf_m32r_howto_table[r_type]; | |
369 | } | |
370 | ||
371 | #define ELF_ARCH bfd_arch_m32r | |
372 | #define ELF_MACHINE_CODE EM_CYGNUS_M32R | |
373 | #define ELF_MAXPAGESIZE 0x1000 | |
374 | ||
375 | #define TARGET_BIG_SYM bfd_elf32_m32r_vec | |
376 | #define TARGET_BIG_NAME "elf32-m32r" | |
377 | ||
378 | #define elf_info_to_howto 0 | |
379 | #define elf_info_to_howto_rel m32r_info_to_howto_rel | |
380 | #define elf_backend_object_p 0 | |
381 | #define elf_backend_final_write_processing 0 | |
382 | ||
383 | #include "elf32-target.h" |