1214571Sdim/* MeP-specific support for 32-bit ELF. 2214571Sdim Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 3214571Sdim Free Software Foundation, Inc. 4214571Sdim 5214571Sdim This file is part of BFD, the Binary File Descriptor library. 6214571Sdim 7214571Sdim This program is free software; you can redistribute it and/or modify 8214571Sdim it under the terms of the GNU General Public License as published by 9214571Sdim the Free Software Foundation; either version 2 of the License, or 10214571Sdim (at your option) any later version. 11214571Sdim 12214571Sdim This program is distributed in the hope that it will be useful, 13214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 14214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15214571Sdim GNU General Public License for more details. 16214571Sdim 17214571Sdim You should have received a copy of the GNU General Public License 18214571Sdim along with this program; if not, write to the Free Software 19214571Sdim Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 20214571Sdim 21214571Sdim#include "sysdep.h" 22214571Sdim#include "bfd.h" 23214571Sdim#include "libbfd.h" 24214571Sdim#include "elf-bfd.h" 25214571Sdim#include "elf/mep.h" 26214571Sdim#include "libiberty.h" 27214571Sdim 28214571Sdim/* Forward declarations. */ 29214571Sdim 30214571Sdim/* Private relocation functions. */ 31214571Sdim 32214571Sdim#define MEPREL(type, size, bits, right, left, pcrel, overflow, mask) \ 33214571Sdim {(unsigned)type, right, size, bits, pcrel, left, overflow, mep_reloc, #type, FALSE, 0, mask, 0 } 34214571Sdim 35214571Sdim#define N complain_overflow_dont 36214571Sdim#define S complain_overflow_signed 37214571Sdim#define U complain_overflow_unsigned 38214571Sdim 39214571Sdimstatic bfd_reloc_status_type mep_reloc (bfd *, arelent *, struct bfd_symbol *, 40214571Sdim void *, asection *, bfd *, char **); 41214571Sdim 42214571Sdimstatic reloc_howto_type mep_elf_howto_table [] = 43214571Sdim{ 44214571Sdim /* type, size, bits, leftshift, rightshift, pcrel, OD/OS/OU, mask. */ 45214571Sdim MEPREL (R_MEP_NONE, 0, 0, 0, 0, 0, N, 0), 46214571Sdim MEPREL (R_RELC, 0, 0, 0, 0, 0, N, 0), 47214571Sdim /* MEPRELOC:HOWTO */ 48214571Sdim /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */ 49214571Sdim MEPREL (R_MEP_8, 0, 8, 0, 0, 0, U, 0xff), 50214571Sdim MEPREL (R_MEP_16, 1, 16, 0, 0, 0, U, 0xffff), 51214571Sdim MEPREL (R_MEP_32, 2, 32, 0, 0, 0, U, 0xffffffff), 52214571Sdim MEPREL (R_MEP_PCREL8A2, 1, 8, 1, 1, 1, S, 0x00fe), 53214571Sdim MEPREL (R_MEP_PCREL12A2,1, 12, 1, 1, 1, S, 0x0ffe), 54214571Sdim MEPREL (R_MEP_PCREL17A2,2, 17, 0, 1, 1, S, 0x0000ffff), 55214571Sdim MEPREL (R_MEP_PCREL24A2,2, 24, 0, 1, 1, S, 0x07f0ffff), 56214571Sdim MEPREL (R_MEP_PCABS24A2,2, 24, 0, 1, 0, U, 0x07f0ffff), 57214571Sdim MEPREL (R_MEP_LOW16, 2, 16, 0, 0, 0, N, 0x0000ffff), 58214571Sdim MEPREL (R_MEP_HI16U, 2, 32, 0,16, 0, N, 0x0000ffff), 59214571Sdim MEPREL (R_MEP_HI16S, 2, 32, 0,16, 0, N, 0x0000ffff), 60214571Sdim MEPREL (R_MEP_GPREL, 2, 16, 0, 0, 0, S, 0x0000ffff), 61214571Sdim MEPREL (R_MEP_TPREL, 2, 16, 0, 0, 0, S, 0x0000ffff), 62214571Sdim MEPREL (R_MEP_TPREL7, 1, 7, 0, 0, 0, U, 0x007f), 63214571Sdim MEPREL (R_MEP_TPREL7A2, 1, 7, 1, 1, 0, U, 0x007e), 64214571Sdim MEPREL (R_MEP_TPREL7A4, 1, 7, 2, 2, 0, U, 0x007c), 65214571Sdim MEPREL (R_MEP_UIMM24, 2, 24, 0, 0, 0, U, 0x00ffffff), 66214571Sdim MEPREL (R_MEP_ADDR24A4, 2, 24, 0, 2, 0, U, 0x00fcffff), 67214571Sdim MEPREL (R_MEP_GNU_VTINHERIT,1, 0,16,32, 0, N, 0x0000), 68214571Sdim MEPREL (R_MEP_GNU_VTENTRY,1, 0,16,32, 0, N, 0x0000), 69214571Sdim /* MEPRELOC:END */ 70214571Sdim}; 71214571Sdim 72214571Sdim#define VALID_MEP_RELOC(N) ((N) >= 0 \ 73214571Sdim && (N) < ARRAY_SIZE (mep_elf_howto_table) 74214571Sdim 75214571Sdim#undef N 76214571Sdim#undef S 77214571Sdim#undef U 78214571Sdim 79214571Sdimstatic bfd_reloc_status_type 80214571Sdimmep_reloc 81214571Sdim (bfd * abfd ATTRIBUTE_UNUSED, 82214571Sdim arelent * reloc_entry ATTRIBUTE_UNUSED, 83214571Sdim struct bfd_symbol * symbol ATTRIBUTE_UNUSED, 84214571Sdim void * data ATTRIBUTE_UNUSED, 85214571Sdim asection * input_section ATTRIBUTE_UNUSED, 86214571Sdim bfd * output_bfd ATTRIBUTE_UNUSED, 87214571Sdim char ** error_message ATTRIBUTE_UNUSED) 88214571Sdim{ 89214571Sdim return bfd_reloc_ok; 90214571Sdim} 91214571Sdim 92214571Sdim 93214571Sdim 94214571Sdim#define BFD_RELOC_MEP_NONE BFD_RELOC_NONE 95214571Sdim#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) 96214571Sdim#define MAP(n) case BFD_RELOC_MEP_##n: type = R_MEP_##n; break 97214571Sdim#else 98214571Sdim#define MAP(n) case BFD_RELOC_MEP_/**/n: type = R_MEP_/**/n; break 99214571Sdim#endif 100214571Sdim 101214571Sdimstatic reloc_howto_type * 102214571Sdimmep_reloc_type_lookup 103214571Sdim (bfd * abfd ATTRIBUTE_UNUSED, 104214571Sdim bfd_reloc_code_real_type code) 105214571Sdim{ 106214571Sdim unsigned int type = 0; 107214571Sdim 108214571Sdim switch (code) 109214571Sdim { 110214571Sdim MAP(NONE); 111214571Sdim case BFD_RELOC_8: 112214571Sdim type = R_MEP_8; 113214571Sdim break; 114214571Sdim case BFD_RELOC_16: 115214571Sdim type = R_MEP_16; 116214571Sdim break; 117214571Sdim case BFD_RELOC_32: 118214571Sdim type = R_MEP_32; 119214571Sdim break; 120214571Sdim case BFD_RELOC_VTABLE_ENTRY: 121214571Sdim type = R_MEP_GNU_VTENTRY; 122214571Sdim break; 123214571Sdim case BFD_RELOC_VTABLE_INHERIT: 124214571Sdim type = R_MEP_GNU_VTINHERIT; 125214571Sdim break; 126214571Sdim case BFD_RELOC_RELC: 127214571Sdim type = R_RELC; 128214571Sdim break; 129214571Sdim 130214571Sdim /* MEPRELOC:MAP */ 131214571Sdim /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */ 132214571Sdim MAP(8); 133214571Sdim MAP(16); 134214571Sdim MAP(32); 135214571Sdim MAP(PCREL8A2); 136214571Sdim MAP(PCREL12A2); 137214571Sdim MAP(PCREL17A2); 138214571Sdim MAP(PCREL24A2); 139214571Sdim MAP(PCABS24A2); 140214571Sdim MAP(LOW16); 141214571Sdim MAP(HI16U); 142214571Sdim MAP(HI16S); 143214571Sdim MAP(GPREL); 144214571Sdim MAP(TPREL); 145214571Sdim MAP(TPREL7); 146214571Sdim MAP(TPREL7A2); 147214571Sdim MAP(TPREL7A4); 148214571Sdim MAP(UIMM24); 149214571Sdim MAP(ADDR24A4); 150214571Sdim MAP(GNU_VTINHERIT); 151214571Sdim MAP(GNU_VTENTRY); 152214571Sdim /* MEPRELOC:END */ 153214571Sdim 154214571Sdim default: 155214571Sdim /* Pacify gcc -Wall. */ 156214571Sdim fprintf (stderr, "mep: no reloc for code %d\n", code); 157214571Sdim return NULL; 158214571Sdim } 159214571Sdim 160214571Sdim if (mep_elf_howto_table[type].type != type) 161214571Sdim { 162214571Sdim fprintf (stderr, "MeP: howto %d has type %d\n", type, mep_elf_howto_table[type].type); 163214571Sdim abort (); 164214571Sdim } 165214571Sdim 166214571Sdim return mep_elf_howto_table + type; 167214571Sdim} 168214571Sdim 169214571Sdim#undef MAP 170214571Sdim 171214571Sdimstatic reloc_howto_type * 172214571Sdimmep_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) 173214571Sdim{ 174214571Sdim unsigned int i; 175214571Sdim 176214571Sdim for (i = 0; 177214571Sdim i < sizeof (mep_elf_howto_table) / sizeof (mep_elf_howto_table[0]); 178214571Sdim i++) 179214571Sdim if (mep_elf_howto_table[i].name != NULL 180214571Sdim && strcasecmp (mep_elf_howto_table[i].name, r_name) == 0) 181214571Sdim return &mep_elf_howto_table[i]; 182214571Sdim 183214571Sdim return NULL; 184214571Sdim} 185214571Sdim 186214571Sdim/* Perform a single relocation. */ 187214571Sdim 188214571Sdimstatic struct bfd_link_info *mep_info; 189214571Sdimstatic int warn_tp = 0, warn_sda = 0; 190214571Sdim 191214571Sdimstatic bfd_vma 192214571Sdimmep_lookup_global 193214571Sdim (char * name, 194214571Sdim bfd_vma ofs, 195214571Sdim bfd_vma * cache, 196214571Sdim int * warn) 197214571Sdim{ 198214571Sdim struct bfd_link_hash_entry *h; 199214571Sdim 200214571Sdim if (*cache || *warn) 201214571Sdim return *cache; 202214571Sdim 203214571Sdim h = bfd_link_hash_lookup (mep_info->hash, name, FALSE, FALSE, TRUE); 204214571Sdim if (h == 0 || h->type != bfd_link_hash_defined) 205214571Sdim { 206214571Sdim *warn = ofs + 1; 207214571Sdim return 0; 208214571Sdim } 209214571Sdim *cache = (h->u.def.value 210214571Sdim + h->u.def.section->output_section->vma 211214571Sdim + h->u.def.section->output_offset); 212214571Sdim return *cache; 213214571Sdim} 214214571Sdim 215214571Sdimstatic bfd_vma 216214571Sdimmep_tpoff_base (bfd_vma ofs) 217214571Sdim{ 218214571Sdim static bfd_vma cache = 0; 219214571Sdim return mep_lookup_global ("__tpbase", ofs, &cache, &warn_tp); 220214571Sdim} 221214571Sdim 222214571Sdimstatic bfd_vma 223214571Sdimmep_sdaoff_base (bfd_vma ofs) 224214571Sdim{ 225214571Sdim static bfd_vma cache = 0; 226214571Sdim return mep_lookup_global ("__sdabase", ofs, &cache, &warn_sda); 227214571Sdim} 228214571Sdim 229214571Sdimstatic bfd_reloc_status_type 230214571Sdimmep_final_link_relocate 231214571Sdim (reloc_howto_type * howto, 232214571Sdim bfd * input_bfd, 233214571Sdim asection * input_section, 234214571Sdim bfd_byte * contents, 235214571Sdim Elf_Internal_Rela * rel, 236214571Sdim bfd_vma relocation) 237214571Sdim{ 238214571Sdim unsigned long u; 239214571Sdim long s; 240214571Sdim unsigned char *byte; 241214571Sdim bfd_vma pc; 242214571Sdim bfd_reloc_status_type r = bfd_reloc_ok; 243214571Sdim int e2, e4; 244214571Sdim 245214571Sdim if (bfd_big_endian (input_bfd)) 246214571Sdim { 247214571Sdim e2 = 0; 248214571Sdim e4 = 0; 249214571Sdim } 250214571Sdim else 251214571Sdim { 252214571Sdim e2 = 1; 253214571Sdim e4 = 3; 254214571Sdim } 255214571Sdim 256214571Sdim pc = (input_section->output_section->vma 257214571Sdim + input_section->output_offset 258214571Sdim + rel->r_offset); 259214571Sdim 260214571Sdim s = relocation + rel->r_addend; 261214571Sdim 262214571Sdim byte = (unsigned char *)contents + rel->r_offset; 263214571Sdim 264214571Sdim if (howto->type == R_MEP_PCREL24A2 265214571Sdim && s == 0 266214571Sdim && pc >= 0x800000) 267214571Sdim { 268214571Sdim /* This is an unreachable branch to an undefined weak function. 269214571Sdim Silently ignore it, since the opcode can't do that but should 270214571Sdim never be executed anyway. */ 271214571Sdim return bfd_reloc_ok; 272214571Sdim } 273214571Sdim 274214571Sdim if (howto->pc_relative) 275214571Sdim s -= pc; 276214571Sdim 277214571Sdim u = (unsigned long) s; 278214571Sdim 279214571Sdim switch (howto->type) 280214571Sdim { 281214571Sdim /* MEPRELOC:APPLY */ 282214571Sdim /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */ 283214571Sdim case R_MEP_8: /* 76543210 */ 284214571Sdim if (u > 255) r = bfd_reloc_overflow; 285214571Sdim byte[0] = (u & 0xff); 286214571Sdim break; 287214571Sdim case R_MEP_16: /* fedcba9876543210 */ 288214571Sdim if (u > 65535) r = bfd_reloc_overflow; 289214571Sdim byte[0^e2] = ((u >> 8) & 0xff); 290214571Sdim byte[1^e2] = (u & 0xff); 291214571Sdim break; 292214571Sdim case R_MEP_32: /* vutsrqponmlkjihgfedcba9876543210 */ 293214571Sdim byte[0^e4] = ((u >> 24) & 0xff); 294214571Sdim byte[1^e4] = ((u >> 16) & 0xff); 295214571Sdim byte[2^e4] = ((u >> 8) & 0xff); 296214571Sdim byte[3^e4] = (u & 0xff); 297214571Sdim break; 298214571Sdim case R_MEP_PCREL8A2: /* --------7654321- */ 299214571Sdim if (-128 > s || s > 127) r = bfd_reloc_overflow; 300214571Sdim byte[1^e2] = (byte[1^e2] & 0x01) | (s & 0xfe); 301214571Sdim break; 302214571Sdim case R_MEP_PCREL12A2: /* ----ba987654321- */ 303214571Sdim if (-2048 > s || s > 2047) r = bfd_reloc_overflow; 304214571Sdim byte[0^e2] = (byte[0^e2] & 0xf0) | ((s >> 8) & 0x0f); 305214571Sdim byte[1^e2] = (byte[1^e2] & 0x01) | (s & 0xfe); 306214571Sdim break; 307214571Sdim case R_MEP_PCREL17A2: /* ----------------gfedcba987654321 */ 308214571Sdim if (-65536 > s || s > 65535) r = bfd_reloc_overflow; 309214571Sdim byte[2^e2] = ((s >> 9) & 0xff); 310214571Sdim byte[3^e2] = ((s >> 1) & 0xff); 311214571Sdim break; 312214571Sdim case R_MEP_PCREL24A2: /* -----7654321----nmlkjihgfedcba98 */ 313214571Sdim if (-8388608 > s || s > 8388607) r = bfd_reloc_overflow; 314214571Sdim byte[0^e2] = (byte[0^e2] & 0xf8) | ((s >> 5) & 0x07); 315214571Sdim byte[1^e2] = (byte[1^e2] & 0x0f) | ((s << 3) & 0xf0); 316214571Sdim byte[2^e2] = ((s >> 16) & 0xff); 317214571Sdim byte[3^e2] = ((s >> 8) & 0xff); 318214571Sdim break; 319214571Sdim case R_MEP_PCABS24A2: /* -----7654321----nmlkjihgfedcba98 */ 320214571Sdim if (u > 16777215) r = bfd_reloc_overflow; 321214571Sdim byte[0^e2] = (byte[0^e2] & 0xf8) | ((u >> 5) & 0x07); 322214571Sdim byte[1^e2] = (byte[1^e2] & 0x0f) | ((u << 3) & 0xf0); 323214571Sdim byte[2^e2] = ((u >> 16) & 0xff); 324214571Sdim byte[3^e2] = ((u >> 8) & 0xff); 325214571Sdim break; 326214571Sdim case R_MEP_LOW16: /* ----------------fedcba9876543210 */ 327214571Sdim byte[2^e2] = ((u >> 8) & 0xff); 328214571Sdim byte[3^e2] = (u & 0xff); 329214571Sdim break; 330214571Sdim case R_MEP_HI16U: /* ----------------vutsrqponmlkjihg */ 331214571Sdim byte[2^e2] = ((u >> 24) & 0xff); 332214571Sdim byte[3^e2] = ((u >> 16) & 0xff); 333214571Sdim break; 334214571Sdim case R_MEP_HI16S: /* ----------------vutsrqponmlkjihg */ 335214571Sdim byte[2^e2] = ((s >> 24) & 0xff); 336214571Sdim byte[3^e2] = ((s >> 16) & 0xff); 337214571Sdim break; 338214571Sdim case R_MEP_GPREL: /* ----------------fedcba9876543210 */ 339214571Sdim s -= mep_sdaoff_base(rel->r_offset); 340214571Sdim if (-32768 > s || s > 32767) r = bfd_reloc_overflow; 341214571Sdim byte[2^e2] = ((s >> 8) & 0xff); 342214571Sdim byte[3^e2] = (s & 0xff); 343214571Sdim break; 344214571Sdim case R_MEP_TPREL: /* ----------------fedcba9876543210 */ 345214571Sdim s -= mep_tpoff_base(rel->r_offset); 346214571Sdim if (-32768 > s || s > 32767) r = bfd_reloc_overflow; 347214571Sdim byte[2^e2] = ((s >> 8) & 0xff); 348214571Sdim byte[3^e2] = (s & 0xff); 349214571Sdim break; 350214571Sdim case R_MEP_TPREL7: /* ---------6543210 */ 351214571Sdim u -= mep_tpoff_base(rel->r_offset); 352214571Sdim if (u > 127) r = bfd_reloc_overflow; 353214571Sdim byte[1^e2] = (byte[1^e2] & 0x80) | (u & 0x7f); 354214571Sdim break; 355214571Sdim case R_MEP_TPREL7A2: /* ---------654321- */ 356214571Sdim u -= mep_tpoff_base(rel->r_offset); 357214571Sdim if (u > 127) r = bfd_reloc_overflow; 358214571Sdim byte[1^e2] = (byte[1^e2] & 0x81) | (u & 0x7e); 359214571Sdim break; 360214571Sdim case R_MEP_TPREL7A4: /* ---------65432-- */ 361214571Sdim u -= mep_tpoff_base(rel->r_offset); 362214571Sdim if (u > 127) r = bfd_reloc_overflow; 363214571Sdim byte[1^e2] = (byte[1^e2] & 0x83) | (u & 0x7c); 364214571Sdim break; 365214571Sdim case R_MEP_UIMM24: /* --------76543210nmlkjihgfedcba98 */ 366214571Sdim if (u > 16777215) r = bfd_reloc_overflow; 367214571Sdim byte[1^e2] = (u & 0xff); 368214571Sdim byte[2^e2] = ((u >> 16) & 0xff); 369214571Sdim byte[3^e2] = ((u >> 8) & 0xff); 370214571Sdim break; 371214571Sdim case R_MEP_ADDR24A4: /* --------765432--nmlkjihgfedcba98 */ 372214571Sdim if (u > 16777215) r = bfd_reloc_overflow; 373214571Sdim byte[1^e2] = (byte[1^e2] & 0x03) | (u & 0xfc); 374214571Sdim byte[2^e2] = ((u >> 16) & 0xff); 375214571Sdim byte[3^e2] = ((u >> 8) & 0xff); 376214571Sdim break; 377214571Sdim case R_MEP_GNU_VTINHERIT: /* ---------------- */ 378214571Sdim break; 379214571Sdim case R_MEP_GNU_VTENTRY: /* ---------------- */ 380214571Sdim break; 381214571Sdim /* MEPRELOC:END */ 382214571Sdim default: 383214571Sdim abort (); 384214571Sdim } 385214571Sdim 386214571Sdim return r; 387214571Sdim} 388214571Sdim 389214571Sdim/* Set the howto pointer for a MEP ELF reloc. */ 390214571Sdim 391214571Sdimstatic void 392214571Sdimmep_info_to_howto_rela 393214571Sdim (bfd * abfd ATTRIBUTE_UNUSED, 394214571Sdim arelent * cache_ptr, 395214571Sdim Elf_Internal_Rela * dst) 396214571Sdim{ 397214571Sdim unsigned int r_type; 398214571Sdim 399214571Sdim r_type = ELF32_R_TYPE (dst->r_info); 400214571Sdim cache_ptr->howto = & mep_elf_howto_table [r_type]; 401214571Sdim} 402214571Sdim 403214571Sdim/* Look through the relocs for a section during the first phase. 404214571Sdim Since we don't do .gots or .plts, we just need to consider the 405214571Sdim virtual table relocs for gc. */ 406214571Sdim 407214571Sdimstatic bfd_boolean 408214571Sdimmep_elf_check_relocs 409214571Sdim (bfd * abfd, 410214571Sdim struct bfd_link_info * info, 411214571Sdim asection * sec, 412214571Sdim const Elf_Internal_Rela * relocs) 413214571Sdim{ 414214571Sdim Elf_Internal_Shdr * symtab_hdr; 415214571Sdim struct elf_link_hash_entry ** sym_hashes; 416214571Sdim struct elf_link_hash_entry ** sym_hashes_end; 417214571Sdim const Elf_Internal_Rela * rel; 418214571Sdim const Elf_Internal_Rela * rel_end; 419214571Sdim 420214571Sdim if (info->relocatable) 421214571Sdim return TRUE; 422214571Sdim 423214571Sdim symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 424214571Sdim sym_hashes = elf_sym_hashes (abfd); 425214571Sdim sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); 426214571Sdim if (!elf_bad_symtab (abfd)) 427214571Sdim sym_hashes_end -= symtab_hdr->sh_info; 428214571Sdim 429214571Sdim rel_end = relocs + sec->reloc_count; 430214571Sdim for (rel = relocs; rel < rel_end; rel++) 431214571Sdim { 432214571Sdim struct elf_link_hash_entry *h; 433214571Sdim unsigned long r_symndx; 434214571Sdim 435214571Sdim r_symndx = ELF32_R_SYM (rel->r_info); 436214571Sdim if (r_symndx < symtab_hdr->sh_info) 437214571Sdim h = NULL; 438214571Sdim else 439214571Sdim h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 440214571Sdim } 441214571Sdim return TRUE; 442214571Sdim} 443214571Sdim 444214571Sdim 445214571Sdim/* Relocate a MEP ELF section. 446214571Sdim There is some attempt to make this function usable for many architectures, 447214571Sdim both USE_REL and USE_RELA ['twould be nice if such a critter existed], 448214571Sdim if only to serve as a learning tool. 449214571Sdim 450214571Sdim The RELOCATE_SECTION function is called by the new ELF backend linker 451214571Sdim to handle the relocations for a section. 452214571Sdim 453214571Sdim The relocs are always passed as Rela structures; if the section 454214571Sdim actually uses Rel structures, the r_addend field will always be 455214571Sdim zero. 456214571Sdim 457214571Sdim This function is responsible for adjusting the section contents as 458214571Sdim necessary, and (if using Rela relocs and generating a relocatable 459214571Sdim output file) adjusting the reloc addend as necessary. 460214571Sdim 461214571Sdim This function does not have to worry about setting the reloc 462214571Sdim address or the reloc symbol index. 463214571Sdim 464214571Sdim LOCAL_SYMS is a pointer to the swapped in local symbols. 465214571Sdim 466214571Sdim LOCAL_SECTIONS is an array giving the section in the input file 467214571Sdim corresponding to the st_shndx field of each local symbol. 468214571Sdim 469214571Sdim The global hash table entry for the global symbols can be found 470214571Sdim via elf_sym_hashes (input_bfd). 471214571Sdim 472214571Sdim When generating relocatable output, this function must handle 473214571Sdim STB_LOCAL/STT_SECTION symbols specially. The output symbol is 474214571Sdim going to be the section symbol corresponding to the output 475214571Sdim section, which means that the addend must be adjusted 476214571Sdim accordingly. */ 477214571Sdim 478214571Sdimstatic bfd_boolean 479214571Sdimmep_elf_relocate_section 480214571Sdim (bfd * output_bfd ATTRIBUTE_UNUSED, 481214571Sdim struct bfd_link_info * info, 482214571Sdim bfd * input_bfd, 483214571Sdim asection * input_section, 484214571Sdim bfd_byte * contents, 485214571Sdim Elf_Internal_Rela * relocs, 486214571Sdim Elf_Internal_Sym * local_syms, 487214571Sdim asection ** local_sections) 488214571Sdim{ 489214571Sdim Elf_Internal_Shdr * symtab_hdr; 490214571Sdim struct elf_link_hash_entry ** sym_hashes; 491214571Sdim Elf_Internal_Rela * rel; 492214571Sdim Elf_Internal_Rela * relend; 493214571Sdim 494214571Sdim symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; 495214571Sdim sym_hashes = elf_sym_hashes (input_bfd); 496214571Sdim relend = relocs + input_section->reloc_count; 497214571Sdim 498214571Sdim mep_info = info; 499214571Sdim 500214571Sdim for (rel = relocs; rel < relend; rel ++) 501214571Sdim { 502214571Sdim reloc_howto_type * howto; 503214571Sdim unsigned long r_symndx; 504214571Sdim Elf_Internal_Sym * sym; 505214571Sdim asection * sec; 506214571Sdim struct elf_link_hash_entry * h; 507214571Sdim bfd_vma relocation; 508214571Sdim bfd_reloc_status_type r; 509214571Sdim const char * name = NULL; 510214571Sdim int r_type; 511214571Sdim 512214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 513214571Sdim 514214571Sdim r_symndx = ELF32_R_SYM (rel->r_info); 515214571Sdim 516214571Sdim /* Is this a complex relocation? */ 517214571Sdim if (!info->relocatable && ELF32_R_TYPE (rel->r_info) == R_RELC) 518214571Sdim { 519214571Sdim bfd_elf_perform_complex_relocation (output_bfd, info, 520214571Sdim input_bfd, input_section, contents, 521214571Sdim rel, local_syms, local_sections); 522214571Sdim continue; 523214571Sdim } 524214571Sdim 525214571Sdim howto = mep_elf_howto_table + ELF32_R_TYPE (rel->r_info); 526214571Sdim h = NULL; 527214571Sdim sym = NULL; 528214571Sdim sec = NULL; 529214571Sdim 530214571Sdim if (r_symndx < symtab_hdr->sh_info) 531214571Sdim { 532214571Sdim sym = local_syms + r_symndx; 533214571Sdim sec = local_sections [r_symndx]; 534214571Sdim relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 535214571Sdim 536214571Sdim name = bfd_elf_string_from_elf_section 537214571Sdim (input_bfd, symtab_hdr->sh_link, sym->st_name); 538214571Sdim name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; 539214571Sdim#if 0 540214571Sdim fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n", 541214571Sdim sec->name, name, sym->st_name, 542214571Sdim sec->output_section->vma, sec->output_offset, 543214571Sdim sym->st_value, rel->r_addend); 544214571Sdim#endif 545214571Sdim } 546214571Sdim else 547214571Sdim { 548214571Sdim relocation = 0; 549214571Sdim h = sym_hashes [r_symndx]; 550214571Sdim 551214571Sdim while (h->root.type == bfd_link_hash_indirect 552214571Sdim || h->root.type == bfd_link_hash_warning) 553214571Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 554214571Sdim 555214571Sdim name = h->root.root.string; 556214571Sdim 557214571Sdim if (h->root.type == bfd_link_hash_defined 558214571Sdim || h->root.type == bfd_link_hash_defweak) 559214571Sdim { 560214571Sdim sec = h->root.u.def.section; 561214571Sdim relocation = (h->root.u.def.value 562214571Sdim + sec->output_section->vma 563214571Sdim + sec->output_offset); 564214571Sdim#if 0 565214571Sdim fprintf (stderr, 566214571Sdim "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n", 567214571Sdim sec->name, name, h->root.u.def.value, 568214571Sdim sec->output_section->vma, sec->output_offset, relocation); 569214571Sdim#endif 570214571Sdim } 571214571Sdim else if (h->root.type == bfd_link_hash_undefweak) 572214571Sdim { 573214571Sdim#if 0 574214571Sdim fprintf (stderr, "undefined: sec: %s, name: %s\n", 575214571Sdim sec->name, name); 576214571Sdim#endif 577214571Sdim } 578214571Sdim else if (!info->relocatable) 579214571Sdim { 580214571Sdim if (! ((*info->callbacks->undefined_symbol) 581214571Sdim (info, h->root.root.string, input_bfd, 582214571Sdim input_section, rel->r_offset, 583214571Sdim (!info->shared && info->unresolved_syms_in_objects == RM_GENERATE_ERROR)))) 584214571Sdim return FALSE; 585214571Sdim#if 0 586214571Sdim fprintf (stderr, "unknown: name: %s\n", name); 587214571Sdim#endif 588214571Sdim } 589214571Sdim } 590214571Sdim 591214571Sdim if (sec != NULL && elf_discarded_section (sec)) 592214571Sdim { 593214571Sdim /* For relocs against symbols from removed linkonce sections, 594214571Sdim or sections discarded by a linker script, we just want the 595214571Sdim section contents zeroed. Avoid any special processing. */ 596214571Sdim _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 597214571Sdim rel->r_info = 0; 598214571Sdim rel->r_addend = 0; 599214571Sdim continue; 600214571Sdim } 601214571Sdim 602214571Sdim if (info->relocatable) 603214571Sdim { 604214571Sdim /* This is a relocatable link. We don't have to change 605214571Sdim anything, unless the reloc is against a section symbol, 606214571Sdim in which case we have to adjust according to where the 607214571Sdim section symbol winds up in the output section. */ 608214571Sdim if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) 609214571Sdim rel->r_addend += sec->output_offset; 610214571Sdim continue; 611214571Sdim } 612214571Sdim 613214571Sdim switch (r_type) 614214571Sdim { 615214571Sdim default: 616214571Sdim r = mep_final_link_relocate (howto, input_bfd, input_section, 617214571Sdim contents, rel, relocation); 618214571Sdim break; 619214571Sdim } 620214571Sdim 621214571Sdim if (r != bfd_reloc_ok) 622214571Sdim { 623214571Sdim const char * msg = (const char *) NULL; 624214571Sdim 625214571Sdim switch (r) 626214571Sdim { 627214571Sdim case bfd_reloc_overflow: 628214571Sdim r = info->callbacks->reloc_overflow 629214571Sdim (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, 630214571Sdim input_bfd, input_section, rel->r_offset); 631214571Sdim break; 632214571Sdim 633214571Sdim case bfd_reloc_undefined: 634214571Sdim r = info->callbacks->undefined_symbol 635214571Sdim (info, name, input_bfd, input_section, rel->r_offset, TRUE); 636214571Sdim break; 637214571Sdim 638214571Sdim case bfd_reloc_outofrange: 639214571Sdim msg = _("internal error: out of range error"); 640214571Sdim break; 641214571Sdim 642214571Sdim case bfd_reloc_notsupported: 643214571Sdim msg = _("internal error: unsupported relocation error"); 644214571Sdim break; 645214571Sdim 646214571Sdim case bfd_reloc_dangerous: 647214571Sdim msg = _("internal error: dangerous relocation"); 648214571Sdim break; 649214571Sdim 650214571Sdim default: 651214571Sdim msg = _("internal error: unknown error"); 652214571Sdim break; 653214571Sdim } 654214571Sdim 655214571Sdim if (msg) 656214571Sdim r = info->callbacks->warning 657214571Sdim (info, msg, name, input_bfd, input_section, rel->r_offset); 658214571Sdim 659214571Sdim if (! r) 660214571Sdim return FALSE; 661214571Sdim } 662214571Sdim } 663214571Sdim 664214571Sdim if (warn_tp) 665214571Sdim info->callbacks->undefined_symbol 666214571Sdim (info, "__tpbase", input_bfd, input_section, warn_tp-1, TRUE); 667214571Sdim if (warn_sda) 668214571Sdim info->callbacks->undefined_symbol 669214571Sdim (info, "__sdabase", input_bfd, input_section, warn_sda-1, TRUE); 670214571Sdim if (warn_sda || warn_tp) 671214571Sdim return FALSE; 672214571Sdim 673214571Sdim return TRUE; 674214571Sdim} 675214571Sdim 676214571Sdim 677214571Sdim/* Update the got entry reference counts for the section being 678214571Sdim removed. */ 679214571Sdim 680214571Sdimstatic bfd_boolean 681214571Sdimmep_elf_gc_sweep_hook 682214571Sdim (bfd * abfd ATTRIBUTE_UNUSED, 683214571Sdim struct bfd_link_info * info ATTRIBUTE_UNUSED, 684214571Sdim asection * sec ATTRIBUTE_UNUSED, 685214571Sdim const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED) 686214571Sdim{ 687214571Sdim return TRUE; 688214571Sdim} 689214571Sdim 690214571Sdim/* Return the section that should be marked against GC for a given 691214571Sdim relocation. */ 692214571Sdim 693214571Sdimstatic asection * 694214571Sdimmep_elf_gc_mark_hook 695214571Sdim (asection * sec, 696214571Sdim struct bfd_link_info * info ATTRIBUTE_UNUSED, 697214571Sdim Elf_Internal_Rela * rel, 698214571Sdim struct elf_link_hash_entry * h, 699214571Sdim Elf_Internal_Sym * sym) 700214571Sdim{ 701214571Sdim if (h != NULL) 702214571Sdim { 703214571Sdim switch (ELF32_R_TYPE (rel->r_info)) 704214571Sdim { 705214571Sdim default: 706214571Sdim switch (h->root.type) 707214571Sdim { 708214571Sdim case bfd_link_hash_defined: 709214571Sdim case bfd_link_hash_defweak: 710214571Sdim return h->root.u.def.section; 711214571Sdim 712214571Sdim case bfd_link_hash_common: 713214571Sdim return h->root.u.c.p->section; 714214571Sdim 715214571Sdim default: 716214571Sdim break; 717214571Sdim } 718214571Sdim } 719214571Sdim } 720214571Sdim else 721214571Sdim { 722214571Sdim if (!(elf_bad_symtab (sec->owner) 723214571Sdim && ELF_ST_BIND (sym->st_info) != STB_LOCAL) 724214571Sdim && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE) 725214571Sdim && sym->st_shndx != SHN_COMMON)) 726214571Sdim return bfd_section_from_elf_index (sec->owner, sym->st_shndx); 727214571Sdim } 728214571Sdim 729214571Sdim return NULL; 730214571Sdim} 731214571Sdim 732214571Sdim 733214571Sdim/* Function to set the ELF flag bits. */ 734214571Sdim 735214571Sdimstatic bfd_boolean 736214571Sdimmep_elf_set_private_flags (bfd * abfd, 737214571Sdim flagword flags) 738214571Sdim{ 739214571Sdim elf_elfheader (abfd)->e_flags = flags; 740214571Sdim elf_flags_init (abfd) = TRUE; 741214571Sdim return TRUE; 742214571Sdim} 743214571Sdim 744214571Sdimstatic bfd_boolean 745214571Sdimmep_elf_copy_private_bfd_data (bfd * ibfd, bfd * obfd) 746214571Sdim{ 747214571Sdim if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour 748214571Sdim || bfd_get_flavour (obfd) != bfd_target_elf_flavour) 749214571Sdim return TRUE; 750214571Sdim 751214571Sdim elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; 752214571Sdim elf_flags_init (obfd) = TRUE; 753214571Sdim 754214571Sdim /* Copy object attributes. */ 755214571Sdim _bfd_elf_copy_obj_attributes (ibfd, obfd); 756214571Sdim 757214571Sdim return TRUE; 758214571Sdim} 759214571Sdim 760214571Sdim/* Merge backend specific data from an object file to the output 761214571Sdim object file when linking. */ 762214571Sdim 763214571Sdimstatic bfd_boolean 764214571Sdimmep_elf_merge_private_bfd_data (bfd * ibfd, bfd * obfd) 765214571Sdim{ 766214571Sdim static bfd *last_ibfd = 0; 767214571Sdim flagword old_flags, new_flags; 768214571Sdim flagword old_partial, new_partial; 769214571Sdim 770214571Sdim /* Check if we have the same endianess. */ 771214571Sdim if (_bfd_generic_verify_endian_match (ibfd, obfd) == FALSE) 772214571Sdim return FALSE; 773214571Sdim 774214571Sdim new_flags = elf_elfheader (ibfd)->e_flags; 775214571Sdim old_flags = elf_elfheader (obfd)->e_flags; 776214571Sdim 777214571Sdim#ifdef DEBUG 778214571Sdim _bfd_error_handler ("%B: old_flags = 0x%.8lx, new_flags = 0x%.8lx, init = %s", 779214571Sdim ibfd, old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no"); 780214571Sdim#endif 781214571Sdim 782214571Sdim /* First call, no flags set. */ 783214571Sdim if (!elf_flags_init (obfd)) 784214571Sdim { 785214571Sdim elf_flags_init (obfd) = TRUE; 786214571Sdim old_flags = new_flags; 787214571Sdim } 788214571Sdim else if ((new_flags | old_flags) & EF_MEP_LIBRARY) 789214571Sdim { 790214571Sdim /* Non-library flags trump library flags. The choice doesn't really 791214571Sdim matter if both OLD_FLAGS and NEW_FLAGS have EF_MEP_LIBRARY set. */ 792214571Sdim if (old_flags & EF_MEP_LIBRARY) 793214571Sdim old_flags = new_flags; 794214571Sdim } 795214571Sdim else 796214571Sdim { 797214571Sdim /* Make sure they're for the same mach. Allow upgrade from the "mep" 798214571Sdim mach. */ 799214571Sdim new_partial = (new_flags & EF_MEP_CPU_MASK); 800214571Sdim old_partial = (old_flags & EF_MEP_CPU_MASK); 801214571Sdim if (new_partial == old_partial) 802214571Sdim ; 803214571Sdim else if (new_partial == EF_MEP_CPU_MEP) 804214571Sdim ; 805214571Sdim else if (old_partial == EF_MEP_CPU_MEP) 806214571Sdim old_flags = (old_flags & ~EF_MEP_CPU_MASK) | new_partial; 807214571Sdim else 808214571Sdim { 809214571Sdim _bfd_error_handler (_("%B and %B are for different cores"), last_ibfd, ibfd); 810214571Sdim bfd_set_error (bfd_error_invalid_target); 811214571Sdim return FALSE; 812214571Sdim } 813214571Sdim 814214571Sdim /* Make sure they're for the same me_module. Allow basic config to 815214571Sdim mix with any other. */ 816214571Sdim new_partial = (new_flags & EF_MEP_INDEX_MASK); 817214571Sdim old_partial = (old_flags & EF_MEP_INDEX_MASK); 818214571Sdim if (new_partial == old_partial) 819214571Sdim ; 820214571Sdim else if (new_partial == 0) 821214571Sdim ; 822214571Sdim else if (old_partial == 0) 823214571Sdim old_flags = (old_flags & ~EF_MEP_INDEX_MASK) | new_partial; 824214571Sdim else 825214571Sdim { 826214571Sdim _bfd_error_handler (_("%B and %B are for different configurations"), last_ibfd, ibfd); 827214571Sdim bfd_set_error (bfd_error_invalid_target); 828214571Sdim return FALSE; 829214571Sdim } 830214571Sdim } 831214571Sdim 832214571Sdim elf_elfheader (obfd)->e_flags = old_flags; 833214571Sdim last_ibfd = ibfd; 834214571Sdim return TRUE; 835214571Sdim} 836214571Sdim 837214571Sdim/* This will be edited by the MeP configration tool. */ 838214571Sdimstatic const char * config_names[] = 839214571Sdim{ 840214571Sdim "basic" 841214571Sdim /* start-mepcfgtool */ 842214571Sdim ,"simple" 843214571Sdim ,"fmax" 844214571Sdim /* end-mepcfgtool */ 845214571Sdim}; 846214571Sdim 847214571Sdimstatic const char * core_names[] = 848214571Sdim{ 849214571Sdim "MeP", "MeP-c2", "MeP-c3", "MeP-h1" 850214571Sdim}; 851214571Sdim 852214571Sdimstatic bfd_boolean 853214571Sdimmep_elf_print_private_bfd_data (bfd * abfd, void * ptr) 854214571Sdim{ 855214571Sdim FILE * file = (FILE *) ptr; 856214571Sdim flagword flags, partial_flags; 857214571Sdim 858214571Sdim BFD_ASSERT (abfd != NULL && ptr != NULL); 859214571Sdim 860214571Sdim /* Print normal ELF private data. */ 861214571Sdim _bfd_elf_print_private_bfd_data (abfd, ptr); 862214571Sdim 863214571Sdim flags = elf_elfheader (abfd)->e_flags; 864214571Sdim fprintf (file, _("private flags = 0x%lx"), (long)flags); 865214571Sdim 866214571Sdim partial_flags = (flags & EF_MEP_CPU_MASK) >> 24; 867214571Sdim if (partial_flags < ARRAY_SIZE (core_names)) 868214571Sdim fprintf (file, " core: %s", core_names[(long)partial_flags]); 869214571Sdim 870214571Sdim partial_flags = flags & EF_MEP_INDEX_MASK; 871214571Sdim if (partial_flags < ARRAY_SIZE (config_names)) 872214571Sdim fprintf (file, " me_module: %s", config_names[(long)partial_flags]); 873214571Sdim 874214571Sdim fputc ('\n', file); 875214571Sdim 876214571Sdim return TRUE; 877214571Sdim} 878214571Sdim 879214571Sdim/* Return the machine subcode from the ELF e_flags header. */ 880214571Sdim 881214571Sdimstatic int 882214571Sdimelf32_mep_machine (bfd * abfd) 883214571Sdim{ 884214571Sdim switch (elf_elfheader (abfd)->e_flags & EF_MEP_CPU_MASK) 885214571Sdim { 886214571Sdim default: break; 887214571Sdim case EF_MEP_CPU_C2: return bfd_mach_mep; 888214571Sdim case EF_MEP_CPU_C3: return bfd_mach_mep; 889214571Sdim case EF_MEP_CPU_C4: return bfd_mach_mep; 890214571Sdim case EF_MEP_CPU_H1: return bfd_mach_mep_h1; 891214571Sdim } 892214571Sdim 893214571Sdim return bfd_mach_mep; 894214571Sdim} 895214571Sdim 896214571Sdimstatic bfd_boolean 897214571Sdimmep_elf_object_p (bfd * abfd) 898214571Sdim{ 899214571Sdim /* Irix 5 and 6 is broken. Object file symbol tables are not always 900214571Sdim sorted correctly such that local symbols preceed global symbols, 901214571Sdim and the sh_info field in the symbol table is not always right. */ 902214571Sdim /* This is needed for the RELC support code. */ 903214571Sdim elf_bad_symtab (abfd) = TRUE; 904214571Sdim bfd_default_set_arch_mach (abfd, bfd_arch_mep, elf32_mep_machine (abfd)); 905214571Sdim return TRUE; 906214571Sdim} 907214571Sdim 908214571Sdimstatic bfd_boolean 909214571Sdimmep_elf_section_flags (flagword * flags, const Elf_Internal_Shdr * hdr) 910214571Sdim{ 911214571Sdim if (hdr->sh_flags & SHF_MEP_VLIW) 912214571Sdim * flags |= SEC_MEP_VLIW; 913214571Sdim return TRUE; 914214571Sdim} 915214571Sdim 916214571Sdimstatic bfd_boolean 917214571Sdimmep_elf_fake_sections (bfd * abfd ATTRIBUTE_UNUSED, 918214571Sdim Elf_Internal_Shdr * hdr, 919214571Sdim asection * sec) 920214571Sdim{ 921214571Sdim if (sec->flags & SEC_MEP_VLIW) 922214571Sdim hdr->sh_flags |= SHF_MEP_VLIW; 923214571Sdim return TRUE; 924214571Sdim} 925214571Sdim 926214571Sdim 927214571Sdim#define ELF_ARCH bfd_arch_mep 928214571Sdim#define ELF_MACHINE_CODE EM_CYGNUS_MEP 929214571Sdim#define ELF_MAXPAGESIZE 0x1000 930214571Sdim 931214571Sdim#define TARGET_BIG_SYM bfd_elf32_mep_vec 932214571Sdim#define TARGET_BIG_NAME "elf32-mep" 933214571Sdim 934214571Sdim#define TARGET_LITTLE_SYM bfd_elf32_mep_little_vec 935214571Sdim#define TARGET_LITTLE_NAME "elf32-mep-little" 936214571Sdim 937214571Sdim#define elf_info_to_howto_rel NULL 938214571Sdim#define elf_info_to_howto mep_info_to_howto_rela 939214571Sdim#define elf_backend_relocate_section mep_elf_relocate_section 940214571Sdim#define elf_backend_gc_mark_hook mep_elf_gc_mark_hook 941214571Sdim#define elf_backend_gc_sweep_hook mep_elf_gc_sweep_hook 942214571Sdim#define elf_backend_check_relocs mep_elf_check_relocs 943214571Sdim#define elf_backend_object_p mep_elf_object_p 944214571Sdim#define elf_backend_section_flags mep_elf_section_flags 945214571Sdim#define elf_backend_fake_sections mep_elf_fake_sections 946214571Sdim 947214571Sdim#define elf_backend_can_gc_sections 1 948214571Sdim 949214571Sdim#define bfd_elf32_bfd_reloc_type_lookup mep_reloc_type_lookup 950214571Sdim#define bfd_elf32_bfd_reloc_name_lookup mep_reloc_name_lookup 951214571Sdim#define bfd_elf32_bfd_set_private_flags mep_elf_set_private_flags 952214571Sdim#define bfd_elf32_bfd_copy_private_bfd_data mep_elf_copy_private_bfd_data 953214571Sdim#define bfd_elf32_bfd_merge_private_bfd_data mep_elf_merge_private_bfd_data 954214571Sdim#define bfd_elf32_bfd_print_private_bfd_data mep_elf_print_private_bfd_data 955214571Sdim 956214571Sdim/* We use only the RELA entries. */ 957214571Sdim#define USE_RELA 958214571Sdim 959214571Sdim#include "elf32-target.h" 960