1/* Motorola 68HC12-specific support for 32-bit ELF
2   Copyright (C) 1999-2017 Free Software Foundation, Inc.
3   Contributed by Stephane Carrez (stcarrez@nerim.fr)
4   (Heavily copied from the D10V port by Martin Hunt (hunt@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 "bfdlink.h"
26#include "libbfd.h"
27#include "elf-bfd.h"
28#include "elf32-m68hc1x.h"
29#include "elf/m68hc11.h"
30#include "opcode/m68hc11.h"
31
32/* Relocation functions.  */
33static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
34  (bfd *, bfd_reloc_code_real_type);
35static void m68hc11_info_to_howto_rel
36  (bfd *, arelent *, Elf_Internal_Rela *);
37
38/* Trampoline generation.  */
39
40
41/* Use REL instead of RELA to save space */
42#define USE_REL	1
43
44/* The 68HC12 microcontroler has a memory bank switching system
45   with a 16Kb window in the 64Kb address space.  The extended memory
46   is mapped in the 16Kb window (at 0x8000).  The page register controls
47   which 16Kb bank is mapped.  The call/rtc instructions take care of
48   bank switching in function calls/returns.
49
50   For GNU Binutils to work, we consider there is a physical memory
51   at 0..0x0ffff and a kind of virtual memory above that.  Symbols
52   in virtual memory have their addresses treated in a special way
53   when disassembling and when linking.
54
55   For the linker to work properly, we must always relocate the virtual
56   memory as if it is mapped at 0x8000.  When a 16-bit relocation is
57   made in the virtual memory, we check that it does not cross the
58   memory bank where it is used.  This would involve a page change
59   which would be wrong.  The 24-bit relocation is for that and it
60   treats the address as a physical address + page number.
61
62
63					Banked
64					Address Space
65                                        |               |       Page n
66					+---------------+ 0x1010000
67                                        |               |
68                                        | jsr _foo      |
69                                        | ..            |       Page 3
70                                        | _foo:         |
71					+---------------+ 0x100C000
72					|	        |
73                                        | call _bar     |
74					| ..	        |	Page 2
75					| _bar:	        |
76					+---------------+ 0x1008000
77				/------>|	        |
78				|	| call _foo     |	Page 1
79				|	|       	|
80				|	+---------------+ 0x1004000
81      Physical			|	|	        |
82      Address Space		|	|	        |	Page 0
83				|	|	        |
84    +-----------+ 0x00FFFF	|	+---------------+ 0x1000000
85    |		|		|
86    | call _foo	|		|
87    |		|		|
88    +-----------+ 0x00BFFF -+---/
89    |		|           |
90    |		|	    |
91    |		| 16K	    |
92    |		|	    |
93    +-----------+ 0x008000 -+
94    |		|
95    |		|
96    =		=
97    |		|
98    |		|
99    +-----------+ 0000
100
101
102   The 'call _foo' must be relocated with page 3 and 16-bit address
103   mapped at 0x8000.
104
105   The 3-bit and 16-bit PC rel relocation is only used by 68HC12.  */
106static reloc_howto_type elf_m68hc11_howto_table[] = {
107  /* This reloc does nothing.  */
108  HOWTO (R_M68HC11_NONE,	/* type */
109	 0,			/* rightshift */
110	 3,			/* size (0 = byte, 1 = short, 2 = long) */
111	 0,			/* bitsize */
112	 FALSE,			/* pc_relative */
113	 0,			/* bitpos */
114	 complain_overflow_dont,/* complain_on_overflow */
115	 bfd_elf_generic_reloc,	/* special_function */
116	 "R_M68HC12_NONE",	/* name */
117	 FALSE,			/* partial_inplace */
118	 0,			/* src_mask */
119	 0,			/* dst_mask */
120	 FALSE),		/* pcrel_offset */
121
122  /* A 8 bit absolute relocation */
123  HOWTO (R_M68HC11_8,		/* type */
124	 0,			/* rightshift */
125	 0,			/* size (0 = byte, 1 = short, 2 = long) */
126	 8,			/* bitsize */
127	 FALSE,			/* pc_relative */
128	 0,			/* bitpos */
129	 complain_overflow_bitfield,	/* complain_on_overflow */
130	 bfd_elf_generic_reloc,	/* special_function */
131	 "R_M68HC12_8",		/* name */
132	 FALSE,			/* partial_inplace */
133	 0x00ff,		/* src_mask */
134	 0x00ff,		/* dst_mask */
135	 FALSE),		/* pcrel_offset */
136
137  /* A 8 bit absolute relocation (upper address) */
138  HOWTO (R_M68HC11_HI8,		/* type */
139	 8,			/* rightshift */
140	 0,			/* size (0 = byte, 1 = short, 2 = long) */
141	 8,			/* bitsize */
142	 FALSE,			/* pc_relative */
143	 0,			/* bitpos */
144	 complain_overflow_bitfield,	/* complain_on_overflow */
145	 bfd_elf_generic_reloc,	/* special_function */
146	 "R_M68HC12_HI8",	/* name */
147	 FALSE,			/* partial_inplace */
148	 0x00ff,		/* src_mask */
149	 0x00ff,		/* dst_mask */
150	 FALSE),		/* pcrel_offset */
151
152  /* A 8 bit absolute relocation (upper address) */
153  HOWTO (R_M68HC11_LO8,		/* type */
154	 0,			/* rightshift */
155	 0,			/* size (0 = byte, 1 = short, 2 = long) */
156	 8,			/* bitsize */
157	 FALSE,			/* pc_relative */
158	 0,			/* bitpos */
159	 complain_overflow_dont,	/* complain_on_overflow */
160	 bfd_elf_generic_reloc,	/* special_function */
161	 "R_M68HC12_LO8",	/* name */
162	 FALSE,			/* partial_inplace */
163	 0x00ff,		/* src_mask */
164	 0x00ff,		/* dst_mask */
165	 FALSE),		/* pcrel_offset */
166
167  /* A 8 bit PC-rel relocation */
168  HOWTO (R_M68HC11_PCREL_8,	/* type */
169	 0,			/* rightshift */
170	 0,			/* size (0 = byte, 1 = short, 2 = long) */
171	 8,			/* bitsize */
172	 TRUE,			/* pc_relative */
173	 0,			/* bitpos */
174	 complain_overflow_bitfield,	/* complain_on_overflow */
175	 bfd_elf_generic_reloc,	/* special_function */
176	 "R_M68HC12_PCREL_8",	/* name */
177	 FALSE,			/* partial_inplace */
178	 0x00ff,		/* src_mask */
179	 0x00ff,		/* dst_mask */
180	 TRUE),                 /* pcrel_offset */
181
182  /* A 16 bit absolute relocation */
183  HOWTO (R_M68HC11_16,		/* type */
184	 0,			/* rightshift */
185	 1,			/* size (0 = byte, 1 = short, 2 = long) */
186	 16,			/* bitsize */
187	 FALSE,			/* pc_relative */
188	 0,			/* bitpos */
189	 complain_overflow_dont /*bitfield */ ,	/* complain_on_overflow */
190	 bfd_elf_generic_reloc,	/* special_function */
191	 "R_M68HC12_16",	/* name */
192	 FALSE,			/* partial_inplace */
193	 0xffff,		/* src_mask */
194	 0xffff,		/* dst_mask */
195	 FALSE),		/* pcrel_offset */
196
197  /* A 32 bit absolute relocation.  This one is never used for the
198     code relocation.  It's used by gas for -gstabs generation.  */
199  HOWTO (R_M68HC11_32,		/* type */
200	 0,			/* rightshift */
201	 2,			/* size (0 = byte, 1 = short, 2 = long) */
202	 32,			/* bitsize */
203	 FALSE,			/* pc_relative */
204	 0,			/* bitpos */
205	 complain_overflow_bitfield,	/* complain_on_overflow */
206	 bfd_elf_generic_reloc,	/* special_function */
207	 "R_M68HC12_32",	/* name */
208	 FALSE,			/* partial_inplace */
209	 0xffffffff,		/* src_mask */
210	 0xffffffff,		/* dst_mask */
211	 FALSE),		/* pcrel_offset */
212
213  /* A 3 bit absolute relocation */
214  HOWTO (R_M68HC11_3B,		/* type */
215	 0,			/* rightshift */
216	 0,			/* size (0 = byte, 1 = short, 2 = long) */
217	 3,			/* bitsize */
218	 FALSE,			/* pc_relative */
219	 0,			/* bitpos */
220	 complain_overflow_bitfield,	/* complain_on_overflow */
221	 bfd_elf_generic_reloc,	/* special_function */
222	 "R_M68HC12_4B",	/* name */
223	 FALSE,			/* partial_inplace */
224	 0x003,			/* src_mask */
225	 0x003,			/* dst_mask */
226	 FALSE),		/* pcrel_offset */
227
228  /* A 16 bit PC-rel relocation */
229  HOWTO (R_M68HC11_PCREL_16,	/* type */
230	 0,			/* rightshift */
231	 1,			/* size (0 = byte, 1 = short, 2 = long) */
232	 16,			/* bitsize */
233	 TRUE,			/* pc_relative */
234	 0,			/* bitpos */
235	 complain_overflow_dont,	/* complain_on_overflow */
236	 bfd_elf_generic_reloc,	/* special_function */
237	 "R_M68HC12_PCREL_16",	/* name */
238	 FALSE,			/* partial_inplace */
239	 0xffff,		/* src_mask */
240	 0xffff,		/* dst_mask */
241	 TRUE),                 /* pcrel_offset */
242
243  /* GNU extension to record C++ vtable hierarchy */
244  HOWTO (R_M68HC11_GNU_VTINHERIT,	/* type */
245	 0,			/* rightshift */
246	 1,			/* size (0 = byte, 1 = short, 2 = long) */
247	 0,			/* bitsize */
248	 FALSE,			/* pc_relative */
249	 0,			/* bitpos */
250	 complain_overflow_dont,	/* complain_on_overflow */
251	 NULL,			/* special_function */
252	 "R_M68HC11_GNU_VTINHERIT",	/* name */
253	 FALSE,			/* partial_inplace */
254	 0,			/* src_mask */
255	 0,			/* dst_mask */
256	 FALSE),		/* pcrel_offset */
257
258  /* GNU extension to record C++ vtable member usage */
259  HOWTO (R_M68HC11_GNU_VTENTRY,	/* type */
260	 0,			/* rightshift */
261	 1,			/* size (0 = byte, 1 = short, 2 = long) */
262	 0,			/* bitsize */
263	 FALSE,			/* pc_relative */
264	 0,			/* bitpos */
265	 complain_overflow_dont,	/* complain_on_overflow */
266	 _bfd_elf_rel_vtable_reloc_fn,	/* special_function */
267	 "R_M68HC11_GNU_VTENTRY",	/* name */
268	 FALSE,			/* partial_inplace */
269	 0,			/* src_mask */
270	 0,			/* dst_mask */
271	 FALSE),		/* pcrel_offset */
272
273  /* A 24 bit relocation */
274  HOWTO (R_M68HC11_24,	        /* type */
275	 0,			/* rightshift */
276	 2,			/* size (0 = byte, 1 = short, 2 = long) */
277	 24,			/* bitsize */
278	 FALSE,			/* pc_relative */
279	 0,			/* bitpos */
280	 complain_overflow_dont,	/* complain_on_overflow */
281	 m68hc11_elf_special_reloc,	/* special_function */
282	 "R_M68HC12_24",	/* name */
283	 FALSE,			/* partial_inplace */
284	 0xffffff,		/* src_mask */
285	 0xffffff,		/* dst_mask */
286	 FALSE),		/* pcrel_offset */
287
288  /* A 16-bit low relocation */
289  HOWTO (R_M68HC11_LO16,        /* type */
290	 0,			/* rightshift */
291	 1,			/* size (0 = byte, 1 = short, 2 = long) */
292	 16,			/* bitsize */
293	 FALSE,			/* pc_relative */
294	 0,			/* bitpos */
295	 complain_overflow_dont,	/* complain_on_overflow */
296	 m68hc11_elf_special_reloc,/* special_function */
297	 "R_M68HC12_LO16",	/* name */
298	 FALSE,			/* partial_inplace */
299	 0xffff,		/* src_mask */
300	 0xffff,		/* dst_mask */
301	 FALSE),		/* pcrel_offset */
302
303  /* A page relocation */
304  HOWTO (R_M68HC11_PAGE,        /* type */
305	 0,			/* rightshift */
306	 0,			/* size (0 = byte, 1 = short, 2 = long) */
307	 8,			/* bitsize */
308	 FALSE,			/* pc_relative */
309	 0,			/* bitpos */
310	 complain_overflow_dont,	/* complain_on_overflow */
311	 m68hc11_elf_special_reloc,/* special_function */
312	 "R_M68HC12_PAGE",	/* name */
313	 FALSE,			/* partial_inplace */
314	 0x00ff,		/* src_mask */
315	 0x00ff,		/* dst_mask */
316	 FALSE),		/* pcrel_offset */
317
318  EMPTY_HOWTO (14),
319
320  /* A 16 bit absolute relocation.  */
321  HOWTO (R_M68HC12_16B,		/* type */
322	 0,			/* rightshift */
323	 1,			/* size (0 = byte, 1 = short, 2 = long) */
324	 16,			/* bitsize */
325	 FALSE,			/* pc_relative */
326	 0,			/* bitpos */
327	 complain_overflow_bitfield,	/* complain_on_overflow */
328	 bfd_elf_generic_reloc,	/* special_function */
329	 "R_M68HC12_16B",	/* name */
330	 FALSE,			/* partial_inplace */
331	 0xffff,			/* src_mask */
332	 0xffff,			/* dst_mask */
333	 FALSE),		/* pcrel_offset */
334
335  /* A 9 bit PC-rel relocation.  */
336  HOWTO (R_M68HC12_PCREL_9,	/* type */
337	 1,			/* rightshift */
338	 1,			/* size (0 = byte, 1 = short, 2 = long) */
339	 10,			/* bitsize (result is >>1) */
340	 TRUE,			/* pc_relative */
341	 0,			/* bitpos */
342	 complain_overflow_dont,	/* complain_on_overflow */
343	 bfd_elf_generic_reloc,	/* special_function */
344	 "R_M68HC12_PCREL_9",	/* name */
345	 TRUE,			/* partial_inplace */
346	 0xfe00,		/* src_mask */
347	 0x01ff,		/* dst_mask */
348	 TRUE),                 /* pcrel_offset */
349
350  /* A 10 bit PC-rel relocation.  */
351  HOWTO (R_M68HC12_PCREL_10,	/* type */
352	 1,			/* rightshift */
353	 1,			/* size (0 = byte, 1 = short, 2 = long) */
354	 11,			/* bitsize (result is >>1) */
355	 TRUE,			/* pc_relative */
356	 0,			/* bitpos */
357	 complain_overflow_dont,	/* complain_on_overflow */
358	 bfd_elf_generic_reloc,	/* special_function */
359	 "R_M68HC12_PCREL_10",	/* name */
360	 TRUE,			/* partial_inplace */
361	 0xfc00,		/* src_mask */
362	 0x03ff,		/* dst_mask */
363	 TRUE),                 /* pcrel_offset */
364
365  /* A 8 bit absolute relocation (upper address).  */
366  HOWTO (R_M68HC12_HI8XG,		/* type */
367	 8,			/* rightshift */
368	 0,			/* size (0 = byte, 1 = short, 2 = long) */
369	 8,			/* bitsize */
370	 FALSE,			/* pc_relative */
371	 0,			/* bitpos */
372	 complain_overflow_bitfield,	/* complain_on_overflow */
373	 bfd_elf_generic_reloc,	/* special_function */
374	 "R_M68HC12_HI8XG",	/* name */
375	 FALSE,			/* partial_inplace */
376	 0x00ff,		/* src_mask */
377	 0x00ff,		/* dst_mask */
378	 FALSE),		/* pcrel_offset */
379
380  /* A 8 bit absolute relocation (lower address).  */
381  HOWTO (R_M68HC12_LO8XG,		/* type */
382	 8,			/* rightshift */
383	 0,			/* size (0 = byte, 1 = short, 2 = long) */
384	 8,			/* bitsize */
385	 FALSE,			/* pc_relative */
386	 0,			/* bitpos */
387	 complain_overflow_bitfield,	/* complain_on_overflow */
388	 bfd_elf_generic_reloc,	/* special_function */
389	 "R_M68HC12_LO8XG",	/* name */
390	 FALSE,			/* partial_inplace */
391	 0x00ff,		/* src_mask */
392	 0x00ff,		/* dst_mask */
393	 FALSE),		/* pcrel_offset */
394
395  /* Mark beginning of a jump instruction (any form).  */
396  HOWTO (R_M68HC11_RL_JUMP,	/* type */
397	 0,			/* rightshift */
398	 1,			/* size (0 = byte, 1 = short, 2 = long) */
399	 0,			/* bitsize */
400	 FALSE,			/* pc_relative */
401	 0,			/* bitpos */
402	 complain_overflow_dont,	/* complain_on_overflow */
403	 m68hc11_elf_ignore_reloc,	/* special_function */
404	 "R_M68HC12_RL_JUMP",	/* name */
405	 TRUE,			/* partial_inplace */
406	 0,			/* src_mask */
407	 0,			/* dst_mask */
408	 TRUE),                 /* pcrel_offset */
409
410  /* Mark beginning of Gcc relaxation group instruction.  */
411  HOWTO (R_M68HC11_RL_GROUP,	/* type */
412	 0,			/* rightshift */
413	 1,			/* size (0 = byte, 1 = short, 2 = long) */
414	 0,			/* bitsize */
415	 FALSE,			/* pc_relative */
416	 0,			/* bitpos */
417	 complain_overflow_dont,	/* complain_on_overflow */
418	 m68hc11_elf_ignore_reloc,	/* special_function */
419	 "R_M68HC12_RL_GROUP",	/* name */
420	 TRUE,			/* partial_inplace */
421	 0,			/* src_mask */
422	 0,			/* dst_mask */
423	 TRUE),                 /* pcrel_offset */
424};
425
426/* Map BFD reloc types to M68HC11 ELF reloc types.  */
427
428struct m68hc11_reloc_map
429{
430  bfd_reloc_code_real_type bfd_reloc_val;
431  unsigned char elf_reloc_val;
432};
433
434static const struct m68hc11_reloc_map m68hc11_reloc_map[] =
435{
436  {BFD_RELOC_NONE, R_M68HC11_NONE,},
437  {BFD_RELOC_8, R_M68HC11_8},
438  {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8},
439  {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8},
440  {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8},
441  {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16},
442  {BFD_RELOC_16, R_M68HC11_16},
443  {BFD_RELOC_32, R_M68HC11_32},
444  {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
445
446  {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
447  {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
448
449  {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16},
450  {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE},
451  {BFD_RELOC_M68HC11_24, R_M68HC11_24},
452
453  {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
454  {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
455
456  {BFD_RELOC_M68HC12_16B, R_M68HC12_16B},
457
458  {BFD_RELOC_M68HC12_9_PCREL, R_M68HC12_PCREL_9},
459  {BFD_RELOC_M68HC12_10_PCREL, R_M68HC12_PCREL_10},
460  {BFD_RELOC_M68HC12_HI8XG, R_M68HC12_HI8XG},
461  {BFD_RELOC_M68HC12_LO8XG, R_M68HC12_LO8XG},
462};
463
464static reloc_howto_type *
465bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
466                                 bfd_reloc_code_real_type code)
467{
468  unsigned int i;
469
470  for (i = 0;
471       i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map);
472       i++)
473    {
474      if (m68hc11_reloc_map[i].bfd_reloc_val == code)
475	return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val];
476    }
477
478  return NULL;
479}
480
481static reloc_howto_type *
482bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
483				 const char *r_name)
484{
485  unsigned int i;
486
487  for (i = 0;
488       i < (sizeof (elf_m68hc11_howto_table)
489	    / sizeof (elf_m68hc11_howto_table[0]));
490       i++)
491    if (elf_m68hc11_howto_table[i].name != NULL
492	&& strcasecmp (elf_m68hc11_howto_table[i].name, r_name) == 0)
493      return &elf_m68hc11_howto_table[i];
494
495  return NULL;
496}
497
498/* Set the howto pointer for an M68HC11 ELF reloc.  */
499
500static void
501m68hc11_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
502                           arelent *cache_ptr, Elf_Internal_Rela *dst)
503{
504  unsigned int r_type;
505
506  r_type = ELF32_R_TYPE (dst->r_info);
507  if (r_type >= (unsigned int) R_M68HC11_max)
508    {
509      /* xgettext:c-format */
510      _bfd_error_handler (_("%B: invalid M68HC12 reloc number: %d"), abfd, r_type);
511      r_type = 0;
512    }
513  cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
514}
515
516
517/* Far trampoline generation.  */
518
519/* Build a 68HC12 trampoline stub.  */
520static bfd_boolean
521m68hc12_elf_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
522{
523  struct elf32_m68hc11_stub_hash_entry *stub_entry;
524  struct bfd_link_info *info;
525  struct m68hc11_elf_link_hash_table *htab;
526  asection *stub_sec;
527  bfd *stub_bfd;
528  bfd_byte *loc;
529  bfd_vma sym_value, phys_page, phys_addr;
530
531  /* Massage our args to the form they really have.  */
532  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
533  info = (struct bfd_link_info *) in_arg;
534
535  htab = m68hc11_elf_hash_table (info);
536
537  stub_sec = stub_entry->stub_sec;
538
539  /* Make a note of the offset within the stubs for this entry.  */
540  stub_entry->stub_offset = stub_sec->size;
541  stub_sec->size += 7;
542  loc = stub_sec->contents + stub_entry->stub_offset;
543
544  stub_bfd = stub_sec->owner;
545
546  /* Create the trampoline call stub:
547
548     ldy #%addr(symbol)
549     call %page(symbol), __trampoline
550
551  */
552  sym_value = (stub_entry->target_value
553               + stub_entry->target_section->output_offset
554               + stub_entry->target_section->output_section->vma);
555  phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
556  phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
557
558  /* ldy #%page(sym) */
559  bfd_put_8 (stub_bfd, 0xCD, loc);
560  bfd_put_16 (stub_bfd, phys_addr, loc + 1);
561  loc += 3;
562
563  /* call %page(sym), __trampoline  */
564  bfd_put_8 (stub_bfd, 0x4a, loc);
565  bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
566  bfd_put_8 (stub_bfd, phys_page, loc + 3);
567
568  return TRUE;
569}
570
571/* As above, but don't actually build the stub.  Just bump offset so
572   we know stub section sizes.  */
573
574static bfd_boolean
575m68hc12_elf_size_one_stub (struct bfd_hash_entry *gen_entry,
576                           void *in_arg ATTRIBUTE_UNUSED)
577{
578  struct elf32_m68hc11_stub_hash_entry *stub_entry;
579
580  /* Massage our args to the form they really have.  */
581  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
582
583  stub_entry->stub_sec->size += 7;
584  return TRUE;
585}
586
587/* Create a 68HC12 ELF linker hash table.  */
588
589static struct bfd_link_hash_table *
590m68hc12_elf_bfd_link_hash_table_create (bfd *abfd)
591{
592  struct m68hc11_elf_link_hash_table *ret;
593
594  ret = m68hc11_elf_hash_table_create (abfd);
595  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
596    return NULL;
597
598  ret->size_one_stub = m68hc12_elf_size_one_stub;
599  ret->build_one_stub = m68hc12_elf_build_one_stub;
600
601  return &ret->root.root;
602}
603
604static bfd_boolean
605m68hc12_elf_set_mach_from_flags (bfd *abfd)
606{
607  flagword flags = elf_elfheader (abfd)->e_flags;
608
609  switch (flags & EF_M68HC11_MACH_MASK)
610    {
611    case EF_M68HC12_MACH:
612      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812);
613      break;
614    case EF_M68HCS12_MACH:
615      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812s);
616      break;
617    case EF_M68HC11_GENERIC:
618      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12,
619                                 bfd_mach_m6812_default);
620      break;
621    default:
622      return FALSE;
623    }
624  return TRUE;
625}
626
627/* Specific sections:
628   - The .page0 is a data section that is mapped in [0x0000..0x00FF].
629     Page0 accesses are faster on the M68HC12.
630   - The .vectors is the section that represents the interrupt
631     vectors.  */
632static const struct bfd_elf_special_section elf32_m68hc12_special_sections[] =
633{
634  { STRING_COMMA_LEN (".eeprom"),   0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
635  { STRING_COMMA_LEN (".page0"),    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
636  { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
637  { STRING_COMMA_LEN (".vectors"),  0, SHT_PROGBITS, SHF_ALLOC },
638  { NULL,                       0,  0, 0,            0 }
639};
640
641#define ELF_ARCH		bfd_arch_m68hc12
642#define ELF_TARGET_ID		M68HC11_ELF_DATA
643#define ELF_MACHINE_CODE	EM_68HC12
644#define ELF_MAXPAGESIZE		0x1000
645
646#define TARGET_BIG_SYM          m68hc12_elf32_vec
647#define TARGET_BIG_NAME		"elf32-m68hc12"
648
649#define elf_info_to_howto	0
650#define elf_info_to_howto_rel	m68hc11_info_to_howto_rel
651#define elf_backend_check_relocs     elf32_m68hc11_check_relocs
652#define elf_backend_relocate_section elf32_m68hc11_relocate_section
653#define elf_backend_object_p		m68hc12_elf_set_mach_from_flags
654#define elf_backend_final_write_processing	0
655#define elf_backend_can_gc_sections		1
656#define elf_backend_special_sections elf32_m68hc12_special_sections
657#define elf_backend_post_process_headers     elf32_m68hc11_post_process_headers
658#define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
659#define elf_backend_merge_symbol_attribute elf32_m68hc11_merge_symbol_attribute
660
661#define bfd_elf32_bfd_link_hash_table_create \
662                                m68hc12_elf_bfd_link_hash_table_create
663#define bfd_elf32_bfd_merge_private_bfd_data \
664					_bfd_m68hc11_elf_merge_private_bfd_data
665#define bfd_elf32_bfd_set_private_flags	_bfd_m68hc11_elf_set_private_flags
666#define bfd_elf32_bfd_print_private_bfd_data \
667					_bfd_m68hc11_elf_print_private_bfd_data
668
669#include "elf32-target.h"
670