1/* picoJava specific support for 32-bit ELF
2   Copyright 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
3   Contributed by Steve Chamberlan of Transmeta (sac@pobox.com).
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21#include "bfd.h"
22#include "sysdep.h"
23#include "bfdlink.h"
24#include "libbfd.h"
25#include "elf-bfd.h"
26#include "elf/pj.h"
27
28/* This function is used for normal relocs.  This is like the COFF
29   function, and is almost certainly incorrect for other ELF targets.  */
30
31static bfd_reloc_status_type
32pj_elf_reloc (bfd *abfd,
33	      arelent *reloc_entry,
34	      asymbol *symbol_in,
35	      void * data,
36	      asection *input_section,
37	      bfd *output_bfd,
38	      char **error_message ATTRIBUTE_UNUSED)
39{
40  unsigned long insn;
41  bfd_vma sym_value;
42  enum elf_pj_reloc_type r_type;
43  bfd_vma addr = reloc_entry->address;
44  bfd_byte *hit_data = addr + (bfd_byte *) data;
45
46  r_type = (enum elf_pj_reloc_type) reloc_entry->howto->type;
47
48  if (output_bfd != NULL)
49    {
50      /* Partial linking--do nothing.  */
51      reloc_entry->address += input_section->output_offset;
52      return bfd_reloc_ok;
53    }
54
55  if (symbol_in != NULL
56      && bfd_is_und_section (symbol_in->section))
57    return bfd_reloc_undefined;
58
59  if (bfd_is_com_section (symbol_in->section))
60    sym_value = 0;
61  else
62    sym_value = (symbol_in->value +
63		 symbol_in->section->output_section->vma +
64		 symbol_in->section->output_offset);
65
66  switch (r_type)
67    {
68    case R_PJ_DATA_DIR32:
69      insn = bfd_get_32 (abfd, hit_data);
70      insn += sym_value + reloc_entry->addend;
71      bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
72      break;
73
74      /* Relocations in code are always bigendian, no matter what the
75	 data endianness is.  */
76
77    case R_PJ_CODE_DIR32:
78      insn = bfd_getb32 (hit_data);
79      insn += sym_value + reloc_entry->addend;
80      bfd_putb32 ((bfd_vma) insn, hit_data);
81      break;
82
83    case R_PJ_CODE_REL16:
84      insn = bfd_getb16 (hit_data);
85      insn += sym_value + reloc_entry->addend
86        -  (input_section->output_section->vma
87            + input_section->output_offset);
88      bfd_putb16 ((bfd_vma) insn, hit_data);
89      break;
90    case R_PJ_CODE_LO16:
91      insn = bfd_getb16 (hit_data);
92      insn += sym_value + reloc_entry->addend;
93      bfd_putb16 ((bfd_vma) insn, hit_data);
94      break;
95
96    case R_PJ_CODE_HI16:
97      insn = bfd_getb16 (hit_data);
98      insn += (sym_value + reloc_entry->addend) >> 16;
99      bfd_putb16 ((bfd_vma) insn, hit_data);
100      break;
101
102    default:
103      abort ();
104      break;
105    }
106
107  return bfd_reloc_ok;
108}
109
110static reloc_howto_type pj_elf_howto_table[] =
111{
112  /* No relocation.  */
113  HOWTO (R_PJ_NONE,		/* type */
114	 0,			/* rightshift */
115	 0,			/* size (0 = byte, 1 = short, 2 = long) */
116	 0,			/* bitsize */
117	 FALSE,			/* pc_relative */
118	 0,			/* bitpos */
119	 complain_overflow_dont, /* complain_on_overflow */
120	 pj_elf_reloc,		/* special_function */
121	 "R_PJ_NONE",		/* name */
122	 FALSE,			/* partial_inplace */
123	 0,			/* src_mask */
124	 0,			/* dst_mask */
125	 FALSE),		/* pcrel_offset */
126
127  /* 32 bit absolute relocation.  Setting partial_inplace to TRUE and
128     src_mask to a non-zero value is similar to the COFF toolchain.  */
129  HOWTO (R_PJ_DATA_DIR32,	/* type */
130	 0,			/* rightshift */
131	 2,			/* size (0 = byte, 1 = short, 2 = long) */
132	 32,			/* bitsize */
133	 FALSE,			/* pc_relative */
134	 0,			/* bitpos */
135	 complain_overflow_bitfield, /* complain_on_overflow */
136	 pj_elf_reloc,		/* special_function */
137	 "R_PJ_DIR32",		/* name */
138	 TRUE,			/* partial_inplace */
139	 0xffffffff,		/* src_mask */
140	 0xffffffff,		/* dst_mask */
141	 FALSE),		/* pcrel_offset */
142
143  /* 32 bit PC relative relocation.  */
144  HOWTO (R_PJ_CODE_REL32,	/* type */
145	 0,			/* rightshift */
146	 2,			/* size (0 = byte, 1 = short, 2 = long) */
147	 32,			/* bitsize */
148	 TRUE,			/* pc_relative */
149	 0,			/* bitpos */
150	 complain_overflow_signed, /* complain_on_overflow */
151	 pj_elf_reloc,		/* special_function */
152	 "R_PJ_REL32",		/* name */
153	 FALSE,			/* partial_inplace */
154	 0,			/* src_mask */
155	 0xffffffff,		/* dst_mask */
156	 TRUE),			/* pcrel_offset */
157
158/* 16 bit PC relative relocation.  */
159  HOWTO (R_PJ_CODE_REL16,	/* type */
160	 0,			/* rightshift */
161	 1,			/* size (0 = byte, 1 = short, 2 = long) */
162	 16,			/* bitsize */
163	 TRUE,			/* pc_relative */
164	 0,			/* bitpos */
165	 complain_overflow_signed, /* complain_on_overf6w */
166	 pj_elf_reloc,		/* special_function */
167	 "R_PJ_REL16",		/* name */
168	 FALSE,			/* partial_inplace */
169	 0xffff,		/* src_mask */
170	 0xffff,		/* dst_mask */
171	 TRUE),			/* pcrel_offset */
172  EMPTY_HOWTO (4),
173  EMPTY_HOWTO (5),
174  HOWTO (R_PJ_CODE_DIR32,	/* type */
175	 0,			/* rightshift */
176	 2,			/* size (0 = byte, 1 = short, 2 = long) */
177	 32,			/* bitsize */
178	 FALSE,			/* pc_relative */
179	 0,			/* bitpos */
180	 complain_overflow_bitfield, /* complain_on_overflow */
181	 pj_elf_reloc,		/* special_function */
182	 "R_PJ_CODE_DIR32",	/* name */
183	 TRUE,			/* partial_inplace */
184	 0xffffffff,		/* src_mask */
185	 0xffffffff,		/* dst_mask */
186	 FALSE),		/* pcrel_offset */
187
188  EMPTY_HOWTO (7),
189  EMPTY_HOWTO (8),
190  EMPTY_HOWTO (9),
191  EMPTY_HOWTO (10),
192  EMPTY_HOWTO (11),
193  EMPTY_HOWTO (12),
194
195  HOWTO (R_PJ_CODE_LO16,	/* type */
196	 0,			/* rightshift */
197	 1,			/* size (0 = byte, 1 = short, 2 = long) */
198	 16,			/* bitsize */
199	 FALSE,			/* pc_relative */
200	 0,			/* bitpos */
201	 complain_overflow_unsigned, /* complain_on_overflow */
202	 pj_elf_reloc,		/* special_function */
203	 "R_PJ_LO16",		/* name */
204	 FALSE,			/* partial_inplace */
205	 0xffff,		/* src_mask */
206	 0xffff,		/* dst_mask */
207	 TRUE),			/* pcrel_offset */
208
209    HOWTO (R_PJ_CODE_HI16,	/* type */
210	 16,			/* rightshift */
211	 1,			/* size (0 = byte, 1 = short, 2 = long) */
212	 16,			/* bitsize */
213	 FALSE,			/* pc_relative */
214	 0,			/* bitpos */
215	 complain_overflow_unsigned, /* complain_on_overflow */
216	 pj_elf_reloc,		/* special_function */
217	 "R_PJ_HI16",		/* name */
218	 FALSE,			/* partial_inplace */
219	 0xffff,		/* src_mask */
220	 0xffff,		/* dst_mask */
221	 TRUE),			/* pcrel_offset */
222
223  /* GNU extension to record C++ vtable hierarchy.  */
224  HOWTO (R_PJ_GNU_VTINHERIT,    /* type */
225         0,                     /* rightshift */
226         2,                     /* size (0 = byte, 1 = short, 2 = long) */
227         0,                     /* bitsize */
228         FALSE,                 /* pc_relative */
229         0,                     /* bitpos */
230         complain_overflow_dont, /* complain_on_overflow */
231         NULL,                  /* special_function */
232         "R_PJ_GNU_VTINHERIT",  /* name */
233         FALSE,                 /* partial_inplace */
234         0,                     /* src_mask */
235         0,                     /* dst_mask */
236         FALSE),                /* pcrel_offset */
237
238  /* GNU extension to record C++ vtable member usage.  */
239  HOWTO (R_PJ_GNU_VTENTRY,     /* type */
240         0,                     /* rightshift */
241         2,                     /* size (0 = byte, 1 = short, 2 = long) */
242         0,                     /* bitsize */
243         FALSE,                 /* pc_relative */
244         0,                     /* bitpos */
245         complain_overflow_dont, /* complain_on_overflow */
246         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
247         "R_PJ_GNU_VTENTRY",   /* name */
248         FALSE,                 /* partial_inplace */
249         0,                     /* src_mask */
250         0,                     /* dst_mask */
251         FALSE),                /* pcrel_offset */
252};
253
254/* This structure is used to map BFD reloc codes to PJ ELF relocs.  */
255
256struct elf_reloc_map
257{
258  bfd_reloc_code_real_type bfd_reloc_val;
259  unsigned char elf_reloc_val;
260};
261
262/* An array mapping BFD reloc codes to PJ ELF relocs.  */
263
264static const struct elf_reloc_map pj_reloc_map[] =
265{
266    { BFD_RELOC_NONE, 		R_PJ_NONE          },
267    { BFD_RELOC_32, 		R_PJ_DATA_DIR32    },
268    { BFD_RELOC_PJ_CODE_DIR16, 	R_PJ_CODE_DIR16    },
269    { BFD_RELOC_PJ_CODE_DIR32, 	R_PJ_CODE_DIR32    },
270    { BFD_RELOC_PJ_CODE_LO16, 	R_PJ_CODE_LO16     },
271    { BFD_RELOC_PJ_CODE_HI16, 	R_PJ_CODE_HI16     },
272    { BFD_RELOC_PJ_CODE_REL32,  R_PJ_CODE_REL32    },
273    { BFD_RELOC_PJ_CODE_REL16,  R_PJ_CODE_REL16    },
274    { BFD_RELOC_VTABLE_INHERIT, R_PJ_GNU_VTINHERIT },
275    { BFD_RELOC_VTABLE_ENTRY,   R_PJ_GNU_VTENTRY   },
276};
277
278/* Given a BFD reloc code, return the howto structure for the
279   corresponding PJ ELf reloc.  */
280
281static reloc_howto_type *
282pj_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
283			  bfd_reloc_code_real_type code)
284{
285  unsigned int i;
286
287  for (i = 0; i < sizeof (pj_reloc_map) / sizeof (struct elf_reloc_map); i++)
288    if (pj_reloc_map[i].bfd_reloc_val == code)
289      return & pj_elf_howto_table[(int) pj_reloc_map[i].elf_reloc_val];
290
291  return NULL;
292}
293
294/* Given an ELF reloc, fill in the howto field of a relent.  */
295
296static void
297pj_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
298		      arelent *cache_ptr,
299		      Elf_Internal_Rela *dst)
300{
301  unsigned int r;
302
303  r = ELF32_R_TYPE (dst->r_info);
304
305  BFD_ASSERT (r < (unsigned int) R_PJ_max);
306
307  cache_ptr->howto = &pj_elf_howto_table[r];
308}
309
310/* Take this moment to fill in the special picoJava bits in the
311   e_flags field.  */
312
313static void
314pj_elf_final_write_processing (bfd *abfd,
315			       bfd_boolean linker ATTRIBUTE_UNUSED)
316{
317  elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_ARCH;
318  elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_GNUCALLS;
319}
320
321#define TARGET_BIG_SYM		bfd_elf32_pj_vec
322#define TARGET_BIG_NAME		"elf32-pj"
323#define TARGET_LITTLE_SYM	bfd_elf32_pjl_vec
324#define TARGET_LITTLE_NAME	"elf32-pjl"
325#define ELF_ARCH		bfd_arch_pj
326#define ELF_MACHINE_CODE	EM_PJ
327#define ELF_MACHINE_ALT1	EM_PJ_OLD
328#define ELF_MAXPAGESIZE		0x1000
329#define bfd_elf32_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
330#define bfd_elf32_bfd_reloc_type_lookup	             pj_elf_reloc_type_lookup
331#define elf_backend_final_write_processing           pj_elf_final_write_processing
332#define elf_info_to_howto		             pj_elf_info_to_howto
333#include "elf32-target.h"
334