From Robin Kirkham <Robin.Kirkham@mlb.dmt.csiro.au>:
[deliverable/binutils-gdb.git] / bfd / elf64-sparc.c
1 /* SPARC-specific support for 64-bit ELF
2 Copyright (C) 1993, 1995, 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 /* We need a published ABI spec for this. Until one comes out, don't
21 assume this'll remain unchanged forever. */
22
23 #include "bfd.h"
24 #include "sysdep.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27
28 #define SPARC64_OLD_RELOCS
29 #include "elf/sparc.h"
30
31 static reloc_howto_type *sparc64_elf_reloc_type_lookup
32 PARAMS ((bfd *, bfd_reloc_code_real_type));
33 static void sparc64_elf_info_to_howto
34 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
35
36 static boolean sparc64_elf_relocate_section
37 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
38 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
39 static boolean sparc64_elf_object_p PARAMS ((bfd *));
40
41 /* The howto table and associated functions.
42 ??? Some of the relocation values have changed. Until we're ready
43 to upgrade, we have our own copy. At some point a non upward compatible
44 change will be made at which point this table can be deleted and we'll
45 use the one in elf32-sparc.c. */
46
47 static bfd_reloc_status_type sparc_elf_wdisp16_reloc
48 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
49
50 static reloc_howto_type sparc64_elf_howto_table[] =
51 {
52 HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true),
53 HOWTO(R_SPARC_8, 0,0, 8,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_8", false,0,0x000000ff,true),
54 HOWTO(R_SPARC_16, 0,1,16,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_16", false,0,0x0000ffff,true),
55 HOWTO(R_SPARC_32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_32", false,0,0xffffffff,true),
56 HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP8", false,0,0x000000ff,true),
57 HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP16", false,0,0x0000ffff,true),
58 HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP32", false,0,0x00ffffff,true),
59 HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP30", false,0,0x3fffffff,true),
60 HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP22", false,0,0x003fffff,true),
61 HOWTO(R_SPARC_HI22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HI22", false,0,0x003fffff,true),
62 HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_22", false,0,0x003fffff,true),
63 HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_13", false,0,0x00001fff,true),
64 HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LO10", false,0,0x000003ff,true),
65 HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOT10", false,0,0x000003ff,true),
66 HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_GOT13", false,0,0x00001fff,true),
67 HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOT22", false,0,0x003fffff,true),
68 HOWTO(R_SPARC_PC10, 0,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_PC10", false,0,0x000003ff,true),
69 HOWTO(R_SPARC_PC22, 10,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_PC22", false,0,0x003fffff,true),
70 HOWTO(R_SPARC_WPLT30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WPLT30", false,0,0x3fffffff,true),
71 HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_COPY", false,0,0x00000000,true),
72 HOWTO(R_SPARC_GLOB_DAT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GLOB_DAT",false,0,0x00000000,true),
73 HOWTO(R_SPARC_JMP_SLOT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_JMP_SLOT",false,0,0x00000000,true),
74 HOWTO(R_SPARC_RELATIVE, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_RELATIVE",false,0,0x00000000,true),
75 HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_UA32", false,0,0x00000000,true),
76 #if 0 /* not used yet */
77 HOWTO(R_SPARC_PLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PLT32", false,0,0x00000000,true),
78 HOWTO(R_SPARC_HIPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_HIPLT22", false,0,0x00000000,true),
79 HOWTO(R_SPARC_LOPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_LOPLT10", false,0,0x00000000,true),
80 HOWTO(R_SPARC_PCPLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT32", false,0,0x00000000,true),
81 HOWTO(R_SPARC_PCPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT22", false,0,0x00000000,true),
82 HOWTO(R_SPARC_PCPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT10", false,0,0x00000000,true),
83 #endif
84 HOWTO(R_SPARC_10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_10", false,0,0x000003ff,true),
85 HOWTO(R_SPARC_11, 0,2,11,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_11", false,0,0x000007ff,true),
86 HOWTO(R_SPARC_64, 0,4,00,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_64", false,0,~ (bfd_vma) 0, true),
87 HOWTO(R_SPARC_OLO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_OLO10", false,0,0x000003ff,true),
88 HOWTO(R_SPARC_HH22, 42,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HH22", false,0,0x003fffff,true),
89 HOWTO(R_SPARC_HM10, 32,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HM10", false,0,0x000003ff,true),
90 HOWTO(R_SPARC_LM22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LM22", false,0,0x003fffff,true),
91 HOWTO(R_SPARC_PC_HH22, 42,2,22,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HH22", false,0,0x003fffff,true),
92 HOWTO(R_SPARC_PC_HM10, 32,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HM10", false,0,0x000003ff,true),
93 HOWTO(R_SPARC_PC_LM22, 10,2,22,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LM22", false,0,0x003fffff,true),
94 HOWTO(R_SPARC_WDISP16, 2,2,16,true, 0,complain_overflow_signed, sparc_elf_wdisp16_reloc,"R_SPARC_WDISP16", false,0,0x00000000,true),
95 HOWTO(R_SPARC_WDISP19, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP19", false,0,0x0007ffff,true),
96 HOWTO(R_SPARC_UNUSED_42, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_UNUSED_42",false,0,0x00000000,true),
97 HOWTO(R_SPARC_7, 0,2, 7,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_7", false,0,0x0000007f,true),
98 HOWTO(R_SPARC_5, 0,2, 5,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_5", false,0,0x0000001f,true),
99 HOWTO(R_SPARC_6, 0,2, 6,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_6", false,0,0x0000003f,true),
100 };
101
102 struct elf_reloc_map {
103 unsigned char bfd_reloc_val;
104 unsigned char elf_reloc_val;
105 };
106
107 static CONST struct elf_reloc_map sparc_reloc_map[] =
108 {
109 { BFD_RELOC_NONE, R_SPARC_NONE, },
110 { BFD_RELOC_16, R_SPARC_16, },
111 { BFD_RELOC_8, R_SPARC_8 },
112 { BFD_RELOC_8_PCREL, R_SPARC_DISP8 },
113 /* ??? This might cause us to need separate functions in elf{32,64}-sparc.c
114 (we could still have just one table), but is this reloc ever used? */
115 { BFD_RELOC_CTOR, R_SPARC_32 }, /* @@ Assumes 32 bits. */
116 { BFD_RELOC_32, R_SPARC_32 },
117 { BFD_RELOC_32_PCREL, R_SPARC_DISP32 },
118 { BFD_RELOC_HI22, R_SPARC_HI22 },
119 { BFD_RELOC_LO10, R_SPARC_LO10, },
120 { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 },
121 { BFD_RELOC_SPARC22, R_SPARC_22 },
122 { BFD_RELOC_SPARC13, R_SPARC_13 },
123 { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 },
124 { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 },
125 { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 },
126 { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 },
127 { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 },
128 { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 },
129 { BFD_RELOC_SPARC_COPY, R_SPARC_COPY },
130 { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT },
131 { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT },
132 { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE },
133 { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 },
134 /* ??? Doesn't dwarf use this? */
135 /*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */
136 {BFD_RELOC_SPARC_10, R_SPARC_10},
137 {BFD_RELOC_SPARC_11, R_SPARC_11},
138 {BFD_RELOC_SPARC_64, R_SPARC_64},
139 {BFD_RELOC_SPARC_OLO10, R_SPARC_OLO10},
140 {BFD_RELOC_SPARC_HH22, R_SPARC_HH22},
141 {BFD_RELOC_SPARC_HM10, R_SPARC_HM10},
142 {BFD_RELOC_SPARC_LM22, R_SPARC_LM22},
143 {BFD_RELOC_SPARC_PC_HH22, R_SPARC_PC_HH22},
144 {BFD_RELOC_SPARC_PC_HM10, R_SPARC_PC_HM10},
145 {BFD_RELOC_SPARC_PC_LM22, R_SPARC_PC_LM22},
146 {BFD_RELOC_SPARC_WDISP16, R_SPARC_WDISP16},
147 {BFD_RELOC_SPARC_WDISP19, R_SPARC_WDISP19},
148 {BFD_RELOC_SPARC_7, R_SPARC_7},
149 {BFD_RELOC_SPARC_5, R_SPARC_5},
150 {BFD_RELOC_SPARC_6, R_SPARC_6},
151 };
152
153 static reloc_howto_type *
154 sparc64_elf_reloc_type_lookup (abfd, code)
155 bfd *abfd;
156 bfd_reloc_code_real_type code;
157 {
158 unsigned int i;
159 for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct elf_reloc_map); i++)
160 {
161 if (sparc_reloc_map[i].bfd_reloc_val == code)
162 return &sparc64_elf_howto_table[(int) sparc_reloc_map[i].elf_reloc_val];
163 }
164 return 0;
165 }
166
167 static void
168 sparc64_elf_info_to_howto (abfd, cache_ptr, dst)
169 bfd *abfd;
170 arelent *cache_ptr;
171 Elf64_Internal_Rela *dst;
172 {
173 BFD_ASSERT (ELF64_R_TYPE (dst->r_info) < (unsigned int) R_SPARC_max);
174 cache_ptr->howto = &sparc64_elf_howto_table[ELF64_R_TYPE (dst->r_info)];
175 }
176 \f
177 /* Handle the WDISP16 reloc. */
178
179 static bfd_reloc_status_type
180 sparc_elf_wdisp16_reloc (abfd,
181 reloc_entry,
182 symbol,
183 data,
184 input_section,
185 output_bfd,
186 error_message)
187 bfd *abfd;
188 arelent *reloc_entry;
189 asymbol *symbol;
190 PTR data;
191 asection *input_section;
192 bfd *output_bfd;
193 char **error_message;
194 {
195 bfd_vma relocation;
196 bfd_vma x;
197
198 if (output_bfd != (bfd *) NULL
199 && (symbol->flags & BSF_SECTION_SYM) == 0
200 && (! reloc_entry->howto->partial_inplace
201 || reloc_entry->addend == 0))
202 {
203 reloc_entry->address += input_section->output_offset;
204 return bfd_reloc_ok;
205 }
206
207 if (output_bfd != NULL)
208 return bfd_reloc_continue;
209
210 if (reloc_entry->address > input_section->_cooked_size)
211 return bfd_reloc_outofrange;
212
213 relocation = (symbol->value
214 + symbol->section->output_section->vma
215 + symbol->section->output_offset);
216 relocation += reloc_entry->addend;
217 relocation -= (input_section->output_section->vma
218 + input_section->output_offset);
219 relocation -= reloc_entry->address;
220
221 x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
222 x |= ((((relocation >> 2) & 0xc000) << 6)
223 | ((relocation >> 2) & 0x3fff));
224 bfd_put_32 (abfd, x, (char *) data + reloc_entry->address);
225
226 if ((bfd_signed_vma) relocation < - 0x40000
227 || (bfd_signed_vma) relocation > 0x3ffff)
228 return bfd_reloc_overflow;
229 else
230 return bfd_reloc_ok;
231 }
232 \f
233 /* Relocate a SPARC64 ELF section. */
234
235 static boolean
236 sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
237 contents, relocs, local_syms, local_sections)
238 bfd *output_bfd;
239 struct bfd_link_info *info;
240 bfd *input_bfd;
241 asection *input_section;
242 bfd_byte *contents;
243 Elf_Internal_Rela *relocs;
244 Elf_Internal_Sym *local_syms;
245 asection **local_sections;
246 {
247 Elf_Internal_Shdr *symtab_hdr;
248 struct elf_link_hash_entry **sym_hashes;
249 Elf_Internal_Rela *rel;
250 Elf_Internal_Rela *relend;
251
252 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
253 sym_hashes = elf_sym_hashes (input_bfd);
254
255 rel = relocs;
256 relend = relocs + input_section->reloc_count;
257 for (; rel < relend; rel++)
258 {
259 int r_type;
260 reloc_howto_type *howto;
261 long r_symndx;
262 struct elf_link_hash_entry *h;
263 Elf_Internal_Sym *sym;
264 asection *sec;
265 bfd_vma relocation;
266 bfd_reloc_status_type r;
267
268 r_type = ELF64_R_TYPE (rel->r_info);
269 if (r_type < 0 || r_type >= (int) R_SPARC_max)
270 {
271 bfd_set_error (bfd_error_bad_value);
272 return false;
273 }
274 howto = sparc64_elf_howto_table + r_type;
275
276 r_symndx = ELF64_R_SYM (rel->r_info);
277
278 if (info->relocateable)
279 {
280 /* This is a relocateable link. We don't have to change
281 anything, unless the reloc is against a section symbol,
282 in which case we have to adjust according to where the
283 section symbol winds up in the output section. */
284 if (r_symndx < symtab_hdr->sh_info)
285 {
286 sym = local_syms + r_symndx;
287 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
288 {
289 sec = local_sections[r_symndx];
290 rel->r_addend += sec->output_offset + sym->st_value;
291 }
292 }
293
294 continue;
295 }
296
297 /* This is a final link. */
298 h = NULL;
299 sym = NULL;
300 sec = NULL;
301 if (r_symndx < symtab_hdr->sh_info)
302 {
303 sym = local_syms + r_symndx;
304 sec = local_sections[r_symndx];
305 relocation = (sec->output_section->vma
306 + sec->output_offset
307 + sym->st_value);
308 }
309 else
310 {
311 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
312 while (h->root.type == bfd_link_hash_indirect
313 || h->root.type == bfd_link_hash_warning)
314 h = (struct elf_link_hash_entry *) h->root.u.i.link;
315 if (h->root.type == bfd_link_hash_defined
316 || h->root.type == bfd_link_hash_defweak)
317 {
318 sec = h->root.u.def.section;
319 relocation = (h->root.u.def.value
320 + sec->output_section->vma
321 + sec->output_offset);
322 }
323 else if (h->root.type == bfd_link_hash_undefweak)
324 relocation = 0;
325 else
326 {
327 if (! ((*info->callbacks->undefined_symbol)
328 (info, h->root.root.string, input_bfd,
329 input_section, rel->r_offset)))
330 return false;
331 relocation = 0;
332 }
333 }
334
335 if (r_type != R_SPARC_WDISP16)
336 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
337 contents, rel->r_offset,
338 relocation, rel->r_addend);
339 else
340 {
341 bfd_vma x;
342
343 relocation += rel->r_addend;
344 relocation -= (input_section->output_section->vma
345 + input_section->output_offset);
346 relocation -= rel->r_offset;
347
348 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
349 x |= ((((relocation >> 2) & 0xc000) << 6)
350 | ((relocation >> 2) & 0x3fff));
351 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
352
353 if ((bfd_signed_vma) relocation < - 0x40000
354 || (bfd_signed_vma) relocation > 0x3ffff)
355 r = bfd_reloc_overflow;
356 else
357 r = bfd_reloc_ok;
358 }
359
360 if (r != bfd_reloc_ok)
361 {
362 switch (r)
363 {
364 default:
365 case bfd_reloc_outofrange:
366 abort ();
367 case bfd_reloc_overflow:
368 {
369 const char *name;
370
371 if (h != NULL)
372 name = h->root.root.string;
373 else
374 {
375 name = (bfd_elf_string_from_elf_section
376 (input_bfd,
377 symtab_hdr->sh_link,
378 sym->st_name));
379 if (name == NULL)
380 return false;
381 if (*name == '\0')
382 name = bfd_section_name (input_bfd, sec);
383 }
384 if (! ((*info->callbacks->reloc_overflow)
385 (info, name, howto->name, (bfd_vma) 0,
386 input_bfd, input_section, rel->r_offset)))
387 return false;
388 }
389 break;
390 }
391 }
392 }
393
394 return true;
395 }
396
397 /* Set the right machine number for a SPARC64 ELF file. */
398
399 static boolean
400 sparc64_elf_object_p (abfd)
401 bfd *abfd;
402 {
403 return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc_v9);
404 }
405
406 #define TARGET_BIG_SYM bfd_elf64_sparc_vec
407 #define TARGET_BIG_NAME "elf64-sparc"
408 #define ELF_ARCH bfd_arch_sparc
409 #define ELF_MACHINE_CODE EM_SPARC64
410 #define ELF_MAXPAGESIZE 0x100000
411
412 #define elf_info_to_howto sparc64_elf_info_to_howto
413 #define bfd_elf64_bfd_reloc_type_lookup sparc64_elf_reloc_type_lookup
414 #define elf_backend_relocate_section sparc64_elf_relocate_section
415 #define elf_backend_object_p sparc64_elf_object_p
416
417 #include "elf64-target.h"
This page took 0.039872 seconds and 4 git commands to generate.