Add new binutils target: moxie
[platform/upstream/binutils.git] / bfd / elf32-moxie.c
1 /* moxie-specific support for 32-bit ELF.
2    Copyright 2008 Anthony Green.
3    Copyright 2009 Free Software Foundation, Inc.
4
5    Copied from elf32-fr30.c which is..
6    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
7    Free Software Foundation, Inc.
8
9    This file is part of BFD, the Binary File Descriptor library.
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24    MA 02110-1301, USA.  */
25
26 #include "sysdep.h"
27 #include "bfd.h"
28 #include "libbfd.h"
29 #include "elf-bfd.h"
30 #include "elf/moxie.h"
31
32 /* Forward declarations.  */
33
34 static reloc_howto_type moxie_elf_howto_table [] =
35 {
36   /* This reloc does nothing.  */
37   HOWTO (R_MOXIE_NONE,          /* type */
38          0,                     /* rightshift */
39          2,                     /* size (0 = byte, 1 = short, 2 = long) */
40          32,                    /* bitsize */
41          FALSE,                 /* pc_relative */
42          0,                     /* bitpos */
43          complain_overflow_bitfield, /* complain_on_overflow */
44          bfd_elf_generic_reloc, /* special_function */
45          "R_MOXIE_NONE",                /* name */
46          FALSE,                 /* partial_inplace */
47          0,                     /* src_mask */
48          0,                     /* dst_mask */
49          FALSE),                /* pcrel_offset */
50
51   /* A 32 bit absolute relocation.  */
52   HOWTO (R_MOXIE_32,            /* type */
53          0,                     /* rightshift */
54          2,                     /* size (0 = byte, 1 = short, 2 = long) */
55          32,                    /* bitsize */
56          FALSE,                 /* pc_relative */
57          0,                     /* bitpos */
58          complain_overflow_bitfield, /* complain_on_overflow */
59          bfd_elf_generic_reloc, /* special_function */
60          "R_MOXIE_32",          /* name */
61          FALSE,                 /* partial_inplace */
62          0x00000000,            /* src_mask */
63          0xffffffff,            /* dst_mask */
64          FALSE),                /* pcrel_offset */
65 };
66 \f
67 /* Map BFD reloc types to MOXIE ELF reloc types.  */
68
69 struct moxie_reloc_map
70 {
71   bfd_reloc_code_real_type bfd_reloc_val;
72   unsigned int moxie_reloc_val;
73 };
74
75 static const struct moxie_reloc_map moxie_reloc_map [] =
76 {
77   { BFD_RELOC_NONE,           R_MOXIE_NONE },
78   { BFD_RELOC_32,             R_MOXIE_32 },
79 };
80
81 static reloc_howto_type *
82 moxie_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
83                          bfd_reloc_code_real_type code)
84 {
85   unsigned int i;
86
87   for (i = sizeof (moxie_reloc_map) / sizeof (moxie_reloc_map[0]);
88        --i;)
89     if (moxie_reloc_map [i].bfd_reloc_val == code)
90       return & moxie_elf_howto_table [moxie_reloc_map[i].moxie_reloc_val];
91
92   return NULL;
93 }
94
95 static reloc_howto_type *
96 moxie_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
97 {
98   unsigned int i;
99
100   for (i = 0;
101        i < sizeof (moxie_elf_howto_table) / sizeof (moxie_elf_howto_table[0]);
102        i++)
103     if (moxie_elf_howto_table[i].name != NULL
104         && strcasecmp (moxie_elf_howto_table[i].name, r_name) == 0)
105       return &moxie_elf_howto_table[i];
106
107   return NULL;
108 }
109
110 /* Set the howto pointer for an MOXIE ELF reloc.  */
111
112 static void
113 moxie_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
114                           arelent *cache_ptr,
115                           Elf_Internal_Rela *dst)
116 {
117   unsigned int r_type;
118
119   r_type = ELF32_R_TYPE (dst->r_info);
120   BFD_ASSERT (r_type < (unsigned int) R_MOXIE_max);
121   cache_ptr->howto = & moxie_elf_howto_table [r_type];
122 }
123 \f
124 /* Perform a single relocation.  By default we use the standard BFD
125    routines, but a few relocs, we have to do them ourselves.  */
126
127 static bfd_reloc_status_type
128 moxie_final_link_relocate (reloc_howto_type *howto,
129                            bfd *input_bfd,
130                            asection *input_section,
131                            bfd_byte *contents,
132                            Elf_Internal_Rela *rel,
133                            bfd_vma relocation)
134 {
135   bfd_reloc_status_type r = bfd_reloc_ok;
136
137   switch (howto->type)
138     {
139     default:
140       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
141                                     contents, rel->r_offset,
142                                     relocation, rel->r_addend);
143     }
144
145   return r;
146 }
147 \f
148 /* Relocate an MOXIE ELF section.
149
150    The RELOCATE_SECTION function is called by the new ELF backend linker
151    to handle the relocations for a section.
152
153    The relocs are always passed as Rela structures; if the section
154    actually uses Rel structures, the r_addend field will always be
155    zero.
156
157    This function is responsible for adjusting the section contents as
158    necessary, and (if using Rela relocs and generating a relocatable
159    output file) adjusting the reloc addend as necessary.
160
161    This function does not have to worry about setting the reloc
162    address or the reloc symbol index.
163
164    LOCAL_SYMS is a pointer to the swapped in local symbols.
165
166    LOCAL_SECTIONS is an array giving the section in the input file
167    corresponding to the st_shndx field of each local symbol.
168
169    The global hash table entry for the global symbols can be found
170    via elf_sym_hashes (input_bfd).
171
172    When generating relocatable output, this function must handle
173    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
174    going to be the section symbol corresponding to the output
175    section, which means that the addend must be adjusted
176    accordingly.  */
177
178 static bfd_boolean
179 moxie_elf_relocate_section (bfd *output_bfd,
180                             struct bfd_link_info *info,
181                             bfd *input_bfd,
182                             asection *input_section,
183                             bfd_byte *contents,
184                             Elf_Internal_Rela *relocs,
185                             Elf_Internal_Sym *local_syms,
186                             asection **local_sections)
187 {
188   Elf_Internal_Shdr *symtab_hdr;
189   struct elf_link_hash_entry **sym_hashes;
190   Elf_Internal_Rela *rel;
191   Elf_Internal_Rela *relend;
192
193   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
194   sym_hashes = elf_sym_hashes (input_bfd);
195   relend     = relocs + input_section->reloc_count;
196
197   for (rel = relocs; rel < relend; rel ++)
198     {
199       reloc_howto_type *howto;
200       unsigned long r_symndx;
201       Elf_Internal_Sym *sym;
202       asection *sec;
203       struct elf_link_hash_entry *h;
204       bfd_vma relocation;
205       bfd_reloc_status_type r;
206       const char *name;
207       int r_type;
208
209       r_type = ELF32_R_TYPE (rel->r_info);
210
211       r_symndx = ELF32_R_SYM (rel->r_info);
212
213       howto  = moxie_elf_howto_table + ELF32_R_TYPE (rel->r_info);
214       h      = NULL;
215       sym    = NULL;
216       sec    = NULL;
217
218       if (r_symndx < symtab_hdr->sh_info)
219         {
220           sym = local_syms + r_symndx;
221           sec = local_sections [r_symndx];
222           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
223
224           name = bfd_elf_string_from_elf_section
225             (input_bfd, symtab_hdr->sh_link, sym->st_name);
226           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
227         }
228       else
229         {
230           bfd_boolean unresolved_reloc, warned;
231
232           RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
233                                    r_symndx, symtab_hdr, sym_hashes,
234                                    h, sec, relocation,
235                                    unresolved_reloc, warned);
236
237           name = h->root.root.string;
238         }
239
240       if (sec != NULL && elf_discarded_section (sec))
241         {
242           /* For relocs against symbols from removed linkonce sections,
243              or sections discarded by a linker script, we just want the
244              section contents zeroed.  Avoid any special processing.  */
245           _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
246           rel->r_info = 0;
247           rel->r_addend = 0;
248           continue;
249         }
250
251       if (info->relocatable)
252         continue;
253
254       r = moxie_final_link_relocate (howto, input_bfd, input_section,
255                                      contents, rel, relocation);
256
257       if (r != bfd_reloc_ok)
258         {
259           const char * msg = NULL;
260
261           switch (r)
262             {
263             case bfd_reloc_overflow:
264               r = info->callbacks->reloc_overflow
265                 (info, (h ? &h->root : NULL), name, howto->name,
266                  (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
267               break;
268
269             case bfd_reloc_undefined:
270               r = info->callbacks->undefined_symbol
271                 (info, name, input_bfd, input_section, rel->r_offset,
272                  TRUE);
273               break;
274
275             case bfd_reloc_outofrange:
276               msg = _("internal error: out of range error");
277               break;
278
279             case bfd_reloc_notsupported:
280               msg = _("internal error: unsupported relocation error");
281               break;
282
283             case bfd_reloc_dangerous:
284               msg = _("internal error: dangerous relocation");
285               break;
286
287             default:
288               msg = _("internal error: unknown error");
289               break;
290             }
291
292           if (msg)
293             r = info->callbacks->warning
294               (info, msg, name, input_bfd, input_section, rel->r_offset);
295
296           if (! r)
297             return FALSE;
298         }
299     }
300
301   return TRUE;
302 }
303 \f
304 /* Return the section that should be marked against GC for a given
305    relocation.  */
306
307 static asection *
308 moxie_elf_gc_mark_hook (asection *sec,
309                         struct bfd_link_info *info,
310                         Elf_Internal_Rela *rel,
311                         struct elf_link_hash_entry *h,
312                         Elf_Internal_Sym *sym)
313 {
314   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
315 }
316
317 /* Look through the relocs for a section during the first phase.
318    Since we don't do .gots or .plts, we just need to consider the
319    virtual table relocs for gc.  */
320
321 static bfd_boolean
322 moxie_elf_check_relocs (bfd *abfd,
323                         struct bfd_link_info *info,
324                         asection *sec,
325                         const Elf_Internal_Rela *relocs)
326 {
327   Elf_Internal_Shdr *symtab_hdr;
328   struct elf_link_hash_entry **sym_hashes;
329   const Elf_Internal_Rela *rel;
330   const Elf_Internal_Rela *rel_end;
331
332   if (info->relocatable)
333     return TRUE;
334
335   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
336   sym_hashes = elf_sym_hashes (abfd);
337
338   rel_end = relocs + sec->reloc_count;
339   for (rel = relocs; rel < rel_end; rel++)
340     {
341       struct elf_link_hash_entry *h;
342       unsigned long r_symndx;
343
344       r_symndx = ELF32_R_SYM (rel->r_info);
345       if (r_symndx < symtab_hdr->sh_info)
346         h = NULL;
347       else
348         {
349           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
350           while (h->root.type == bfd_link_hash_indirect
351                  || h->root.type == bfd_link_hash_warning)
352             h = (struct elf_link_hash_entry *) h->root.u.i.link;
353         }
354     }
355
356   return TRUE;
357 }
358 \f
359 #define ELF_ARCH                bfd_arch_moxie
360 #define ELF_MACHINE_CODE        EM_MOXIE
361 #define ELF_MAXPAGESIZE         0x1
362
363 #define TARGET_BIG_SYM          bfd_elf32_moxie_vec
364 #define TARGET_BIG_NAME         "elf32-moxie"
365
366 #define elf_info_to_howto_rel                   NULL
367 #define elf_info_to_howto                       moxie_info_to_howto_rela
368 #define elf_backend_relocate_section            moxie_elf_relocate_section
369 #define elf_backend_gc_mark_hook                moxie_elf_gc_mark_hook
370 #define elf_backend_check_relocs                moxie_elf_check_relocs
371
372 #define elf_backend_can_gc_sections             1
373 #define elf_backend_rela_normal                 1
374
375 #define bfd_elf32_bfd_reloc_type_lookup         moxie_reloc_type_lookup
376 #define bfd_elf32_bfd_reloc_name_lookup         moxie_reloc_name_lookup
377
378 #include "elf32-target.h"