Commit | Line | Data |
---|---|---|
bcbe2c71 MM |
1 | /* PowerPC-specific support for 32-bit ELF |
2 | Copyright 1994, 1995 Free Software Foundation, Inc. | |
3 | Written by Ian Lance Taylor, Cygnus Support. | |
4 | ||
5 | This file is part of BFD, the Binary File Descriptor library. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | /* This file is based on a preliminary PowerPC ELF ABI. The | |
22 | information may not match the final PowerPC ELF ABI. It includes | |
23 | suggestions from the in-progress Embedded PowerPC ABI, and that | |
24 | information may also not match. */ | |
25 | ||
26 | #include "bfd.h" | |
27 | #include "sysdep.h" | |
28 | #include "libbfd.h" | |
29 | #include "libelf.h" | |
30 | ||
31 | static bfd_reloc_status_type ppc_elf_unsupported_reloc | |
32 | PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); | |
33 | static bfd_reloc_status_type ppc_elf_addr16_ha_reloc | |
34 | PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); | |
35 | static bfd_reloc_status_type ppc_elf_got16_reloc | |
36 | PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); | |
37 | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup | |
38 | PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); | |
39 | static void powerpc_info_to_howto | |
40 | PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); | |
41 | ||
42 | #define USE_RELA | |
43 | ||
44 | enum reloc_type | |
45 | { | |
46 | R_PPC_NONE = 0, /* 0 */ | |
47 | R_PPC_ADDR32, /* 1 */ | |
48 | R_PPC_ADDR24, /* 2 */ | |
49 | R_PPC_ADDR16, /* 3 */ | |
50 | R_PPC_ADDR16_LO, /* 4 */ | |
51 | R_PPC_ADDR16_HI, /* 5 */ | |
52 | R_PPC_ADDR16_HA, /* 6 */ | |
53 | R_PPC_ADDR14, /* 7 */ | |
54 | R_PPC_ADDR14_BRTAKEN, /* 8 */ | |
55 | R_PPC_ADDR14_BRNTAKEN, /* 9 */ | |
56 | R_PPC_REL24, /* 10 */ | |
57 | R_PPC_REL14, /* 11 */ | |
58 | R_PPC_REL14_BRTAKEN, /* 12 */ | |
59 | R_PPC_REL14_BRNTAKEN, /* 13 */ | |
60 | R_PPC_GOT16, /* 14 */ | |
61 | R_PPC_GOT16_LO, /* 15 */ | |
62 | R_PPC_GOT16_HI, /* 16 */ | |
63 | R_PPC_GOT16_HA, /* 17 */ | |
64 | R_PPC_PLT24, /* 18 */ | |
65 | R_PPC_COPY, /* 19 */ | |
66 | R_PPC_GLOB_DAT, /* 20 -- not in final System V spec */ | |
67 | R_PPC_JMP_SLOT, /* 21 */ | |
68 | R_PPC_RELATIVE, /* 22 */ | |
69 | R_PPC_LOCAL24PC, /* 23 */ | |
70 | R_PPC_UADDR32, /* 24 */ | |
71 | R_PPC_UADDR16, /* 25 */ | |
72 | R_PPC_REL32, /* 26 */ | |
73 | R_PPC_PLT32, /* 27 */ | |
74 | R_PPC_PLTREL32, /* 28 */ | |
75 | R_PPC_PLT16_LO, /* 29 */ | |
76 | R_PPC_PLT16_HI, /* 30 */ | |
77 | R_PPC_PLT16_HA, /* 31 */ | |
78 | R_PPC_SDAREL, /* 32 */ | |
79 | ||
80 | /* Relocations added by Sun. */ | |
81 | R_PPC_SECTOFF, /* 33 */ | |
82 | R_PPC_SECTOFF_LO, /* 34 */ | |
83 | R_PPC_SECTOFF_HI, /* 35 */ | |
84 | R_PPC_SECTOFF_HA, /* 36 */ | |
85 | ||
86 | /* The remaining relocs are from the Embedded ELF ABI, and are not | |
87 | in the SVR4 ELF ABI. */ | |
88 | R_PPC_EMB_NADDR32 = 101, /* 101 */ | |
89 | R_PPC_EMB_NADDR16, /* 102 */ | |
90 | R_PPC_EMB_NADDR16_LO, /* 103 */ | |
91 | R_PPC_EMB_NADDR16_HI, /* 104 */ | |
92 | R_PPC_EMB_NADDR16_HA, /* 105 */ | |
93 | R_PPC_EMB_SDAI16, /* 106 */ | |
94 | R_PPC_EMB_SDA2I16, /* 107 */ | |
95 | R_PPC_EMB_SDA2REL, /* 108 */ | |
96 | R_PPC_EMB_SDA21, /* 109 */ | |
97 | R_PPC_EMB_MRKREF, /* 110 */ | |
98 | R_PPC_EMB_RELSEC16, /* 111 */ | |
99 | R_PPC_EMB_RELST_LO, /* 112 */ | |
100 | R_PPC_EMB_RELST_HI, /* 113 */ | |
101 | R_PPC_EMB_RELST_HA, /* 114 */ | |
102 | R_PPC_EMB_BIT_FLD, /* 115 */ | |
103 | R_PPC_EMB_RELSDA, /* 116 */ | |
104 | R_PPC_max | |
105 | }; | |
106 | ||
107 | static reloc_howto_type elf_powerpc_howto_table[] = | |
108 | { | |
109 | /* This reloc does nothing. */ | |
110 | HOWTO (R_PPC_NONE, /* type */ | |
111 | 0, /* rightshift */ | |
112 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
113 | 32, /* bitsize */ | |
114 | false, /* pc_relative */ | |
115 | 0, /* bitpos */ | |
116 | complain_overflow_bitfield, /* complain_on_overflow */ | |
117 | bfd_elf_generic_reloc, /* special_function */ | |
118 | "R_PPC_NONE", /* name */ | |
119 | false, /* partial_inplace */ | |
120 | 0, /* src_mask */ | |
121 | 0, /* dst_mask */ | |
122 | false), /* pcrel_offset */ | |
123 | ||
124 | /* A standard 32 bit relocation. */ | |
125 | HOWTO (R_PPC_ADDR32, /* type */ | |
126 | 0, /* rightshift */ | |
127 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
128 | 32, /* bitsize */ | |
129 | false, /* pc_relative */ | |
130 | 0, /* bitpos */ | |
131 | complain_overflow_bitfield, /* complain_on_overflow */ | |
132 | bfd_elf_generic_reloc, /* special_function */ | |
133 | "R_PPC_ADDR32", /* name */ | |
134 | false, /* partial_inplace */ | |
135 | 0, /* src_mask */ | |
136 | 0xffffffff, /* dst_mask */ | |
137 | false), /* pcrel_offset */ | |
138 | ||
139 | /* An absolute 26 bit branch; the lower two bits must be zero. | |
140 | FIXME: we don't check that, we just clear them. */ | |
141 | HOWTO (R_PPC_ADDR24, /* type */ | |
142 | 0, /* rightshift */ | |
143 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
144 | 26, /* bitsize */ | |
145 | false, /* pc_relative */ | |
146 | 0, /* bitpos */ | |
147 | complain_overflow_bitfield, /* complain_on_overflow */ | |
148 | bfd_elf_generic_reloc, /* special_function */ | |
149 | "R_PPC_ADDR24", /* name */ | |
150 | false, /* partial_inplace */ | |
151 | 0, /* src_mask */ | |
152 | 0x3fffffc, /* dst_mask */ | |
153 | false), /* pcrel_offset */ | |
154 | ||
155 | /* A standard 16 bit relocation. */ | |
156 | HOWTO (R_PPC_ADDR16, /* type */ | |
157 | 0, /* rightshift */ | |
158 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
159 | 16, /* bitsize */ | |
160 | false, /* pc_relative */ | |
161 | 0, /* bitpos */ | |
162 | complain_overflow_bitfield, /* complain_on_overflow */ | |
163 | bfd_elf_generic_reloc, /* special_function */ | |
164 | "R_PPC_ADDR16", /* name */ | |
165 | false, /* partial_inplace */ | |
166 | 0, /* src_mask */ | |
167 | 0xffff, /* dst_mask */ | |
168 | false), /* pcrel_offset */ | |
169 | ||
170 | /* A 16 bit relocation without overflow. */ | |
171 | HOWTO (R_PPC_ADDR16_LO, /* type */ | |
172 | 0, /* rightshift */ | |
173 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
174 | 16, /* bitsize */ | |
175 | false, /* pc_relative */ | |
176 | 0, /* bitpos */ | |
177 | complain_overflow_dont,/* complain_on_overflow */ | |
178 | bfd_elf_generic_reloc, /* special_function */ | |
179 | "R_PPC_ADDR16_LO", /* name */ | |
180 | false, /* partial_inplace */ | |
181 | 0, /* src_mask */ | |
182 | 0xffff, /* dst_mask */ | |
183 | false), /* pcrel_offset */ | |
184 | ||
185 | /* The high order 16 bits of an address. */ | |
186 | HOWTO (R_PPC_ADDR16_HI, /* type */ | |
187 | 16, /* rightshift */ | |
188 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
189 | 16, /* bitsize */ | |
190 | false, /* pc_relative */ | |
191 | 0, /* bitpos */ | |
192 | complain_overflow_dont, /* complain_on_overflow */ | |
193 | bfd_elf_generic_reloc, /* special_function */ | |
194 | "R_PPC_ADDR16_HI", /* name */ | |
195 | false, /* partial_inplace */ | |
196 | 0, /* src_mask */ | |
197 | 0xffff, /* dst_mask */ | |
198 | false), /* pcrel_offset */ | |
199 | ||
200 | /* The high order 16 bits of an address, plus 1 if the contents of | |
201 | the low 16 bits, treated as a signed number, is negative. */ | |
202 | HOWTO (R_PPC_ADDR16_HA, /* type */ | |
203 | 16, /* rightshift */ | |
204 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
205 | 16, /* bitsize */ | |
206 | false, /* pc_relative */ | |
207 | 0, /* bitpos */ | |
208 | complain_overflow_dont, /* complain_on_overflow */ | |
209 | ppc_elf_addr16_ha_reloc, /* special_function */ | |
210 | "R_PPC_ADDR16_HA", /* name */ | |
211 | false, /* partial_inplace */ | |
212 | 0, /* src_mask */ | |
213 | 0xffff, /* dst_mask */ | |
214 | false), /* pcrel_offset */ | |
215 | ||
216 | /* An absolute 16 bit branch; the lower two bits must be zero. | |
217 | FIXME: we don't check that, we just clear them. */ | |
218 | HOWTO (R_PPC_ADDR14, /* type */ | |
219 | 0, /* rightshift */ | |
220 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
221 | 16, /* bitsize */ | |
222 | false, /* pc_relative */ | |
223 | 0, /* bitpos */ | |
224 | complain_overflow_bitfield, /* complain_on_overflow */ | |
225 | bfd_elf_generic_reloc, /* special_function */ | |
226 | "R_PPC_ADDR14", /* name */ | |
227 | false, /* partial_inplace */ | |
228 | 0, /* src_mask */ | |
229 | 0xfffc, /* dst_mask */ | |
230 | false), /* pcrel_offset */ | |
231 | ||
232 | /* An absolute 16 bit branch, for which bit 10 should be set to | |
233 | indicate that the branch is expected to be taken. The lower two | |
234 | bits must be zero. */ | |
235 | HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ | |
236 | 0, /* rightshift */ | |
237 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
238 | 16, /* bitsize */ | |
239 | false, /* pc_relative */ | |
240 | 0, /* bitpos */ | |
241 | complain_overflow_bitfield, /* complain_on_overflow */ | |
242 | ppc_elf_unsupported_reloc, /* special_function */ | |
243 | "R_PPC_ADDR14_BRTAKEN",/* name */ | |
244 | false, /* partial_inplace */ | |
245 | 0, /* src_mask */ | |
246 | 0xfffc, /* dst_mask */ | |
247 | false), /* pcrel_offset */ | |
248 | ||
249 | /* An absolute 16 bit branch, for which bit 10 should be set to | |
250 | indicate that the branch is not expected to be taken. The lower | |
251 | two bits must be zero. */ | |
252 | HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ | |
253 | 0, /* rightshift */ | |
254 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
255 | 16, /* bitsize */ | |
256 | false, /* pc_relative */ | |
257 | 0, /* bitpos */ | |
258 | complain_overflow_bitfield, /* complain_on_overflow */ | |
259 | ppc_elf_unsupported_reloc, /* special_function */ | |
260 | "R_PPC_ADDR14_BRNTAKEN",/* name */ | |
261 | false, /* partial_inplace */ | |
262 | 0, /* src_mask */ | |
263 | 0xfffc, /* dst_mask */ | |
264 | false), /* pcrel_offset */ | |
265 | ||
266 | /* A relative 26 bit branch; the lower two bits must be zero. */ | |
267 | HOWTO (R_PPC_REL24, /* type */ | |
268 | 0, /* rightshift */ | |
269 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
270 | 26, /* bitsize */ | |
271 | true, /* pc_relative */ | |
272 | 0, /* bitpos */ | |
273 | complain_overflow_signed, /* complain_on_overflow */ | |
274 | bfd_elf_generic_reloc, /* special_function */ | |
275 | "R_PPC_REL24", /* name */ | |
276 | false, /* partial_inplace */ | |
277 | 0, /* src_mask */ | |
278 | 0x3fffffc, /* dst_mask */ | |
279 | true), /* pcrel_offset */ | |
280 | ||
281 | /* A relative 16 bit branch; the lower two bits must be zero. */ | |
282 | HOWTO (R_PPC_REL14, /* type */ | |
283 | 0, /* rightshift */ | |
284 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
285 | 16, /* bitsize */ | |
286 | true, /* pc_relative */ | |
287 | 0, /* bitpos */ | |
288 | complain_overflow_signed, /* complain_on_overflow */ | |
289 | bfd_elf_generic_reloc, /* special_function */ | |
290 | "R_PPC_REL14", /* name */ | |
291 | false, /* partial_inplace */ | |
292 | 0, /* src_mask */ | |
293 | 0xfffc, /* dst_mask */ | |
294 | true), /* pcrel_offset */ | |
295 | ||
296 | /* A relative 16 bit branch. Bit 10 should be set to indicate that | |
297 | the branch is expected to be taken. The lower two bits must be | |
298 | zero. */ | |
299 | HOWTO (R_PPC_REL14_BRTAKEN, /* type */ | |
300 | 0, /* rightshift */ | |
301 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
302 | 16, /* bitsize */ | |
303 | false, /* pc_relative */ | |
304 | 0, /* bitpos */ | |
305 | complain_overflow_signed, /* complain_on_overflow */ | |
306 | ppc_elf_unsupported_reloc, /* special_function */ | |
307 | "R_PPC_REL14_BRTAKEN", /* name */ | |
308 | false, /* partial_inplace */ | |
309 | 0, /* src_mask */ | |
310 | 0xfffc, /* dst_mask */ | |
311 | true), /* pcrel_offset */ | |
312 | ||
313 | /* A relative 16 bit branch. Bit 10 should be set to indicate that | |
314 | the branch is not expected to be taken. The lower two bits must | |
315 | be zero. */ | |
316 | HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ | |
317 | 0, /* rightshift */ | |
318 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
319 | 16, /* bitsize */ | |
320 | false, /* pc_relative */ | |
321 | 0, /* bitpos */ | |
322 | complain_overflow_signed, /* complain_on_overflow */ | |
323 | ppc_elf_unsupported_reloc, /* special_function */ | |
324 | "R_PPC_REL14_BRNTAKEN",/* name */ | |
325 | false, /* partial_inplace */ | |
326 | 0, /* src_mask */ | |
327 | 0xfffc, /* dst_mask */ | |
328 | true), /* pcrel_offset */ | |
329 | ||
330 | /* Like R_PPC_ADDR16, but referring to the GOT table entry for the | |
331 | symbol. */ | |
332 | HOWTO (R_PPC_GOT16, /* type */ | |
333 | 0, /* rightshift */ | |
334 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
335 | 16, /* bitsize */ | |
336 | false, /* pc_relative */ | |
337 | 0, /* bitpos */ | |
338 | complain_overflow_bitfield, /* complain_on_overflow */ | |
339 | ppc_elf_got16_reloc, /* special_function */ | |
340 | "R_PPC_GOT16", /* name */ | |
341 | false, /* partial_inplace */ | |
342 | 0, /* src_mask */ | |
343 | 0xffff, /* dst_mask */ | |
344 | false), /* pcrel_offset */ | |
345 | ||
346 | /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for | |
347 | the symbol. */ | |
348 | HOWTO (R_PPC_GOT16_LO, /* type */ | |
349 | 0, /* rightshift */ | |
350 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
351 | 16, /* bitsize */ | |
352 | false, /* pc_relative */ | |
353 | 0, /* bitpos */ | |
354 | complain_overflow_bitfield, /* complain_on_overflow */ | |
355 | ppc_elf_got16_reloc, /* special_function */ | |
356 | "R_PPC_GOT16_LO", /* name */ | |
357 | false, /* partial_inplace */ | |
358 | 0, /* src_mask */ | |
359 | 0xffff, /* dst_mask */ | |
360 | false), /* pcrel_offset */ | |
361 | ||
362 | /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for | |
363 | the symbol. */ | |
364 | HOWTO (R_PPC_GOT16_HI, /* type */ | |
365 | 16, /* rightshift */ | |
366 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
367 | 16, /* bitsize */ | |
368 | false, /* pc_relative */ | |
369 | 0, /* bitpos */ | |
370 | complain_overflow_bitfield, /* complain_on_overflow */ | |
371 | ppc_elf_got16_reloc, /* special_function */ | |
372 | "R_PPC_GOT16_HI", /* name */ | |
373 | false, /* partial_inplace */ | |
374 | 0, /* src_mask */ | |
375 | 0xffff, /* dst_mask */ | |
376 | false), /* pcrel_offset */ | |
377 | ||
378 | /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for | |
379 | the symbol. FIXME: Not supported. */ | |
380 | HOWTO (R_PPC_GOT16_HA, /* type */ | |
381 | 0, /* rightshift */ | |
382 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
383 | 16, /* bitsize */ | |
384 | false, /* pc_relative */ | |
385 | 0, /* bitpos */ | |
386 | complain_overflow_bitfield, /* complain_on_overflow */ | |
387 | ppc_elf_unsupported_reloc, /* special_function */ | |
388 | "R_PPC_GOT16_HA", /* name */ | |
389 | false, /* partial_inplace */ | |
390 | 0, /* src_mask */ | |
391 | 0xffff, /* dst_mask */ | |
392 | false), /* pcrel_offset */ | |
393 | ||
394 | /* Like R_PPC_REL24, but referring to the procedure linkage table | |
395 | entry for the symbol. FIXME: Not supported. */ | |
396 | HOWTO (R_PPC_PLT24, /* type */ | |
397 | 0, /* rightshift */ | |
398 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
399 | 26, /* bitsize */ | |
400 | true, /* pc_relative */ | |
401 | 0, /* bitpos */ | |
402 | complain_overflow_signed, /* complain_on_overflow */ | |
403 | bfd_elf_generic_reloc, /* special_function */ | |
404 | "R_PPC_PLT24", /* name */ | |
405 | false, /* partial_inplace */ | |
406 | 0, /* src_mask */ | |
407 | 0x3fffffc, /* dst_mask */ | |
408 | true), /* pcrel_offset */ | |
409 | ||
410 | /* This is used only by the dynamic linker. The symbol should exist | |
411 | both in the object being run and in some shared library. The | |
412 | dynamic linker copies the data addressed by the symbol from the | |
413 | shared library into the object. I have no idea what the purpose | |
414 | of this is. */ | |
415 | HOWTO (R_PPC_COPY, /* type */ | |
416 | 0, /* rightshift */ | |
417 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
418 | 32, /* bitsize */ | |
419 | false, /* pc_relative */ | |
420 | 0, /* bitpos */ | |
421 | complain_overflow_bitfield, /* complain_on_overflow */ | |
422 | bfd_elf_generic_reloc, /* special_function */ | |
423 | "R_PPC_COPY", /* name */ | |
424 | false, /* partial_inplace */ | |
425 | 0, /* src_mask */ | |
426 | 0, /* dst_mask */ | |
427 | false), /* pcrel_offset */ | |
428 | ||
429 | /* Like R_PPC_ADDR32, but used when setting global offset table | |
430 | entries. */ | |
431 | HOWTO (R_PPC_GLOB_DAT, /* type */ | |
432 | 0, /* rightshift */ | |
433 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
434 | 32, /* bitsize */ | |
435 | false, /* pc_relative */ | |
436 | 0, /* bitpos */ | |
437 | complain_overflow_bitfield, /* complain_on_overflow */ | |
438 | bfd_elf_generic_reloc, /* special_function */ | |
439 | "R_PPC_GLOB_DAT", /* name */ | |
440 | false, /* partial_inplace */ | |
441 | 0, /* src_mask */ | |
442 | 0xffffffff, /* dst_mask */ | |
443 | false), /* pcrel_offset */ | |
444 | ||
445 | /* Marks a procedure linkage table entry for a symbol. */ | |
446 | HOWTO (R_PPC_JMP_SLOT, /* type */ | |
447 | 0, /* rightshift */ | |
448 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
449 | 32, /* bitsize */ | |
450 | false, /* pc_relative */ | |
451 | 0, /* bitpos */ | |
452 | complain_overflow_bitfield, /* complain_on_overflow */ | |
453 | bfd_elf_generic_reloc, /* special_function */ | |
454 | "R_PPC_JMP_SLOT", /* name */ | |
455 | false, /* partial_inplace */ | |
456 | 0, /* src_mask */ | |
457 | 0, /* dst_mask */ | |
458 | false), /* pcrel_offset */ | |
459 | ||
460 | /* Used only by the dynamic linker. When the object is run, this | |
461 | longword is set to the load address of the object, plus the | |
462 | addend. */ | |
463 | HOWTO (R_PPC_RELATIVE, /* type */ | |
464 | 0, /* rightshift */ | |
465 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
466 | 32, /* bitsize */ | |
467 | false, /* pc_relative */ | |
468 | 0, /* bitpos */ | |
469 | complain_overflow_bitfield, /* complain_on_overflow */ | |
470 | bfd_elf_generic_reloc, /* special_function */ | |
471 | "R_PPC_RELATIVE", /* name */ | |
472 | false, /* partial_inplace */ | |
473 | 0, /* src_mask */ | |
474 | 0xffffffff, /* dst_mask */ | |
475 | false), /* pcrel_offset */ | |
476 | ||
477 | /* Like R_PPC_REL24, but uses the value of the symbol within the | |
478 | object rather than the final value. Normally used for | |
479 | _GLOBAL_OFFSET_TABLE_. FIXME: Not supported. */ | |
480 | HOWTO (R_PPC_LOCAL24PC, /* type */ | |
481 | 0, /* rightshift */ | |
482 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
483 | 26, /* bitsize */ | |
484 | true, /* pc_relative */ | |
485 | 0, /* bitpos */ | |
486 | complain_overflow_signed, /* complain_on_overflow */ | |
487 | ppc_elf_unsupported_reloc, /* special_function */ | |
488 | "R_PPC_LOCAL24PC", /* name */ | |
489 | false, /* partial_inplace */ | |
490 | 0, /* src_mask */ | |
491 | 0x3fffffc, /* dst_mask */ | |
492 | true), /* pcrel_offset */ | |
493 | ||
494 | /* Like R_PPC_ADDR32, but may be unaligned. */ | |
495 | HOWTO (R_PPC_UADDR32, /* type */ | |
496 | 0, /* rightshift */ | |
497 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
498 | 32, /* bitsize */ | |
499 | false, /* pc_relative */ | |
500 | 0, /* bitpos */ | |
501 | complain_overflow_bitfield, /* complain_on_overflow */ | |
502 | bfd_elf_generic_reloc, /* special_function */ | |
503 | "R_PPC_UADDR32", /* name */ | |
504 | false, /* partial_inplace */ | |
505 | 0, /* src_mask */ | |
506 | 0xffffffff, /* dst_mask */ | |
507 | false), /* pcrel_offset */ | |
508 | ||
509 | /* Like R_PPC_ADDR16, but may be unaligned. */ | |
510 | HOWTO (R_PPC_UADDR16, /* type */ | |
511 | 0, /* rightshift */ | |
512 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
513 | 16, /* bitsize */ | |
514 | false, /* pc_relative */ | |
515 | 0, /* bitpos */ | |
516 | complain_overflow_bitfield, /* complain_on_overflow */ | |
517 | bfd_elf_generic_reloc, /* special_function */ | |
518 | "R_PPC_UADDR16", /* name */ | |
519 | false, /* partial_inplace */ | |
520 | 0, /* src_mask */ | |
521 | 0xffff, /* dst_mask */ | |
522 | false), /* pcrel_offset */ | |
523 | ||
524 | /* 32-bit PC relative */ | |
525 | HOWTO (R_PPC_REL32, /* type */ | |
526 | 0, /* rightshift */ | |
527 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
528 | 32, /* bitsize */ | |
529 | true, /* pc_relative */ | |
530 | 0, /* bitpos */ | |
531 | complain_overflow_bitfield, /* complain_on_overflow */ | |
532 | bfd_elf_generic_reloc, /* special_function */ | |
533 | "R_PPC_REL32", /* name */ | |
534 | false, /* partial_inplace */ | |
535 | 0, /* src_mask */ | |
536 | 0xffffffff, /* dst_mask */ | |
537 | true), /* pcrel_offset */ | |
538 | ||
539 | /* 32-bit relocation to the symbol's procedure linkage table. | |
540 | FIXEME: not supported. */ | |
541 | HOWTO (R_PPC_PLT32, /* type */ | |
542 | 0, /* rightshift */ | |
543 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
544 | 32, /* bitsize */ | |
545 | false, /* pc_relative */ | |
546 | 0, /* bitpos */ | |
547 | complain_overflow_bitfield, /* complain_on_overflow */ | |
548 | ppc_elf_unsupported_reloc, /* special_function */ | |
549 | "R_PPC_PLT32", /* name */ | |
550 | false, /* partial_inplace */ | |
551 | 0, /* src_mask */ | |
552 | 0, /* dst_mask */ | |
553 | false), /* pcrel_offset */ | |
554 | ||
555 | /* 32-bit PC relative relocation to the symbol's procedure linkage table. | |
556 | FIXEME: not supported. */ | |
557 | HOWTO (R_PPC_PLTREL32, /* type */ | |
558 | 0, /* rightshift */ | |
559 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
560 | 32, /* bitsize */ | |
561 | true, /* pc_relative */ | |
562 | 0, /* bitpos */ | |
563 | complain_overflow_bitfield, /* complain_on_overflow */ | |
564 | ppc_elf_unsupported_reloc, /* special_function */ | |
565 | "R_PPC_PLTREL32", /* name */ | |
566 | false, /* partial_inplace */ | |
567 | 0, /* src_mask */ | |
568 | 0, /* dst_mask */ | |
569 | true), /* pcrel_offset */ | |
570 | ||
571 | /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for | |
572 | the symbol. */ | |
573 | HOWTO (R_PPC_PLT16_LO, /* type */ | |
574 | 0, /* rightshift */ | |
575 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
576 | 16, /* bitsize */ | |
577 | false, /* pc_relative */ | |
578 | 0, /* bitpos */ | |
579 | complain_overflow_bitfield, /* complain_on_overflow */ | |
580 | ppc_elf_unsupported_reloc, /* special_function */ | |
581 | "R_PPC_PLT16_LO", /* name */ | |
582 | false, /* partial_inplace */ | |
583 | 0, /* src_mask */ | |
584 | 0xffff, /* dst_mask */ | |
585 | false), /* pcrel_offset */ | |
586 | ||
587 | /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for | |
588 | the symbol. */ | |
589 | HOWTO (R_PPC_PLT16_HI, /* type */ | |
590 | 16, /* rightshift */ | |
591 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
592 | 16, /* bitsize */ | |
593 | false, /* pc_relative */ | |
594 | 0, /* bitpos */ | |
595 | complain_overflow_bitfield, /* complain_on_overflow */ | |
596 | ppc_elf_unsupported_reloc, /* special_function */ | |
597 | "R_PPC_PLT16_HI", /* name */ | |
598 | false, /* partial_inplace */ | |
599 | 0, /* src_mask */ | |
600 | 0xffff, /* dst_mask */ | |
601 | false), /* pcrel_offset */ | |
602 | ||
603 | /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for | |
604 | the symbol. FIXME: Not supported. */ | |
605 | HOWTO (R_PPC_PLT16_HA, /* type */ | |
606 | 0, /* rightshift */ | |
607 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
608 | 16, /* bitsize */ | |
609 | false, /* pc_relative */ | |
610 | 0, /* bitpos */ | |
611 | complain_overflow_bitfield, /* complain_on_overflow */ | |
612 | ppc_elf_unsupported_reloc, /* special_function */ | |
613 | "R_PPC_PLT16_HA", /* name */ | |
614 | false, /* partial_inplace */ | |
615 | 0, /* src_mask */ | |
616 | 0xffff, /* dst_mask */ | |
617 | false), /* pcrel_offset */ | |
618 | ||
619 | /* A sign-extended 16 bit value relative to _SDA_BASE, for use with | |
620 | small data items. */ | |
621 | HOWTO (R_PPC_SDAREL, /* type */ | |
622 | 0, /* rightshift */ | |
623 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
624 | 16, /* bitsize */ | |
625 | false, /* pc_relative */ | |
626 | 0, /* bitpos */ | |
627 | complain_overflow_bitfield, /* complain_on_overflow */ | |
628 | ppc_elf_unsupported_reloc, /* special_function */ | |
629 | "R_PPC_SDAREL", /* name */ | |
630 | false, /* partial_inplace */ | |
631 | 0, /* src_mask */ | |
632 | 0xffff, /* dst_mask */ | |
633 | false), /* pcrel_offset */ | |
634 | ||
635 | /* These next 4 relocations were added by Sun. */ | |
636 | /* 32-bit section relative relocation. FIXME: not supported. */ | |
637 | HOWTO (R_PPC_SECTOFF, /* type */ | |
638 | 0, /* rightshift */ | |
639 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
640 | 32, /* bitsize */ | |
641 | true, /* pc_relative */ | |
642 | 0, /* bitpos */ | |
643 | complain_overflow_bitfield, /* complain_on_overflow */ | |
644 | ppc_elf_unsupported_reloc, /* special_function */ | |
645 | "R_PPC_SECTOFF", /* name */ | |
646 | false, /* partial_inplace */ | |
647 | 0, /* src_mask */ | |
648 | 0, /* dst_mask */ | |
649 | true), /* pcrel_offset */ | |
650 | ||
651 | /* 16-bit lower half section relative relocation. FIXME: not supported. */ | |
652 | HOWTO (R_PPC_SECTOFF_LO, /* type */ | |
653 | 0, /* rightshift */ | |
654 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
655 | 16, /* bitsize */ | |
656 | false, /* pc_relative */ | |
657 | 0, /* bitpos */ | |
658 | complain_overflow_bitfield, /* complain_on_overflow */ | |
659 | ppc_elf_unsupported_reloc, /* special_function */ | |
660 | "R_PPC_SECTOFF_LO", /* name */ | |
661 | false, /* partial_inplace */ | |
662 | 0, /* src_mask */ | |
663 | 0xffff, /* dst_mask */ | |
664 | false), /* pcrel_offset */ | |
665 | ||
666 | /* 16-bit upper half section relative relocation. FIXME: not supported. */ | |
667 | HOWTO (R_PPC_SECTOFF_HI, /* type */ | |
668 | 16, /* rightshift */ | |
669 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
670 | 16, /* bitsize */ | |
671 | false, /* pc_relative */ | |
672 | 0, /* bitpos */ | |
673 | complain_overflow_bitfield, /* complain_on_overflow */ | |
674 | ppc_elf_unsupported_reloc, /* special_function */ | |
675 | "R_PPC_SECTOFF_HI", /* name */ | |
676 | false, /* partial_inplace */ | |
677 | 0, /* src_mask */ | |
678 | 0xffff, /* dst_mask */ | |
679 | false), /* pcrel_offset */ | |
680 | ||
681 | /* 16-bit upper half adjusted section relative relocation. FIXME: not supported. */ | |
682 | HOWTO (R_PPC_SECTOFF_HA, /* type */ | |
683 | 0, /* rightshift */ | |
684 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
685 | 16, /* bitsize */ | |
686 | false, /* pc_relative */ | |
687 | 0, /* bitpos */ | |
688 | complain_overflow_bitfield, /* complain_on_overflow */ | |
689 | ppc_elf_unsupported_reloc, /* special_function */ | |
690 | "R_PPC_SECTOFF_HA", /* name */ | |
691 | false, /* partial_inplace */ | |
692 | 0, /* src_mask */ | |
693 | 0xffff, /* dst_mask */ | |
694 | false), /* pcrel_offset */ | |
695 | ||
696 | /* The remaining relocs are from the Embedded ELF ABI, and are not | |
697 | in the SVR4 ELF ABI. */ | |
698 | ||
699 | /* 32 bit value resulting from the addend minus the symbol */ | |
700 | HOWTO (R_PPC_EMB_NADDR32, /* type */ | |
701 | 0, /* rightshift */ | |
702 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
703 | 32, /* bitsize */ | |
704 | false, /* pc_relative */ | |
705 | 0, /* bitpos */ | |
706 | complain_overflow_bitfield, /* complain_on_overflow */ | |
707 | ppc_elf_unsupported_reloc, /* special_function */ | |
708 | "R_PPC_EMB_NADDR32", /* name */ | |
709 | false, /* partial_inplace */ | |
710 | 0, /* src_mask */ | |
711 | 0xffffffff, /* dst_mask */ | |
712 | false), /* pcrel_offset */ | |
713 | ||
714 | /* 16 bit value resulting from the addend minus the symbol */ | |
715 | HOWTO (R_PPC_EMB_NADDR16, /* type */ | |
716 | 0, /* rightshift */ | |
717 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
718 | 16, /* bitsize */ | |
719 | false, /* pc_relative */ | |
720 | 0, /* bitpos */ | |
721 | complain_overflow_bitfield, /* complain_on_overflow */ | |
722 | ppc_elf_unsupported_reloc, /* special_function */ | |
723 | "R_PPC_EMB_NADDR16", /* name */ | |
724 | false, /* partial_inplace */ | |
725 | 0, /* src_mask */ | |
726 | 0xffff, /* dst_mask */ | |
727 | false), /* pcrel_offset */ | |
728 | ||
729 | /* 16 bit value resulting from the addend minus the symbol */ | |
730 | HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ | |
731 | 0, /* rightshift */ | |
732 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
733 | 16, /* bitsize */ | |
734 | false, /* pc_relative */ | |
735 | 0, /* bitpos */ | |
736 | complain_overflow_dont,/* complain_on_overflow */ | |
737 | ppc_elf_unsupported_reloc, /* special_function */ | |
738 | "R_PPC_EMB_ADDR16_LO", /* name */ | |
739 | false, /* partial_inplace */ | |
740 | 0, /* src_mask */ | |
741 | 0xffff, /* dst_mask */ | |
742 | false), /* pcrel_offset */ | |
743 | ||
744 | /* The high order 16 bits of the addend minus the symbol */ | |
745 | HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ | |
746 | 16, /* rightshift */ | |
747 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
748 | 16, /* bitsize */ | |
749 | false, /* pc_relative */ | |
750 | 0, /* bitpos */ | |
751 | complain_overflow_dont, /* complain_on_overflow */ | |
752 | ppc_elf_unsupported_reloc, /* special_function */ | |
753 | "R_PPC_EMB_NADDR16_HI", /* name */ | |
754 | false, /* partial_inplace */ | |
755 | 0, /* src_mask */ | |
756 | 0xffff, /* dst_mask */ | |
757 | false), /* pcrel_offset */ | |
758 | ||
759 | /* The high order 16 bits of the result of the addend minus the address, | |
760 | plus 1 if the contents of the low 16 bits, treated as a signed number, | |
761 | is negative. */ | |
762 | HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ | |
763 | 16, /* rightshift */ | |
764 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
765 | 16, /* bitsize */ | |
766 | false, /* pc_relative */ | |
767 | 0, /* bitpos */ | |
768 | complain_overflow_dont, /* complain_on_overflow */ | |
769 | ppc_elf_unsupported_reloc, /* special_function */ | |
770 | "R_PPC_EMB_NADDR16_HA", /* name */ | |
771 | false, /* partial_inplace */ | |
772 | 0, /* src_mask */ | |
773 | 0xffff, /* dst_mask */ | |
774 | false), /* pcrel_offset */ | |
775 | }; | |
776 | ||
777 | /* Don't pretend we can deal with unsupported relocs. */ | |
778 | ||
779 | /*ARGSUSED*/ | |
780 | static bfd_reloc_status_type | |
781 | ppc_elf_unsupported_reloc (abfd, reloc_entry, symbol, data, input_section, | |
782 | output_bfd, error_message) | |
783 | bfd *abfd; | |
784 | arelent *reloc_entry; | |
785 | asymbol *symbol; | |
786 | PTR data; | |
787 | asection *input_section; | |
788 | bfd *output_bfd; | |
789 | char **error_message; | |
790 | { | |
791 | abort (); | |
792 | } | |
793 | ||
794 | /* Handle the ADDR16_HA reloc by adjusting the reloc addend. */ | |
795 | ||
796 | static bfd_reloc_status_type | |
797 | ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, | |
798 | output_bfd, error_message) | |
799 | bfd *abfd; | |
800 | arelent *reloc_entry; | |
801 | asymbol *symbol; | |
802 | PTR data; | |
803 | asection *input_section; | |
804 | bfd *output_bfd; | |
805 | char **error_message; | |
806 | { | |
807 | bfd_vma relocation; | |
808 | ||
809 | if (output_bfd != (bfd *) NULL) | |
810 | return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, | |
811 | input_section, output_bfd, error_message); | |
812 | ||
813 | if (bfd_is_com_section (symbol->section)) | |
814 | relocation = 0; | |
815 | else | |
816 | relocation = symbol->value; | |
817 | ||
818 | relocation += (symbol->section->output_section->vma | |
819 | + symbol->section->output_offset | |
820 | + reloc_entry->addend); | |
821 | ||
822 | if ((relocation & 0x8000) != 0) | |
823 | reloc_entry->addend += 0x10000; | |
824 | ||
825 | return bfd_reloc_continue; | |
826 | } | |
827 | ||
828 | /* Handle the GOT16 reloc. We want to use the offset within the .got | |
829 | section, not the actual VMA. This is appropriate when generating | |
830 | an embedded ELF object, for which the .got section acts like the | |
831 | AIX .toc section. When and if we support PIC code, we will have to | |
832 | change this, perhaps by switching off on the e_type field. */ | |
833 | ||
834 | static bfd_reloc_status_type | |
835 | ppc_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section, | |
836 | output_bfd, error_message) | |
837 | bfd *abfd; | |
838 | arelent *reloc_entry; | |
839 | asymbol *symbol; | |
840 | PTR data; | |
841 | asection *input_section; | |
842 | bfd *output_bfd; | |
843 | char **error_message; | |
844 | { | |
845 | asection *sec; | |
846 | ||
847 | if (output_bfd != (bfd *) NULL) | |
848 | return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, | |
849 | input_section, output_bfd, error_message); | |
850 | ||
851 | sec = bfd_get_section (*reloc_entry->sym_ptr_ptr); | |
852 | BFD_ASSERT (bfd_is_und_section (sec) | |
853 | || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 | |
854 | || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0); | |
855 | reloc_entry->addend -= sec->output_section->vma; | |
856 | return bfd_reloc_continue; | |
857 | } | |
858 | ||
859 | /* Map BFD reloc types to PowerPC ELF reloc types. */ | |
860 | ||
861 | struct powerpc_reloc_map | |
862 | { | |
863 | unsigned char bfd_reloc_val; | |
864 | unsigned char elf_reloc_val; | |
865 | }; | |
866 | ||
867 | static const struct powerpc_reloc_map powerpc_reloc_map[] = | |
868 | { | |
869 | { BFD_RELOC_NONE, R_PPC_NONE, }, | |
870 | { BFD_RELOC_32, R_PPC_ADDR32 }, | |
871 | { BFD_RELOC_32_PCREL, R_PPC_REL32 }, | |
872 | { BFD_RELOC_CTOR, R_PPC_ADDR32 }, | |
873 | { BFD_RELOC_PPC_B26, R_PPC_REL24 }, | |
874 | { BFD_RELOC_PPC_BA26, R_PPC_ADDR24 }, | |
875 | { BFD_RELOC_PPC_TOC16, R_PPC_GOT16 }, | |
876 | { BFD_RELOC_LO16, R_PPC_ADDR16_LO }, | |
877 | { BFD_RELOC_HI16, R_PPC_ADDR16_HI }, | |
878 | { BFD_RELOC_HI16_S, R_PPC_ADDR16_HA } | |
879 | }; | |
880 | ||
881 | static reloc_howto_type * | |
882 | bfd_elf32_bfd_reloc_type_lookup (abfd, code) | |
883 | bfd *abfd; | |
884 | bfd_reloc_code_real_type code; | |
885 | { | |
886 | int i; | |
887 | ||
888 | for (i = 0; | |
889 | i < sizeof (powerpc_reloc_map) / sizeof (struct powerpc_reloc_map); | |
890 | i++) | |
891 | { | |
892 | if (powerpc_reloc_map[i].bfd_reloc_val == code) | |
893 | return &elf_powerpc_howto_table[powerpc_reloc_map[i].elf_reloc_val]; | |
894 | } | |
895 | ||
896 | return NULL; | |
897 | } | |
898 | ||
899 | /* Set the howto pointer for a PowerPC ELF reloc. */ | |
900 | ||
901 | static void | |
902 | powerpc_info_to_howto (abfd, cache_ptr, dst) | |
903 | bfd *abfd; | |
904 | arelent *cache_ptr; | |
905 | Elf32_Internal_Rela *dst; | |
906 | { | |
907 | BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); | |
908 | cache_ptr->howto = &elf_powerpc_howto_table[ELF32_R_TYPE (dst->r_info)]; | |
909 | } | |
910 | ||
911 | #define TARGET_BIG_SYM bfd_elf32_powerpc_vec | |
912 | #define TARGET_BIG_NAME "elf32-powerpc" | |
913 | #define ELF_ARCH bfd_arch_powerpc | |
914 | #define ELF_MACHINE_CODE EM_PPC | |
915 | #define ELF_MAXPAGESIZE 0x10000 | |
916 | #define elf_info_to_howto powerpc_info_to_howto | |
917 | ||
918 | #ifdef EM_CYGNUS_POWERPC | |
919 | #define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC | |
920 | #endif | |
921 | ||
922 | #ifdef EM_PPC_OLD | |
923 | #define ELF_MACHINE_ALT2 EM_PPC_OLD | |
924 | #endif | |
925 | ||
926 | #include "elf32-target.h" |