Add support for 9_PCREL and 12_PCREL relocs.
[external/binutils.git] / bfd / elf32-fr30.c
1 /* FR30-specific support for 32-bit ELF.
2    Copyright (C) 1998 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 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/fr30.h"
25
26 /* Forward declarations.  */
27 static bfd_reloc_status_type fr30_elf_i20_reloc
28   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
29 static bfd_reloc_status_type fr30_elf_i32_reloc
30   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
31 static bfd_reloc_status_type fr30_elf_pc9_reloc
32   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
33 static bfd_reloc_status_type fr30_elf_pc12_reloc
34   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
35 static reloc_howto_type * fr30_reloc_type_lookup
36   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
37 static void fr30_info_to_howto_rela 
38   PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
39 static boolean fr30_elf_relocate_section 
40   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
41 static bfd_reloc_status_type fr30_final_link_relocate
42   PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma));
43
44 static reloc_howto_type fr30_elf_howto_table [] =
45 {
46   /* This reloc does nothing.  */
47   HOWTO (R_FR30_NONE,           /* type */
48          0,                     /* rightshift */
49          2,                     /* size (0 = byte, 1 = short, 2 = long) */
50          32,                    /* bitsize */
51          false,                 /* pc_relative */
52          0,                     /* bitpos */
53          complain_overflow_bitfield, /* complain_on_overflow */
54          bfd_elf_generic_reloc, /* special_function */
55          "R_FR30_NONE",         /* name */
56          false,                 /* partial_inplace */
57          0,                     /* src_mask */
58          0,                     /* dst_mask */
59          false),                /* pcrel_offset */
60
61   /* An 8 bit absolute relocation.  */
62   HOWTO (R_FR30_8,              /* type */
63          0,                     /* rightshift */
64          1,                     /* size (0 = byte, 1 = short, 2 = long) */
65          8,                     /* bitsize */
66          false,                 /* pc_relative */
67          4,                     /* bitpos */
68          complain_overflow_bitfield, /* complain_on_overflow */
69          bfd_elf_generic_reloc, /* special_function */
70          "R_FR30_8",            /* name */
71          true,                  /* partial_inplace */
72          0x0ff0,                /* src_mask */
73          0x0ff0,                /* dst_mask */
74          false),                /* pcrel_offset */
75
76   /* A 20 bit absolute relocation.  */
77   HOWTO (R_FR30_20,             /* type */
78          0,                     /* rightshift */
79          2,                     /* size (0 = byte, 1 = short, 2 = long) */
80          20,                    /* bitsize */
81          false,                 /* pc_relative */
82          0,                     /* bitpos */
83          complain_overflow_bitfield, /* complain_on_overflow */
84          fr30_elf_i20_reloc,    /* special_function */
85          "R_FR30_20",           /* name */
86          true,                  /* partial_inplace */
87          0x00f0ffff,            /* src_mask */
88          0x00f0ffff,            /* dst_mask */
89          false),                /* pcrel_offset */
90
91   /* A 32 bit absolute relocation.  */
92   HOWTO (R_FR30_32,             /* type */
93          0,                     /* rightshift */
94          2,                     /* size (0 = byte, 1 = short, 2 = long) */
95          32,                    /* bitsize */
96          false,                 /* pc_relative */
97          0,                     /* bitpos */
98          complain_overflow_bitfield, /* complain_on_overflow */
99          fr30_elf_i32_reloc,    /* special_function */
100          "R_FR30_32",           /* name */
101          true,                  /* partial_inplace */
102          0xffffffff,            /* src_mask */
103          0xffffffff,            /* dst_mask */
104          false),                /* pcrel_offset */
105
106   /* A 6 bit absolute relocation.  */
107   HOWTO (R_FR30_6_IN_4,         /* type */
108          2,                     /* rightshift */
109          1,                     /* size (0 = byte, 1 = short, 2 = long) */
110          6,                     /* bitsize */
111          false,                 /* pc_relative */
112          4,                     /* bitpos */
113          complain_overflow_unsigned, /* complain_on_overflow */
114          bfd_elf_generic_reloc, /* special_function */
115          "R_FR30_6_IN_4",       /* name */
116          true,                  /* partial_inplace */
117          0x00f0,                /* src_mask */
118          0x00f0,                /* dst_mask */
119          false),                /* pcrel_offset */
120   
121   /* An 8 bit absolute relocation.  */
122   HOWTO (R_FR30_8_IN_8,         /* type */
123          0,                     /* rightshift */
124          1,                     /* size (0 = byte, 1 = short, 2 = long) */
125          8,                     /* bitsize */
126          false,                 /* pc_relative */
127          4,                     /* bitpos */
128          complain_overflow_signed, /* complain_on_overflow */
129          bfd_elf_generic_reloc,/* special_function */
130          "R_FR30_8_IN_8",       /* name */
131          true,                  /* partial_inplace */
132          0x0ff0,                /* src_mask */
133          0x0ff0,                /* dst_mask */
134          false),                /* pcrel_offset */
135   
136   /* A 9 bit absolute relocation.  */
137   HOWTO (R_FR30_9_IN_8,         /* type */
138          1,                     /* rightshift */
139          1,                     /* size (0 = byte, 1 = short, 2 = long) */
140          9,                     /* bitsize */
141          false,                 /* pc_relative */
142          4,                     /* bitpos */
143          complain_overflow_signed, /* complain_on_overflow */
144          bfd_elf_generic_reloc,/* special_function */
145          "R_FR30_9_IN_8",       /* name */
146          true,                  /* partial_inplace */
147          0x0ff0,                /* src_mask */
148          0x0ff0,                /* dst_mask */
149          false),                /* pcrel_offset */
150   
151   /* A 10 bit absolute relocation.  */
152   HOWTO (R_FR30_10_IN_8,        /* type */
153          2,                     /* rightshift */
154          1,                     /* size (0 = byte, 1 = short, 2 = long) */
155          10,                    /* bitsize */
156          false,                 /* pc_relative */
157          4,                     /* bitpos */
158          complain_overflow_signed, /* complain_on_overflow */
159          bfd_elf_generic_reloc,/* special_function */
160          "R_FR30_10_IN_8",      /* name */
161          true,                  /* partial_inplace */
162          0x0ff0,                /* src_mask */
163          0x0ff0,                /* dst_mask */
164          false),                /* pcrel_offset */
165
166   /* A PC relative 9 bit relocation, right shifted by 1.  */
167   HOWTO (R_FR30_9_PCREL,        /* type */
168          1,                     /* rightshift */
169          1,                     /* size (0 = byte, 1 = short, 2 = long) */
170          9,                     /* bitsize */
171          true,                  /* pc_relative */
172          0,                     /* bitpos */
173          complain_overflow_signed, /* complain_on_overflow */
174          fr30_elf_pc9_reloc,    /* special_function */
175          "R_FR30_9_PCREL",      /* name */
176          false,                 /* partial_inplace */
177          0x00ff,                /* src_mask */
178          0x00ff,                /* dst_mask */
179          false),                /* pcrel_offset */
180
181   /* A PC relative 12 bit relocation, right shifted by 1.  */
182   HOWTO (R_FR30_12_PCREL,       /* type */
183          1,                     /* rightshift */
184          1,                     /* size (0 = byte, 1 = short, 2 = long) */
185          12,                    /* bitsize */
186          true,                  /* pc_relative */
187          0,                     /* bitpos */
188          complain_overflow_signed, /* complain_on_overflow */
189          fr30_elf_pc12_reloc,   /* special_function */
190          "R_FR30_12_PCREL",     /* name */
191          false,                 /* partial_inplace */
192          0x07ff,                /* src_mask */
193          0x07ff,                /* dst_mask */
194          false),                /* pcrel_offset */
195 };
196 \f
197 /* Utility to actually perform an R_FR30_20 reloc.  */
198
199 static bfd_reloc_status_type
200 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
201                     input_section, output_bfd, error_message)
202      bfd *      abfd;
203      arelent *  reloc_entry;
204      asymbol *  symbol;
205      PTR        data;
206      asection * input_section;
207      bfd *      output_bfd;
208      char **    error_message;
209 {
210   bfd_vma       relocation;
211   unsigned long x;
212   
213   /* This part is from bfd_elf_generic_reloc.  */
214   if (output_bfd != (bfd *) NULL
215       && (symbol->flags & BSF_SECTION_SYM) == 0
216       && (! reloc_entry->howto->partial_inplace
217           || reloc_entry->addend == 0))
218     {
219       reloc_entry->address += input_section->output_offset;
220       return bfd_reloc_ok;
221     }
222
223   if (output_bfd != NULL)
224     /* FIXME: See bfd_perform_relocation.  Is this right?  */
225     return bfd_reloc_ok;
226
227   relocation =
228     symbol->value
229     + symbol->section->output_section->vma
230     + symbol->section->output_offset
231     + reloc_entry->addend;
232
233   if (relocation > ((1U << 20) - 1))
234     return bfd_reloc_overflow;
235
236   x = bfd_get_32 (abfd, data + reloc_entry->address);
237   x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
238   bfd_put_32 (abfd, x, data + reloc_entry->address);
239
240   return bfd_reloc_ok;
241 }
242
243 \f
244 /* Utility to actually perform a R_FR30_32 reloc.  */
245
246 static bfd_reloc_status_type
247 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
248                     input_section, output_bfd, error_message)
249      bfd *      abfd;
250      arelent *  reloc_entry;
251      asymbol *  symbol;
252      PTR        data;
253      asection * input_section;
254      bfd *      output_bfd;
255      char **    error_message;
256 {
257   bfd_vma       relocation;
258
259   /* This part is from bfd_elf_generic_reloc.  */
260   if (output_bfd != (bfd *) NULL
261       && (symbol->flags & BSF_SECTION_SYM) == 0
262       && (! reloc_entry->howto->partial_inplace
263           || reloc_entry->addend == 0))
264     {
265       reloc_entry->address += input_section->output_offset;
266       return bfd_reloc_ok;
267     }
268
269   if (output_bfd != NULL)
270     /* FIXME: See bfd_perform_relocation.  Is this right?  */
271     return bfd_reloc_ok;
272
273   relocation =
274     symbol->value
275     + symbol->section->output_section->vma
276     + symbol->section->output_offset
277     + reloc_entry->addend;
278
279   bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
280
281   return bfd_reloc_ok;
282 }
283
284 \f
285 /* Utility to actually perform a R_FR30_9_PCREL reloc.  */
286
287 static bfd_reloc_status_type
288 fr30_elf_pc9_reloc (abfd, reloc_entry, symbol, data,
289                     input_section, output_bfd, error_message)
290      bfd *      abfd;
291      arelent *  reloc_entry;
292      asymbol *  symbol;
293      PTR        data;
294      asection * input_section;
295      bfd *      output_bfd;
296      char **    error_message;
297 {
298   bfd_signed_vma       relocation;
299
300   /* This part is from bfd_elf_generic_reloc.  */
301   if (output_bfd != (bfd *) NULL
302       && (symbol->flags & BSF_SECTION_SYM) == 0
303       && (! reloc_entry->howto->partial_inplace
304           || reloc_entry->addend == 0))
305     {
306       reloc_entry->address += input_section->output_offset;
307       return bfd_reloc_ok;
308     }
309
310   if (output_bfd != NULL)
311     /* FIXME: See bfd_perform_relocation.  Is this right?  */
312     return bfd_reloc_ok;
313
314   relocation =
315     symbol->value
316     + symbol->section->output_section->vma
317     + symbol->section->output_offset
318     + reloc_entry->addend
319     - input_section->output_section->vma
320     - input_section->output_offset
321     - 2;
322
323   if (relocation & 1)
324     return bfd_reloc_outofrange;
325
326   if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
327     return bfd_reloc_overflow;
328
329   bfd_put_8 (abfd, relocation >> 1, data + reloc_entry->address + 1);
330
331   return bfd_reloc_ok;
332 }
333
334 \f
335 /* Utility to actually perform a R_FR30_12_PCREL reloc.  */
336
337 static bfd_reloc_status_type
338 fr30_elf_pc12_reloc (abfd, reloc_entry, symbol, data,
339                     input_section, output_bfd, error_message)
340      bfd *      abfd;
341      arelent *  reloc_entry;
342      asymbol *  symbol;
343      PTR        data;
344      asection * input_section;
345      bfd *      output_bfd;
346      char **    error_message;
347 {
348   bfd_signed_vma        relocation;
349   bfd_vma               x;
350
351   
352   /* This part is from bfd_elf_generic_reloc.  */
353   if (output_bfd != (bfd *) NULL
354       && (symbol->flags & BSF_SECTION_SYM) == 0
355       && (! reloc_entry->howto->partial_inplace
356           || reloc_entry->addend == 0))
357     {
358       reloc_entry->address += input_section->output_offset;
359       return bfd_reloc_ok;
360     }
361
362   if (output_bfd != NULL)
363     /* FIXME: See bfd_perform_relocation.  Is this right?  */
364     return bfd_reloc_ok;
365
366   relocation =
367     symbol->value
368     + symbol->section->output_section->vma
369     + symbol->section->output_offset
370     + reloc_entry->addend
371     - input_section->output_section->vma
372     - input_section->output_offset
373     - 2;
374
375   if (relocation & 1)
376     return bfd_reloc_outofrange;
377
378   if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
379     return bfd_reloc_overflow;
380
381   data += reloc_entry->address;
382   
383   x = bfd_get_16 (abfd, data);
384   x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
385   bfd_put_16 (abfd, x, data);
386
387   return bfd_reloc_ok;
388 }
389
390 \f
391 /* Map BFD reloc types to FR30 ELF reloc types.  */
392
393 struct fr30_reloc_map
394 {
395   unsigned int bfd_reloc_val;
396   unsigned int fr30_reloc_val;
397 };
398
399 static const struct fr30_reloc_map fr30_reloc_map [] =
400 {
401   { BFD_RELOC_NONE,           R_FR30_NONE },
402   { BFD_RELOC_8,              R_FR30_8 },
403   { BFD_RELOC_FR30_20,        R_FR30_20 },
404   { BFD_RELOC_32,             R_FR30_32 },
405   { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
406   { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
407   { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
408   { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
409   { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
410   { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
411 };
412
413 static reloc_howto_type *
414 fr30_reloc_type_lookup (abfd, code)
415      bfd * abfd;
416      bfd_reloc_code_real_type code;
417 {
418   unsigned int i;
419
420   for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
421        --i;)
422     if (fr30_reloc_map [i].bfd_reloc_val == code)
423       return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
424   
425   return NULL;
426 }
427
428 /* Set the howto pointer for an FR30 ELF reloc.  */
429
430 static void
431 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
432      bfd * abfd;
433      arelent * cache_ptr;
434      Elf32_Internal_Rela * dst;
435 {
436   unsigned int r_type;
437
438   r_type = ELF32_R_TYPE (dst->r_info);
439   BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
440   cache_ptr->howto = & fr30_elf_howto_table [r_type];
441 }
442 \f
443 /* Perform a single relocation.  By default we use the standard BFD
444    routines, but a few relocs, we have to do them ourselves.  */
445
446 static bfd_reloc_status_type
447 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
448      reloc_howto_type *  howto;
449      bfd *               input_bfd;
450      asection *          input_section;
451      bfd_byte *          contents;
452      Elf_Internal_Rela * rel;
453      bfd_vma             relocation;
454 {
455   bfd_reloc_status_type r = bfd_reloc_ok;
456   bfd_vma               x;
457   
458   switch (howto->type)
459     {
460     case R_FR30_20:
461       contents   += rel->r_offset;
462       relocation += rel->r_addend;
463
464       if (relocation > ((1 << 20) - 1))
465         return bfd_reloc_overflow;
466       
467       x = bfd_get_32 (input_bfd, contents);
468       x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
469       bfd_put_32 (input_bfd, relocation, contents);
470       break;
471       
472     case R_FR30_32:
473       contents   += rel->r_offset + 2;
474       relocation += rel->r_addend;
475       bfd_put_32 (input_bfd, relocation, contents);
476       break;
477
478     case R_FR30_9_PCREL:
479       contents   += rel->r_offset + 1;
480       relocation += rel->r_addend;
481       relocation -= (input_section->output_section->vma +
482                      input_section->output_offset);
483       
484       if (relocation & 1)
485         return bfd_reloc_outofrange;
486       if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
487         return bfd_reloc_overflow;
488       
489       bfd_put_8 (input_bfd, relocation >> 1, contents);
490       break;
491
492     case R_FR30_12_PCREL:
493       contents   += rel->r_offset;
494       relocation += rel->r_addend;
495       relocation -= (input_section->output_section->vma +
496                      input_section->output_offset);
497       
498       if (relocation & 1)
499         return bfd_reloc_outofrange;
500       if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
501         return bfd_reloc_overflow;
502       
503       x = bfd_get_16 (input_bfd, contents);
504       x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
505       bfd_put_16 (input_bfd, x, contents);
506       break;
507
508     default:
509       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
510                                     contents, rel->r_offset,
511                                     relocation, rel->r_addend);
512     }
513
514   return r;
515 }
516
517 \f
518 /* Relocate an FR30 ELF section.
519    There is some attempt to make this function usable for many architectures,
520    both USE_REL and USE_RELA ['twould be nice if such a critter existed],
521    if only to serve as a learning tool.
522
523    The RELOCATE_SECTION function is called by the new ELF backend linker
524    to handle the relocations for a section.
525
526    The relocs are always passed as Rela structures; if the section
527    actually uses Rel structures, the r_addend field will always be
528    zero.
529
530    This function is responsible for adjusting the section contents as
531    necessary, and (if using Rela relocs and generating a relocateable
532    output file) adjusting the reloc addend as necessary.
533
534    This function does not have to worry about setting the reloc
535    address or the reloc symbol index.
536
537    LOCAL_SYMS is a pointer to the swapped in local symbols.
538
539    LOCAL_SECTIONS is an array giving the section in the input file
540    corresponding to the st_shndx field of each local symbol.
541
542    The global hash table entry for the global symbols can be found
543    via elf_sym_hashes (input_bfd).
544
545    When generating relocateable output, this function must handle
546    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
547    going to be the section symbol corresponding to the output
548    section, which means that the addend must be adjusted
549    accordingly.  */
550
551 static boolean
552 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
553                            contents, relocs, local_syms, local_sections)
554      bfd *                   output_bfd;
555      struct bfd_link_info *  info;
556      bfd *                   input_bfd;
557      asection *              input_section;
558      bfd_byte *              contents;
559      Elf_Internal_Rela *     relocs;
560      Elf_Internal_Sym *      local_syms;
561      asection **             local_sections;
562 {
563   Elf_Internal_Shdr *           symtab_hdr;
564   struct elf_link_hash_entry ** sym_hashes;
565   Elf_Internal_Rela *           rel;
566   Elf_Internal_Rela *           relend;
567
568   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
569   sym_hashes = elf_sym_hashes (input_bfd);
570   relend     = relocs + input_section->reloc_count;
571
572   for (rel = relocs; rel < relend; rel ++)
573     {
574       reloc_howto_type *           howto;
575       unsigned long                r_symndx;
576       Elf_Internal_Sym *           sym;
577       asection *                   sec;
578       struct elf_link_hash_entry * h;
579       bfd_vma                      relocation;
580       bfd_reloc_status_type        r;
581       const char *                 name = NULL;
582
583       r_symndx = ELF32_R_SYM (rel->r_info);
584
585       if (info->relocateable)
586         {
587           /* This is a relocateable link.  We don't have to change
588              anything, unless the reloc is against a section symbol,
589              in which case we have to adjust according to where the
590              section symbol winds up in the output section.  */
591           if (r_symndx < symtab_hdr->sh_info)
592             {
593               sym = local_syms + r_symndx;
594               
595               if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
596                 {
597                   sec = local_sections [r_symndx];
598                   rel->r_addend += sec->output_offset + sym->st_value;
599                 }
600             }
601
602           continue;
603         }
604
605       /* This is a final link.  */
606       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
607       h      = NULL;
608       sym    = NULL;
609       sec    = NULL;
610       
611       if (r_symndx < symtab_hdr->sh_info)
612         {
613           sym = local_syms + r_symndx;
614           sec = local_sections [r_symndx];
615           relocation = (sec->output_section->vma
616                         + sec->output_offset
617                         + sym->st_value);
618           
619           name = bfd_elf_string_from_elf_section
620             (input_bfd, symtab_hdr->sh_link, sym->st_name);
621           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
622 #if 0
623           fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
624                    sec->name, name, sym->st_name,
625                    sec->output_section->vma, sec->output_offset,
626                    sym->st_value, rel->r_addend);
627 #endif
628         }
629       else
630         {
631           h = sym_hashes [r_symndx - symtab_hdr->sh_info];
632           
633           while (h->root.type == bfd_link_hash_indirect
634                  || h->root.type == bfd_link_hash_warning)
635             h = (struct elf_link_hash_entry *) h->root.u.i.link;
636
637           name = h->root.root.string;
638           
639           if (h->root.type == bfd_link_hash_defined
640               || h->root.type == bfd_link_hash_defweak)
641             {
642               sec = h->root.u.def.section;
643               relocation = (h->root.u.def.value
644                             + sec->output_section->vma
645                             + sec->output_offset);
646 #if 0
647               fprintf (stderr,
648                        "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
649                        sec->name, name, h->root.u.def.value,
650                        sec->output_section->vma, sec->output_offset, relocation);
651 #endif
652             }
653           else if (h->root.type == bfd_link_hash_undefweak)
654             {
655 #if 0
656               fprintf (stderr, "undefined: sec: %s, name: %s\n",
657                        sec->name, name);
658 #endif
659               relocation = 0;
660             }
661           else
662             {
663               if (! ((*info->callbacks->undefined_symbol)
664                      (info, h->root.root.string, input_bfd,
665                       input_section, rel->r_offset)))
666                 return false;
667 #if 0
668               fprintf (stderr, "unknown: name: %s\n", name);
669 #endif
670               relocation = 0;
671             }
672         }
673       
674       r = fr30_final_link_relocate (howto, input_bfd, input_section,
675                                      contents, rel, relocation);
676
677       if (r != bfd_reloc_ok)
678         {
679           const char * msg = (const char *) NULL;
680
681           switch (r)
682             {
683             case bfd_reloc_overflow:
684               r = info->callbacks->reloc_overflow
685                 (info, name, howto->name, (bfd_vma) 0,
686                  input_bfd, input_section, rel->r_offset);
687               break;
688               
689             case bfd_reloc_undefined:
690               r = info->callbacks->undefined_symbol
691                 (info, name, input_bfd, input_section, rel->r_offset);
692               break;
693               
694             case bfd_reloc_outofrange:
695               msg = _("internal error: out of range error");
696               break;
697
698             case bfd_reloc_notsupported:
699               msg = _("internal error: unsupported relocation error");
700               break;
701
702             case bfd_reloc_dangerous:
703               msg = _("internal error: dangerous relocation");
704               break;
705
706             default:
707               msg = _("internal error: unknown error");
708               break;
709             }
710
711           if (msg)
712             r = info->callbacks->warning
713               (info, msg, name, input_bfd, input_section, rel->r_offset);
714
715           if (! r)
716             return false;
717         }
718     }
719
720   return true;
721 }
722 \f
723 #define ELF_ARCH                bfd_arch_fr30
724 #define ELF_MACHINE_CODE        EM_CYGNUS_FR30
725 #define ELF_MAXPAGESIZE         0x1000
726
727 #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
728 #define TARGET_BIG_NAME         "elf32-fr30"
729
730 #define elf_info_to_howto_rel                   NULL
731 #define elf_info_to_howto                       fr30_info_to_howto_rela
732 #define elf_backend_relocate_section            fr30_elf_relocate_section
733
734 #define bfd_elf32_bfd_reloc_type_lookup         fr30_reloc_type_lookup
735                                         
736 #include "elf32-target.h"