1 /* PowerPC-specific support for 32-bit ELF
2 Copyright 1994 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
21 /* I wrote this file without the benefit of a PowerPC ELF ABI. Thus,
22 it probably does not correspond to whatever people finally settle
30 static bfd_reloc_status_type powerpc_elf_toc16_reloc
PARAMS ((bfd
*abfd
,
37 static bfd_reloc_status_type powerpc_elf_b26_reloc
PARAMS ((bfd
*abfd
,
44 static const struct reloc_howto_struct
*bfd_elf32_bfd_reloc_type_lookup
45 PARAMS ((bfd
*abfd
, bfd_reloc_code_real_type code
));
46 static void powerpc_info_to_howto_rel
47 PARAMS ((bfd
*abfd
, arelent
*cache_ptr
, Elf32_Internal_Rel
*dst
));
61 static reloc_howto_type elf_powerpc_howto_table
[] =
63 /* This relocation does not do anything. */
64 HOWTO (R_POWERPC_NONE
, /* type */
66 2, /* size (0 = byte, 1 = short, 2 = long) */
68 false, /* pc_relative */
70 complain_overflow_bitfield
, /* complain_on_overflow */
71 bfd_elf_generic_reloc
, /* special_function */
72 "R_POWERPC_NONE", /* name */
73 true, /* partial_inplace */
76 false), /* pcrel_offset */
78 /* Standard 32 bit relocation. */
79 HOWTO (R_POWERPC_32
, /* type */
81 2, /* size (0 = byte, 1 = short, 2 = long) */
83 false, /* pc_relative */
85 complain_overflow_bitfield
, /* complain_on_overflow */
86 bfd_elf_generic_reloc
, /* special_function */
87 "R_POWERPC_32", /* name */
88 true, /* partial_inplace */
89 0xffffffff, /* src_mask */
90 0xffffffff, /* dst_mask */
91 false), /* pcrel_offset */
93 /* 26 bit relative branch. */
94 HOWTO (R_POWERPC_B26
, /* type */
96 2, /* size (0 = byte, 1 = short, 2 = long) */
98 true, /* pc_relative */
100 complain_overflow_signed
, /* complain_on_overflow */
101 powerpc_elf_b26_reloc
, /* special_function */
102 "R_POWERPC_B26", /* name */
103 true, /* partial_inplace */
104 0x3fffffc, /* src_mask */
105 0x3fffffc, /* dst_mask */
106 false), /* pcrel_offset */
108 /* 26 bit absolute branch. */
109 HOWTO (R_POWERPC_BA26
, /* type */
111 2, /* size (0 = byte, 1 = short, 2 = long) */
113 false, /* pc_relative */
115 complain_overflow_bitfield
, /* complain_on_overflow */
116 bfd_elf_generic_reloc
, /* special_function */
117 "R_POWERPC_BA26", /* name */
118 true, /* partial_inplace */
119 0x3fffffc, /* src_mask */
120 0x3fffffc, /* dst_mask */
121 false), /* pcrel_offset */
123 /* 16 bit reference to TOC section. */
124 HOWTO (R_POWERPC_TOC16
, /* type */
126 1, /* size (0 = byte, 1 = short, 2 = long) */
128 false, /* pc_relative */
130 complain_overflow_signed
, /* complain_on_overflow */
131 powerpc_elf_toc16_reloc
, /* special_function */
132 "R_POWERPC_TOC16", /* name */
133 true, /* partial_inplace */
134 0xffff, /* src_mask */
135 0xffff, /* dst_mask */
136 false), /* pcrel_offset */
139 /* Handle the TOC16 reloc. We want to use the offset within the .toc
140 section, not the actual VMA. */
142 static bfd_reloc_status_type
143 powerpc_elf_toc16_reloc (abfd
,
151 arelent
*reloc_entry
;
154 asection
*input_section
;
156 char **error_message
;
160 /* Simply adjust the reloc addend by the negative of the VMA of the
162 sec
= bfd_get_section (*reloc_entry
->sym_ptr_ptr
);
163 if (sec
== &bfd_und_section
)
164 return bfd_reloc_continue
;
165 BFD_ASSERT (strcmp (bfd_get_section_name (abfd
, sec
), ".toc") == 0);
166 reloc_entry
->addend
-= sec
->output_section
->vma
;
167 return bfd_reloc_continue
;
170 /* Handle a branch. If the next instruction is the special
171 instruction "cror 31,31,31", and this branch is to a stub routine
172 we have created, we must change the cror instruction into an
173 instruction which reloads the TOC register. We can detect a stub
174 routine because it is in a BFD named "linker stubs". FIXME: What a
177 static bfd_reloc_status_type
178 powerpc_elf_b26_reloc (abfd
,
186 arelent
*reloc_entry
;
189 asection
*input_section
;
191 char **error_message
;
193 if (bfd_get_section (symbol
) != &bfd_und_section
194 && (strcmp (bfd_get_section (symbol
)->owner
->filename
, "linker stubs")
199 /* This symbol is a stub created by the linker. */
200 val
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc_entry
->address
+ 4);
201 if (val
== 0x4ffffb82) /* cror 31,31,31 */
202 bfd_put_32 (abfd
, (bfd_vma
) 0x80410014, /* l r2,20(r1) */
203 (bfd_byte
*) data
+ reloc_entry
->address
+ 4);
206 if (output_bfd
!= (bfd
*) NULL
207 && bfd_get_section (symbol
) == &bfd_und_section
)
209 bfd_size_type address
;
211 /* If we are generating relocateable output, and the symbol is
212 undefined, we just want to adjust the reloc by the amount the
214 address
= reloc_entry
->address
;
215 reloc_entry
->address
+= input_section
->output_offset
;
216 return _bfd_relocate_contents (reloc_entry
->howto
, abfd
,
217 - input_section
->output_offset
,
218 (bfd_byte
*) data
+ address
);
221 /* Otherwise, let bfd_perform_relocation handle it. */
222 return bfd_reloc_continue
;
225 /* Map BFD reloc types to PowerPC ELF reloc types. */
227 struct powerpc_reloc_map
229 unsigned char bfd_reloc_val
;
230 unsigned char elf_reloc_val
;
233 static const struct powerpc_reloc_map powerpc_reloc_map
[] =
235 { BFD_RELOC_NONE
, R_POWERPC_NONE
, },
236 { BFD_RELOC_32
, R_POWERPC_32
},
237 { BFD_RELOC_CTOR
, R_POWERPC_32
},
238 { BFD_RELOC_PPC_B26
, R_POWERPC_B26
},
239 { BFD_RELOC_PPC_BA26
, R_POWERPC_BA26
},
240 { BFD_RELOC_PPC_TOC16
, R_POWERPC_TOC16
}
243 static const struct reloc_howto_struct
*
244 bfd_elf32_bfd_reloc_type_lookup (abfd
, code
)
246 bfd_reloc_code_real_type code
;
251 i
< sizeof (powerpc_reloc_map
) / sizeof (struct powerpc_reloc_map
);
254 if (powerpc_reloc_map
[i
].bfd_reloc_val
== code
)
255 return &elf_powerpc_howto_table
[powerpc_reloc_map
[i
].elf_reloc_val
];
261 /* Set the howto pointer for a PowerPC ELF reloc. */
264 powerpc_info_to_howto_rel (abfd
, cache_ptr
, dst
)
267 Elf32_Internal_Rel
*dst
;
269 BFD_ASSERT (ELF32_R_TYPE (dst
->r_info
) < (unsigned int) R_POWERPC_max
);
270 cache_ptr
->howto
= &elf_powerpc_howto_table
[ELF32_R_TYPE(dst
->r_info
)];
273 #define TARGET_BIG_SYM bfd_elf32_powerpc_vec
274 #define TARGET_BIG_NAME "elf32-powerpc"
275 #define ELF_ARCH bfd_arch_powerpc
276 #define ELF_MACHINE_CODE EM_CYGNUS_POWERPC
277 #define ELF_MAXPAGESIZE 0x10000
278 #define elf_info_to_howto 0
279 #define elf_info_to_howto_rel powerpc_info_to_howto_rel
281 #include "elf32-target.h"