1 /* BFD backend for MIPS BSD (a.out) binaries. 2 Copyright 1993, 1994, 1995, 1997, 1998, 1999, 2000 3 Free Software Foundation, Inc. 4 Written by Ralph Campbell. 5 6 This file is part of BFD, the Binary File Descriptor library. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 21 22 #define BYTES_IN_WORD 4 23 /* #define ENTRY_CAN_BE_ZERO */ 24 #define N_HEADER_IN_TEXT(x) 1 25 #define N_SHARED_LIB(x) 0 26 #define N_TXTADDR(x) \ 27 (N_MAGIC(x) != ZMAGIC ? (x).a_entry : /* object file or NMAGIC */\ 28 TEXT_START_ADDR + EXEC_BYTES_SIZE /* no padding */\ 29 ) 30 #define N_DATADDR(x) (N_TXTADDR(x)+N_TXTSIZE(x)) 31 #define TEXT_START_ADDR 4096 32 #define TARGET_PAGE_SIZE 4096 33 #define SEGMENT_SIZE TARGET_PAGE_SIZE 34 #define DEFAULT_ARCH bfd_arch_mips 35 #define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \ 36 || (mtype) == M_MIPS1 || (mtype) == M_MIPS2) 37 #define MY_symbol_leading_char '\0' 38 39 #define MY(OP) CAT(mipsbsd_,OP) 40 41 #include "bfd.h" 42 #include "sysdep.h" 43 #include "libbfd.h" 44 #include "libaout.h" 45 46 #define SET_ARCH_MACH(ABFD, EXEC) \ 47 MY(set_arch_mach) (ABFD, N_MACHTYPE (EXEC)); \ 48 MY(choose_reloc_size) (ABFD); 49 static void MY(set_arch_mach) PARAMS ((bfd *abfd, int machtype)); 50 static void MY(choose_reloc_size) PARAMS ((bfd *abfd)); 51 52 #define MY_write_object_contents MY(write_object_contents) 53 static boolean MY(write_object_contents) PARAMS ((bfd *abfd)); 54 55 /* We can't use MY(x) here because it leads to a recursive call to CAT 56 when expanded inside JUMP_TABLE. */ 57 #define MY_bfd_reloc_type_lookup mipsbsd_reloc_howto_type_lookup 58 #define MY_canonicalize_reloc mipsbsd_canonicalize_reloc 59 60 #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create 61 #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols 62 #define MY_final_link_callback unused 63 #define MY_bfd_final_link _bfd_generic_final_link 64 65 #define MY_backend_data &MY(backend_data) 66 #define MY_BFD_TARGET 67 68 #include "aout-target.h" 69 70 static void 71 MY(set_arch_mach) (abfd, machtype) 72 bfd *abfd; 73 int machtype; 74 { 75 enum bfd_architecture arch; 76 long machine; 77 78 /* Determine the architecture and machine type of the object file. */ 79 switch (machtype) { 80 81 case M_MIPS1: 82 arch = bfd_arch_mips; 83 machine = 3000; 84 break; 85 86 case M_MIPS2: 87 arch = bfd_arch_mips; 88 machine = 4000; 89 break; 90 91 default: 92 arch = bfd_arch_obscure; 93 machine = 0; 94 break; 95 } 96 bfd_set_arch_mach(abfd, arch, machine); 97 } 98 99 /* Determine the size of a relocation entry, based on the architecture */ 100 static void 101 MY(choose_reloc_size) (abfd) 102 bfd *abfd; 103 { 104 switch (bfd_get_arch(abfd)) { 105 case bfd_arch_sparc: 106 case bfd_arch_a29k: 107 case bfd_arch_mips: 108 obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; 109 break; 110 default: 111 obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; 112 break; 113 } 114 } 115 116 /* Write an object file in BSD a.out format. 117 Section contents have already been written. We write the 118 file header, symbols, and relocation. */ 119 120 static boolean 121 MY(write_object_contents) (abfd) 122 bfd *abfd; 123 { 124 struct external_exec exec_bytes; 125 struct internal_exec *execp = exec_hdr (abfd); 126 127 /* Magic number, maestro, please! */ 128 switch (bfd_get_arch(abfd)) { 129 case bfd_arch_m68k: 130 switch (bfd_get_mach(abfd)) { 131 case bfd_mach_m68010: 132 N_SET_MACHTYPE(*execp, M_68010); 133 break; 134 default: 135 case bfd_mach_m68020: 136 N_SET_MACHTYPE(*execp, M_68020); 137 break; 138 } 139 break; 140 case bfd_arch_sparc: 141 N_SET_MACHTYPE(*execp, M_SPARC); 142 break; 143 case bfd_arch_i386: 144 N_SET_MACHTYPE(*execp, M_386); 145 break; 146 case bfd_arch_a29k: 147 N_SET_MACHTYPE(*execp, M_29K); 148 break; 149 case bfd_arch_mips: 150 switch (bfd_get_mach(abfd)) { 151 case 4000: 152 case 6000: 153 N_SET_MACHTYPE(*execp, M_MIPS2); 154 break; 155 default: 156 N_SET_MACHTYPE(*execp, M_MIPS1); 157 break; 158 } 159 break; 160 default: 161 N_SET_MACHTYPE(*execp, M_UNKNOWN); 162 } 163 164 MY(choose_reloc_size) (abfd); 165 166 WRITE_HEADERS(abfd, execp); 167 168 return true; 169 } 170 171 /* 172 * MIPS relocation types. 173 */ 174 #define MIPS_RELOC_32 0 175 #define MIPS_RELOC_JMP 1 176 #define MIPS_RELOC_WDISP16 2 177 #define MIPS_RELOC_HI16 3 178 #define MIPS_RELOC_HI16_S 4 179 #define MIPS_RELOC_LO16 5 180 181 /* 182 * This is only called when performing a BFD_RELOC_MIPS_JMP relocation. 183 * The jump destination address is formed from the upper 4 bits of the 184 * "current" program counter concatenated with the jump instruction's 185 * 26 bit field and two trailing zeros. 186 * If the destination address is not in the same segment as the "current" 187 * program counter, then we need to signal an error. 188 */ 189 static bfd_reloc_status_type 190 mips_fix_jmp_addr (abfd,reloc_entry,symbol,data,input_section,output_bfd) 191 bfd *abfd ATTRIBUTE_UNUSED; 192 arelent *reloc_entry; 193 struct symbol_cache_entry *symbol; 194 PTR data ATTRIBUTE_UNUSED; 195 asection *input_section; 196 bfd *output_bfd; 197 { 198 bfd_vma relocation, pc; 199 200 /* If this is a partial relocation, just continue. */ 201 if (output_bfd != (bfd *)NULL) 202 return bfd_reloc_continue; 203 204 /* If this is an undefined symbol, return error */ 205 if (bfd_is_und_section (symbol->section) 206 && (symbol->flags & BSF_WEAK) == 0) 207 return bfd_reloc_undefined; 208 209 /* 210 * Work out which section the relocation is targetted at and the 211 * initial relocation command value. 212 */ 213 if (bfd_is_com_section (symbol->section)) 214 relocation = 0; 215 else 216 relocation = symbol->value; 217 218 relocation += symbol->section->output_section->vma; 219 relocation += symbol->section->output_offset; 220 relocation += reloc_entry->addend; 221 222 pc = input_section->output_section->vma + input_section->output_offset + 223 reloc_entry->address + 4; 224 225 if ((relocation & 0xF0000000) != (pc & 0xF0000000)) 226 return bfd_reloc_overflow; 227 228 return bfd_reloc_continue; 229 } 230 231 /* 232 * This is only called when performing a BFD_RELOC_HI16_S relocation. 233 * We need to see if bit 15 is set in the result. If it is, we add 234 * 0x10000 and continue normally. This will compensate for the sign extension 235 * when the low bits are added at run time. 236 */ 237 static bfd_reloc_status_type 238 mips_fix_hi16_s PARAMS ((bfd *, arelent *, asymbol *, PTR, 239 asection *, bfd *, char **)); 240 241 static bfd_reloc_status_type 242 mips_fix_hi16_s (abfd, reloc_entry, symbol, data, input_section, 243 output_bfd, error_message) 244 bfd *abfd ATTRIBUTE_UNUSED; 245 arelent *reloc_entry; 246 asymbol *symbol; 247 PTR data ATTRIBUTE_UNUSED; 248 asection *input_section ATTRIBUTE_UNUSED; 249 bfd *output_bfd; 250 char **error_message ATTRIBUTE_UNUSED; 251 { 252 bfd_vma relocation; 253 254 /* If this is a partial relocation, just continue. */ 255 if (output_bfd != (bfd *)NULL) 256 return bfd_reloc_continue; 257 258 /* If this is an undefined symbol, return error */ 259 if (bfd_is_und_section (symbol->section) 260 && (symbol->flags & BSF_WEAK) == 0) 261 return bfd_reloc_undefined; 262 263 /* 264 * Work out which section the relocation is targetted at and the 265 * initial relocation command value. 266 */ 267 if (bfd_is_com_section (symbol->section)) 268 relocation = 0; 269 else 270 relocation = symbol->value; 271 272 relocation += symbol->section->output_section->vma; 273 relocation += symbol->section->output_offset; 274 relocation += reloc_entry->addend; 275 276 if (relocation & 0x8000) 277 reloc_entry->addend += 0x10000; 278 279 return bfd_reloc_continue; 280 } 281 282 static reloc_howto_type mips_howto_table_ext[] = { 283 {MIPS_RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, 284 "32", false, 0, 0xffffffff, false}, 285 {MIPS_RELOC_JMP, 2, 2, 26, false, 0, complain_overflow_dont, 286 mips_fix_jmp_addr, 287 "MIPS_JMP", false, 0, 0x03ffffff, false}, 288 {MIPS_RELOC_WDISP16, 2, 2, 16, true, 0, complain_overflow_signed, 0, 289 "WDISP16", false, 0, 0x0000ffff, false}, 290 {MIPS_RELOC_HI16, 16, 2, 16, false, 0, complain_overflow_bitfield, 0, 291 "HI16", false, 0, 0x0000ffff, false}, 292 {MIPS_RELOC_HI16_S, 16, 2, 16, false, 0, complain_overflow_bitfield, 293 mips_fix_hi16_s, 294 "HI16_S", false, 0, 0x0000ffff, false}, 295 {MIPS_RELOC_LO16, 0, 2, 16, false, 0, complain_overflow_dont, 0, 296 "LO16", false, 0, 0x0000ffff, false}, 297 }; 298 299 static reloc_howto_type * 300 MY(reloc_howto_type_lookup) (abfd, code) 301 bfd *abfd; 302 bfd_reloc_code_real_type code; 303 { 304 305 if (bfd_get_arch (abfd) != bfd_arch_mips) 306 return 0; 307 308 switch (code) 309 { 310 case BFD_RELOC_CTOR: 311 case BFD_RELOC_32: 312 return (&mips_howto_table_ext[MIPS_RELOC_32]); 313 case BFD_RELOC_MIPS_JMP: 314 return (&mips_howto_table_ext[MIPS_RELOC_JMP]); 315 case BFD_RELOC_16_PCREL_S2: 316 return (&mips_howto_table_ext[MIPS_RELOC_WDISP16]); 317 case BFD_RELOC_HI16: 318 return (&mips_howto_table_ext[MIPS_RELOC_HI16]); 319 case BFD_RELOC_HI16_S: 320 return (&mips_howto_table_ext[MIPS_RELOC_HI16_S]); 321 case BFD_RELOC_LO16: 322 return (&mips_howto_table_ext[MIPS_RELOC_LO16]); 323 default: 324 return 0; 325 } 326 } 327 328 /* 329 * This is just like the standard aoutx.h version but we need to do our 330 * own mapping of external reloc type values to howto entries. 331 */ 332 long 333 MY(canonicalize_reloc) (abfd, section, relptr, symbols) 334 bfd *abfd; 335 sec_ptr section; 336 arelent **relptr; 337 asymbol **symbols; 338 { 339 arelent *tblptr = section->relocation; 340 unsigned int count, c; 341 extern reloc_howto_type NAME(aout,ext_howto_table)[]; 342 343 /* If we have already read in the relocation table, return the values. */ 344 if (section->flags & SEC_CONSTRUCTOR) { 345 arelent_chain *chain = section->constructor_chain; 346 347 for (count = 0; count < section->reloc_count; count++) { 348 *relptr++ = &chain->relent; 349 chain = chain->next; 350 } 351 *relptr = 0; 352 return section->reloc_count; 353 } 354 if (tblptr && section->reloc_count) { 355 for (count = 0; count++ < section->reloc_count;) 356 *relptr++ = tblptr++; 357 *relptr = 0; 358 return section->reloc_count; 359 } 360 361 if (!NAME(aout,slurp_reloc_table) (abfd, section, symbols)) 362 return -1; 363 tblptr = section->relocation; 364 365 /* fix up howto entries */ 366 for (count = 0; count++ < section->reloc_count;) 367 { 368 c = tblptr->howto - NAME(aout,ext_howto_table); 369 tblptr->howto = &mips_howto_table_ext[c]; 370 371 *relptr++ = tblptr++; 372 } 373 *relptr = 0; 374 return section->reloc_count; 375 } 376 377 static CONST struct aout_backend_data MY(backend_data) = { 378 0, /* zmagic contiguous */ 379 1, /* text incl header */ 380 0, /* entry is text address */ 381 0, /* exec_hdr_flags */ 382 TARGET_PAGE_SIZE, /* text vma */ 383 MY_set_sizes, 384 0, /* text size includes exec header */ 385 0, /* add_dynamic_symbols */ 386 0, /* add_one_symbol */ 387 0, /* link_dynamic_object */ 388 0, /* write_dynamic_symbol */ 389 0, /* check_dynamic_reloc */ 390 0 /* finish_dynamic_link */ 391 }; 392 393 extern const bfd_target aout_mips_big_vec; 394 395 const bfd_target aout_mips_little_vec = 396 { 397 "a.out-mips-little", /* name */ 398 bfd_target_aout_flavour, 399 BFD_ENDIAN_LITTLE, /* target byte order (little) */ 400 BFD_ENDIAN_LITTLE, /* target headers byte order (little) */ 401 (HAS_RELOC | EXEC_P | /* object flags */ 402 HAS_LINENO | HAS_DEBUG | 403 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 404 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 405 MY_symbol_leading_char, 406 ' ', /* ar_pad_char */ 407 15, /* ar_max_namelen */ 408 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 409 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 410 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 411 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 412 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 413 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ 414 {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ 415 bfd_generic_archive_p, MY_core_file_p}, 416 {bfd_false, MY_mkobject, /* bfd_set_format */ 417 _bfd_generic_mkarchive, bfd_false}, 418 {bfd_false, MY_write_object_contents, /* bfd_write_contents */ 419 _bfd_write_archive_contents, bfd_false}, 420 421 BFD_JUMP_TABLE_GENERIC (MY), 422 BFD_JUMP_TABLE_COPY (MY), 423 BFD_JUMP_TABLE_CORE (MY), 424 BFD_JUMP_TABLE_ARCHIVE (MY), 425 BFD_JUMP_TABLE_SYMBOLS (MY), 426 BFD_JUMP_TABLE_RELOCS (MY), 427 BFD_JUMP_TABLE_WRITE (MY), 428 BFD_JUMP_TABLE_LINK (MY), 429 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 430 431 & aout_mips_big_vec, 432 433 (PTR) MY_backend_data 434 }; 435 436 const bfd_target aout_mips_big_vec = 437 { 438 "a.out-mips-big", /* name */ 439 bfd_target_aout_flavour, 440 BFD_ENDIAN_BIG, /* target byte order (big) */ 441 BFD_ENDIAN_BIG, /* target headers byte order (big) */ 442 (HAS_RELOC | EXEC_P | /* object flags */ 443 HAS_LINENO | HAS_DEBUG | 444 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 445 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 446 MY_symbol_leading_char, 447 ' ', /* ar_pad_char */ 448 15, /* ar_max_namelen */ 449 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 450 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 451 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ 452 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 453 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 454 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ 455 {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ 456 bfd_generic_archive_p, MY_core_file_p}, 457 {bfd_false, MY_mkobject, /* bfd_set_format */ 458 _bfd_generic_mkarchive, bfd_false}, 459 {bfd_false, MY_write_object_contents, /* bfd_write_contents */ 460 _bfd_write_archive_contents, bfd_false}, 461 462 BFD_JUMP_TABLE_GENERIC (MY), 463 BFD_JUMP_TABLE_COPY (MY), 464 BFD_JUMP_TABLE_CORE (MY), 465 BFD_JUMP_TABLE_ARCHIVE (MY), 466 BFD_JUMP_TABLE_SYMBOLS (MY), 467 BFD_JUMP_TABLE_RELOCS (MY), 468 BFD_JUMP_TABLE_WRITE (MY), 469 BFD_JUMP_TABLE_LINK (MY), 470 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 471 472 & aout_mips_little_vec, 473 474 (PTR) MY_backend_data 475 }; 476