|  | /* Freescale S12Z-specific support for 32-bit ELF | 
|  | Copyright (C) 1999-2023 Free Software Foundation, Inc. | 
|  | (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com)) | 
|  |  | 
|  | This file is part of BFD, the Binary File Descriptor library. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "bfdlink.h" | 
|  | #include "libbfd.h" | 
|  | #include "elf-bfd.h" | 
|  |  | 
|  | #include "elf/s12z.h" | 
|  |  | 
|  | /* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */ | 
|  | #define OCTETS_PER_BYTE(ABFD, SEC) 1 | 
|  |  | 
|  | /* Relocation functions.  */ | 
|  | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup | 
|  | (bfd *, bfd_reloc_code_real_type); | 
|  | static bool s12z_info_to_howto_rel | 
|  | (bfd *, arelent *, Elf_Internal_Rela *); | 
|  |  | 
|  | static bfd_reloc_status_type | 
|  | opru18_reloc (bfd *abfd, arelent *reloc_entry, struct bfd_symbol *symbol, | 
|  | void *data, asection *input_section ATTRIBUTE_UNUSED, | 
|  | bfd *output ATTRIBUTE_UNUSED, char **msg ATTRIBUTE_UNUSED) | 
|  | { | 
|  | /* This reloc is used for 18 bit General Operand Addressing Postbyte in the | 
|  | INST opru18 form.  This is an 18 bit reloc, but the most significant bit | 
|  | is shifted one place to the left of where it would normally be.  See | 
|  | Appendix A.4 of the S12Z reference manual.  */ | 
|  |  | 
|  | bfd_size_type octets = (reloc_entry->address | 
|  | * OCTETS_PER_BYTE (abfd, input_section)); | 
|  | bfd_vma result = bfd_get_24 (abfd, (unsigned char *) data + octets); | 
|  | bfd_vma val = bfd_asymbol_value (symbol); | 
|  |  | 
|  | /* Keep the wanted bits and discard the rest.  */ | 
|  | result &= 0xFA0000; | 
|  |  | 
|  | val += symbol->section->output_section->vma; | 
|  | val += symbol->section->output_offset; | 
|  |  | 
|  | /* The lowest 17 bits are copied verbatim.  */ | 
|  | result |= val & 0x1FFFF; | 
|  |  | 
|  | /* The 18th bit is put into the 19th position.  */ | 
|  | result |= (val & 0x020000) << 1; | 
|  |  | 
|  | bfd_put_24 (abfd, result, (unsigned char *) data + octets); | 
|  |  | 
|  | return bfd_reloc_ok; | 
|  | } | 
|  |  | 
|  |  | 
|  | static bfd_reloc_status_type | 
|  | shift_addend_reloc (bfd *abfd, arelent *reloc_entry, struct bfd_symbol *symbol ATTRIBUTE_UNUSED, | 
|  | void *data ATTRIBUTE_UNUSED, asection *input_section ATTRIBUTE_UNUSED, | 
|  | bfd *output ATTRIBUTE_UNUSED, char **msg ATTRIBUTE_UNUSED) | 
|  | { | 
|  | /* This is a really peculiar reloc, which is done for compatibility | 
|  | with the Freescale toolchain. | 
|  |  | 
|  | That toolchain appears to (ab)use the lowest 15 bits of the addend for | 
|  | the purpose of holding flags.  The purpose of these flags are unknown. | 
|  | So in this function, when writing the bfd we left shift the addend by | 
|  | 15, and when reading we right shift it by 15 (discarding the lower bits). | 
|  |  | 
|  | This allows the linker to work with object files generated by Freescale, | 
|  | as well as by Gas.  */ | 
|  |  | 
|  | if (abfd->is_linker_input) | 
|  | reloc_entry->addend >>= 15; | 
|  | else | 
|  | reloc_entry->addend <<= 15; | 
|  |  | 
|  | return bfd_reloc_continue; | 
|  | } | 
|  |  | 
|  | #define USE_REL	0 | 
|  |  | 
|  | static reloc_howto_type elf_s12z_howto_table[] = | 
|  | { | 
|  | /* This reloc does nothing.  */ | 
|  | HOWTO (R_S12Z_NONE,	/* type */ | 
|  | 0,			/* rightshift */ | 
|  | 0,			/* size */ | 
|  | 0,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont,/* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc,	/* special_function */ | 
|  | "R_S12Z_NONE",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0,			/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* A 24 bit absolute relocation emitted by the OPR mode operands  */ | 
|  | HOWTO (R_S12Z_OPR,        /* type */ | 
|  | 0,			/* rightshift */ | 
|  | 3,			/* size */ | 
|  | 24,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_bitfield,	/* complain_on_overflow */ | 
|  | shift_addend_reloc, | 
|  | "R_S12Z_OPR",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0x00ffffff,            /* src_mask */ | 
|  | 0x00ffffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* The purpose of this reloc is not known */ | 
|  | HOWTO (R_S12Z_UKNWN_2,	/* type */ | 
|  | 0,			/* rightshift */ | 
|  | 0,			/* size */ | 
|  | 0,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont,/* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc,	/* special_function */ | 
|  | "R_S12Z_UKNWN_2",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0,			/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* A 15 bit PC-rel relocation */ | 
|  | HOWTO (R_S12Z_PCREL_7_15,	/* type */ | 
|  | 0,			/* rightshift */ | 
|  | 2,			/* size */ | 
|  | 15,			/* bitsize */ | 
|  | true,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_bitfield,	/* complain_on_overflow */ | 
|  | shift_addend_reloc, | 
|  | "R_S12Z_PCREL_7_15",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0x00,                  /* src_mask */ | 
|  | 0x007fff,		/* dst_mask */ | 
|  | true),			/* pcrel_offset */ | 
|  |  | 
|  | /* A 24 bit absolute relocation emitted by EXT24 mode operands */ | 
|  | HOWTO (R_S12Z_EXT24,        /* type */ | 
|  | 0,			/* rightshift */ | 
|  | 3,			/* size */ | 
|  | 24,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_bitfield,	/* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc,	/* special_function */ | 
|  | "R_S12Z_EXT24",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0x00000000,            /* src_mask */ | 
|  | 0x00ffffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* An 18 bit absolute relocation */ | 
|  | HOWTO (R_S12Z_EXT18,        /* type */ | 
|  | 0,			/* rightshift */ | 
|  | 3,			/* size */ | 
|  | 18,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_bitfield,	/* complain_on_overflow */ | 
|  | opru18_reloc,	        /* special_function */ | 
|  | "R_S12Z_EXT18",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0x00000000,            /* src_mask */ | 
|  | 0x0005ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* A 32 bit absolute relocation.   This kind of relocation is | 
|  | schizophrenic - Although they appear in sections named .rela.debug.* | 
|  | in some sections they behave as RELA relocs, but in others they have | 
|  | an added of zero and behave as REL. | 
|  |  | 
|  | It is not recommended that new code  emits this reloc.   It is here | 
|  | only to support existing elf files generated by third party | 
|  | applications.  */ | 
|  |  | 
|  | HOWTO (R_S12Z_CW32,        /* type */ | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_bitfield,	/* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc,	/* special_function */ | 
|  | "R_S12Z_CW32",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0xffffffff,            /* src_mask */ | 
|  | 0xffffffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* A 32 bit absolute relocation  */ | 
|  | HOWTO (R_S12Z_EXT32,        /* type */ | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_bitfield,	/* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc,	/* special_function */ | 
|  | "R_S12Z_EXT32",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0x00000000,            /* src_mask */ | 
|  | 0xffffffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  | }; | 
|  |  | 
|  | /* Map BFD reloc types to S12Z ELF reloc types.  */ | 
|  |  | 
|  | struct s12z_reloc_map | 
|  | { | 
|  | bfd_reloc_code_real_type bfd_reloc_val; | 
|  | unsigned char elf_reloc_val; | 
|  | }; | 
|  |  | 
|  | static const struct s12z_reloc_map s12z_reloc_map[] = | 
|  | { | 
|  | /* bfd reloc val */  /* elf reloc val */ | 
|  | {BFD_RELOC_NONE,     R_S12Z_NONE}, | 
|  | {BFD_RELOC_32,       R_S12Z_EXT32}, | 
|  | {BFD_RELOC_24,       R_S12Z_EXT24}, | 
|  | {BFD_RELOC_16_PCREL, R_S12Z_PCREL_7_15}, | 
|  | {BFD_RELOC_S12Z_OPR, R_S12Z_OPR} | 
|  | }; | 
|  |  | 
|  | static reloc_howto_type * | 
|  | bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | bfd_reloc_code_real_type code) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; | 
|  | i < sizeof (s12z_reloc_map) / sizeof (struct s12z_reloc_map); | 
|  | i++) | 
|  | { | 
|  | if (s12z_reloc_map[i].bfd_reloc_val == code) | 
|  | { | 
|  | return &elf_s12z_howto_table[s12z_reloc_map[i].elf_reloc_val]; | 
|  | } | 
|  | } | 
|  |  | 
|  | printf ("%s:%d Not found type %d\n", __FILE__, __LINE__, code); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static reloc_howto_type * | 
|  | bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | const char *r_name) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; | 
|  | i < (sizeof (elf_s12z_howto_table) | 
|  | / sizeof (elf_s12z_howto_table[0])); | 
|  | i++) | 
|  | if (elf_s12z_howto_table[i].name != NULL | 
|  | && strcasecmp (elf_s12z_howto_table[i].name, r_name) == 0) | 
|  | return &elf_s12z_howto_table[i]; | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Set the howto pointer for an S12Z ELF reloc.  */ | 
|  |  | 
|  | static bool | 
|  | s12z_info_to_howto_rel (bfd *abfd, | 
|  | arelent *cache_ptr, Elf_Internal_Rela *dst) | 
|  | { | 
|  | unsigned int  r_type = ELF32_R_TYPE (dst->r_info); | 
|  |  | 
|  | if (r_type >= (unsigned int) R_S12Z_max) | 
|  | { | 
|  | /* xgettext:c-format */ | 
|  | _bfd_error_handler (_("%pB: unsupported relocation type %#x"), | 
|  | abfd, r_type); | 
|  | bfd_set_error (bfd_error_bad_value); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | cache_ptr->howto = &elf_s12z_howto_table[r_type]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | s12z_elf_set_mach_from_flags (bfd *abfd) | 
|  | { | 
|  | bfd_default_set_arch_mach (abfd, bfd_arch_s12z, 0); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | #define ELF_ARCH		bfd_arch_s12z | 
|  | #define ELF_MACHINE_CODE	EM_S12Z | 
|  | #define ELF_MAXPAGESIZE		0x1000 | 
|  |  | 
|  | #define TARGET_BIG_SYM		s12z_elf32_vec | 
|  | #define TARGET_BIG_NAME		"elf32-s12z" | 
|  |  | 
|  | #define elf_info_to_howto			NULL | 
|  | #define elf_info_to_howto_rel			s12z_info_to_howto_rel | 
|  | #define elf_backend_object_p			s12z_elf_set_mach_from_flags | 
|  |  | 
|  | #include "elf32-target.h" |