]>
Commit | Line | Data |
---|---|---|
b3c0fc57 | 1 | /* MIPS-specific support for 32-bit ELF |
6b4b4d17 JK |
2 | Copyright 1993 Free Software Foundation, Inc. |
3 | ||
b3c0fc57 ILT |
4 | Most of the information added by Ian Lance Taylor, Cygnus Support, |
5 | <[email protected]>. | |
6 | ||
6b4b4d17 JK |
7 | This file is part of BFD, the Binary File Descriptor library. |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
22 | ||
23 | #include "bfd.h" | |
24 | #include "sysdep.h" | |
25 | #include "libbfd.h" | |
b3c0fc57 | 26 | #include "seclet.h" |
6b4b4d17 | 27 | #include "libelf.h" |
b3c0fc57 ILT |
28 | #include "elf/mips.h" |
29 | ||
30 | static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *abfd, | |
31 | arelent *reloc, | |
32 | asymbol *symbol, | |
33 | PTR data, | |
34 | asection *section, | |
35 | bfd *output_bfd)); | |
36 | static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *abfd, | |
37 | arelent *reloc, | |
38 | asymbol *symbol, | |
39 | PTR data, | |
40 | asection *section, | |
41 | bfd *output_bfd)); | |
42 | static bfd_reloc_status_type mips_elf_gprel16_reloc PARAMS ((bfd *abfd, | |
43 | arelent *reloc, | |
44 | asymbol *symbol, | |
45 | PTR data, | |
46 | asection *section, | |
47 | bfd *output_bfd)); | |
48 | ||
49 | #define USE_REL 1 /* MIPS uses REL relocations instead of RELA */ | |
50 | ||
51 | enum reloc_type | |
52 | { | |
53 | R_MIPS_NONE = 0, | |
54 | R_MIPS_16, R_MIPS_32, | |
55 | R_MIPS_REL32, R_MIPS_26, | |
56 | R_MIPS_HI16, R_MIPS_LO16, | |
57 | R_MIPS_GPREL16, R_MIPS_LITERAL, | |
58 | R_MIPS_GOT16, R_MIPS_PC16, | |
59 | R_MIPS_CALL16, R_MIPS_GPREL32, | |
60 | R_MIPS_max | |
61 | }; | |
62 | ||
63 | static reloc_howto_type elf_mips_howto_table[] = | |
64 | { | |
65 | /* No relocation. */ | |
66 | HOWTO (R_MIPS_NONE, /* type */ | |
67 | 0, /* rightshift */ | |
68 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
69 | 0, /* bitsize */ | |
70 | false, /* pc_relative */ | |
71 | 0, /* bitpos */ | |
72 | complain_overflow_dont, /* complain_on_overflow */ | |
73 | bfd_elf_generic_reloc, /* special_function */ | |
74 | "R_MIPS_NONE", /* name */ | |
75 | false, /* partial_inplace */ | |
76 | 0, /* src_mask */ | |
77 | 0, /* dst_mask */ | |
78 | false), /* pcrel_offset */ | |
79 | ||
80 | /* 16 bit relocation. */ | |
81 | HOWTO (R_MIPS_16, /* type */ | |
82 | 0, /* rightshift */ | |
83 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
84 | 16, /* bitsize */ | |
85 | false, /* pc_relative */ | |
86 | 0, /* bitpos */ | |
87 | complain_overflow_bitfield, /* complain_on_overflow */ | |
88 | bfd_elf_generic_reloc, /* special_function */ | |
89 | "R_MIPS_16", /* name */ | |
90 | true, /* partial_inplace */ | |
91 | 0xffff, /* src_mask */ | |
92 | 0xffff, /* dst_mask */ | |
93 | false), /* pcrel_offset */ | |
94 | ||
95 | /* 32 bit relocation. */ | |
96 | HOWTO (R_MIPS_32, /* type */ | |
97 | 0, /* rightshift */ | |
98 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
99 | 32, /* bitsize */ | |
100 | false, /* pc_relative */ | |
101 | 0, /* bitpos */ | |
102 | complain_overflow_bitfield, /* complain_on_overflow */ | |
103 | bfd_elf_generic_reloc, /* special_function */ | |
104 | "R_MIPS_32", /* name */ | |
105 | true, /* partial_inplace */ | |
106 | 0xffffffff, /* src_mask */ | |
107 | 0xffffffff, /* dst_mask */ | |
108 | false), /* pcrel_offset */ | |
109 | ||
110 | /* 32 bit symbol relative relocation. */ | |
111 | HOWTO (R_MIPS_REL32, /* type */ | |
112 | 0, /* rightshift */ | |
113 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
114 | 32, /* bitsize */ | |
115 | false, /* pc_relative */ | |
116 | 0, /* bitpos */ | |
117 | complain_overflow_bitfield, /* complain_on_overflow */ | |
118 | bfd_elf_generic_reloc, /* special_function */ | |
119 | "R_MIPS_REL32", /* name */ | |
120 | true, /* partial_inplace */ | |
121 | 0xffffffff, /* src_mask */ | |
122 | 0xffffffff, /* dst_mask */ | |
123 | false), /* pcrel_offset */ | |
124 | ||
125 | /* 26 bit branch address. */ | |
126 | HOWTO (R_MIPS_26, /* type */ | |
127 | 2, /* rightshift */ | |
128 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
129 | 26, /* bitsize */ | |
130 | false, /* pc_relative */ | |
131 | 0, /* bitpos */ | |
132 | complain_overflow_bitfield, /* complain_on_overflow */ | |
133 | bfd_elf_generic_reloc, /* special_function */ | |
134 | "R_MIPS_26", /* name */ | |
135 | true, /* partial_inplace */ | |
136 | 0x3ffffff, /* src_mask */ | |
137 | 0x3ffffff, /* dst_mask */ | |
138 | false), /* pcrel_offset */ | |
139 | ||
140 | /* High 16 bits of symbol value. */ | |
141 | HOWTO (R_MIPS_HI16, /* type */ | |
142 | 0, /* rightshift */ | |
143 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
144 | 16, /* bitsize */ | |
145 | false, /* pc_relative */ | |
146 | 0, /* bitpos */ | |
147 | complain_overflow_dont, /* complain_on_overflow */ | |
148 | mips_elf_hi16_reloc, /* special_function */ | |
149 | "R_MIPS_HI16", /* name */ | |
150 | true, /* partial_inplace */ | |
151 | 0xffff, /* src_mask */ | |
152 | 0xffff, /* dst_mask */ | |
153 | false), /* pcrel_offset */ | |
154 | ||
155 | /* Low 16 bits of symbol value. */ | |
156 | HOWTO (R_MIPS_LO16, /* type */ | |
157 | 0, /* rightshift */ | |
158 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
159 | 16, /* bitsize */ | |
160 | false, /* pc_relative */ | |
161 | 0, /* bitpos */ | |
162 | complain_overflow_dont, /* complain_on_overflow */ | |
163 | mips_elf_lo16_reloc, /* special_function */ | |
164 | "R_MIPS_LO16", /* name */ | |
165 | true, /* partial_inplace */ | |
166 | 0xffff, /* src_mask */ | |
167 | 0xffff, /* dst_mask */ | |
168 | false), /* pcrel_offset */ | |
169 | ||
170 | /* GP relative reference. */ | |
171 | HOWTO (R_MIPS_GPREL16, /* type */ | |
172 | 0, /* rightshift */ | |
173 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
174 | 16, /* bitsize */ | |
175 | false, /* pc_relative */ | |
176 | 0, /* bitpos */ | |
177 | complain_overflow_signed, /* complain_on_overflow */ | |
178 | mips_elf_gprel16_reloc, /* special_function */ | |
179 | "R_MIPS_GPREL16", /* name */ | |
180 | true, /* partial_inplace */ | |
181 | 0xffff, /* src_mask */ | |
182 | 0xffff, /* dst_mask */ | |
183 | false), /* pcrel_offset */ | |
184 | ||
185 | /* Reference to literal section. */ | |
186 | HOWTO (R_MIPS_LITERAL, /* type */ | |
187 | 0, /* rightshift */ | |
188 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
189 | 16, /* bitsize */ | |
190 | false, /* pc_relative */ | |
191 | 0, /* bitpos */ | |
192 | complain_overflow_signed, /* complain_on_overflow */ | |
193 | mips_elf_gprel16_reloc, /* special_function */ | |
194 | "R_MIPS_LITERAL", /* name */ | |
195 | true, /* partial_inplace */ | |
196 | 0xffff, /* src_mask */ | |
197 | 0xffff, /* dst_mask */ | |
198 | false), /* pcrel_offset */ | |
199 | ||
200 | /* Reference to global offset table. */ | |
201 | /* FIXME: This is not handled correctly. */ | |
202 | HOWTO (R_MIPS_GOT16, /* type */ | |
203 | 0, /* rightshift */ | |
204 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
205 | 16, /* bitsize */ | |
206 | false, /* pc_relative */ | |
207 | 0, /* bitpos */ | |
208 | complain_overflow_signed, /* complain_on_overflow */ | |
209 | bfd_elf_generic_reloc, /* special_function */ | |
210 | "R_MIPS_GOT16", /* name */ | |
211 | false, /* partial_inplace */ | |
212 | 0, /* src_mask */ | |
213 | 0xffff, /* dst_mask */ | |
214 | false), /* pcrel_offset */ | |
215 | ||
216 | /* 16 bit PC relative reference. */ | |
217 | HOWTO (R_MIPS_PC16, /* type */ | |
218 | 0, /* rightshift */ | |
219 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
220 | 16, /* bitsize */ | |
221 | true, /* pc_relative */ | |
222 | 0, /* bitpos */ | |
223 | complain_overflow_signed, /* complain_on_overflow */ | |
224 | bfd_elf_generic_reloc, /* special_function */ | |
225 | "R_MIPS_PC16", /* name */ | |
226 | true, /* partial_inplace */ | |
227 | 0xffff, /* src_mask */ | |
228 | 0xffff, /* dst_mask */ | |
229 | false), /* pcrel_offset */ | |
230 | ||
231 | /* 16 bit call through global offset table. */ | |
232 | /* FIXME: This is not handled correctly. */ | |
233 | HOWTO (R_MIPS_CALL16, /* type */ | |
234 | 0, /* rightshift */ | |
235 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
236 | 16, /* bitsize */ | |
237 | false, /* pc_relative */ | |
238 | 0, /* bitpos */ | |
239 | complain_overflow_signed, /* complain_on_overflow */ | |
240 | bfd_elf_generic_reloc, /* special_function */ | |
241 | "R_MIPS_CALL16", /* name */ | |
242 | false, /* partial_inplace */ | |
243 | 0, /* src_mask */ | |
244 | 0xffff, /* dst_mask */ | |
245 | false), /* pcrel_offset */ | |
246 | ||
247 | /* 32 bit GP relative reference. */ | |
248 | /* FIXME: This is not handled correctly. */ | |
249 | HOWTO (R_MIPS_GPREL32, /* type */ | |
250 | 0, /* rightshift */ | |
251 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
252 | 32, /* bitsize */ | |
253 | false, /* pc_relative */ | |
254 | 0, /* bitpos */ | |
255 | complain_overflow_bitfield, /* complain_on_overflow */ | |
256 | bfd_elf_generic_reloc, /* special_function */ | |
257 | "R_MIPS_GPREL32", /* name */ | |
258 | true, /* partial_inplace */ | |
259 | 0xffffffff, /* src_mask */ | |
260 | 0xffffffff, /* dst_mask */ | |
261 | false) /* pcrel_offset */ | |
262 | }; | |
263 | ||
264 | /* Do a R_MIPS_HI16 relocation. This has to be done in combination | |
265 | with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to | |
266 | the HI16. Here we just save the information we need; we do the | |
267 | actual relocation when we see the LO16. MIPS ELF requires that the | |
268 | LO16 immediately follow the HI16, so this ought to work. */ | |
269 | ||
270 | static bfd_byte *mips_hi16_addr; | |
271 | static bfd_vma mips_hi16_addend; | |
272 | ||
273 | static bfd_reloc_status_type | |
274 | mips_elf_hi16_reloc (abfd, | |
275 | reloc_entry, | |
276 | symbol, | |
277 | data, | |
278 | input_section, | |
279 | output_bfd) | |
280 | bfd *abfd; | |
281 | arelent *reloc_entry; | |
282 | asymbol *symbol; | |
283 | PTR data; | |
284 | asection *input_section; | |
285 | bfd *output_bfd; | |
286 | { | |
287 | bfd_reloc_status_type ret; | |
288 | bfd_vma relocation; | |
289 | ||
290 | /* FIXME: The symbol _gp_disp requires special handling, which we do | |
291 | not do. */ | |
292 | if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0) | |
293 | abort (); | |
294 | ||
295 | /* If we're relocating, and this an external symbol, we don't want | |
296 | to change anything. */ | |
297 | if (output_bfd != (bfd *) NULL | |
298 | && (symbol->flags & BSF_SECTION_SYM) == 0 | |
299 | && reloc_entry->addend == 0) | |
300 | { | |
301 | reloc_entry->address += input_section->output_offset; | |
302 | return bfd_reloc_ok; | |
303 | } | |
304 | ||
305 | ret = bfd_reloc_ok; | |
306 | if (symbol->section == &bfd_und_section | |
307 | && output_bfd == (bfd *) NULL) | |
308 | ret = bfd_reloc_undefined; | |
309 | ||
310 | if (bfd_is_com_section (symbol->section)) | |
311 | relocation = 0; | |
312 | else | |
313 | relocation = symbol->value; | |
314 | ||
315 | relocation += symbol->section->output_section->vma; | |
316 | relocation += symbol->section->output_offset; | |
317 | relocation += reloc_entry->addend; | |
318 | ||
319 | if (reloc_entry->address > input_section->_cooked_size) | |
320 | return bfd_reloc_outofrange; | |
321 | ||
322 | /* Save the information, and let LO16 do the actual relocation. */ | |
323 | mips_hi16_addr = (bfd_byte *) data + reloc_entry->address; | |
324 | mips_hi16_addend = relocation; | |
325 | ||
326 | if (output_bfd != (bfd *) NULL) | |
327 | reloc_entry->address += input_section->output_offset; | |
328 | ||
329 | return ret; | |
330 | } | |
331 | ||
332 | /* Do a R_MIPS_LO16 relocation. This is a straightforward 16 bit | |
333 | inplace relocation; this function exists in order to do the | |
334 | R_MIPS_HI16 relocation described above. */ | |
335 | ||
336 | static bfd_reloc_status_type | |
337 | mips_elf_lo16_reloc (abfd, | |
338 | reloc_entry, | |
339 | symbol, | |
340 | data, | |
341 | input_section, | |
342 | output_bfd) | |
343 | bfd *abfd; | |
344 | arelent *reloc_entry; | |
345 | asymbol *symbol; | |
346 | PTR data; | |
347 | asection *input_section; | |
348 | bfd *output_bfd; | |
349 | { | |
350 | /* FIXME: The symbol _gp_disp requires special handling, which we do | |
351 | not do. */ | |
352 | if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0) | |
353 | abort (); | |
354 | ||
355 | if (mips_hi16_addr != (bfd_byte *) NULL) | |
356 | { | |
357 | unsigned long insn; | |
358 | unsigned long val; | |
359 | unsigned long vallo; | |
360 | ||
361 | /* Do the HI16 relocation. Note that we actually don't need to | |
362 | know anything about the LO16 itself, except where to find the | |
363 | low 16 bits of the addend needed by the LO16. */ | |
364 | insn = bfd_get_32 (abfd, mips_hi16_addr); | |
365 | vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) | |
366 | & 0xffff); | |
367 | val = ((insn & 0xffff) << 16) + vallo; | |
368 | val += mips_hi16_addend; | |
369 | ||
370 | /* The low order 16 bits are always treated as a signed value. | |
371 | Therefore, a negative value in the low order bits requires an | |
372 | adjustment in the high order bits. We need to make this | |
373 | adjustment in two ways: once for the bits we took from the | |
374 | data, and once for the bits we are putting back in to the | |
375 | data. */ | |
376 | if ((vallo & 0x8000) != 0) | |
377 | val -= 0x10000; | |
378 | if ((val & 0x8000) != 0) | |
379 | val += 0x10000; | |
380 | ||
381 | insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); | |
382 | bfd_put_32 (abfd, insn, mips_hi16_addr); | |
383 | ||
384 | mips_hi16_addr = (bfd_byte *) NULL; | |
385 | } | |
386 | ||
387 | /* Now do the LO16 reloc in the usual way. */ | |
388 | return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, | |
389 | input_section, output_bfd); | |
390 | } | |
391 | ||
392 | /* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must | |
393 | become the offset from the gp register. This function also handles | |
394 | R_MIPS_LITERAL relocations, although those can be handled more | |
395 | cleverly because the entries in the .lit8 and .lit4 sections can be | |
396 | merged. */ | |
397 | ||
398 | static bfd_reloc_status_type | |
399 | mips_elf_gprel16_reloc (abfd, | |
400 | reloc_entry, | |
401 | symbol, | |
402 | data, | |
403 | input_section, | |
404 | output_bfd) | |
405 | bfd *abfd; | |
406 | arelent *reloc_entry; | |
407 | asymbol *symbol; | |
408 | PTR data; | |
409 | asection *input_section; | |
410 | bfd *output_bfd; | |
411 | { | |
412 | boolean relocateable; | |
413 | bfd_vma relocation; | |
414 | unsigned long val; | |
415 | unsigned long insn; | |
416 | ||
417 | /* If we're relocating, and this is an external symbol with no | |
418 | addend, we don't want to change anything. We will only have an | |
419 | addend if this is a newly created reloc, not read from an ELF | |
420 | file. */ | |
421 | if (output_bfd != (bfd *) NULL | |
422 | && (symbol->flags & BSF_SECTION_SYM) == 0 | |
423 | && reloc_entry->addend == 0) | |
424 | { | |
425 | reloc_entry->address += input_section->output_offset; | |
426 | return bfd_reloc_ok; | |
427 | } | |
428 | ||
429 | if (output_bfd != (bfd *) NULL) | |
430 | relocateable = true; | |
431 | else | |
432 | { | |
433 | relocateable = false; | |
434 | output_bfd = symbol->section->output_section->owner; | |
435 | } | |
436 | ||
437 | if (symbol->section == &bfd_und_section | |
438 | && relocateable == false) | |
439 | return bfd_reloc_undefined; | |
440 | ||
441 | /* We have to figure out the gp value, so that we can adjust the | |
442 | symbol value correctly. We look up the symbol _gp in the output | |
443 | BFD. If we can't find it, we're stuck. We cache it in the ELF | |
444 | target data. We don't need to adjust the symbol value for an | |
445 | external symbol if we are producing relocateable output. */ | |
446 | if (elf_gp (output_bfd) == 0 | |
447 | && (relocateable == false | |
448 | || (symbol->flags & BSF_SECTION_SYM) != 0)) | |
449 | { | |
450 | if (relocateable != false) | |
451 | { | |
452 | /* Make up a value. */ | |
453 | elf_gp (output_bfd) = | |
454 | symbol->section->output_section->vma + 0x4000; | |
455 | } | |
456 | else | |
457 | { | |
458 | unsigned int count; | |
459 | asymbol **sym; | |
460 | unsigned int i; | |
461 | ||
462 | count = bfd_get_symcount (output_bfd); | |
463 | sym = bfd_get_outsymbols (output_bfd); | |
464 | ||
465 | if (sym == (asymbol **) NULL) | |
466 | i = count; | |
467 | else | |
468 | { | |
469 | for (i = 0; i < count; i++, sym++) | |
470 | { | |
471 | register CONST char *name; | |
472 | ||
473 | name = bfd_asymbol_name (*sym); | |
474 | if (*name == '_' && strcmp (name, "_gp") == 0) | |
475 | { | |
476 | elf_gp (output_bfd) = bfd_asymbol_value (*sym); | |
477 | break; | |
478 | } | |
479 | } | |
480 | } | |
481 | ||
482 | if (i >= count) | |
483 | { | |
484 | /* Only get the error once. */ | |
485 | elf_gp (output_bfd) = 4; | |
486 | /* FIXME: How can we get the program name here? */ | |
487 | fprintf (stderr, | |
488 | "GP relative relocation when _gp not defined\n"); | |
489 | return bfd_reloc_dangerous; | |
490 | } | |
491 | } | |
492 | } | |
493 | ||
494 | if (bfd_is_com_section (symbol->section)) | |
495 | relocation = 0; | |
496 | else | |
497 | relocation = symbol->value; | |
498 | ||
499 | relocation += symbol->section->output_section->vma; | |
500 | relocation += symbol->section->output_offset; | |
501 | ||
502 | if (reloc_entry->address > input_section->_cooked_size) | |
503 | return bfd_reloc_outofrange; | |
504 | ||
505 | insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); | |
506 | ||
507 | /* Set val to the offset into the section or symbol. */ | |
508 | val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; | |
509 | if (val & 0x8000) | |
510 | val -= 0x10000; | |
511 | ||
512 | /* Adjust val for the final section location and GP value. If we | |
513 | are producing relocateable output, we don't want to do this for | |
514 | an external symbol. */ | |
515 | if (relocateable == false | |
516 | || (symbol->flags & BSF_SECTION_SYM) != 0) | |
517 | val += relocation - elf_gp (output_bfd); | |
518 | ||
519 | insn = (insn &~ 0xffff) | (val & 0xffff); | |
520 | bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); | |
521 | ||
522 | if (relocateable != false) | |
523 | reloc_entry->address += input_section->output_offset; | |
524 | ||
525 | /* Make sure it fit in 16 bits. */ | |
526 | if (val >= 0x8000 && val < 0xffff8000) | |
527 | return bfd_reloc_outofrange; | |
528 | ||
529 | return bfd_reloc_ok; | |
530 | } | |
6b4b4d17 | 531 | |
b3c0fc57 | 532 | /* A mapping from BFD reloc types to MIPS ELF reloc types. */ |
6b4b4d17 | 533 | |
b3c0fc57 ILT |
534 | struct elf_reloc_map { |
535 | bfd_reloc_code_real_type bfd_reloc_val; | |
536 | enum reloc_type elf_reloc_val; | |
537 | }; | |
538 | ||
539 | static CONST struct elf_reloc_map mips_reloc_map[] = | |
540 | { | |
541 | { BFD_RELOC_NONE, R_MIPS_NONE, }, | |
542 | { BFD_RELOC_16, R_MIPS_16 }, | |
543 | { BFD_RELOC_32, R_MIPS_32 }, | |
544 | { BFD_RELOC_CTOR, R_MIPS_32 }, | |
545 | { BFD_RELOC_32_PCREL, R_MIPS_REL32 }, | |
546 | { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, | |
547 | { BFD_RELOC_HI16_S, R_MIPS_HI16 }, | |
548 | { BFD_RELOC_LO16, R_MIPS_LO16 }, | |
549 | { BFD_RELOC_MIPS_GPREL, R_MIPS_GPREL16 }, | |
550 | { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, | |
551 | { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, | |
552 | { BFD_RELOC_16_PCREL, R_MIPS_PC16 }, | |
553 | { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, | |
554 | { BFD_RELOC_MIPS_GPREL32, R_MIPS_GPREL32 } | |
555 | }; | |
556 | ||
557 | /* Given a BFD reloc type, return a howto structure. */ | |
558 | ||
559 | static CONST struct reloc_howto_struct * | |
560 | bfd_elf32_bfd_reloc_type_lookup (abfd, code) | |
561 | bfd *abfd; | |
562 | bfd_reloc_code_real_type code; | |
563 | { | |
564 | int i; | |
565 | ||
566 | for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++) | |
567 | { | |
568 | if (mips_reloc_map[i].bfd_reloc_val == code) | |
569 | return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val]; | |
570 | } | |
571 | return NULL; | |
572 | } | |
573 | ||
574 | /* Given a MIPS reloc type, fill in an arelent structure. */ | |
575 | ||
576 | static void | |
577 | mips_info_to_howto_rel (abfd, cache_ptr, dst) | |
578 | bfd *abfd; | |
579 | arelent *cache_ptr; | |
580 | Elf32_Internal_Rel *dst; | |
581 | { | |
582 | unsigned int r_type; | |
583 | ||
584 | r_type = ELF32_R_TYPE (dst->r_info); | |
585 | BFD_ASSERT (r_type < (unsigned int) R_MIPS_max); | |
586 | cache_ptr->howto = &elf_mips_howto_table[r_type]; | |
587 | ||
588 | /* The addend for a GPREL16 or LITERAL relocation comes from the GP | |
589 | value for the object file. We get the addend now, rather than | |
590 | when we do the relocation, because the symbol manipulations done | |
591 | by the linker may cause us to lose track of the input BFD. */ | |
592 | if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0 | |
593 | && (r_type == (unsigned int) R_MIPS_GPREL16 | |
594 | || r_type == (unsigned int) R_MIPS_LITERAL)) | |
595 | cache_ptr->addend = elf_gp (abfd); | |
596 | } | |
597 | \f | |
598 | /* A .reginfo section holds a single Elf32_RegInfo structure. These | |
599 | routines swap this structure in and out. They are used outside of | |
600 | BFD, so they are globally visible. */ | |
601 | ||
602 | void | |
603 | bfd_mips_elf32_swap_reginfo_in (abfd, ex, in) | |
604 | bfd *abfd; | |
605 | const Elf32_External_RegInfo *ex; | |
606 | Elf32_RegInfo *in; | |
607 | { | |
608 | in->ri_gprmask = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gprmask); | |
609 | in->ri_cprmask[0] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[0]); | |
610 | in->ri_cprmask[1] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[1]); | |
611 | in->ri_cprmask[2] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[2]); | |
612 | in->ri_cprmask[3] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[3]); | |
613 | in->ri_gp_value = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gp_value); | |
614 | } | |
615 | ||
616 | void | |
617 | bfd_mips_elf32_swap_reginfo_out (abfd, in, ex) | |
618 | bfd *abfd; | |
619 | const Elf32_RegInfo *in; | |
620 | Elf32_External_RegInfo *ex; | |
621 | { | |
622 | bfd_h_put_32 (abfd, (bfd_vma) in->ri_gprmask, | |
623 | (bfd_byte *) ex->ri_gprmask); | |
624 | bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[0], | |
625 | (bfd_byte *) ex->ri_cprmask[0]); | |
626 | bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[1], | |
627 | (bfd_byte *) ex->ri_cprmask[1]); | |
628 | bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[2], | |
629 | (bfd_byte *) ex->ri_cprmask[2]); | |
630 | bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[3], | |
631 | (bfd_byte *) ex->ri_cprmask[3]); | |
632 | bfd_h_put_32 (abfd, (bfd_vma) in->ri_gp_value, | |
633 | (bfd_byte *) ex->ri_gp_value); | |
634 | } | |
635 | \f | |
636 | /* Handle a MIPS specific section when reading an object file. This | |
637 | is called when elfcode.h finds a section with an unknown type. | |
638 | FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure | |
639 | how to. */ | |
640 | ||
641 | static boolean | |
642 | mips_elf_section_from_shdr (abfd, hdr, name) | |
643 | bfd *abfd; | |
644 | Elf32_Internal_Shdr *hdr; | |
645 | char *name; | |
646 | { | |
647 | /* There ought to be a place to keep ELF backend specific flags, but | |
648 | at the moment there isn't one. We just keep track of the | |
649 | sections by their name, instead. Fortunately, the ABI gives | |
650 | suggested names for all the MIPS specific sections, so we will | |
651 | probably get away with this. */ | |
652 | switch (hdr->sh_type) | |
653 | { | |
654 | case SHT_MIPS_LIBLIST: | |
655 | if (strcmp (name, ".liblist") != 0) | |
656 | return false; | |
657 | break; | |
658 | case SHT_MIPS_CONFLICT: | |
659 | if (strcmp (name, ".conflict") != 0) | |
660 | return false; | |
661 | break; | |
662 | case SHT_MIPS_GPTAB: | |
663 | if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) != 0) | |
664 | return false; | |
665 | break; | |
666 | case SHT_MIPS_UCODE: | |
667 | if (strcmp (name, ".ucode") != 0) | |
668 | return false; | |
669 | break; | |
670 | case SHT_MIPS_DEBUG: | |
671 | if (strcmp (name, ".mdebug") != 0) | |
672 | return false; | |
673 | break; | |
674 | case SHT_MIPS_REGINFO: | |
675 | if (strcmp (name, ".reginfo") != 0 | |
676 | || hdr->sh_size != sizeof (Elf32_External_RegInfo)) | |
677 | return false; | |
678 | break; | |
679 | default: | |
680 | return false; | |
681 | } | |
682 | ||
683 | if (hdr->rawdata == NULL) | |
684 | { | |
685 | asection *newsect; | |
686 | ||
687 | newsect = bfd_make_section (abfd, name); | |
688 | if (newsect != NULL) | |
689 | { | |
690 | newsect->filepos = hdr->sh_offset; | |
691 | newsect->flags |= SEC_HAS_CONTENTS; | |
692 | newsect->vma = hdr->sh_addr; | |
693 | newsect->_raw_size = hdr->sh_size; | |
694 | newsect->alignment_power = bfd_log2 (hdr->sh_addralign); | |
695 | ||
696 | if (hdr->sh_flags & SHF_ALLOC) | |
697 | { | |
698 | newsect->flags |= SEC_ALLOC; | |
699 | newsect->flags |= SEC_LOAD; | |
700 | } | |
701 | ||
702 | if (!(hdr->sh_flags & SHF_WRITE)) | |
703 | newsect->flags |= SEC_READONLY; | |
704 | ||
705 | if (hdr->sh_flags & SHF_EXECINSTR) | |
706 | newsect->flags |= SEC_CODE; | |
707 | else if (newsect->flags & SEC_ALLOC) | |
708 | newsect->flags |= SEC_DATA; | |
709 | ||
710 | if (hdr->sh_type == SHT_MIPS_DEBUG) | |
711 | newsect->flags |= SEC_DEBUGGING; | |
712 | ||
713 | hdr->rawdata = (void *) newsect; | |
714 | ||
715 | /* FIXME: We should record the sh_info field for a .gptab | |
716 | section. */ | |
717 | ||
718 | /* For a .reginfo section, set the gp value in the tdata | |
719 | information from the contents of this section. We need | |
720 | the gp value while processing relocs, so we just get it | |
721 | now. */ | |
722 | if (hdr->sh_type == SHT_MIPS_REGINFO) | |
723 | { | |
724 | Elf32_External_RegInfo ext; | |
725 | Elf32_RegInfo s; | |
726 | ||
727 | if (bfd_get_section_contents (abfd, newsect, (PTR) &ext, | |
728 | (file_ptr) 0, | |
729 | sizeof ext) == false) | |
730 | return false; | |
731 | bfd_mips_elf32_swap_reginfo_in (abfd, &ext, &s); | |
732 | elf_gp (abfd) = s.ri_gp_value; | |
733 | } | |
734 | } | |
735 | else | |
736 | hdr->rawdata = (void *) bfd_get_section_by_name (abfd, name); | |
737 | } | |
738 | ||
739 | return true; | |
740 | } | |
741 | ||
742 | /* Set the correct type for a MIPS ELF section. We do this by the | |
743 | section name, which is a hack, but ought to work. */ | |
744 | ||
745 | static boolean | |
746 | mips_elf_fake_sections (abfd, hdr, sec) | |
747 | bfd *abfd; | |
748 | Elf32_Internal_Shdr *hdr; | |
749 | asection *sec; | |
750 | { | |
751 | register const char *name; | |
752 | ||
753 | name = bfd_get_section_name (abfd, sec); | |
754 | ||
755 | if (strcmp (name, ".liblist") == 0) | |
756 | { | |
757 | hdr->sh_type = SHT_MIPS_LIBLIST; | |
758 | hdr->sh_info = sec->_raw_size / sizeof (Elf32_Lib); | |
759 | /* FIXME: Set the sh_link field. */ | |
760 | } | |
761 | else if (strcmp (name, ".conflict") == 0) | |
762 | hdr->sh_type = SHT_MIPS_CONFLICT; | |
763 | else if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0) | |
764 | { | |
765 | hdr->sh_type = SHT_MIPS_GPTAB; | |
766 | /* FIXME: Set the sh_info field. */ | |
767 | } | |
768 | else if (strcmp (name, ".ucode") == 0) | |
769 | hdr->sh_type = SHT_MIPS_UCODE; | |
770 | else if (strcmp (name, ".mdebug") == 0) | |
771 | hdr->sh_type = SHT_MIPS_DEBUG; | |
772 | else if (strcmp (name, ".reginfo") == 0) | |
773 | { | |
774 | hdr->sh_type = SHT_MIPS_REGINFO; | |
775 | ||
776 | /* Force the section size to the correct value, even if the | |
777 | linker thinks it is larger. The link routine below will only | |
778 | write out this much data for .reginfo. */ | |
779 | hdr->sh_size = sec->_raw_size = sizeof (Elf32_External_RegInfo); | |
780 | } | |
781 | ||
782 | return true; | |
783 | } | |
784 | ||
785 | /* Given a BFD section, try to locate the corresponding ELF section | |
786 | index. */ | |
787 | ||
788 | static boolean | |
789 | mips_elf_section_from_bfd_section (abfd, hdr, sec, retval) | |
790 | bfd *abfd; | |
791 | Elf32_Internal_Shdr *hdr; | |
792 | asection *sec; | |
793 | int *retval; | |
794 | { | |
795 | if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) | |
796 | { | |
797 | *retval = SHN_MIPS_SCOMMON; | |
798 | return true; | |
799 | } | |
800 | if ((asection *) hdr->rawdata == sec) | |
801 | return true; | |
802 | return false; | |
803 | } | |
804 | ||
805 | /* Work over a section just before writing it out. We update the GP | |
806 | value in the .reginfo section based on the value we are using. | |
807 | FIXME: We recognize sections that need the SHF_MIPS_GPREL flag by | |
808 | name; there has to be a better way. */ | |
809 | ||
810 | static boolean | |
811 | mips_elf_section_processing (abfd, hdr) | |
812 | bfd *abfd; | |
813 | Elf32_Internal_Shdr *hdr; | |
814 | { | |
815 | if (hdr->sh_type == SHT_MIPS_REGINFO) | |
816 | { | |
817 | bfd_byte buf[4]; | |
818 | ||
819 | BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo)); | |
820 | BFD_ASSERT (hdr->contents == NULL); | |
821 | ||
822 | if (bfd_seek (abfd, | |
823 | hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4, | |
824 | SEEK_SET) == -1) | |
825 | return false; | |
826 | bfd_h_put_32 (abfd, (bfd_vma) elf_gp (abfd), buf); | |
827 | if (bfd_write (buf, (bfd_size_type) 1, (bfd_size_type) 4, abfd) != 4) | |
828 | return false; | |
829 | } | |
830 | ||
831 | if (hdr->rawdata != NULL) | |
832 | { | |
833 | const char *name = ((asection *) hdr->rawdata)->name; | |
834 | ||
835 | if (strcmp (name, ".sdata") == 0) | |
836 | { | |
837 | hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; | |
838 | hdr->sh_type = SHT_PROGBITS; | |
839 | } | |
840 | else if (strcmp (name, ".sbss") == 0) | |
841 | { | |
842 | hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; | |
843 | hdr->sh_type = SHT_NOBITS; | |
844 | } | |
845 | else if (strcmp (name, ".lit8") == 0 | |
846 | || strcmp (name, ".lit4") == 0) | |
847 | { | |
848 | hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; | |
849 | hdr->sh_type = SHT_PROGBITS; | |
850 | } | |
851 | } | |
852 | ||
853 | return true; | |
854 | } | |
855 | \f | |
856 | /* We need to use a special link routine to handle the .reginfo | |
857 | section. We need to merge all the .reginfo sections together, not | |
858 | write them all out sequentially. */ | |
859 | ||
860 | static boolean | |
861 | mips_elf_seclet_link (abfd, data, relocateable) | |
862 | bfd *abfd; | |
863 | PTR data; | |
864 | boolean relocateable; | |
865 | { | |
866 | asection *sec; | |
867 | Elf32_RegInfo reginfo; | |
868 | ||
869 | memset (®info, 0, sizeof reginfo); | |
870 | ||
871 | for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) | |
872 | { | |
873 | if (strcmp (sec->name, ".reginfo") == 0) | |
874 | { | |
875 | bfd_seclet_type *p; | |
876 | Elf32_External_RegInfo ext; | |
877 | ||
878 | /* We have found the .reginfo section in the output file. | |
879 | Look through all the seclets comprising it and merge the | |
880 | information together. */ | |
881 | for (p = sec->seclets_head; | |
882 | p != (bfd_seclet_type *) NULL; | |
883 | p = p->next) | |
884 | { | |
885 | switch (p->type) | |
886 | { | |
887 | case bfd_indirect_seclet: | |
888 | { | |
889 | asection *input_section; | |
890 | bfd *input_bfd; | |
891 | Elf32_RegInfo sub; | |
892 | ||
893 | input_section = p->u.indirect.section; | |
894 | input_bfd = input_section->owner; | |
895 | BFD_ASSERT (input_section->_raw_size | |
896 | == sizeof (Elf32_External_RegInfo)); | |
897 | if (! bfd_get_section_contents (input_bfd, input_section, | |
898 | (PTR) &ext, | |
899 | (file_ptr) 0, | |
900 | sizeof ext)) | |
901 | return false; | |
902 | ||
903 | bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub); | |
904 | ||
905 | reginfo.ri_gprmask |= sub.ri_gprmask; | |
906 | reginfo.ri_cprmask[0] |= sub.ri_cprmask[0]; | |
907 | reginfo.ri_cprmask[1] |= sub.ri_cprmask[1]; | |
908 | reginfo.ri_cprmask[2] |= sub.ri_cprmask[2]; | |
909 | reginfo.ri_cprmask[3] |= sub.ri_cprmask[3]; | |
910 | ||
911 | /* ri_gp_value is set by the function | |
912 | mips_elf_section_processing when the section is | |
913 | finally written out. */ | |
914 | } | |
915 | break; | |
916 | ||
917 | default: | |
918 | break; | |
919 | } | |
920 | } | |
921 | ||
922 | /* Write out the information we have accumulated. */ | |
923 | bfd_mips_elf32_swap_reginfo_out (abfd, ®info, &ext); | |
924 | if (! bfd_set_section_contents (abfd, sec, (PTR) &ext, | |
925 | (file_ptr) 0, sizeof ext)) | |
926 | return false; | |
927 | ||
928 | /* Force the section size to the value we want. */ | |
929 | sec->_raw_size = sizeof (Elf32_External_RegInfo); | |
930 | ||
931 | /* Force bfd_generic_seclet_link to ignore this section. */ | |
932 | sec->seclets_head = (bfd_seclet_type *) NULL; | |
933 | ||
934 | break; | |
935 | } | |
936 | } | |
937 | ||
938 | return bfd_generic_seclet_link (abfd, data, relocateable); | |
939 | } | |
940 | \f | |
941 | /* MIPS ELF uses two common sections. One is the usual one, and the | |
942 | other is for small objects. All the small objects are kept | |
943 | together, and then referenced via the gp pointer, which yields | |
944 | faster assembler code. This is what we use for the small common | |
945 | section. This approach is copied from ecoff.c. */ | |
946 | static asection mips_elf_scom_section; | |
947 | static asymbol mips_elf_scom_symbol; | |
948 | static asymbol *mips_elf_scom_symbol_ptr; | |
949 | ||
950 | /* Handle the special MIPS section numbers that a symbol may use. */ | |
951 | ||
952 | static void | |
953 | mips_elf_symbol_processing (abfd, asym) | |
954 | bfd *abfd; | |
955 | asymbol *asym; | |
956 | { | |
957 | elf_symbol_type *elfsym; | |
958 | ||
959 | elfsym = (elf_symbol_type *) asym; | |
960 | switch (elfsym->internal_elf_sym.st_shndx) | |
961 | { | |
962 | case SHN_MIPS_ACOMMON: | |
963 | /* FIXME: I don't really understand just what this section | |
964 | means or when it would be used. */ | |
965 | abort (); | |
966 | break; | |
967 | ||
968 | case SHN_COMMON: | |
969 | /* Common symbols less than the GP size are automatically | |
970 | treated as SHN_MIPS_SCOMMON symbols. */ | |
971 | if (asym->value > elf_gp_size (abfd)) | |
972 | break; | |
973 | /* Fall through. */ | |
974 | case SHN_MIPS_SCOMMON: | |
975 | if (mips_elf_scom_section.name == NULL) | |
976 | { | |
977 | /* Initialize the small common section. */ | |
978 | mips_elf_scom_section.name = ".scommon"; | |
979 | mips_elf_scom_section.flags = SEC_IS_COMMON; | |
980 | mips_elf_scom_section.output_section = &mips_elf_scom_section; | |
981 | mips_elf_scom_section.symbol = &mips_elf_scom_symbol; | |
982 | mips_elf_scom_section.symbol_ptr_ptr = &mips_elf_scom_symbol_ptr; | |
983 | mips_elf_scom_symbol.name = ".scommon"; | |
984 | mips_elf_scom_symbol.flags = BSF_SECTION_SYM; | |
985 | mips_elf_scom_symbol.section = &mips_elf_scom_section; | |
986 | mips_elf_scom_symbol_ptr = &mips_elf_scom_symbol; | |
987 | } | |
988 | asym->section = &mips_elf_scom_section; | |
989 | asym->value = elfsym->internal_elf_sym.st_size; | |
990 | break; | |
991 | ||
992 | case SHN_MIPS_SUNDEFINED: | |
993 | asym->section = &bfd_und_section; | |
994 | break; | |
995 | } | |
996 | } | |
997 | \f | |
6b4b4d17 JK |
998 | #define TARGET_LITTLE_SYM bfd_elf32_littlemips_vec |
999 | #define TARGET_LITTLE_NAME "elf32-littlemips" | |
1000 | #define TARGET_BIG_SYM bfd_elf32_bigmips_vec | |
1001 | #define TARGET_BIG_NAME "elf32-bigmips" | |
1002 | #define ELF_ARCH bfd_arch_mips | |
b3c0fc57 ILT |
1003 | #define ELF_MAXPAGESIZE 0x10000 |
1004 | #define elf_info_to_howto 0 | |
1005 | #define elf_info_to_howto_rel mips_info_to_howto_rel | |
1006 | #define elf_backend_section_from_shdr mips_elf_section_from_shdr | |
1007 | #define elf_backend_fake_sections mips_elf_fake_sections | |
1008 | #define elf_backend_section_from_bfd_section \ | |
1009 | mips_elf_section_from_bfd_section | |
1010 | #define elf_backend_section_processing mips_elf_section_processing | |
1011 | #define elf_backend_symbol_processing mips_elf_symbol_processing | |
1012 | ||
1013 | #define bfd_elf32_bfd_seclet_link mips_elf_seclet_link | |
6b4b4d17 JK |
1014 | |
1015 | #include "elf32-target.h" |