1/* BFD back-end for Renesas H8/500 COFF binaries.
2   Copyright (C) 1993-2017 Free Software Foundation, Inc.
3   Contributed by Cygnus Support.
4   Written by Steve Chamberlain, <sac@cygnus.com>.
5
6   This file is part of BFD, the Binary File Descriptor library.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21   MA 02110-1301, USA.  */
22
23#include "sysdep.h"
24#include "bfd.h"
25#include "libbfd.h"
26#include "bfdlink.h"
27#include "coff/h8500.h"
28#include "coff/internal.h"
29#include "libcoff.h"
30
31
32#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1)
33
34static reloc_howto_type r_imm8 =
35HOWTO (R_H8500_IMM8, 0, 1, 8, FALSE, 0,
36       complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff, FALSE);
37
38static reloc_howto_type r_imm16 =
39HOWTO (R_H8500_IMM16, 0, 1, 16, FALSE, 0,
40       complain_overflow_bitfield, 0, "r_imm16", TRUE, 0x0000ffff, 0x0000ffff, FALSE);
41
42static reloc_howto_type r_imm24 =
43HOWTO (R_H8500_IMM24, 0, 1, 24, FALSE, 0,
44       complain_overflow_bitfield, 0, "r_imm24", TRUE, 0x00ffffff, 0x00ffffff, FALSE);
45
46static reloc_howto_type r_imm32 =
47HOWTO (R_H8500_IMM32, 0, 1, 32, FALSE, 0,
48       complain_overflow_bitfield, 0, "r_imm32", TRUE, 0xffffffff, 0xffffffff, FALSE);
49
50static reloc_howto_type r_high8 =
51HOWTO (R_H8500_HIGH8, 0, 1, 8, FALSE, 0,
52       complain_overflow_dont, 0, "r_high8", TRUE, 0x000000ff, 0x000000ff, FALSE);
53
54static reloc_howto_type r_low16 =
55HOWTO (R_H8500_LOW16, 0, 1, 16, FALSE, 0,
56       complain_overflow_dont, 0, "r_low16", TRUE, 0x0000ffff, 0x0000ffff, FALSE);
57
58static reloc_howto_type r_pcrel8 =
59HOWTO (R_H8500_PCREL8, 0, 1, 8, TRUE, 0, complain_overflow_signed, 0, "r_pcrel8", TRUE, 0, 0, TRUE);
60
61static reloc_howto_type r_pcrel16 =
62HOWTO (R_H8500_PCREL16, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "r_pcrel16", TRUE, 0, 0, TRUE);
63
64static reloc_howto_type r_high16 =
65HOWTO (R_H8500_HIGH16, 0, 1, 8, FALSE, 0,
66       complain_overflow_dont, 0, "r_high16", TRUE, 0x000ffff, 0x0000ffff, FALSE);
67
68/* Turn a howto into a reloc number.  */
69
70static int
71coff_h8500_select_reloc (reloc_howto_type *howto)
72{
73  return howto->type;
74}
75
76#define SELECT_RELOC(x,howto) x.r_type = coff_h8500_select_reloc(howto)
77
78#define BADMAG(x) H8500BADMAG(x)
79#define H8500 1			/* Customize coffcode.h */
80
81#define __A_MAGIC_SET__
82
83/* Code to swap in the reloc.  */
84#define SWAP_IN_RELOC_OFFSET	H_GET_32
85#define SWAP_OUT_RELOC_OFFSET	H_PUT_32
86#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
87  dst->r_stuff[0] = 'S'; \
88  dst->r_stuff[1] = 'C';
89
90/* Code to turn a r_type into a howto ptr, uses the above howto table.  */
91
92static void
93rtype2howto (arelent * internal, struct internal_reloc *dst)
94{
95  switch (dst->r_type)
96    {
97    default:
98      internal->howto = NULL;
99      break;
100    case R_H8500_IMM8:
101      internal->howto = &r_imm8;
102      break;
103    case R_H8500_IMM16:
104      internal->howto = &r_imm16;
105      break;
106    case R_H8500_IMM24:
107      internal->howto = &r_imm24;
108      break;
109    case R_H8500_IMM32:
110      internal->howto = &r_imm32;
111      break;
112    case R_H8500_PCREL8:
113      internal->howto = &r_pcrel8;
114      break;
115    case R_H8500_PCREL16:
116      internal->howto = &r_pcrel16;
117      break;
118    case R_H8500_HIGH8:
119      internal->howto = &r_high8;
120      break;
121    case R_H8500_HIGH16:
122      internal->howto = &r_high16;
123      break;
124    case R_H8500_LOW16:
125      internal->howto = &r_low16;
126      break;
127    }
128}
129
130#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry)
131
132/* Perform any necessary magic to the addend in a reloc entry.  */
133
134#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
135 cache_ptr->addend =  ext_reloc.r_offset;
136
137#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
138 reloc_processing(relent, reloc, symbols, abfd, section)
139
140static void
141reloc_processing (arelent * relent,
142		  struct internal_reloc *reloc,
143		  asymbol ** symbols,
144		  bfd * abfd,
145		  asection * section)
146{
147  relent->address = reloc->r_vaddr;
148  rtype2howto (relent, reloc);
149
150  if (reloc->r_symndx > 0)
151    relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
152  else
153    relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
154
155  relent->addend = reloc->r_offset;
156  relent->address -= section->vma;
157}
158
159static void
160extra_case (bfd *in_abfd,
161	    struct bfd_link_info *link_info,
162	    struct bfd_link_order *link_order,
163	    arelent *reloc,
164	    bfd_byte *data,
165	    unsigned int *src_ptr,
166	    unsigned int *dst_ptr)
167{
168  bfd_byte *d = data+*dst_ptr;
169  asection *input_section = link_order->u.indirect.section;
170
171  switch (reloc->howto->type)
172    {
173    case R_H8500_IMM8:
174      bfd_put_8 (in_abfd,
175		 bfd_coff_reloc16_get_value (reloc, link_info, input_section),
176		 d);
177      (*dst_ptr) += 1;
178      (*src_ptr) += 1;
179      break;
180
181    case R_H8500_HIGH8:
182      bfd_put_8 (in_abfd,
183		 (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
184		  >> 16),
185		 d);
186      (*dst_ptr) += 1;
187      (*src_ptr) += 1;
188      break;
189
190    case R_H8500_IMM16:
191      bfd_put_16 (in_abfd,
192		  bfd_coff_reloc16_get_value (reloc, link_info, input_section),
193		  d);
194      (*dst_ptr) += 2;
195      (*src_ptr) += 2;
196      break;
197
198    case R_H8500_LOW16:
199      bfd_put_16 (in_abfd,
200		  bfd_coff_reloc16_get_value (reloc, link_info, input_section),
201		  d);
202
203      (*dst_ptr) += 2;
204      (*src_ptr) += 2;
205      break;
206
207    case R_H8500_HIGH16:
208      bfd_put_16 (in_abfd,
209		  (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
210		   >> 16),
211		  d);
212
213      (*dst_ptr) += 2;
214      (*src_ptr) += 2;
215      break;
216
217    case R_H8500_IMM24:
218      {
219	int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
220	int o = bfd_get_32 (in_abfd, data+ *dst_ptr -1);
221	v = (v & 0x00ffffff) | (o & 0xff00000);
222	bfd_put_32 (in_abfd, (bfd_vma) v, data  + *dst_ptr -1);
223	(*dst_ptr) += 3;
224	(*src_ptr) += 3;
225      }
226      break;
227    case R_H8500_IMM32:
228      {
229	int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
230	bfd_put_32 (in_abfd, (bfd_vma) v, data  + *dst_ptr);
231	(*dst_ptr) += 4;
232	(*src_ptr) += 4;
233      }
234      break;
235
236    case R_H8500_PCREL8:
237      {
238	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
239						  input_section);
240	bfd_vma dot = (*dst_ptr
241		       + input_section->output_offset
242		       + input_section->output_section->vma);
243	int gap = dst - dot - 1; /* -1 since were in the odd byte of the
244				    word and the pc's been incremented.  */
245
246	if (gap > 128 || gap < -128)
247	  (*link_info->callbacks->reloc_overflow)
248	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
249	     reloc->howto->name, reloc->addend, input_section->owner,
250	     input_section, reloc->address);
251
252	bfd_put_8 (in_abfd, gap, data + *dst_ptr);
253	(*dst_ptr)++;
254	(*src_ptr)++;
255	break;
256      }
257    case R_H8500_PCREL16:
258      {
259	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
260						  input_section);
261	bfd_vma dot = (*dst_ptr
262		       + input_section->output_offset
263		       + input_section->output_section->vma);
264	int gap = dst - dot - 1; /* -1 since were in the odd byte of the
265				    word and the pc's been incremented.  */
266
267	if (gap > 32767 || gap < -32768)
268	  (*link_info->callbacks->reloc_overflow)
269	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
270	     reloc->howto->name, reloc->addend, input_section->owner,
271	     input_section, reloc->address);
272
273	bfd_put_16 (in_abfd, (bfd_vma) gap, data + *dst_ptr);
274	(*dst_ptr) += 2;
275	(*src_ptr) += 2;
276	break;
277      }
278
279    default:
280      abort ();
281    }
282}
283
284#define coff_reloc16_extra_cases extra_case
285
286#ifndef bfd_pe_print_pdata
287#define bfd_pe_print_pdata	NULL
288#endif
289
290#include "coffcode.h"
291
292#undef  coff_bfd_get_relocated_section_contents
293#undef coff_bfd_relax_section
294#define coff_bfd_get_relocated_section_contents \
295  bfd_coff_reloc16_get_relocated_section_contents
296#define coff_bfd_relax_section bfd_coff_reloc16_relax_section
297
298CREATE_BIG_COFF_TARGET_VEC (h8500_coff_vec, "coff-h8500", 0, 0, '_', NULL, COFF_SWAP_TABLE)
299