* configure.host: Recognize i[34]86-sequent-*.
[binutils-gdb.git] / bfd / elf32-powerpc.c
1 /* PowerPC-specific support for 32-bit ELF
2 Copyright 1994 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 /* I wrote this file without the benefit of a PowerPC ELF ABI. Thus,
22 it probably does not correspond to whatever people finally settle
23 on. Ian Taylor. */
24
25 #include "bfd.h"
26 #include "sysdep.h"
27 #include "libbfd.h"
28 #include "libelf.h"
29
30 static bfd_reloc_status_type powerpc_elf_toc16_reloc PARAMS ((bfd *abfd,
31 arelent *reloc,
32 asymbol *symbol,
33 PTR data,
34 asection *sec,
35 bfd *output_bfd,
36 char **error));
37 static bfd_reloc_status_type powerpc_elf_b26_reloc PARAMS ((bfd *abfd,
38 arelent *reloc,
39 asymbol *symbol,
40 PTR data,
41 asection *sec,
42 bfd *output_bfd,
43 char **error));
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));
48
49 #define USE_REL
50
51 enum reloc_type
52 {
53 R_POWERPC_NONE = 0,
54 R_POWERPC_32,
55 R_POWERPC_B26,
56 R_POWERPC_BA26,
57 R_POWERPC_TOC16,
58 R_POWERPC_max
59 };
60
61 static reloc_howto_type elf_powerpc_howto_table[] =
62 {
63 /* This relocation does not do anything. */
64 HOWTO (R_POWERPC_NONE, /* type */
65 0, /* rightshift */
66 2, /* size (0 = byte, 1 = short, 2 = long) */
67 32, /* bitsize */
68 false, /* pc_relative */
69 0, /* bitpos */
70 complain_overflow_bitfield, /* complain_on_overflow */
71 bfd_elf_generic_reloc, /* special_function */
72 "R_POWERPC_NONE", /* name */
73 true, /* partial_inplace */
74 0, /* src_mask */
75 0, /* dst_mask */
76 false), /* pcrel_offset */
77
78 /* Standard 32 bit relocation. */
79 HOWTO (R_POWERPC_32, /* type */
80 0, /* rightshift */
81 2, /* size (0 = byte, 1 = short, 2 = long) */
82 32, /* bitsize */
83 false, /* pc_relative */
84 0, /* bitpos */
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 */
92
93 /* 26 bit relative branch. */
94 HOWTO (R_POWERPC_B26, /* type */
95 0, /* rightshift */
96 2, /* size (0 = byte, 1 = short, 2 = long) */
97 26, /* bitsize */
98 true, /* pc_relative */
99 0, /* bitpos */
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 */
107
108 /* 26 bit absolute branch. */
109 HOWTO (R_POWERPC_BA26, /* type */
110 0, /* rightshift */
111 2, /* size (0 = byte, 1 = short, 2 = long) */
112 26, /* bitsize */
113 false, /* pc_relative */
114 0, /* bitpos */
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 */
122
123 /* 16 bit reference to TOC section. */
124 HOWTO (R_POWERPC_TOC16, /* type */
125 0, /* rightshift */
126 1, /* size (0 = byte, 1 = short, 2 = long) */
127 16, /* bitsize */
128 false, /* pc_relative */
129 0, /* bitpos */
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 */
137 };
138
139 /* Handle the TOC16 reloc. We want to use the offset within the .toc
140 section, not the actual VMA. */
141
142 static bfd_reloc_status_type
143 powerpc_elf_toc16_reloc (abfd,
144 reloc_entry,
145 symbol,
146 data,
147 input_section,
148 output_bfd,
149 error_message)
150 bfd *abfd;
151 arelent *reloc_entry;
152 asymbol *symbol;
153 PTR data;
154 asection *input_section;
155 bfd *output_bfd;
156 char **error_message;
157 {
158 asection *sec;
159
160 /* Simply adjust the reloc addend by the negative of the VMA of the
161 .toc section. */
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;
168 }
169
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
175 hack. */
176
177 static bfd_reloc_status_type
178 powerpc_elf_b26_reloc (abfd,
179 reloc_entry,
180 symbol,
181 data,
182 input_section,
183 output_bfd,
184 error_message)
185 bfd *abfd;
186 arelent *reloc_entry;
187 asymbol *symbol;
188 PTR data;
189 asection *input_section;
190 bfd *output_bfd;
191 char **error_message;
192 {
193 if (bfd_get_section (symbol) != &bfd_und_section
194 && (strcmp (bfd_get_section (symbol)->owner->filename, "linker stubs")
195 == 0))
196 {
197 bfd_vma val;
198
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);
204 }
205
206 if (output_bfd != (bfd *) NULL
207 && bfd_get_section (symbol) == &bfd_und_section)
208 {
209 bfd_size_type address;
210
211 /* If we are generating relocateable output, and the symbol is
212 undefined, we just want to adjust the reloc by the amount the
213 section moved. */
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);
219 }
220
221 /* Otherwise, let bfd_perform_relocation handle it. */
222 return bfd_reloc_continue;
223 }
224
225 /* Map BFD reloc types to PowerPC ELF reloc types. */
226
227 struct powerpc_reloc_map
228 {
229 unsigned char bfd_reloc_val;
230 unsigned char elf_reloc_val;
231 };
232
233 static const struct powerpc_reloc_map powerpc_reloc_map[] =
234 {
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 }
241 };
242
243 static const struct reloc_howto_struct *
244 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
245 bfd *abfd;
246 bfd_reloc_code_real_type code;
247 {
248 int i;
249
250 for (i = 0;
251 i < sizeof (powerpc_reloc_map) / sizeof (struct powerpc_reloc_map);
252 i++)
253 {
254 if (powerpc_reloc_map[i].bfd_reloc_val == code)
255 return &elf_powerpc_howto_table[powerpc_reloc_map[i].elf_reloc_val];
256 }
257
258 return NULL;
259 }
260
261 /* Set the howto pointer for a PowerPC ELF reloc. */
262
263 static void
264 powerpc_info_to_howto_rel (abfd, cache_ptr, dst)
265 bfd *abfd;
266 arelent *cache_ptr;
267 Elf32_Internal_Rel *dst;
268 {
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)];
271 }
272
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
280
281 #include "elf32-target.h"