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