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))
6 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
26 #include "elf/m68hc11.h"
27 #include "opcode/m68hc11.h"
29 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
30 PARAMS ((bfd * abfd, bfd_reloc_code_real_type code));
31 static void m68hc11_info_to_howto_rel
32 PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
34 static bfd_reloc_status_type m68hc11_elf_ignore_reloc
35 PARAMS ((bfd *abfd, arelent *reloc_entry,
36 asymbol *symbol, PTR data, asection *input_section,
37 bfd *output_bfd, char **error_message));
38 static bfd_reloc_status_type m68hc12_elf_special_reloc
39 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
40 static int m68hc12_addr_is_banked PARAMS ((bfd_vma));
41 static bfd_vma m68hc12_phys_addr PARAMS ((bfd_vma));
42 static bfd_vma m68hc12_phys_page PARAMS ((bfd_vma));
44 boolean _bfd_m68hc12_elf_merge_private_bfd_data PARAMS ((bfd*, bfd*));
45 boolean _bfd_m68hc12_elf_set_private_flags PARAMS ((bfd*, flagword));
46 boolean _bfd_m68hc12_elf_print_private_bfd_data PARAMS ((bfd*, PTR));
50 /* Use REL instead of RELA to save space */
53 /* The Motorola 68HC11 microcontroler only addresses 64Kb.
54 We must handle 8 and 16-bit relocations. The 32-bit relocation
55 is defined but not used except by gas when -gstabs is used (which
58 The 68HC12 microcontroler has a memory bank switching system
59 with a 16Kb window in the 64Kb address space. The extended memory
60 is mapped in the 16Kb window (at 0x8000). The page register controls
61 which 16Kb bank is mapped. The call/rtc instructions take care of
62 bank switching in function calls/returns.
64 For GNU Binutils to work, we consider there is a physical memory
65 at 0..0x0ffff and a kind of virtual memory above that. Symbols
66 in virtual memory have their addresses treated in a special way
67 when disassembling and when linking.
69 For the linker to work properly, we must always relocate the virtual
70 memory as if it is mapped at 0x8000. When a 16-bit relocation is
71 made in the virtual memory, we check that it does not cross the
72 memory bank where it is used. This would involve a page change
73 which would be wrong. The 24-bit relocation is for that and it
74 treats the address as a physical address + page number.
80 +---------------+ 0x1010000
85 +---------------+ 0x100C000
90 +---------------+ 0x1008000
92 | | call _foo | Page 1
94 | +---------------+ 0x1004000
96 Address Space | | | Page 0
98 +-----------+ 0x00FFFF | +---------------+ 0x1000000
102 +-----------+ 0x00BFFF -+---/
107 +-----------+ 0x008000 -+
116 The 'call _foo' must be relocated with page 3 and 16-bit address
119 The 3-bit and 16-bit PC rel relocation is only used by 68HC12. */
120 static reloc_howto_type elf_m68hc11_howto_table[] = {
121 /* This reloc does nothing. */
122 HOWTO (R_M68HC11_NONE, /* type */
124 2, /* size (0 = byte, 1 = short, 2 = long) */
126 false, /* pc_relative */
128 complain_overflow_dont,/* complain_on_overflow */
129 bfd_elf_generic_reloc, /* special_function */
130 "R_M68HC12_NONE", /* name */
131 false, /* partial_inplace */
134 false), /* pcrel_offset */
136 /* A 8 bit absolute relocation */
137 HOWTO (R_M68HC11_8, /* type */
139 0, /* size (0 = byte, 1 = short, 2 = long) */
141 false, /* pc_relative */
143 complain_overflow_bitfield, /* complain_on_overflow */
144 bfd_elf_generic_reloc, /* special_function */
145 "R_M68HC12_8", /* name */
146 false, /* partial_inplace */
147 0x00ff, /* src_mask */
148 0x00ff, /* dst_mask */
149 false), /* pcrel_offset */
151 /* A 8 bit absolute relocation (upper address) */
152 HOWTO (R_M68HC11_HI8, /* type */
154 0, /* size (0 = byte, 1 = short, 2 = long) */
156 false, /* pc_relative */
158 complain_overflow_bitfield, /* complain_on_overflow */
159 bfd_elf_generic_reloc, /* special_function */
160 "R_M68HC12_HI8", /* name */
161 false, /* partial_inplace */
162 0x00ff, /* src_mask */
163 0x00ff, /* dst_mask */
164 false), /* pcrel_offset */
166 /* A 8 bit absolute relocation (upper address) */
167 HOWTO (R_M68HC11_LO8, /* type */
169 0, /* size (0 = byte, 1 = short, 2 = long) */
171 false, /* pc_relative */
173 complain_overflow_dont, /* complain_on_overflow */
174 bfd_elf_generic_reloc, /* special_function */
175 "R_M68HC12_LO8", /* name */
176 false, /* partial_inplace */
177 0x00ff, /* src_mask */
178 0x00ff, /* dst_mask */
179 false), /* pcrel_offset */
181 /* A 8 bit PC-rel relocation */
182 HOWTO (R_M68HC11_PCREL_8, /* type */
184 0, /* size (0 = byte, 1 = short, 2 = long) */
186 true, /* pc_relative */
188 complain_overflow_bitfield, /* complain_on_overflow */
189 bfd_elf_generic_reloc, /* special_function */
190 "R_M68HC12_PCREL_8", /* name */
191 false, /* partial_inplace */
192 0x00ff, /* src_mask */
193 0x00ff, /* dst_mask */
194 false), /* pcrel_offset */
196 /* A 16 bit absolute relocation */
197 HOWTO (R_M68HC11_16, /* type */
199 1, /* size (0 = byte, 1 = short, 2 = long) */
201 false, /* pc_relative */
203 complain_overflow_dont /*bitfield */ , /* complain_on_overflow */
204 m68hc12_elf_special_reloc, /* special_function */
205 "R_M68HC12_16", /* name */
206 false, /* partial_inplace */
207 0xffff, /* src_mask */
208 0xffff, /* dst_mask */
209 false), /* pcrel_offset */
211 /* A 32 bit absolute relocation. This one is never used for the
212 code relocation. It's used by gas for -gstabs generation. */
213 HOWTO (R_M68HC11_32, /* type */
215 2, /* size (0 = byte, 1 = short, 2 = long) */
217 false, /* pc_relative */
219 complain_overflow_bitfield, /* complain_on_overflow */
220 bfd_elf_generic_reloc, /* special_function */
221 "R_M68HC12_32", /* name */
222 false, /* partial_inplace */
223 0xffffffff, /* src_mask */
224 0xffffffff, /* dst_mask */
225 false), /* pcrel_offset */
227 /* A 3 bit absolute relocation */
228 HOWTO (R_M68HC11_3B, /* type */
230 0, /* size (0 = byte, 1 = short, 2 = long) */
232 false, /* pc_relative */
234 complain_overflow_bitfield, /* complain_on_overflow */
235 bfd_elf_generic_reloc, /* special_function */
236 "R_M68HC12_4B", /* name */
237 false, /* partial_inplace */
238 0x003, /* src_mask */
239 0x003, /* dst_mask */
240 false), /* pcrel_offset */
242 /* A 16 bit PC-rel relocation */
243 HOWTO (R_M68HC11_PCREL_16, /* type */
245 1, /* size (0 = byte, 1 = short, 2 = long) */
247 true, /* pc_relative */
249 complain_overflow_dont, /* complain_on_overflow */
250 bfd_elf_generic_reloc, /* special_function */
251 "R_M68HC12_PCREL_16", /* name */
252 false, /* partial_inplace */
253 0xffff, /* src_mask */
254 0xffff, /* dst_mask */
255 false), /* pcrel_offset */
257 /* GNU extension to record C++ vtable hierarchy */
258 HOWTO (R_M68HC11_GNU_VTINHERIT, /* type */
260 1, /* size (0 = byte, 1 = short, 2 = long) */
262 false, /* pc_relative */
264 complain_overflow_dont, /* complain_on_overflow */
265 NULL, /* special_function */
266 "R_M68HC11_GNU_VTINHERIT", /* name */
267 false, /* partial_inplace */
270 false), /* pcrel_offset */
272 /* GNU extension to record C++ vtable member usage */
273 HOWTO (R_M68HC11_GNU_VTENTRY, /* type */
275 1, /* size (0 = byte, 1 = short, 2 = long) */
277 false, /* pc_relative */
279 complain_overflow_dont, /* complain_on_overflow */
280 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
281 "R_M68HC11_GNU_VTENTRY", /* name */
282 false, /* partial_inplace */
285 false), /* pcrel_offset */
287 /* A 24 bit relocation */
288 HOWTO (R_M68HC11_24, /* type */
290 1, /* size (0 = byte, 1 = short, 2 = long) */
292 false, /* pc_relative */
294 complain_overflow_dont, /* complain_on_overflow */
295 m68hc12_elf_special_reloc, /* special_function */
296 "R_M68HC12_24", /* name */
297 false, /* partial_inplace */
298 0xffff, /* src_mask */
299 0xffff, /* dst_mask */
300 false), /* pcrel_offset */
302 /* A 16-bit low relocation */
303 HOWTO (R_M68HC11_LO16, /* type */
305 1, /* size (0 = byte, 1 = short, 2 = long) */
307 false, /* pc_relative */
309 complain_overflow_dont, /* complain_on_overflow */
310 m68hc12_elf_special_reloc,/* special_function */
311 "R_M68HC12_LO16", /* name */
312 false, /* partial_inplace */
313 0xffff, /* src_mask */
314 0xffff, /* dst_mask */
315 false), /* pcrel_offset */
317 /* A page relocation */
318 HOWTO (R_M68HC11_PAGE, /* type */
320 0, /* size (0 = byte, 1 = short, 2 = long) */
322 false, /* pc_relative */
324 complain_overflow_dont, /* complain_on_overflow */
325 m68hc12_elf_special_reloc,/* special_function */
326 "R_M68HC12_PAGE", /* name */
327 false, /* partial_inplace */
328 0x00ff, /* src_mask */
329 0x00ff, /* dst_mask */
330 false), /* pcrel_offset */
339 /* Mark beginning of a jump instruction (any form). */
340 HOWTO (R_M68HC11_RL_JUMP, /* type */
342 1, /* size (0 = byte, 1 = short, 2 = long) */
344 false, /* pc_relative */
346 complain_overflow_dont, /* complain_on_overflow */
347 m68hc11_elf_ignore_reloc, /* special_function */
348 "R_M68HC12_RL_JUMP", /* name */
349 true, /* partial_inplace */
352 true), /* pcrel_offset */
354 /* Mark beginning of Gcc relaxation group instruction. */
355 HOWTO (R_M68HC11_RL_GROUP, /* type */
357 1, /* size (0 = byte, 1 = short, 2 = long) */
359 false, /* pc_relative */
361 complain_overflow_dont, /* complain_on_overflow */
362 m68hc11_elf_ignore_reloc, /* special_function */
363 "R_M68HC12_RL_GROUP", /* name */
364 true, /* partial_inplace */
367 true), /* pcrel_offset */
370 /* Map BFD reloc types to M68HC11 ELF reloc types. */
372 struct m68hc11_reloc_map
374 bfd_reloc_code_real_type bfd_reloc_val;
375 unsigned char elf_reloc_val;
378 static const struct m68hc11_reloc_map m68hc11_reloc_map[] = {
379 {BFD_RELOC_NONE, R_M68HC11_NONE,},
380 {BFD_RELOC_8, R_M68HC11_8},
381 {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8},
382 {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8},
383 {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8},
384 {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16},
385 {BFD_RELOC_16, R_M68HC11_16},
386 {BFD_RELOC_32, R_M68HC11_32},
387 {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
389 {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
390 {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
392 {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16},
393 {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE},
394 {BFD_RELOC_M68HC11_24, R_M68HC11_24},
396 {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
397 {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
400 static reloc_howto_type *
401 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
402 bfd *abfd ATTRIBUTE_UNUSED;
403 bfd_reloc_code_real_type code;
408 i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map);
411 if (m68hc11_reloc_map[i].bfd_reloc_val == code)
412 return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val];
418 /* This function is used for relocs which are only used for relaxing,
419 which the linker should otherwise ignore. */
421 static bfd_reloc_status_type
422 m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
423 output_bfd, error_message)
424 bfd *abfd ATTRIBUTE_UNUSED;
425 arelent *reloc_entry;
426 asymbol *symbol ATTRIBUTE_UNUSED;
427 PTR data ATTRIBUTE_UNUSED;
428 asection *input_section;
430 char **error_message ATTRIBUTE_UNUSED;
432 if (output_bfd != NULL)
433 reloc_entry->address += input_section->output_offset;
438 m68hc12_addr_is_banked (addr)
441 return (addr >= M68HC12_BANK_VIRT) ? 1 : 0;
444 /* Return the physical address seen by the processor, taking
445 into account banked memory. */
447 m68hc12_phys_addr (addr)
450 if (addr < M68HC12_BANK_VIRT)
453 /* Map the address to the memory bank. */
454 addr -= M68HC12_BANK_VIRT;
455 addr &= M68HC12_BANK_MASK;
456 addr += M68HC12_BANK_BASE;
460 /* Return the page number corresponding to an address in banked memory. */
462 m68hc12_phys_page (addr)
465 if (addr < M68HC12_BANK_VIRT)
468 /* Map the address to the memory bank. */
469 addr -= M68HC12_BANK_VIRT;
470 addr >>= M68HC12_BANK_SHIFT;
471 addr &= M68HC12_BANK_PAGE_MASK;
475 static bfd_reloc_status_type
476 m68hc12_elf_special_reloc (abfd, reloc_entry, symbol, data, input_section,
477 output_bfd, error_message)
479 arelent *reloc_entry;
482 asection *input_section;
484 char **error_message ATTRIBUTE_UNUSED;
486 reloc_howto_type *howto;
493 if (output_bfd != (bfd *) NULL
494 && (symbol->flags & BSF_SECTION_SYM) == 0
495 && (! reloc_entry->howto->partial_inplace
496 || reloc_entry->addend == 0))
498 reloc_entry->address += input_section->output_offset;
502 if (output_bfd != NULL)
503 return bfd_reloc_continue;
505 if (reloc_entry->address > input_section->_cooked_size)
506 return bfd_reloc_outofrange;
508 /* Compute relocation. */
509 relocation = (symbol->value
510 + symbol->section->output_section->vma
511 + symbol->section->output_offset);
512 relocation += reloc_entry->addend;
513 relocation += bfd_get_16 (abfd, (bfd_byte*) data + reloc_entry->address);
515 /* Do the memory bank mapping. */
516 phys_addr = m68hc12_phys_addr (relocation);
517 phys_page = m68hc12_phys_page (relocation);
519 howto = reloc_entry->howto;
520 if (howto->complain_on_overflow != complain_overflow_dont
521 && (phys_addr & (((bfd_vma) -1) << 16)))
522 return bfd_reloc_overflow;
527 /* Get virtual address of instruction having the relocation. */
528 insn_addr = input_section->output_section->vma
529 + input_section->output_offset
530 + reloc_entry->address;
532 insn_page = m68hc12_phys_page (insn_addr);
534 if (m68hc12_addr_is_banked (relocation)
535 && m68hc12_addr_is_banked (insn_addr)
536 && phys_page != insn_page)
538 *error_message = _("address is not in the same bank");
539 return bfd_reloc_dangerous;
541 if (m68hc12_addr_is_banked (relocation)
542 && !m68hc12_addr_is_banked (insn_addr))
544 *error_message = _("reference to a banked address in "
545 "the normal address space");
546 return bfd_reloc_dangerous;
550 bfd_put_16 (abfd, phys_addr, (bfd_byte*) data + reloc_entry->address);
554 bfd_put_16 (abfd, phys_addr, (bfd_byte*) data + reloc_entry->address);
555 bfd_put_8 (abfd, phys_page, (bfd_byte*) data + reloc_entry->address + 2);
559 bfd_put_8 (abfd, phys_page, (bfd_byte*) data + reloc_entry->address);
570 /* Set the howto pointer for an M68HC11 ELF reloc. */
573 m68hc11_info_to_howto_rel (abfd, cache_ptr, dst)
574 bfd *abfd ATTRIBUTE_UNUSED;
576 Elf32_Internal_Rel *dst;
580 r_type = ELF32_R_TYPE (dst->r_info);
581 BFD_ASSERT (r_type < (unsigned int) R_M68HC11_max);
582 cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
586 /* Set and control ELF flags in ELF header. */
589 _bfd_m68hc12_elf_set_private_flags (abfd, flags)
593 BFD_ASSERT (!elf_flags_init (abfd)
594 || elf_elfheader (abfd)->e_flags == flags);
596 elf_elfheader (abfd)->e_flags = flags;
597 elf_flags_init (abfd) = true;
601 /* Merge backend specific data from an object file to the output
602 object file when linking. */
605 _bfd_m68hc12_elf_merge_private_bfd_data (ibfd, obfd)
613 /* Check if we have the same endianess */
614 if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
617 if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
618 || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
621 new_flags = elf_elfheader (ibfd)->e_flags;
622 elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI;
623 old_flags = elf_elfheader (obfd)->e_flags;
625 if (! elf_flags_init (obfd))
627 elf_flags_init (obfd) = true;
628 elf_elfheader (obfd)->e_flags = new_flags;
629 elf_elfheader (obfd)->e_ident[EI_CLASS]
630 = elf_elfheader (ibfd)->e_ident[EI_CLASS];
632 if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
633 && bfd_get_arch_info (obfd)->the_default)
635 if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
636 bfd_get_mach (ibfd)))
643 /* Check ABI compatibility. */
644 if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
646 (*_bfd_error_handler)
647 (_("%s: linking files compiled for 16-bit integers (-mshort) "
648 "and others for 32-bit integers"),
649 bfd_archive_filename (ibfd));
652 if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
654 (*_bfd_error_handler)
655 (_("%s: linking files compiled for 32-bit double (-fshort-double) "
656 "and others for 64-bit double"),
657 bfd_archive_filename (ibfd));
660 new_flags &= ~EF_M68HC11_ABI;
661 old_flags &= ~EF_M68HC11_ABI;
663 /* Warn about any other mismatches */
664 if (new_flags != old_flags)
666 (*_bfd_error_handler)
667 (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
668 bfd_archive_filename (ibfd), (unsigned long) new_flags,
669 (unsigned long) old_flags);
675 bfd_set_error (bfd_error_bad_value);
683 _bfd_m68hc12_elf_print_private_bfd_data (abfd, ptr)
687 FILE *file = (FILE *) ptr;
689 BFD_ASSERT (abfd != NULL && ptr != NULL);
691 /* Print normal ELF private data. */
692 _bfd_elf_print_private_bfd_data (abfd, ptr);
694 /* xgettext:c-format */
695 fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
697 if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
698 fprintf (file, _("[abi=32-bit int,"));
700 fprintf (file, _("[abi=16-bit int,"));
702 if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
703 fprintf (file, _(" 64-bit double]"));
705 fprintf (file, _(" 32-bit double]"));
712 /* Below is the only difference between elf32-m68hc12.c and elf32-m68hc11.c.
713 The Motorola spec says to use a different Elf machine code. */
714 #define ELF_ARCH bfd_arch_m68hc12
715 #define ELF_MACHINE_CODE EM_68HC12
716 #define ELF_MAXPAGESIZE 0x1000
718 #define TARGET_BIG_SYM bfd_elf32_m68hc12_vec
719 #define TARGET_BIG_NAME "elf32-m68hc12"
721 #define elf_info_to_howto 0
722 #define elf_info_to_howto_rel m68hc11_info_to_howto_rel
723 #define elf_backend_object_p 0
724 #define elf_backend_final_write_processing 0
726 #define bfd_elf32_bfd_merge_private_bfd_data \
727 _bfd_m68hc12_elf_merge_private_bfd_data
728 #define bfd_elf32_bfd_set_private_flags _bfd_m68hc12_elf_set_private_flags
729 #define bfd_elf32_bfd_print_private_bfd_data \
730 _bfd_m68hc12_elf_print_private_bfd_data
732 #include "elf32-target.h"