* bfd-in.h: Comment typo fix. Formatting.
[external/binutils.git] / bfd / elf32-m68hc12.c
1 /* Motorola 68HC12-specific support for 32-bit ELF
2    Copyright 1999, 2000, 2002 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 #include "bfd.h"
23 #include "sysdep.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/m68hc11.h"
27 #include "opcode/m68hc11.h"
28
29 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
30   PARAMS ((bfd *, bfd_reloc_code_real_type));
31 static void m68hc11_info_to_howto_rel
32   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33
34 static bfd_reloc_status_type m68hc11_elf_ignore_reloc
35   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
36 static bfd_reloc_status_type m68hc12_elf_special_reloc
37   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
38 static int m68hc12_addr_is_banked PARAMS ((bfd_vma));
39 static bfd_vma m68hc12_phys_addr PARAMS ((bfd_vma));
40 static bfd_vma m68hc12_phys_page PARAMS ((bfd_vma));
41
42 /* GC mark and sweep.  */
43 static asection *elf32_m68hc11_gc_mark_hook
44   PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
45            struct elf_link_hash_entry *, Elf_Internal_Sym *));
46 static bfd_boolean elf32_m68hc11_gc_sweep_hook
47   PARAMS ((bfd *, struct bfd_link_info *, asection *,
48            const Elf_Internal_Rela *));
49
50 static bfd_boolean m68hc12_elf_set_mach_from_flags PARAMS ((bfd *));
51
52 bfd_boolean _bfd_m68hc12_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
53 bfd_boolean _bfd_m68hc12_elf_set_private_flags PARAMS ((bfd *, flagword));
54 bfd_boolean _bfd_m68hc12_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
55
56
57
58 /* Use REL instead of RELA to save space */
59 #define USE_REL 1
60
61 /* The Motorola 68HC11 microcontroler only addresses 64Kb.
62    We must handle 8 and 16-bit relocations.  The 32-bit relocation
63    is defined but not used except by gas when -gstabs is used (which
64    is wrong).
65
66    The 68HC12 microcontroler has a memory bank switching system
67    with a 16Kb window in the 64Kb address space.  The extended memory
68    is mapped in the 16Kb window (at 0x8000).  The page register controls
69    which 16Kb bank is mapped.  The call/rtc instructions take care of
70    bank switching in function calls/returns.
71
72    For GNU Binutils to work, we consider there is a physical memory
73    at 0..0x0ffff and a kind of virtual memory above that.  Symbols
74    in virtual memory have their addresses treated in a special way
75    when disassembling and when linking.
76
77    For the linker to work properly, we must always relocate the virtual
78    memory as if it is mapped at 0x8000.  When a 16-bit relocation is
79    made in the virtual memory, we check that it does not cross the
80    memory bank where it is used.  This would involve a page change
81    which would be wrong.  The 24-bit relocation is for that and it
82    treats the address as a physical address + page number.
83
84
85                                         Banked
86                                         Address Space
87                                         |               |       Page n
88                                         +---------------+ 0x1010000
89                                         |               |
90                                         | jsr _foo      |
91                                         | ..            |       Page 3
92                                         | _foo:         |
93                                         +---------------+ 0x100C000
94                                         |               |
95                                         | call _bar     |
96                                         | ..            |       Page 2
97                                         | _bar:         |
98                                         +---------------+ 0x1008000
99                                 /------>|               |
100                                 |       | call _foo     |       Page 1
101                                 |       |               |
102                                 |       +---------------+ 0x1004000
103       Physical                  |       |               |
104       Address Space             |       |               |       Page 0
105                                 |       |               |
106     +-----------+ 0x00FFFF      |       +---------------+ 0x1000000
107     |           |               |
108     | call _foo |               |
109     |           |               |
110     +-----------+ 0x00BFFF -+---/
111     |           |           |
112     |           |           |
113     |           | 16K       |
114     |           |           |
115     +-----------+ 0x008000 -+
116     |           |
117     |           |
118     =           =
119     |           |
120     |           |
121     +-----------+ 0000
122
123
124    The 'call _foo' must be relocated with page 3 and 16-bit address
125    mapped at 0x8000.
126
127    The 3-bit and 16-bit PC rel relocation is only used by 68HC12.  */
128 static reloc_howto_type elf_m68hc11_howto_table[] = {
129   /* This reloc does nothing.  */
130   HOWTO (R_M68HC11_NONE,        /* type */
131          0,                     /* rightshift */
132          2,                     /* size (0 = byte, 1 = short, 2 = long) */
133          32,                    /* bitsize */
134          FALSE,                 /* pc_relative */
135          0,                     /* bitpos */
136          complain_overflow_dont,/* complain_on_overflow */
137          bfd_elf_generic_reloc, /* special_function */
138          "R_M68HC12_NONE",      /* name */
139          FALSE,                 /* partial_inplace */
140          0,                     /* src_mask */
141          0,                     /* dst_mask */
142          FALSE),                /* pcrel_offset */
143
144   /* A 8 bit absolute relocation */
145   HOWTO (R_M68HC11_8,           /* type */
146          0,                     /* rightshift */
147          0,                     /* size (0 = byte, 1 = short, 2 = long) */
148          8,                     /* bitsize */
149          FALSE,                 /* pc_relative */
150          0,                     /* bitpos */
151          complain_overflow_bitfield,    /* complain_on_overflow */
152          bfd_elf_generic_reloc, /* special_function */
153          "R_M68HC12_8",         /* name */
154          FALSE,                 /* partial_inplace */
155          0x00ff,                /* src_mask */
156          0x00ff,                /* dst_mask */
157          FALSE),                /* pcrel_offset */
158
159   /* A 8 bit absolute relocation (upper address) */
160   HOWTO (R_M68HC11_HI8,         /* type */
161          8,                     /* rightshift */
162          0,                     /* size (0 = byte, 1 = short, 2 = long) */
163          8,                     /* bitsize */
164          FALSE,                 /* pc_relative */
165          0,                     /* bitpos */
166          complain_overflow_bitfield,    /* complain_on_overflow */
167          bfd_elf_generic_reloc, /* special_function */
168          "R_M68HC12_HI8",       /* name */
169          FALSE,                 /* partial_inplace */
170          0x00ff,                /* src_mask */
171          0x00ff,                /* dst_mask */
172          FALSE),                /* pcrel_offset */
173
174   /* A 8 bit absolute relocation (upper address) */
175   HOWTO (R_M68HC11_LO8,         /* type */
176          0,                     /* rightshift */
177          0,                     /* size (0 = byte, 1 = short, 2 = long) */
178          8,                     /* bitsize */
179          FALSE,                 /* pc_relative */
180          0,                     /* bitpos */
181          complain_overflow_dont,        /* complain_on_overflow */
182          bfd_elf_generic_reloc, /* special_function */
183          "R_M68HC12_LO8",       /* name */
184          FALSE,                 /* partial_inplace */
185          0x00ff,                /* src_mask */
186          0x00ff,                /* dst_mask */
187          FALSE),                /* pcrel_offset */
188
189   /* A 8 bit PC-rel relocation */
190   HOWTO (R_M68HC11_PCREL_8,     /* type */
191          0,                     /* rightshift */
192          0,                     /* size (0 = byte, 1 = short, 2 = long) */
193          8,                     /* bitsize */
194          TRUE,                  /* pc_relative */
195          0,                     /* bitpos */
196          complain_overflow_bitfield,    /* complain_on_overflow */
197          bfd_elf_generic_reloc, /* special_function */
198          "R_M68HC12_PCREL_8",   /* name */
199          FALSE,                 /* partial_inplace */
200          0x00ff,                /* src_mask */
201          0x00ff,                /* dst_mask */
202          FALSE),                /* pcrel_offset */
203
204   /* A 16 bit absolute relocation */
205   HOWTO (R_M68HC11_16,          /* type */
206          0,                     /* rightshift */
207          1,                     /* size (0 = byte, 1 = short, 2 = long) */
208          16,                    /* bitsize */
209          FALSE,                 /* pc_relative */
210          0,                     /* bitpos */
211          complain_overflow_dont /*bitfield */ , /* complain_on_overflow */
212          m68hc12_elf_special_reloc,     /* special_function */
213          "R_M68HC12_16",        /* name */
214          FALSE,                 /* partial_inplace */
215          0xffff,                /* src_mask */
216          0xffff,                /* dst_mask */
217          FALSE),                /* pcrel_offset */
218
219   /* A 32 bit absolute relocation.  This one is never used for the
220      code relocation.  It's used by gas for -gstabs generation.  */
221   HOWTO (R_M68HC11_32,          /* type */
222          0,                     /* rightshift */
223          2,                     /* size (0 = byte, 1 = short, 2 = long) */
224          32,                    /* bitsize */
225          FALSE,                 /* pc_relative */
226          0,                     /* bitpos */
227          complain_overflow_bitfield,    /* complain_on_overflow */
228          bfd_elf_generic_reloc, /* special_function */
229          "R_M68HC12_32",        /* name */
230          FALSE,                 /* partial_inplace */
231          0xffffffff,            /* src_mask */
232          0xffffffff,            /* dst_mask */
233          FALSE),                /* pcrel_offset */
234
235   /* A 3 bit absolute relocation */
236   HOWTO (R_M68HC11_3B,          /* type */
237          0,                     /* rightshift */
238          0,                     /* size (0 = byte, 1 = short, 2 = long) */
239          3,                     /* bitsize */
240          FALSE,                 /* pc_relative */
241          0,                     /* bitpos */
242          complain_overflow_bitfield,    /* complain_on_overflow */
243          bfd_elf_generic_reloc, /* special_function */
244          "R_M68HC12_4B",        /* name */
245          FALSE,                 /* partial_inplace */
246          0x003,                 /* src_mask */
247          0x003,                 /* dst_mask */
248          FALSE),                /* pcrel_offset */
249
250   /* A 16 bit PC-rel relocation */
251   HOWTO (R_M68HC11_PCREL_16,    /* type */
252          0,                     /* rightshift */
253          1,                     /* size (0 = byte, 1 = short, 2 = long) */
254          16,                    /* bitsize */
255          TRUE,                  /* pc_relative */
256          0,                     /* bitpos */
257          complain_overflow_dont,        /* complain_on_overflow */
258          bfd_elf_generic_reloc, /* special_function */
259          "R_M68HC12_PCREL_16",  /* name */
260          FALSE,                 /* partial_inplace */
261          0xffff,                /* src_mask */
262          0xffff,                /* dst_mask */
263          FALSE),                /* pcrel_offset */
264
265   /* GNU extension to record C++ vtable hierarchy */
266   HOWTO (R_M68HC11_GNU_VTINHERIT,       /* type */
267          0,                     /* rightshift */
268          1,                     /* size (0 = byte, 1 = short, 2 = long) */
269          0,                     /* bitsize */
270          FALSE,                 /* pc_relative */
271          0,                     /* bitpos */
272          complain_overflow_dont,        /* complain_on_overflow */
273          NULL,                  /* special_function */
274          "R_M68HC11_GNU_VTINHERIT",     /* name */
275          FALSE,                 /* partial_inplace */
276          0,                     /* src_mask */
277          0,                     /* dst_mask */
278          FALSE),                /* pcrel_offset */
279
280   /* GNU extension to record C++ vtable member usage */
281   HOWTO (R_M68HC11_GNU_VTENTRY, /* type */
282          0,                     /* rightshift */
283          1,                     /* size (0 = byte, 1 = short, 2 = long) */
284          0,                     /* bitsize */
285          FALSE,                 /* pc_relative */
286          0,                     /* bitpos */
287          complain_overflow_dont,        /* complain_on_overflow */
288          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
289          "R_M68HC11_GNU_VTENTRY",       /* name */
290          FALSE,                 /* partial_inplace */
291          0,                     /* src_mask */
292          0,                     /* dst_mask */
293          FALSE),                /* pcrel_offset */
294
295   /* A 24 bit relocation */
296   HOWTO (R_M68HC11_24,          /* type */
297          0,                     /* rightshift */
298          1,                     /* size (0 = byte, 1 = short, 2 = long) */
299          24,                    /* bitsize */
300          FALSE,                 /* pc_relative */
301          0,                     /* bitpos */
302          complain_overflow_dont,        /* complain_on_overflow */
303          m68hc12_elf_special_reloc,     /* special_function */
304          "R_M68HC12_24",        /* name */
305          FALSE,                 /* partial_inplace */
306          0xffff,                /* src_mask */
307          0xffff,                /* dst_mask */
308          FALSE),                /* pcrel_offset */
309
310   /* A 16-bit low relocation */
311   HOWTO (R_M68HC11_LO16,        /* type */
312          0,                     /* rightshift */
313          1,                     /* size (0 = byte, 1 = short, 2 = long) */
314          16,                    /* bitsize */
315          FALSE,                 /* pc_relative */
316          0,                     /* bitpos */
317          complain_overflow_dont,        /* complain_on_overflow */
318          m68hc12_elf_special_reloc,/* special_function */
319          "R_M68HC12_LO16",      /* name */
320          FALSE,                 /* partial_inplace */
321          0xffff,                /* src_mask */
322          0xffff,                /* dst_mask */
323          FALSE),                /* pcrel_offset */
324
325   /* A page relocation */
326   HOWTO (R_M68HC11_PAGE,        /* type */
327          0,                     /* rightshift */
328          0,                     /* size (0 = byte, 1 = short, 2 = long) */
329          8,                     /* bitsize */
330          FALSE,                 /* pc_relative */
331          0,                     /* bitpos */
332          complain_overflow_dont,        /* complain_on_overflow */
333          m68hc12_elf_special_reloc,/* special_function */
334          "R_M68HC12_PAGE",      /* name */
335          FALSE,                 /* partial_inplace */
336          0x00ff,                /* src_mask */
337          0x00ff,                /* dst_mask */
338          FALSE),                /* pcrel_offset */
339
340   EMPTY_HOWTO (14),
341   EMPTY_HOWTO (15),
342   EMPTY_HOWTO (16),
343   EMPTY_HOWTO (17),
344   EMPTY_HOWTO (18),
345   EMPTY_HOWTO (19),
346
347   /* Mark beginning of a jump instruction (any form).  */
348   HOWTO (R_M68HC11_RL_JUMP,     /* type */
349          0,                     /* rightshift */
350          1,                     /* size (0 = byte, 1 = short, 2 = long) */
351          0,                     /* bitsize */
352          FALSE,                 /* pc_relative */
353          0,                     /* bitpos */
354          complain_overflow_dont,        /* complain_on_overflow */
355          m68hc11_elf_ignore_reloc,      /* special_function */
356          "R_M68HC12_RL_JUMP",   /* name */
357          TRUE,                  /* partial_inplace */
358          0,                     /* src_mask */
359          0,                     /* dst_mask */
360          TRUE),                 /* pcrel_offset */
361
362   /* Mark beginning of Gcc relaxation group instruction.  */
363   HOWTO (R_M68HC11_RL_GROUP,    /* type */
364          0,                     /* rightshift */
365          1,                     /* size (0 = byte, 1 = short, 2 = long) */
366          0,                     /* bitsize */
367          FALSE,                 /* pc_relative */
368          0,                     /* bitpos */
369          complain_overflow_dont,        /* complain_on_overflow */
370          m68hc11_elf_ignore_reloc,      /* special_function */
371          "R_M68HC12_RL_GROUP",  /* name */
372          TRUE,                  /* partial_inplace */
373          0,                     /* src_mask */
374          0,                     /* dst_mask */
375          TRUE),                 /* pcrel_offset */
376 };
377
378 /* Map BFD reloc types to M68HC11 ELF reloc types.  */
379
380 struct m68hc11_reloc_map
381 {
382   bfd_reloc_code_real_type bfd_reloc_val;
383   unsigned char elf_reloc_val;
384 };
385
386 static const struct m68hc11_reloc_map m68hc11_reloc_map[] = {
387   {BFD_RELOC_NONE, R_M68HC11_NONE,},
388   {BFD_RELOC_8, R_M68HC11_8},
389   {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8},
390   {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8},
391   {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8},
392   {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16},
393   {BFD_RELOC_16, R_M68HC11_16},
394   {BFD_RELOC_32, R_M68HC11_32},
395   {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
396
397   {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
398   {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
399
400   {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16},
401   {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE},
402   {BFD_RELOC_M68HC11_24, R_M68HC11_24},
403
404   {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
405   {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
406 };
407
408 static reloc_howto_type *
409 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
410      bfd *abfd ATTRIBUTE_UNUSED;
411      bfd_reloc_code_real_type code;
412 {
413   unsigned int i;
414
415   for (i = 0;
416        i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map);
417        i++)
418     {
419       if (m68hc11_reloc_map[i].bfd_reloc_val == code)
420         return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val];
421     }
422
423   return NULL;
424 }
425
426 /* This function is used for relocs which are only used for relaxing,
427    which the linker should otherwise ignore.  */
428
429 static bfd_reloc_status_type
430 m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
431                           output_bfd, error_message)
432      bfd *abfd ATTRIBUTE_UNUSED;
433      arelent *reloc_entry;
434      asymbol *symbol ATTRIBUTE_UNUSED;
435      PTR data ATTRIBUTE_UNUSED;
436      asection *input_section;
437      bfd *output_bfd;
438      char **error_message ATTRIBUTE_UNUSED;
439 {
440   if (output_bfd != NULL)
441     reloc_entry->address += input_section->output_offset;
442   return bfd_reloc_ok;
443 }
444
445 static int
446 m68hc12_addr_is_banked (addr)
447      bfd_vma addr;
448 {
449    return (addr >= M68HC12_BANK_VIRT) ? 1 : 0;
450 }
451
452 /* Return the physical address seen by the processor, taking
453    into account banked memory.  */
454 static bfd_vma
455 m68hc12_phys_addr (addr)
456      bfd_vma addr;
457 {
458   if (addr < M68HC12_BANK_VIRT)
459     return addr;
460
461   /* Map the address to the memory bank.  */
462   addr -= M68HC12_BANK_VIRT;
463   addr &= M68HC12_BANK_MASK;
464   addr += M68HC12_BANK_BASE;
465   return addr;
466 }
467
468 /* Return the page number corresponding to an address in banked memory.  */
469 static bfd_vma
470 m68hc12_phys_page (addr)
471      bfd_vma addr;
472 {
473   if (addr < M68HC12_BANK_VIRT)
474     return 0;
475
476   /* Map the address to the memory bank.  */
477   addr -= M68HC12_BANK_VIRT;
478   addr >>= M68HC12_BANK_SHIFT;
479   addr &= M68HC12_BANK_PAGE_MASK;
480   return addr;
481 }
482
483 static bfd_reloc_status_type
484 m68hc12_elf_special_reloc (abfd, reloc_entry, symbol, data, input_section,
485                            output_bfd, error_message)
486      bfd *abfd;
487      arelent *reloc_entry;
488      asymbol *symbol;
489      PTR data;
490      asection *input_section;
491      bfd *output_bfd;
492      char **error_message ATTRIBUTE_UNUSED;
493 {
494   reloc_howto_type *howto;
495   bfd_vma relocation;
496   bfd_vma phys_addr;
497   bfd_vma phys_page;
498   bfd_vma insn_page;
499   bfd_vma insn_addr;
500
501   if (output_bfd != (bfd *) NULL
502       && (symbol->flags & BSF_SECTION_SYM) == 0
503       && (! reloc_entry->howto->partial_inplace
504           || reloc_entry->addend == 0))
505     {
506       reloc_entry->address += input_section->output_offset;
507       return bfd_reloc_ok;
508     }
509
510   if (output_bfd != NULL)
511     return bfd_reloc_continue;
512
513   if (reloc_entry->address > input_section->_cooked_size)
514     return bfd_reloc_outofrange;
515
516   /* Compute relocation.  */
517   relocation = (symbol->value
518                 + symbol->section->output_section->vma
519                 + symbol->section->output_offset);
520   relocation += reloc_entry->addend;
521   relocation += bfd_get_16 (abfd, (bfd_byte*) data + reloc_entry->address);
522
523   /* Do the memory bank mapping.  */
524   phys_addr = m68hc12_phys_addr (relocation);
525   phys_page = m68hc12_phys_page (relocation);
526
527   howto = reloc_entry->howto;
528   if (howto->complain_on_overflow != complain_overflow_dont
529       && (phys_addr & (((bfd_vma) -1) << 16)))
530      return bfd_reloc_overflow;
531
532   switch (howto->type)
533     {
534     case R_M68HC11_16:
535           /* Get virtual address of instruction having the relocation.  */
536        insn_addr = input_section->output_section->vma
537           + input_section->output_offset
538           + reloc_entry->address;
539
540       insn_page = m68hc12_phys_page (insn_addr);
541
542       if (m68hc12_addr_is_banked (relocation)
543           && m68hc12_addr_is_banked (insn_addr)
544           && phys_page != insn_page)
545          {
546             *error_message = _("address is not in the same bank");
547             return bfd_reloc_dangerous;
548          }
549       if (m68hc12_addr_is_banked (relocation)
550           && !m68hc12_addr_is_banked (insn_addr))
551          {
552             *error_message = _("reference to a banked address in "
553                                "the normal address space");
554             return bfd_reloc_dangerous;
555          }
556
557     case R_M68HC11_LO16:
558       bfd_put_16 (abfd, phys_addr, (bfd_byte*) data + reloc_entry->address);
559       break;
560
561     case R_M68HC11_24:
562       bfd_put_16 (abfd, phys_addr, (bfd_byte*) data + reloc_entry->address);
563       bfd_put_8 (abfd, phys_page, (bfd_byte*) data + reloc_entry->address + 2);
564       break;
565
566     case R_M68HC11_PAGE:
567       bfd_put_8 (abfd, phys_page, (bfd_byte*) data + reloc_entry->address);
568       break;
569
570     default:
571        abort ();
572        break;
573     }
574
575   return bfd_reloc_ok;
576 }
577
578 /* Set the howto pointer for an M68HC11 ELF reloc.  */
579
580 static void
581 m68hc11_info_to_howto_rel (abfd, cache_ptr, dst)
582      bfd *abfd ATTRIBUTE_UNUSED;
583      arelent *cache_ptr;
584      Elf_Internal_Rela *dst;
585 {
586   unsigned int r_type;
587
588   r_type = ELF32_R_TYPE (dst->r_info);
589   BFD_ASSERT (r_type < (unsigned int) R_M68HC11_max);
590   cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
591 }
592
593 static asection *
594 elf32_m68hc11_gc_mark_hook (sec, info, rel, h, sym)
595      asection *sec;
596      struct bfd_link_info *info ATTRIBUTE_UNUSED;
597      Elf_Internal_Rela *rel;
598      struct elf_link_hash_entry *h;
599      Elf_Internal_Sym *sym;
600 {
601   if (h != NULL)
602     {
603       switch (ELF32_R_TYPE (rel->r_info))
604         {
605         default:
606           switch (h->root.type)
607             {
608             case bfd_link_hash_defined:
609             case bfd_link_hash_defweak:
610               return h->root.u.def.section;
611
612             case bfd_link_hash_common:
613               return h->root.u.c.p->section;
614
615             default:
616               break;
617             }
618         }
619     }
620   else
621     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
622
623   return NULL;
624 }
625
626 static bfd_boolean
627 elf32_m68hc11_gc_sweep_hook (abfd, info, sec, relocs)
628      bfd *abfd ATTRIBUTE_UNUSED;
629      struct bfd_link_info *info ATTRIBUTE_UNUSED;
630      asection *sec ATTRIBUTE_UNUSED;
631      const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
632 {
633   /* We don't use got and plt entries for 68hc11/68hc12.  */
634   return TRUE;
635 }
636
637 \f
638 static bfd_boolean
639 m68hc12_elf_set_mach_from_flags (abfd)
640      bfd *abfd;
641 {
642   flagword flags = elf_elfheader (abfd)->e_flags;
643
644   switch (flags & EF_M68HC11_MACH_MASK)
645     {
646     case EF_M68HC12_MACH:
647       bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812);
648       break;
649     case EF_M68HCS12_MACH:
650       bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812s);
651       break;
652     case EF_M68HC11_GENERIC:
653       bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12,
654                                  bfd_mach_m6812_default);
655       break;
656     default:
657       return FALSE;
658     }
659   return TRUE;
660 }
661
662 /* Set and control ELF flags in ELF header.  */
663
664 bfd_boolean
665 _bfd_m68hc12_elf_set_private_flags (abfd, flags)
666      bfd *abfd;
667      flagword flags;
668 {
669   BFD_ASSERT (!elf_flags_init (abfd)
670               || elf_elfheader (abfd)->e_flags == flags);
671
672   elf_elfheader (abfd)->e_flags = flags;
673   elf_flags_init (abfd) = TRUE;
674   return m68hc12_elf_set_mach_from_flags (abfd);
675 }
676
677 /* Merge backend specific data from an object file to the output
678    object file when linking.  */
679
680 bfd_boolean
681 _bfd_m68hc12_elf_merge_private_bfd_data (ibfd, obfd)
682      bfd *ibfd;
683      bfd *obfd;
684 {
685   flagword old_flags;
686   flagword new_flags;
687   bfd_boolean ok = TRUE;
688
689   /* Check if we have the same endianess */
690   if (!_bfd_generic_verify_endian_match (ibfd, obfd))
691     return FALSE;
692
693   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
694       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
695     return TRUE;
696
697   new_flags = elf_elfheader (ibfd)->e_flags;
698   old_flags = elf_elfheader (obfd)->e_flags;
699
700   if (! elf_flags_init (obfd))
701     {
702       elf_flags_init (obfd) = TRUE;
703       elf_elfheader (obfd)->e_flags = new_flags;
704       elf_elfheader (obfd)->e_ident[EI_CLASS]
705         = elf_elfheader (ibfd)->e_ident[EI_CLASS];
706
707       if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
708           && bfd_get_arch_info (obfd)->the_default)
709         {
710           if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
711                                    bfd_get_mach (ibfd)))
712             return FALSE;
713         }
714
715       return TRUE;
716     }
717
718   /* Check ABI compatibility.  */
719   if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
720     {
721       (*_bfd_error_handler)
722         (_("%s: linking files compiled for 16-bit integers (-mshort) "
723            "and others for 32-bit integers"),
724          bfd_archive_filename (ibfd));
725       ok = FALSE;
726     }
727   if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
728     {
729       (*_bfd_error_handler)
730         (_("%s: linking files compiled for 32-bit double (-fshort-double) "
731            "and others for 64-bit double"),
732          bfd_archive_filename (ibfd));
733       ok = FALSE;
734     }
735
736   /* Processor compatibility.  */
737   if (!EF_M68HC11_CAN_MERGE_MACH (new_flags, old_flags))
738     {
739       (*_bfd_error_handler)
740         (_("%s: linking files compiled for HCS12 with "
741            "others compiled for HC12"),
742          bfd_archive_filename (ibfd));
743       ok = FALSE;
744     }
745   new_flags = ((new_flags & ~EF_M68HC11_MACH_MASK)
746                | (EF_M68HC11_MERGE_MACH (new_flags, old_flags)));
747
748   elf_elfheader (obfd)->e_flags = new_flags;
749
750   /* Warn about any other mismatches */
751   new_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
752   old_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
753   if (new_flags != old_flags)
754     {
755       (*_bfd_error_handler)
756         (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
757          bfd_archive_filename (ibfd), (unsigned long) new_flags,
758          (unsigned long) old_flags);
759       ok = FALSE;
760     }
761
762   if (! ok)
763     {
764       bfd_set_error (bfd_error_bad_value);
765       return FALSE;
766     }
767
768   return TRUE;
769 }
770
771 bfd_boolean
772 _bfd_m68hc12_elf_print_private_bfd_data (abfd, ptr)
773      bfd *abfd;
774      PTR ptr;
775 {
776   FILE *file = (FILE *) ptr;
777
778   BFD_ASSERT (abfd != NULL && ptr != NULL);
779
780   /* Print normal ELF private data.  */
781   _bfd_elf_print_private_bfd_data (abfd, ptr);
782
783   /* xgettext:c-format */
784   fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
785
786   if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
787     fprintf (file, _("[abi=32-bit int,"));
788   else
789     fprintf (file, _("[abi=16-bit int,"));
790
791   if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
792     fprintf (file, _(" 64-bit double,"));
793   else
794     fprintf (file, _(" 32-bit double,"));
795
796   if (elf_elfheader (abfd)->e_flags & EF_M68HCS12_MACH)
797     fprintf (file, _(" cpu=HCS12]"));
798   else
799     fprintf (file, _(" cpu=HC12]"));
800   fputc ('\n', file);
801
802   return TRUE;
803 }
804
805 #define ELF_ARCH                bfd_arch_m68hc12
806 #define ELF_MACHINE_CODE        EM_68HC12
807 #define ELF_MAXPAGESIZE         0x1000
808
809 #define TARGET_BIG_SYM          bfd_elf32_m68hc12_vec
810 #define TARGET_BIG_NAME         "elf32-m68hc12"
811
812 #define elf_info_to_howto       0
813 #define elf_info_to_howto_rel   m68hc11_info_to_howto_rel
814 #define elf_backend_gc_mark_hook     elf32_m68hc11_gc_mark_hook
815 #define elf_backend_gc_sweep_hook    elf32_m68hc11_gc_sweep_hook
816 #define elf_backend_object_p            m68hc12_elf_set_mach_from_flags
817 #define elf_backend_final_write_processing      0
818 /* Disabled as this backend uses the generic linker.  */
819 #define elf_backend_can_gc_sections             0
820
821 #define bfd_elf32_bfd_merge_private_bfd_data \
822                                         _bfd_m68hc12_elf_merge_private_bfd_data
823 #define bfd_elf32_bfd_set_private_flags _bfd_m68hc12_elf_set_private_flags
824 #define bfd_elf32_bfd_print_private_bfd_data \
825                                         _bfd_m68hc12_elf_print_private_bfd_data
826
827 #include "elf32-target.h"