1/* Motorola 68HC12-specific support for 32-bit ELF
2   Copyright (C) 1999-2020 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 bfd_boolean 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 bfd_boolean
501m68hc11_info_to_howto_rel (bfd *abfd,
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 (_("%pB: unsupported relocation type %#x"),
511			  abfd, r_type);
512      bfd_set_error (bfd_error_bad_value);
513      return FALSE;
514    }
515  cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
516  return TRUE;
517}
518
519
520/* Far trampoline generation.  */
521
522/* Build a 68HC12 trampoline stub.  */
523static bfd_boolean
524m68hc12_elf_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
525{
526  struct elf32_m68hc11_stub_hash_entry *stub_entry;
527  struct bfd_link_info *info;
528  struct m68hc11_elf_link_hash_table *htab;
529  asection *stub_sec;
530  bfd *stub_bfd;
531  bfd_byte *loc;
532  bfd_vma sym_value, phys_page, phys_addr;
533
534  /* Massage our args to the form they really have.  */
535  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
536  info = (struct bfd_link_info *) in_arg;
537
538  htab = m68hc11_elf_hash_table (info);
539
540  stub_sec = stub_entry->stub_sec;
541
542  /* Make a note of the offset within the stubs for this entry.  */
543  stub_entry->stub_offset = stub_sec->size;
544  stub_sec->size += 7;
545  loc = stub_sec->contents + stub_entry->stub_offset;
546
547  stub_bfd = stub_sec->owner;
548
549  /* Create the trampoline call stub:
550
551     ldy #%addr(symbol)
552     call %page(symbol), __trampoline
553
554  */
555  sym_value = (stub_entry->target_value
556	       + stub_entry->target_section->output_offset
557	       + stub_entry->target_section->output_section->vma);
558  phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
559  phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
560
561  /* ldy #%page(sym) */
562  bfd_put_8 (stub_bfd, 0xCD, loc);
563  bfd_put_16 (stub_bfd, phys_addr, loc + 1);
564  loc += 3;
565
566  /* call %page(sym), __trampoline  */
567  bfd_put_8 (stub_bfd, 0x4a, loc);
568  bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
569  bfd_put_8 (stub_bfd, phys_page, loc + 3);
570
571  return TRUE;
572}
573
574/* As above, but don't actually build the stub.  Just bump offset so
575   we know stub section sizes.  */
576
577static bfd_boolean
578m68hc12_elf_size_one_stub (struct bfd_hash_entry *gen_entry,
579			   void *in_arg ATTRIBUTE_UNUSED)
580{
581  struct elf32_m68hc11_stub_hash_entry *stub_entry;
582
583  /* Massage our args to the form they really have.  */
584  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
585
586  stub_entry->stub_sec->size += 7;
587  return TRUE;
588}
589
590/* Create a 68HC12 ELF linker hash table.  */
591
592static struct bfd_link_hash_table *
593m68hc12_elf_bfd_link_hash_table_create (bfd *abfd)
594{
595  struct m68hc11_elf_link_hash_table *ret;
596
597  ret = m68hc11_elf_hash_table_create (abfd);
598  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
599    return NULL;
600
601  ret->size_one_stub = m68hc12_elf_size_one_stub;
602  ret->build_one_stub = m68hc12_elf_build_one_stub;
603
604  return &ret->root.root;
605}
606
607static bfd_boolean
608m68hc12_elf_set_mach_from_flags (bfd *abfd)
609{
610  flagword flags = elf_elfheader (abfd)->e_flags;
611
612  switch (flags & EF_M68HC11_MACH_MASK)
613    {
614    case EF_M68HC12_MACH:
615      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812);
616      break;
617    case EF_M68HCS12_MACH:
618      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812s);
619      break;
620    case EF_M68HC11_GENERIC:
621      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12,
622				 bfd_mach_m6812_default);
623      break;
624    default:
625      return FALSE;
626    }
627  return TRUE;
628}
629
630/* Specific sections:
631   - The .page0 is a data section that is mapped in [0x0000..0x00FF].
632     Page0 accesses are faster on the M68HC12.
633   - The .vectors is the section that represents the interrupt
634     vectors.  */
635static const struct bfd_elf_special_section elf32_m68hc12_special_sections[] =
636{
637  { STRING_COMMA_LEN (".eeprom"),   0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
638  { STRING_COMMA_LEN (".page0"),    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
639  { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
640  { STRING_COMMA_LEN (".vectors"),  0, SHT_PROGBITS, SHF_ALLOC },
641  { NULL,			0,  0, 0,	     0 }
642};
643
644#define ELF_ARCH		bfd_arch_m68hc12
645#define ELF_TARGET_ID		M68HC11_ELF_DATA
646#define ELF_MACHINE_CODE	EM_68HC12
647#define ELF_MAXPAGESIZE		0x1000
648
649#define TARGET_BIG_SYM		m68hc12_elf32_vec
650#define TARGET_BIG_NAME		"elf32-m68hc12"
651
652#define elf_info_to_howto	NULL
653#define elf_info_to_howto_rel	m68hc11_info_to_howto_rel
654#define elf_backend_check_relocs     elf32_m68hc11_check_relocs
655#define elf_backend_relocate_section elf32_m68hc11_relocate_section
656#define elf_backend_object_p		m68hc12_elf_set_mach_from_flags
657#define elf_backend_can_gc_sections		1
658#define elf_backend_special_sections elf32_m68hc12_special_sections
659#define elf_backend_init_file_header     elf32_m68hc11_init_file_header
660#define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
661#define elf_backend_merge_symbol_attribute elf32_m68hc11_merge_symbol_attribute
662
663#define bfd_elf32_bfd_link_hash_table_create \
664				m68hc12_elf_bfd_link_hash_table_create
665#define bfd_elf32_bfd_merge_private_bfd_data \
666					_bfd_m68hc11_elf_merge_private_bfd_data
667#define bfd_elf32_bfd_set_private_flags	_bfd_m68hc11_elf_set_private_flags
668#define bfd_elf32_bfd_print_private_bfd_data \
669					_bfd_m68hc11_elf_print_private_bfd_data
670
671#include "elf32-target.h"
672