1/* Motorola 68HC12-specific support for 32-bit ELF
2   Copyright (C) 1999-2022 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 bool 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	 0,			/* size */
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	 1,			/* size */
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	 1,			/* size */
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	 1,			/* size */
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	 1,			/* size */
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	 2,			/* size */
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	 4,			/* size */
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	 1,			/* size */
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	 2,			/* size */
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	 2,			/* size */
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	 2,			/* size */
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	 4,			/* size */
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	 2,			/* size */
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	 1,			/* size */
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	 2,			/* size */
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	 2,			/* size */
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	 2,			/* size */
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	 1,			/* size */
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	 1,			/* size */
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	 2,			/* size */
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	 2,			/* size */
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 bool
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 bool
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  /* Fail if the target section could not be assigned to an output
539     section.  The user should fix his linker script.  */
540  if (stub_entry->target_section->output_section == NULL
541      && info->non_contiguous_regions)
542    info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. "
543			      "Retry without --enable-non-contiguous-regions.\n"),
544			    stub_entry->target_section);
545
546  htab = m68hc11_elf_hash_table (info);
547
548  stub_sec = stub_entry->stub_sec;
549
550  /* Make a note of the offset within the stubs for this entry.  */
551  stub_entry->stub_offset = stub_sec->size;
552  stub_sec->size += 7;
553  loc = stub_sec->contents + stub_entry->stub_offset;
554
555  stub_bfd = stub_sec->owner;
556
557  /* Create the trampoline call stub:
558
559     ldy #%addr(symbol)
560     call %page(symbol), __trampoline
561
562  */
563  sym_value = (stub_entry->target_value
564	       + stub_entry->target_section->output_offset
565	       + stub_entry->target_section->output_section->vma);
566  phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
567  phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
568
569  /* ldy #%page(sym) */
570  bfd_put_8 (stub_bfd, 0xCD, loc);
571  bfd_put_16 (stub_bfd, phys_addr, loc + 1);
572  loc += 3;
573
574  /* call %page(sym), __trampoline  */
575  bfd_put_8 (stub_bfd, 0x4a, loc);
576  bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
577  bfd_put_8 (stub_bfd, phys_page, loc + 3);
578
579  return true;
580}
581
582/* As above, but don't actually build the stub.  Just bump offset so
583   we know stub section sizes.  */
584
585static bool
586m68hc12_elf_size_one_stub (struct bfd_hash_entry *gen_entry,
587			   void *in_arg ATTRIBUTE_UNUSED)
588{
589  struct elf32_m68hc11_stub_hash_entry *stub_entry;
590
591  /* Massage our args to the form they really have.  */
592  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
593
594  stub_entry->stub_sec->size += 7;
595  return true;
596}
597
598/* Create a 68HC12 ELF linker hash table.  */
599
600static struct bfd_link_hash_table *
601m68hc12_elf_bfd_link_hash_table_create (bfd *abfd)
602{
603  struct m68hc11_elf_link_hash_table *ret;
604
605  ret = m68hc11_elf_hash_table_create (abfd);
606  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
607    return NULL;
608
609  ret->size_one_stub = m68hc12_elf_size_one_stub;
610  ret->build_one_stub = m68hc12_elf_build_one_stub;
611
612  return &ret->root.root;
613}
614
615static bool
616m68hc12_elf_set_mach_from_flags (bfd *abfd)
617{
618  flagword flags = elf_elfheader (abfd)->e_flags;
619
620  switch (flags & EF_M68HC11_MACH_MASK)
621    {
622    case EF_M68HC12_MACH:
623      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812);
624      break;
625    case EF_M68HCS12_MACH:
626      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812s);
627      break;
628    case EF_M68HC11_GENERIC:
629      bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12,
630				 bfd_mach_m6812_default);
631      break;
632    default:
633      return false;
634    }
635  return true;
636}
637
638/* Specific sections:
639   - The .page0 is a data section that is mapped in [0x0000..0x00FF].
640     Page0 accesses are faster on the M68HC12.
641   - The .vectors is the section that represents the interrupt
642     vectors.  */
643static const struct bfd_elf_special_section elf32_m68hc12_special_sections[] =
644{
645  { STRING_COMMA_LEN (".eeprom"),   0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
646  { STRING_COMMA_LEN (".page0"),    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
647  { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
648  { STRING_COMMA_LEN (".vectors"),  0, SHT_PROGBITS, SHF_ALLOC },
649  { NULL,			0,  0, 0,	     0 }
650};
651
652#define ELF_ARCH		bfd_arch_m68hc12
653#define ELF_TARGET_ID		M68HC11_ELF_DATA
654#define ELF_MACHINE_CODE	EM_68HC12
655#define ELF_MAXPAGESIZE		0x1000
656
657#define TARGET_BIG_SYM		m68hc12_elf32_vec
658#define TARGET_BIG_NAME		"elf32-m68hc12"
659
660#define elf_info_to_howto	NULL
661#define elf_info_to_howto_rel	m68hc11_info_to_howto_rel
662#define elf_backend_check_relocs     elf32_m68hc11_check_relocs
663#define elf_backend_relocate_section elf32_m68hc11_relocate_section
664#define elf_backend_object_p		m68hc12_elf_set_mach_from_flags
665#define elf_backend_can_gc_sections		1
666#define elf_backend_special_sections elf32_m68hc12_special_sections
667#define elf_backend_init_file_header     elf32_m68hc11_init_file_header
668#define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
669#define elf_backend_merge_symbol_attribute elf32_m68hc11_merge_symbol_attribute
670
671#define bfd_elf32_bfd_link_hash_table_create \
672				m68hc12_elf_bfd_link_hash_table_create
673#define bfd_elf32_bfd_merge_private_bfd_data \
674					_bfd_m68hc11_elf_merge_private_bfd_data
675#define bfd_elf32_bfd_set_private_flags	_bfd_m68hc11_elf_set_private_flags
676#define bfd_elf32_bfd_print_private_bfd_data \
677					_bfd_m68hc11_elf_print_private_bfd_data
678
679#include "elf32-target.h"
680