|  | /* MeP-specific support for 32-bit ELF. | 
|  | Copyright (C) 2001-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | 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 "libbfd.h" | 
|  | #include "elf-bfd.h" | 
|  | #include "elf/mep.h" | 
|  | #include "libiberty.h" | 
|  |  | 
|  | /* Forward declarations.  */ | 
|  |  | 
|  | /* Private relocation functions.  */ | 
|  |  | 
|  | #define MEPREL(type, size, bits, right, left, pcrel, overflow, mask) \ | 
|  | HOWTO (type, right, size, bits, pcrel, left, overflow, bfd_elf_generic_reloc, #type, false, 0, mask, 0) | 
|  |  | 
|  | #define N complain_overflow_dont | 
|  | #define S complain_overflow_signed | 
|  | #define U complain_overflow_unsigned | 
|  |  | 
|  | static reloc_howto_type mep_elf_howto_table [] = | 
|  | { | 
|  | /* type, size, bits, leftshift, rightshift, pcrel, OD/OS/OU, mask.  */ | 
|  | MEPREL (R_MEP_NONE,	  0,  0, 0, 0, 0, N, 0), | 
|  | MEPREL (R_RELC,	  0,  0, 0, 0, 0, N, 0), | 
|  | /* MEPRELOC:HOWTO */ | 
|  | /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h.  */ | 
|  | MEPREL (R_MEP_8,        1,  8, 0, 0, 0, U, 0xff), | 
|  | MEPREL (R_MEP_16,       2, 16, 0, 0, 0, U, 0xffff), | 
|  | MEPREL (R_MEP_32,       4, 32, 0, 0, 0, U, 0xffffffff), | 
|  | MEPREL (R_MEP_PCREL8A2, 2,  8, 1, 1, 1, S, 0x00fe), | 
|  | MEPREL (R_MEP_PCREL12A2,2, 12, 1, 1, 1, S, 0x0ffe), | 
|  | MEPREL (R_MEP_PCREL17A2,4, 17, 0, 1, 1, S, 0x0000ffff), | 
|  | MEPREL (R_MEP_PCREL24A2,4, 24, 0, 1, 1, S, 0x07f0ffff), | 
|  | MEPREL (R_MEP_PCABS24A2,4, 24, 0, 1, 0, U, 0x07f0ffff), | 
|  | MEPREL (R_MEP_LOW16,    4, 16, 0, 0, 0, N, 0x0000ffff), | 
|  | MEPREL (R_MEP_HI16U,    4, 32, 0,16, 0, N, 0x0000ffff), | 
|  | MEPREL (R_MEP_HI16S,    4, 32, 0,16, 0, N, 0x0000ffff), | 
|  | MEPREL (R_MEP_GPREL,    4, 16, 0, 0, 0, S, 0x0000ffff), | 
|  | MEPREL (R_MEP_TPREL,    4, 16, 0, 0, 0, S, 0x0000ffff), | 
|  | MEPREL (R_MEP_TPREL7,   2,  7, 0, 0, 0, U, 0x007f), | 
|  | MEPREL (R_MEP_TPREL7A2, 2,  7, 1, 1, 0, U, 0x007e), | 
|  | MEPREL (R_MEP_TPREL7A4, 2,  7, 2, 2, 0, U, 0x007c), | 
|  | MEPREL (R_MEP_UIMM24,   4, 24, 0, 0, 0, U, 0x00ffffff), | 
|  | MEPREL (R_MEP_ADDR24A4, 4, 24, 0, 2, 0, U, 0x00fcffff), | 
|  | MEPREL (R_MEP_GNU_VTINHERIT,2,  0,16,32, 0, N, 0x0000), | 
|  | MEPREL (R_MEP_GNU_VTENTRY,2,  0,16,32, 0, N, 0x0000), | 
|  | /* MEPRELOC:END */ | 
|  | }; | 
|  |  | 
|  | #define VALID_MEP_RELOC(N) ((N) >= 0 \ | 
|  | && (N) < ARRAY_SIZE (mep_elf_howto_table) | 
|  |  | 
|  | #undef N | 
|  | #undef S | 
|  | #undef U | 
|  |  | 
|  |  | 
|  | #define BFD_RELOC_MEP_NONE BFD_RELOC_NONE | 
|  | #if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) | 
|  | #define MAP(n) case BFD_RELOC_MEP_##n: type = R_MEP_##n; break | 
|  | #else | 
|  | #define MAP(n) case BFD_RELOC_MEP_/**/n: type = R_MEP_/**/n; break | 
|  | #endif | 
|  |  | 
|  | static reloc_howto_type * | 
|  | mep_reloc_type_lookup | 
|  | (bfd * abfd ATTRIBUTE_UNUSED, | 
|  | bfd_reloc_code_real_type code) | 
|  | { | 
|  | unsigned int type = 0; | 
|  |  | 
|  | switch (code) | 
|  | { | 
|  | MAP(NONE); | 
|  | case BFD_RELOC_8: | 
|  | type = R_MEP_8; | 
|  | break; | 
|  | case BFD_RELOC_16: | 
|  | type = R_MEP_16; | 
|  | break; | 
|  | case BFD_RELOC_32: | 
|  | type = R_MEP_32; | 
|  | break; | 
|  | case BFD_RELOC_VTABLE_ENTRY: | 
|  | type = R_MEP_GNU_VTENTRY; | 
|  | break; | 
|  | case BFD_RELOC_VTABLE_INHERIT: | 
|  | type = R_MEP_GNU_VTINHERIT; | 
|  | break; | 
|  | case BFD_RELOC_RELC: | 
|  | type = R_RELC; | 
|  | break; | 
|  |  | 
|  | /* MEPRELOC:MAP */ | 
|  | /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h.  */ | 
|  | MAP(8); | 
|  | MAP(16); | 
|  | MAP(32); | 
|  | MAP(PCREL8A2); | 
|  | MAP(PCREL12A2); | 
|  | MAP(PCREL17A2); | 
|  | MAP(PCREL24A2); | 
|  | MAP(PCABS24A2); | 
|  | MAP(LOW16); | 
|  | MAP(HI16U); | 
|  | MAP(HI16S); | 
|  | MAP(GPREL); | 
|  | MAP(TPREL); | 
|  | MAP(TPREL7); | 
|  | MAP(TPREL7A2); | 
|  | MAP(TPREL7A4); | 
|  | MAP(UIMM24); | 
|  | MAP(ADDR24A4); | 
|  | MAP(GNU_VTINHERIT); | 
|  | MAP(GNU_VTENTRY); | 
|  | /* MEPRELOC:END */ | 
|  |  | 
|  | default: | 
|  | /* Pacify gcc -Wall.  */ | 
|  | _bfd_error_handler (_("mep: no reloc for code %d"), code); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (mep_elf_howto_table[type].type != type) | 
|  | { | 
|  | /* xgettext:c-format */ | 
|  | _bfd_error_handler (_("MeP: howto %d has type %d"), | 
|  | type, mep_elf_howto_table[type].type); | 
|  | abort (); | 
|  | } | 
|  |  | 
|  | return mep_elf_howto_table + type; | 
|  | } | 
|  |  | 
|  | #undef MAP | 
|  |  | 
|  | static reloc_howto_type * | 
|  | mep_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; | 
|  | i < sizeof (mep_elf_howto_table) / sizeof (mep_elf_howto_table[0]); | 
|  | i++) | 
|  | if (mep_elf_howto_table[i].name != NULL | 
|  | && strcasecmp (mep_elf_howto_table[i].name, r_name) == 0) | 
|  | return &mep_elf_howto_table[i]; | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Perform a single relocation.  */ | 
|  |  | 
|  | static struct bfd_link_info *mep_info; | 
|  | static int warn_tp = 0, warn_sda = 0; | 
|  |  | 
|  | static bfd_vma | 
|  | mep_lookup_global | 
|  | (char *    name, | 
|  | bfd_vma   ofs, | 
|  | bfd_vma * cache, | 
|  | int *     warn) | 
|  | { | 
|  | struct bfd_link_hash_entry *h; | 
|  |  | 
|  | if (*cache || *warn) | 
|  | return *cache; | 
|  |  | 
|  | h = bfd_link_hash_lookup (mep_info->hash, name, false, false, true); | 
|  | if (h == 0 || h->type != bfd_link_hash_defined) | 
|  | { | 
|  | *warn = ofs + 1; | 
|  | return 0; | 
|  | } | 
|  | *cache = (h->u.def.value | 
|  | + h->u.def.section->output_section->vma | 
|  | + h->u.def.section->output_offset); | 
|  | return *cache; | 
|  | } | 
|  |  | 
|  | static bfd_vma | 
|  | mep_tpoff_base (bfd_vma ofs) | 
|  | { | 
|  | static bfd_vma cache = 0; | 
|  | return mep_lookup_global ("__tpbase", ofs, &cache, &warn_tp); | 
|  | } | 
|  |  | 
|  | static bfd_vma | 
|  | mep_sdaoff_base (bfd_vma ofs) | 
|  | { | 
|  | static bfd_vma cache = 0; | 
|  | return mep_lookup_global ("__sdabase", ofs, &cache, &warn_sda); | 
|  | } | 
|  |  | 
|  | static bfd_reloc_status_type | 
|  | mep_final_link_relocate | 
|  | (reloc_howto_type *	 howto, | 
|  | bfd *		 input_bfd, | 
|  | asection *		 input_section, | 
|  | bfd_byte *		 contents, | 
|  | Elf_Internal_Rela * rel, | 
|  | bfd_vma		 relocation) | 
|  | { | 
|  | unsigned long u; | 
|  | unsigned char *byte; | 
|  | bfd_vma pc; | 
|  | bfd_reloc_status_type r = bfd_reloc_ok; | 
|  | int e2, e4; | 
|  |  | 
|  | if (bfd_big_endian (input_bfd)) | 
|  | { | 
|  | e2 = 0; | 
|  | e4 = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | e2 = 1; | 
|  | e4 = 3; | 
|  | } | 
|  |  | 
|  | pc = (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + rel->r_offset); | 
|  |  | 
|  | u = relocation + rel->r_addend; | 
|  |  | 
|  | byte = (unsigned char *)contents + rel->r_offset; | 
|  |  | 
|  | if (howto->type == R_MEP_PCREL24A2 | 
|  | && u == 0 | 
|  | && pc >= 0x800000) | 
|  | { | 
|  | /* This is an unreachable branch to an undefined weak function. | 
|  | Silently ignore it, since the opcode can't do that but should | 
|  | never be executed anyway.  */ | 
|  | return bfd_reloc_ok; | 
|  | } | 
|  |  | 
|  | if (howto->pc_relative) | 
|  | u -= pc; | 
|  |  | 
|  | switch (howto->type) | 
|  | { | 
|  | /* MEPRELOC:APPLY */ | 
|  | /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h.  */ | 
|  | case R_MEP_8: /* 76543210 */ | 
|  | if (u > 255) r = bfd_reloc_overflow; | 
|  | byte[0] = (u & 0xff); | 
|  | break; | 
|  | case R_MEP_16: /* fedcba9876543210 */ | 
|  | if (u > 65535) r = bfd_reloc_overflow; | 
|  | byte[0^e2] = ((u >> 8) & 0xff); | 
|  | byte[1^e2] = (u & 0xff); | 
|  | break; | 
|  | case R_MEP_32: /* vutsrqponmlkjihgfedcba9876543210 */ | 
|  | byte[0^e4] = ((u >> 24) & 0xff); | 
|  | byte[1^e4] = ((u >> 16) & 0xff); | 
|  | byte[2^e4] = ((u >> 8) & 0xff); | 
|  | byte[3^e4] = (u & 0xff); | 
|  | break; | 
|  | case R_MEP_PCREL8A2: /* --------7654321- */ | 
|  | if (u + 128 > 255) r = bfd_reloc_overflow; | 
|  | byte[1^e2] = (byte[1^e2] & 0x01) | (u & 0xfe); | 
|  | break; | 
|  | case R_MEP_PCREL12A2: /* ----ba987654321- */ | 
|  | if (u + 2048 > 4095) r = bfd_reloc_overflow; | 
|  | byte[0^e2] = (byte[0^e2] & 0xf0) | ((u >> 8) & 0x0f); | 
|  | byte[1^e2] = (byte[1^e2] & 0x01) | (u & 0xfe); | 
|  | break; | 
|  | case R_MEP_PCREL17A2: /* ----------------gfedcba987654321 */ | 
|  | if (u + 65536 > 131071) r = bfd_reloc_overflow; | 
|  | byte[2^e2] = ((u >> 9) & 0xff); | 
|  | byte[3^e2] = ((u >> 1) & 0xff); | 
|  | break; | 
|  | case R_MEP_PCREL24A2: /* -----7654321----nmlkjihgfedcba98 */ | 
|  | if (u + 8388608 > 16777215) r = bfd_reloc_overflow; | 
|  | byte[0^e2] = (byte[0^e2] & 0xf8) | ((u >> 5) & 0x07); | 
|  | byte[1^e2] = (byte[1^e2] & 0x0f) | ((u << 3) & 0xf0); | 
|  | byte[2^e2] = ((u >> 16) & 0xff); | 
|  | byte[3^e2] = ((u >> 8) & 0xff); | 
|  | break; | 
|  | case R_MEP_PCABS24A2: /* -----7654321----nmlkjihgfedcba98 */ | 
|  | if (u > 16777215) r = bfd_reloc_overflow; | 
|  | byte[0^e2] = (byte[0^e2] & 0xf8) | ((u >> 5) & 0x07); | 
|  | byte[1^e2] = (byte[1^e2] & 0x0f) | ((u << 3) & 0xf0); | 
|  | byte[2^e2] = ((u >> 16) & 0xff); | 
|  | byte[3^e2] = ((u >> 8) & 0xff); | 
|  | break; | 
|  | case R_MEP_LOW16: /* ----------------fedcba9876543210 */ | 
|  | byte[2^e2] = ((u >> 8) & 0xff); | 
|  | byte[3^e2] = (u & 0xff); | 
|  | break; | 
|  | case R_MEP_HI16U: /* ----------------vutsrqponmlkjihg */ | 
|  | byte[2^e2] = ((u >> 24) & 0xff); | 
|  | byte[3^e2] = ((u >> 16) & 0xff); | 
|  | break; | 
|  | case R_MEP_HI16S: /* ----------------vutsrqponmlkjihg */ | 
|  | u += 0x8000; | 
|  | byte[2^e2] = ((u >> 24) & 0xff); | 
|  | byte[3^e2] = ((u >> 16) & 0xff); | 
|  | break; | 
|  | case R_MEP_GPREL: /* ----------------fedcba9876543210 */ | 
|  | u -= mep_sdaoff_base(rel->r_offset); | 
|  | if (u + 32768 > 65535) r = bfd_reloc_overflow; | 
|  | byte[2^e2] = ((u >> 8) & 0xff); | 
|  | byte[3^e2] = (u & 0xff); | 
|  | break; | 
|  | case R_MEP_TPREL: /* ----------------fedcba9876543210 */ | 
|  | u -= mep_tpoff_base(rel->r_offset); | 
|  | if (u + 32768 > 65535) r = bfd_reloc_overflow; | 
|  | byte[2^e2] = ((u >> 8) & 0xff); | 
|  | byte[3^e2] = (u & 0xff); | 
|  | break; | 
|  | case R_MEP_TPREL7: /* ---------6543210 */ | 
|  | u -= mep_tpoff_base(rel->r_offset); | 
|  | if (u > 127) r = bfd_reloc_overflow; | 
|  | byte[1^e2] = (byte[1^e2] & 0x80) | (u & 0x7f); | 
|  | break; | 
|  | case R_MEP_TPREL7A2: /* ---------654321- */ | 
|  | u -= mep_tpoff_base(rel->r_offset); | 
|  | if (u > 127) r = bfd_reloc_overflow; | 
|  | byte[1^e2] = (byte[1^e2] & 0x81) | (u & 0x7e); | 
|  | break; | 
|  | case R_MEP_TPREL7A4: /* ---------65432-- */ | 
|  | u -= mep_tpoff_base(rel->r_offset); | 
|  | if (u > 127) r = bfd_reloc_overflow; | 
|  | byte[1^e2] = (byte[1^e2] & 0x83) | (u & 0x7c); | 
|  | break; | 
|  | case R_MEP_UIMM24: /* --------76543210nmlkjihgfedcba98 */ | 
|  | if (u > 16777215) r = bfd_reloc_overflow; | 
|  | byte[1^e2] = (u & 0xff); | 
|  | byte[2^e2] = ((u >> 16) & 0xff); | 
|  | byte[3^e2] = ((u >> 8) & 0xff); | 
|  | break; | 
|  | case R_MEP_ADDR24A4: /* --------765432--nmlkjihgfedcba98 */ | 
|  | if (u > 16777215) r = bfd_reloc_overflow; | 
|  | byte[1^e2] = (byte[1^e2] & 0x03) | (u & 0xfc); | 
|  | byte[2^e2] = ((u >> 16) & 0xff); | 
|  | byte[3^e2] = ((u >> 8) & 0xff); | 
|  | break; | 
|  | case R_MEP_GNU_VTINHERIT: /* ---------------- */ | 
|  | break; | 
|  | case R_MEP_GNU_VTENTRY: /* ---------------- */ | 
|  | break; | 
|  | /* MEPRELOC:END */ | 
|  | default: | 
|  | abort (); | 
|  | } | 
|  |  | 
|  | return r; | 
|  | } | 
|  |  | 
|  | /* Set the howto pointer for a MEP ELF reloc.  */ | 
|  |  | 
|  | static bool | 
|  | mep_info_to_howto_rela (bfd *		    abfd, | 
|  | arelent *	    cache_ptr, | 
|  | Elf_Internal_Rela * dst) | 
|  | { | 
|  | unsigned int r_type; | 
|  |  | 
|  | r_type = ELF32_R_TYPE (dst->r_info); | 
|  | if (r_type >= R_MEP_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 = & mep_elf_howto_table [r_type]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Relocate a MEP ELF section. | 
|  | There is some attempt to make this function usable for many architectures, | 
|  | both USE_REL and USE_RELA ['twould be nice if such a critter existed], | 
|  | if only to serve as a learning tool. | 
|  |  | 
|  | The RELOCATE_SECTION function is called by the new ELF backend linker | 
|  | to handle the relocations for a section. | 
|  |  | 
|  | The relocs are always passed as Rela structures; if the section | 
|  | actually uses Rel structures, the r_addend field will always be | 
|  | zero. | 
|  |  | 
|  | This function is responsible for adjusting the section contents as | 
|  | necessary, and (if using Rela relocs and generating a relocatable | 
|  | output file) adjusting the reloc addend as necessary. | 
|  |  | 
|  | This function does not have to worry about setting the reloc | 
|  | address or the reloc symbol index. | 
|  |  | 
|  | LOCAL_SYMS is a pointer to the swapped in local symbols. | 
|  |  | 
|  | LOCAL_SECTIONS is an array giving the section in the input file | 
|  | corresponding to the st_shndx field of each local symbol. | 
|  |  | 
|  | The global hash table entry for the global symbols can be found | 
|  | via elf_sym_hashes (input_bfd). | 
|  |  | 
|  | When generating relocatable output, this function must handle | 
|  | STB_LOCAL/STT_SECTION symbols specially.  The output symbol is | 
|  | going to be the section symbol corresponding to the output | 
|  | section, which means that the addend must be adjusted | 
|  | accordingly.  */ | 
|  |  | 
|  | static int | 
|  | mep_elf_relocate_section | 
|  | (bfd *		     output_bfd ATTRIBUTE_UNUSED, | 
|  | struct bfd_link_info *  info, | 
|  | bfd *		     input_bfd, | 
|  | asection *		     input_section, | 
|  | bfd_byte *		     contents, | 
|  | Elf_Internal_Rela *     relocs, | 
|  | Elf_Internal_Sym *	     local_syms, | 
|  | asection **	     local_sections) | 
|  | { | 
|  | Elf_Internal_Shdr *		symtab_hdr; | 
|  | struct elf_link_hash_entry ** sym_hashes; | 
|  | Elf_Internal_Rela *		rel; | 
|  | Elf_Internal_Rela *		relend; | 
|  |  | 
|  | symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; | 
|  | sym_hashes = elf_sym_hashes (input_bfd); | 
|  | relend     = relocs + input_section->reloc_count; | 
|  |  | 
|  | mep_info = info; | 
|  |  | 
|  | for (rel = relocs; rel < relend; rel ++) | 
|  | { | 
|  | reloc_howto_type *	   howto; | 
|  | unsigned long		   r_symndx; | 
|  | Elf_Internal_Sym *	   sym; | 
|  | asection *		   sec; | 
|  | struct elf_link_hash_entry * h; | 
|  | bfd_vma			   relocation; | 
|  | bfd_reloc_status_type	   r; | 
|  | const char *		   name = NULL; | 
|  | int			   r_type; | 
|  |  | 
|  | r_type = ELF32_R_TYPE (rel->r_info); | 
|  | r_symndx = ELF32_R_SYM (rel->r_info); | 
|  | howto  = mep_elf_howto_table + ELF32_R_TYPE (rel->r_info); | 
|  | h      = NULL; | 
|  | sym    = NULL; | 
|  | sec    = NULL; | 
|  |  | 
|  | if (r_symndx < symtab_hdr->sh_info) | 
|  | { | 
|  | sym = local_syms + r_symndx; | 
|  | sec = local_sections [r_symndx]; | 
|  | relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); | 
|  |  | 
|  | name = bfd_elf_string_from_elf_section | 
|  | (input_bfd, symtab_hdr->sh_link, sym->st_name); | 
|  | name = name == NULL ? bfd_section_name (sec) : name; | 
|  | } | 
|  | else | 
|  | { | 
|  | bool warned, unresolved_reloc, ignored; | 
|  |  | 
|  | RELOC_FOR_GLOBAL_SYMBOL(info, input_bfd, input_section, rel, | 
|  | r_symndx, symtab_hdr, sym_hashes, | 
|  | h, sec, relocation, | 
|  | unresolved_reloc, warned, ignored); | 
|  |  | 
|  | name = h->root.root.string; | 
|  | } | 
|  |  | 
|  | if (sec != NULL && discarded_section (sec)) | 
|  | RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, | 
|  | rel, 1, relend, howto, 0, contents); | 
|  |  | 
|  | if (bfd_link_relocatable (info)) | 
|  | continue; | 
|  |  | 
|  | if (r_type == R_RELC) | 
|  | r = bfd_elf_perform_complex_relocation (input_bfd, input_section, | 
|  | contents, rel, relocation); | 
|  | else | 
|  | r = mep_final_link_relocate (howto, input_bfd, input_section, | 
|  | contents, rel, relocation); | 
|  |  | 
|  | if (r != bfd_reloc_ok) | 
|  | { | 
|  | const char * msg = (const char *) NULL; | 
|  |  | 
|  | switch (r) | 
|  | { | 
|  | case bfd_reloc_overflow: | 
|  | (*info->callbacks->reloc_overflow) | 
|  | (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, | 
|  | input_bfd, input_section, rel->r_offset); | 
|  | break; | 
|  |  | 
|  | case bfd_reloc_undefined: | 
|  | (*info->callbacks->undefined_symbol) | 
|  | (info, name, input_bfd, input_section, rel->r_offset, true); | 
|  | break; | 
|  |  | 
|  | case bfd_reloc_outofrange: | 
|  | msg = _("internal error: out of range error"); | 
|  | break; | 
|  |  | 
|  | case bfd_reloc_notsupported: | 
|  | msg = _("internal error: unsupported relocation error"); | 
|  | break; | 
|  |  | 
|  | case bfd_reloc_dangerous: | 
|  | msg = _("internal error: dangerous relocation"); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | msg = _("internal error: unknown error"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (msg) | 
|  | (*info->callbacks->warning) (info, msg, name, input_bfd, | 
|  | input_section, rel->r_offset); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (warn_tp) | 
|  | info->callbacks->undefined_symbol | 
|  | (info, "__tpbase", input_bfd, input_section, warn_tp-1, true); | 
|  | if (warn_sda) | 
|  | info->callbacks->undefined_symbol | 
|  | (info, "__sdabase", input_bfd, input_section, warn_sda-1, true); | 
|  | if (warn_sda || warn_tp) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Function to set the ELF flag bits.  */ | 
|  |  | 
|  | static bool | 
|  | mep_elf_set_private_flags (bfd *    abfd, | 
|  | flagword flags) | 
|  | { | 
|  | elf_elfheader (abfd)->e_flags = flags; | 
|  | elf_flags_init (abfd) = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Merge backend specific data from an object file to the output | 
|  | object file when linking.  */ | 
|  |  | 
|  | static bool | 
|  | mep_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) | 
|  | { | 
|  | bfd *obfd = info->output_bfd; | 
|  | static bfd *last_ibfd = 0; | 
|  | flagword old_flags, new_flags; | 
|  | flagword old_partial, new_partial; | 
|  |  | 
|  | /* Check if we have the same endianness.  */ | 
|  | if (!_bfd_generic_verify_endian_match (ibfd, info)) | 
|  | return false; | 
|  |  | 
|  | new_flags = elf_elfheader (ibfd)->e_flags; | 
|  | old_flags = elf_elfheader (obfd)->e_flags; | 
|  |  | 
|  | #ifdef DEBUG | 
|  | _bfd_error_handler ("%pB: old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s", | 
|  | ibfd, old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no"); | 
|  | #endif | 
|  |  | 
|  | /* First call, no flags set.  */ | 
|  | if (!elf_flags_init (obfd)) | 
|  | { | 
|  | elf_flags_init (obfd) = true; | 
|  | old_flags = new_flags; | 
|  | } | 
|  | else if ((new_flags | old_flags) & EF_MEP_LIBRARY) | 
|  | { | 
|  | /* Non-library flags trump library flags.  The choice doesn't really | 
|  | matter if both OLD_FLAGS and NEW_FLAGS have EF_MEP_LIBRARY set.  */ | 
|  | if (old_flags & EF_MEP_LIBRARY) | 
|  | old_flags = new_flags; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Make sure they're for the same mach.  Allow upgrade from the "mep" | 
|  | mach.  */ | 
|  | new_partial = (new_flags & EF_MEP_CPU_MASK); | 
|  | old_partial = (old_flags & EF_MEP_CPU_MASK); | 
|  | if (new_partial == old_partial) | 
|  | ; | 
|  | else if (new_partial == EF_MEP_CPU_MEP) | 
|  | ; | 
|  | else if (old_partial == EF_MEP_CPU_MEP) | 
|  | old_flags = (old_flags & ~EF_MEP_CPU_MASK) | new_partial; | 
|  | else | 
|  | { | 
|  | /* xgettext:c-format */ | 
|  | _bfd_error_handler (_("%pB and %pB are for different cores"), | 
|  | last_ibfd, ibfd); | 
|  | bfd_set_error (bfd_error_invalid_target); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Make sure they're for the same me_module.  Allow basic config to | 
|  | mix with any other.  */ | 
|  | new_partial = (new_flags & EF_MEP_INDEX_MASK); | 
|  | old_partial = (old_flags & EF_MEP_INDEX_MASK); | 
|  | if (new_partial == old_partial) | 
|  | ; | 
|  | else if (new_partial == 0) | 
|  | ; | 
|  | else if (old_partial == 0) | 
|  | old_flags = (old_flags & ~EF_MEP_INDEX_MASK) | new_partial; | 
|  | else | 
|  | { | 
|  | /* xgettext:c-format */ | 
|  | _bfd_error_handler (_("%pB and %pB are for different configurations"), | 
|  | last_ibfd, ibfd); | 
|  | bfd_set_error (bfd_error_invalid_target); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | elf_elfheader (obfd)->e_flags = old_flags; | 
|  | last_ibfd = ibfd; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* This will be edited by the MeP configration tool.  */ | 
|  | static const char * config_names[] = | 
|  | { | 
|  | "basic" | 
|  | /* start-mepcfgtool */ | 
|  | ,"default" | 
|  | /* end-mepcfgtool */ | 
|  | }; | 
|  |  | 
|  | static const char * core_names[] = | 
|  | { | 
|  | "MeP", "MeP-c2", "MeP-c3", "MeP-h1" | 
|  | }; | 
|  |  | 
|  | static bool | 
|  | mep_elf_print_private_bfd_data (bfd * abfd, void * ptr) | 
|  | { | 
|  | FILE *   file = (FILE *) ptr; | 
|  | flagword flags, partial_flags; | 
|  |  | 
|  | BFD_ASSERT (abfd != NULL && ptr != NULL); | 
|  |  | 
|  | /* Print normal ELF private data.  */ | 
|  | _bfd_elf_print_private_bfd_data (abfd, ptr); | 
|  |  | 
|  | flags = elf_elfheader (abfd)->e_flags; | 
|  | fprintf (file, _("private flags = 0x%lx"), (unsigned long) flags); | 
|  |  | 
|  | partial_flags = (flags & EF_MEP_CPU_MASK) >> 24; | 
|  | if (partial_flags < ARRAY_SIZE (core_names)) | 
|  | fprintf (file, "  core: %s", core_names[(long)partial_flags]); | 
|  |  | 
|  | partial_flags = flags & EF_MEP_INDEX_MASK; | 
|  | if (partial_flags < ARRAY_SIZE (config_names)) | 
|  | fprintf (file, "  me_module: %s", config_names[(long)partial_flags]); | 
|  |  | 
|  | fputc ('\n', file); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Return the machine subcode from the ELF e_flags header.  */ | 
|  |  | 
|  | static int | 
|  | elf32_mep_machine (bfd * abfd) | 
|  | { | 
|  | switch (elf_elfheader (abfd)->e_flags & EF_MEP_CPU_MASK) | 
|  | { | 
|  | default: break; | 
|  | case EF_MEP_CPU_C2: return bfd_mach_mep; | 
|  | case EF_MEP_CPU_C3: return bfd_mach_mep; | 
|  | case EF_MEP_CPU_C4: return bfd_mach_mep; | 
|  | case EF_MEP_CPU_C5: return bfd_mach_mep_c5; | 
|  | case EF_MEP_CPU_H1: return bfd_mach_mep_h1; | 
|  | } | 
|  |  | 
|  | return bfd_mach_mep; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | mep_elf_object_p (bfd * abfd) | 
|  | { | 
|  | bfd_default_set_arch_mach (abfd, bfd_arch_mep, elf32_mep_machine (abfd)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | mep_elf_section_flags (const Elf_Internal_Shdr *hdr) | 
|  | { | 
|  | if (hdr->sh_flags & SHF_MEP_VLIW) | 
|  | hdr->bfd_section->flags |= SEC_MEP_VLIW; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | mep_elf_fake_sections (bfd *		   abfd ATTRIBUTE_UNUSED, | 
|  | Elf_Internal_Shdr * hdr, | 
|  | asection *	   sec) | 
|  | { | 
|  | if (sec->flags & SEC_MEP_VLIW) | 
|  | hdr->sh_flags |= SHF_MEP_VLIW; | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  | #define ELF_ARCH		bfd_arch_mep | 
|  | #define ELF_MACHINE_CODE	EM_CYGNUS_MEP | 
|  | #define ELF_MAXPAGESIZE		0x1000 | 
|  |  | 
|  | #define TARGET_BIG_SYM		mep_elf32_vec | 
|  | #define TARGET_BIG_NAME		"elf32-mep" | 
|  |  | 
|  | #define TARGET_LITTLE_SYM	mep_elf32_le_vec | 
|  | #define TARGET_LITTLE_NAME	"elf32-mep-little" | 
|  |  | 
|  | #define elf_info_to_howto_rel			NULL | 
|  | #define elf_info_to_howto			mep_info_to_howto_rela | 
|  | #define elf_backend_relocate_section		mep_elf_relocate_section | 
|  | #define elf_backend_object_p			mep_elf_object_p | 
|  | #define elf_backend_section_flags		mep_elf_section_flags | 
|  | #define elf_backend_fake_sections		mep_elf_fake_sections | 
|  |  | 
|  | #define bfd_elf32_bfd_reloc_type_lookup		mep_reloc_type_lookup | 
|  | #define bfd_elf32_bfd_reloc_name_lookup		mep_reloc_name_lookup | 
|  | #define bfd_elf32_bfd_set_private_flags		mep_elf_set_private_flags | 
|  | #define bfd_elf32_bfd_merge_private_bfd_data	mep_elf_merge_private_bfd_data | 
|  | #define bfd_elf32_bfd_print_private_bfd_data	mep_elf_print_private_bfd_data | 
|  |  | 
|  | #define elf_backend_rela_normal			1 | 
|  |  | 
|  | #include "elf32-target.h" |