1 /* picoJava specific support for 32-bit ELF 2 Copyright (C) 1999-2016 Free Software Foundation, Inc. 3 Contributed by Steve Chamberlan of Transmeta (sac (at) pobox.com). 4 5 This file is part of BFD, the Binary File Descriptor library. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22 #include "sysdep.h" 23 #include "bfd.h" 24 #include "bfdlink.h" 25 #include "libbfd.h" 26 #include "elf-bfd.h" 27 #include "elf/pj.h" 28 29 /* This function is used for normal relocs. This is like the COFF 30 function, and is almost certainly incorrect for other ELF targets. */ 31 32 static bfd_reloc_status_type 33 pj_elf_reloc (bfd *abfd, 34 arelent *reloc_entry, 35 asymbol *symbol_in, 36 void * data, 37 asection *input_section, 38 bfd *output_bfd, 39 char **error_message ATTRIBUTE_UNUSED) 40 { 41 unsigned long insn; 42 bfd_vma sym_value; 43 enum elf_pj_reloc_type r_type; 44 bfd_vma addr = reloc_entry->address; 45 bfd_byte *hit_data = addr + (bfd_byte *) data; 46 47 r_type = (enum elf_pj_reloc_type) reloc_entry->howto->type; 48 49 if (output_bfd != NULL) 50 { 51 /* Partial linking--do nothing. */ 52 reloc_entry->address += input_section->output_offset; 53 return bfd_reloc_ok; 54 } 55 56 if (symbol_in != NULL 57 && bfd_is_und_section (symbol_in->section)) 58 return bfd_reloc_undefined; 59 60 if (bfd_is_com_section (symbol_in->section)) 61 sym_value = 0; 62 else 63 sym_value = (symbol_in->value + 64 symbol_in->section->output_section->vma + 65 symbol_in->section->output_offset); 66 67 switch (r_type) 68 { 69 case R_PJ_DATA_DIR32: 70 insn = bfd_get_32 (abfd, hit_data); 71 insn += sym_value + reloc_entry->addend; 72 bfd_put_32 (abfd, (bfd_vma) insn, hit_data); 73 break; 74 75 /* Relocations in code are always bigendian, no matter what the 76 data endianness is. */ 77 78 case R_PJ_CODE_DIR32: 79 insn = bfd_getb32 (hit_data); 80 insn += sym_value + reloc_entry->addend; 81 bfd_putb32 ((bfd_vma) insn, hit_data); 82 break; 83 84 case R_PJ_CODE_REL16: 85 insn = bfd_getb16 (hit_data); 86 insn += sym_value + reloc_entry->addend 87 - (input_section->output_section->vma 88 + input_section->output_offset); 89 bfd_putb16 ((bfd_vma) insn, hit_data); 90 break; 91 case R_PJ_CODE_LO16: 92 insn = bfd_getb16 (hit_data); 93 insn += sym_value + reloc_entry->addend; 94 bfd_putb16 ((bfd_vma) insn, hit_data); 95 break; 96 97 case R_PJ_CODE_HI16: 98 insn = bfd_getb16 (hit_data); 99 insn += (sym_value + reloc_entry->addend) >> 16; 100 bfd_putb16 ((bfd_vma) insn, hit_data); 101 break; 102 103 default: 104 abort (); 105 break; 106 } 107 108 return bfd_reloc_ok; 109 } 110 111 static reloc_howto_type pj_elf_howto_table[] = 112 { 113 /* No relocation. */ 114 HOWTO (R_PJ_NONE, /* type */ 115 0, /* rightshift */ 116 3, /* size (0 = byte, 1 = short, 2 = long) */ 117 0, /* bitsize */ 118 FALSE, /* pc_relative */ 119 0, /* bitpos */ 120 complain_overflow_dont, /* complain_on_overflow */ 121 pj_elf_reloc, /* special_function */ 122 "R_PJ_NONE", /* name */ 123 FALSE, /* partial_inplace */ 124 0, /* src_mask */ 125 0, /* dst_mask */ 126 FALSE), /* pcrel_offset */ 127 128 /* 32 bit absolute relocation. Setting partial_inplace to TRUE and 129 src_mask to a non-zero value is similar to the COFF toolchain. */ 130 HOWTO (R_PJ_DATA_DIR32, /* type */ 131 0, /* rightshift */ 132 2, /* size (0 = byte, 1 = short, 2 = long) */ 133 32, /* bitsize */ 134 FALSE, /* pc_relative */ 135 0, /* bitpos */ 136 complain_overflow_bitfield, /* complain_on_overflow */ 137 pj_elf_reloc, /* special_function */ 138 "R_PJ_DIR32", /* name */ 139 TRUE, /* partial_inplace */ 140 0xffffffff, /* src_mask */ 141 0xffffffff, /* dst_mask */ 142 FALSE), /* pcrel_offset */ 143 144 /* 32 bit PC relative relocation. */ 145 HOWTO (R_PJ_CODE_REL32, /* type */ 146 0, /* rightshift */ 147 2, /* size (0 = byte, 1 = short, 2 = long) */ 148 32, /* bitsize */ 149 TRUE, /* pc_relative */ 150 0, /* bitpos */ 151 complain_overflow_signed, /* complain_on_overflow */ 152 pj_elf_reloc, /* special_function */ 153 "R_PJ_REL32", /* name */ 154 FALSE, /* partial_inplace */ 155 0, /* src_mask */ 156 0xffffffff, /* dst_mask */ 157 TRUE), /* pcrel_offset */ 158 159 /* 16 bit PC relative relocation. */ 160 HOWTO (R_PJ_CODE_REL16, /* type */ 161 0, /* rightshift */ 162 1, /* size (0 = byte, 1 = short, 2 = long) */ 163 16, /* bitsize */ 164 TRUE, /* pc_relative */ 165 0, /* bitpos */ 166 complain_overflow_signed, /* complain_on_overf6w */ 167 pj_elf_reloc, /* special_function */ 168 "R_PJ_REL16", /* name */ 169 FALSE, /* partial_inplace */ 170 0xffff, /* src_mask */ 171 0xffff, /* dst_mask */ 172 TRUE), /* pcrel_offset */ 173 EMPTY_HOWTO (4), 174 EMPTY_HOWTO (5), 175 HOWTO (R_PJ_CODE_DIR32, /* type */ 176 0, /* rightshift */ 177 2, /* size (0 = byte, 1 = short, 2 = long) */ 178 32, /* bitsize */ 179 FALSE, /* pc_relative */ 180 0, /* bitpos */ 181 complain_overflow_bitfield, /* complain_on_overflow */ 182 pj_elf_reloc, /* special_function */ 183 "R_PJ_CODE_DIR32", /* name */ 184 TRUE, /* partial_inplace */ 185 0xffffffff, /* src_mask */ 186 0xffffffff, /* dst_mask */ 187 FALSE), /* pcrel_offset */ 188 189 EMPTY_HOWTO (7), 190 EMPTY_HOWTO (8), 191 EMPTY_HOWTO (9), 192 EMPTY_HOWTO (10), 193 EMPTY_HOWTO (11), 194 EMPTY_HOWTO (12), 195 196 HOWTO (R_PJ_CODE_LO16, /* type */ 197 0, /* rightshift */ 198 1, /* size (0 = byte, 1 = short, 2 = long) */ 199 16, /* bitsize */ 200 FALSE, /* pc_relative */ 201 0, /* bitpos */ 202 complain_overflow_unsigned, /* complain_on_overflow */ 203 pj_elf_reloc, /* special_function */ 204 "R_PJ_LO16", /* name */ 205 FALSE, /* partial_inplace */ 206 0xffff, /* src_mask */ 207 0xffff, /* dst_mask */ 208 TRUE), /* pcrel_offset */ 209 210 HOWTO (R_PJ_CODE_HI16, /* type */ 211 16, /* rightshift */ 212 1, /* size (0 = byte, 1 = short, 2 = long) */ 213 16, /* bitsize */ 214 FALSE, /* pc_relative */ 215 0, /* bitpos */ 216 complain_overflow_unsigned, /* complain_on_overflow */ 217 pj_elf_reloc, /* special_function */ 218 "R_PJ_HI16", /* name */ 219 FALSE, /* partial_inplace */ 220 0xffff, /* src_mask */ 221 0xffff, /* dst_mask */ 222 TRUE), /* pcrel_offset */ 223 224 /* GNU extension to record C++ vtable hierarchy. */ 225 HOWTO (R_PJ_GNU_VTINHERIT, /* type */ 226 0, /* rightshift */ 227 2, /* size (0 = byte, 1 = short, 2 = long) */ 228 0, /* bitsize */ 229 FALSE, /* pc_relative */ 230 0, /* bitpos */ 231 complain_overflow_dont, /* complain_on_overflow */ 232 NULL, /* special_function */ 233 "R_PJ_GNU_VTINHERIT", /* name */ 234 FALSE, /* partial_inplace */ 235 0, /* src_mask */ 236 0, /* dst_mask */ 237 FALSE), /* pcrel_offset */ 238 239 /* GNU extension to record C++ vtable member usage. */ 240 HOWTO (R_PJ_GNU_VTENTRY, /* type */ 241 0, /* rightshift */ 242 2, /* size (0 = byte, 1 = short, 2 = long) */ 243 0, /* bitsize */ 244 FALSE, /* pc_relative */ 245 0, /* bitpos */ 246 complain_overflow_dont, /* complain_on_overflow */ 247 _bfd_elf_rel_vtable_reloc_fn, /* special_function */ 248 "R_PJ_GNU_VTENTRY", /* name */ 249 FALSE, /* partial_inplace */ 250 0, /* src_mask */ 251 0, /* dst_mask */ 252 FALSE), /* pcrel_offset */ 253 }; 254 255 /* This structure is used to map BFD reloc codes to PJ ELF relocs. */ 256 257 struct elf_reloc_map 258 { 259 bfd_reloc_code_real_type bfd_reloc_val; 260 unsigned char elf_reloc_val; 261 }; 262 263 /* An array mapping BFD reloc codes to PJ ELF relocs. */ 264 265 static const struct elf_reloc_map pj_reloc_map[] = 266 { 267 { BFD_RELOC_NONE, R_PJ_NONE }, 268 { BFD_RELOC_32, R_PJ_DATA_DIR32 }, 269 { BFD_RELOC_PJ_CODE_DIR16, R_PJ_CODE_DIR16 }, 270 { BFD_RELOC_PJ_CODE_DIR32, R_PJ_CODE_DIR32 }, 271 { BFD_RELOC_PJ_CODE_LO16, R_PJ_CODE_LO16 }, 272 { BFD_RELOC_PJ_CODE_HI16, R_PJ_CODE_HI16 }, 273 { BFD_RELOC_PJ_CODE_REL32, R_PJ_CODE_REL32 }, 274 { BFD_RELOC_PJ_CODE_REL16, R_PJ_CODE_REL16 }, 275 { BFD_RELOC_VTABLE_INHERIT, R_PJ_GNU_VTINHERIT }, 276 { BFD_RELOC_VTABLE_ENTRY, R_PJ_GNU_VTENTRY }, 277 }; 278 279 /* Given a BFD reloc code, return the howto structure for the 280 corresponding PJ ELf reloc. */ 281 282 static reloc_howto_type * 283 pj_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 284 bfd_reloc_code_real_type code) 285 { 286 unsigned int i; 287 288 for (i = 0; i < sizeof (pj_reloc_map) / sizeof (struct elf_reloc_map); i++) 289 if (pj_reloc_map[i].bfd_reloc_val == code) 290 return & pj_elf_howto_table[(int) pj_reloc_map[i].elf_reloc_val]; 291 292 return NULL; 293 } 294 295 static reloc_howto_type * 296 pj_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 297 const char *r_name) 298 { 299 unsigned int i; 300 301 for (i = 0; 302 i < sizeof (pj_elf_howto_table) / sizeof (pj_elf_howto_table[0]); 303 i++) 304 if (pj_elf_howto_table[i].name != NULL 305 && strcasecmp (pj_elf_howto_table[i].name, r_name) == 0) 306 return &pj_elf_howto_table[i]; 307 308 return NULL; 309 } 310 311 /* Given an ELF reloc, fill in the howto field of a relent. */ 312 313 static void 314 pj_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, 315 arelent *cache_ptr, 316 Elf_Internal_Rela *dst) 317 { 318 unsigned int r; 319 320 r = ELF32_R_TYPE (dst->r_info); 321 322 if (r >= R_PJ_max) 323 { 324 (*_bfd_error_handler) (_("%B: unrecognised PicoJava reloc number: %d"), 325 abfd, r); 326 bfd_set_error (bfd_error_bad_value); 327 r = R_PJ_NONE; 328 } 329 330 cache_ptr->howto = &pj_elf_howto_table[r]; 331 } 332 333 /* Take this moment to fill in the special picoJava bits in the 334 e_flags field. */ 335 336 static void 337 pj_elf_final_write_processing (bfd *abfd, 338 bfd_boolean linker ATTRIBUTE_UNUSED) 339 { 340 elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_ARCH; 341 elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_GNUCALLS; 342 } 343 344 #define TARGET_BIG_SYM pj_elf32_vec 345 #define TARGET_BIG_NAME "elf32-pj" 346 #define TARGET_LITTLE_SYM pj_elf32_le_vec 347 #define TARGET_LITTLE_NAME "elf32-pjl" 348 #define ELF_ARCH bfd_arch_pj 349 #define ELF_MACHINE_CODE EM_PJ 350 #define ELF_MACHINE_ALT1 EM_PJ_OLD 351 #define ELF_MAXPAGESIZE 0x1000 352 #define bfd_elf32_bfd_get_relocated_section_contents \ 353 bfd_generic_get_relocated_section_contents 354 #define bfd_elf32_bfd_reloc_type_lookup pj_elf_reloc_type_lookup 355 #define bfd_elf32_bfd_reloc_name_lookup pj_elf_reloc_name_lookup 356 #define elf_backend_final_write_processing pj_elf_final_write_processing 357 #define elf_info_to_howto pj_elf_info_to_howto 358 #include "elf32-target.h" 359