00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define A29K 1
00028
00029 #include "bfd.h"
00030 #include "sysdep.h"
00031 #include "libbfd.h"
00032 #include "coff/a29k.h"
00033 #include "coff/internal.h"
00034 #include "libcoff.h"
00035
00036 static long get_symbol_value PARAMS ((asymbol *));
00037 static bfd_reloc_status_type a29k_reloc
00038 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
00039 static bfd_boolean coff_a29k_relocate_section
00040 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
00041 struct internal_reloc *, struct internal_syment *, asection **));
00042 static bfd_boolean coff_a29k_adjust_symndx
00043 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
00044 struct internal_reloc *, bfd_boolean *));
00045 static void reloc_processing
00046 PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
00047
00048 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
00049
00050 #define INSERT_HWORD(WORD,HWORD) \
00051 (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
00052 #define EXTRACT_HWORD(WORD) \
00053 ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
00054 #define SIGN_EXTEND_HWORD(HWORD) \
00055 (((HWORD) ^ 0x8000) - 0x8000)
00056
00057
00058
00059 static long
00060 get_symbol_value (symbol)
00061 asymbol *symbol;
00062 {
00063 long relocation = 0;
00064
00065 if (bfd_is_com_section (symbol->section))
00066 relocation = 0;
00067 else
00068 relocation = symbol->value +
00069 symbol->section->output_section->vma +
00070 symbol->section->output_offset;
00071
00072 return relocation;
00073 }
00074
00075
00076
00077 static bfd_reloc_status_type
00078 a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
00079 error_message)
00080 bfd *abfd;
00081 arelent *reloc_entry;
00082 asymbol *symbol_in;
00083 PTR data;
00084 asection *input_section;
00085 bfd *output_bfd;
00086 char **error_message;
00087 {
00088
00089
00090 static bfd_boolean part1_consth_active = FALSE;
00091 static unsigned long part1_consth_value;
00092 unsigned long insn;
00093 unsigned long sym_value;
00094 unsigned long unsigned_value;
00095 unsigned short r_type;
00096 long signed_value;
00097 unsigned long addr = reloc_entry->address ;
00098 bfd_byte *hit_data =addr + (bfd_byte *) (data);
00099
00100 r_type = reloc_entry->howto->type;
00101
00102 if (output_bfd)
00103 {
00104
00105 reloc_entry->address += input_section->output_offset;
00106 return bfd_reloc_ok;
00107 }
00108
00109 if (symbol_in != NULL
00110 && bfd_is_und_section (symbol_in->section))
00111 {
00112
00113 if (r_type == R_IHIHALF)
00114 {
00115 part1_consth_active = TRUE;
00116 part1_consth_value = 0;
00117 }
00118 return bfd_reloc_undefined;
00119 }
00120
00121 if ((part1_consth_active) && (r_type != R_IHCONST))
00122 {
00123 part1_consth_active = FALSE;
00124 *error_message = (char *) _("Missing IHCONST");
00125
00126 return bfd_reloc_dangerous;
00127 }
00128
00129 sym_value = get_symbol_value(symbol_in);
00130
00131 switch (r_type)
00132 {
00133 case R_IREL:
00134 insn = bfd_get_32 (abfd, hit_data);
00135
00136 signed_value = EXTRACT_HWORD(insn);
00137 signed_value = SIGN_EXTEND_HWORD(signed_value);
00138 signed_value <<= 2;
00139
00140
00141 if (signed_value == - (long) reloc_entry->address)
00142 signed_value = 0;
00143
00144 signed_value += sym_value + reloc_entry->addend;
00145 if ((signed_value & ~0x3ffff) == 0)
00146 {
00147 insn |= (1 << 24);
00148
00149 }
00150 else
00151 {
00152
00153
00154 signed_value -= (reloc_entry->address
00155 + input_section->output_section->vma
00156 + input_section->output_offset);
00157 if (signed_value > 0x1ffff || signed_value < -0x20000)
00158 return bfd_reloc_overflow;
00159 }
00160 signed_value >>= 2;
00161 insn = INSERT_HWORD (insn, signed_value);
00162 bfd_put_32 (abfd, (bfd_vma) insn ,hit_data);
00163 break;
00164 case R_ILOHALF:
00165 insn = bfd_get_32 (abfd, hit_data);
00166 unsigned_value = EXTRACT_HWORD(insn);
00167 unsigned_value += sym_value + reloc_entry->addend;
00168 insn = INSERT_HWORD(insn, unsigned_value);
00169 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
00170 break;
00171 case R_IHIHALF:
00172 insn = bfd_get_32 (abfd, hit_data);
00173
00174
00175 part1_consth_active = TRUE;
00176 part1_consth_value = sym_value + reloc_entry->addend;
00177
00178 break;
00179 case R_IHCONST:
00180 insn = bfd_get_32 (abfd, hit_data);
00181
00182
00183 if (! part1_consth_active)
00184 {
00185 *error_message = (char *) _("Missing IHIHALF");
00186 return bfd_reloc_dangerous;
00187 }
00188
00189 unsigned_value = 0;
00190 unsigned_value += reloc_entry->addend;
00191 unsigned_value += part1_consth_value;
00192 unsigned_value = unsigned_value >> 16;
00193 insn = INSERT_HWORD(insn, unsigned_value);
00194 part1_consth_active = FALSE;
00195 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
00196 break;
00197 case R_BYTE:
00198 insn = bfd_get_8 (abfd, hit_data);
00199 unsigned_value = insn + sym_value + reloc_entry->addend;
00200 if (unsigned_value & 0xffffff00)
00201 return bfd_reloc_overflow;
00202 bfd_put_8 (abfd, unsigned_value, hit_data);
00203 break;
00204 case R_HWORD:
00205 insn = bfd_get_16 (abfd, hit_data);
00206 unsigned_value = insn + sym_value + reloc_entry->addend;
00207 if (unsigned_value & 0xffff0000)
00208 return bfd_reloc_overflow;
00209 bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
00210 break;
00211 case R_WORD:
00212 insn = bfd_get_32 (abfd, hit_data);
00213 insn += sym_value + reloc_entry->addend;
00214 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
00215 break;
00216 default:
00217 *error_message = _("Unrecognized reloc");
00218 return bfd_reloc_dangerous;
00219 }
00220
00221 return(bfd_reloc_ok);
00222 }
00223
00224
00225 static reloc_howto_type howto_table[] =
00226 {
00227 {R_ABS, 0, 3, 32, FALSE, 0, complain_overflow_bitfield,a29k_reloc,"ABS", TRUE, 0xffffffff,0xffffffff, FALSE},
00228 EMPTY_HOWTO (1),
00229 EMPTY_HOWTO (2),
00230 EMPTY_HOWTO (3),
00231 EMPTY_HOWTO (4),
00232 EMPTY_HOWTO (5),
00233 EMPTY_HOWTO (6),
00234 EMPTY_HOWTO (7),
00235 EMPTY_HOWTO (8),
00236 EMPTY_HOWTO (9),
00237 EMPTY_HOWTO (10),
00238 EMPTY_HOWTO (11),
00239 EMPTY_HOWTO (12),
00240 EMPTY_HOWTO (13),
00241 EMPTY_HOWTO (14),
00242 EMPTY_HOWTO (15),
00243 EMPTY_HOWTO (16),
00244 EMPTY_HOWTO (17),
00245 EMPTY_HOWTO (18),
00246 EMPTY_HOWTO (19),
00247 EMPTY_HOWTO (20),
00248 EMPTY_HOWTO (21),
00249 EMPTY_HOWTO (22),
00250 EMPTY_HOWTO (23),
00251 {R_IREL, 0, 3, 32, TRUE, 0, complain_overflow_signed,a29k_reloc,"IREL", TRUE, 0xffffffff,0xffffffff, FALSE},
00252 {R_IABS, 0, 3, 32, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"IABS", TRUE, 0xffffffff,0xffffffff, FALSE},
00253 {R_ILOHALF, 0, 3, 16, TRUE, 0, complain_overflow_signed, a29k_reloc,"ILOHALF", TRUE, 0x0000ffff,0x0000ffff, FALSE},
00254 {R_IHIHALF, 0, 3, 16, TRUE, 16, complain_overflow_signed, a29k_reloc,"IHIHALF", TRUE, 0xffff0000,0xffff0000, FALSE},
00255 {R_IHCONST, 0, 3, 16, TRUE, 0, complain_overflow_signed, a29k_reloc,"IHCONST", TRUE, 0xffff0000,0xffff0000, FALSE},
00256 {R_BYTE, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"BYTE", TRUE, 0x000000ff,0x000000ff, FALSE},
00257 {R_HWORD, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"HWORD", TRUE, 0x0000ffff,0x0000ffff, FALSE},
00258 {R_WORD, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"WORD", TRUE, 0xffffffff,0xffffffff, FALSE},
00259 };
00260
00261 #define BADMAG(x) A29KBADMAG(x)
00262
00263 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
00264 reloc_processing(relent, reloc, symbols, abfd, section)
00265
00266 static void
00267 reloc_processing (relent,reloc, symbols, abfd, section)
00268 arelent *relent;
00269 struct internal_reloc *reloc;
00270 asymbol **symbols;
00271 bfd *abfd;
00272 asection *section;
00273 {
00274 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
00275
00276 relent->address = reloc->r_vaddr;
00277 relent->howto = howto_table + reloc->r_type;
00278 if (reloc->r_type == R_IHCONST)
00279 {
00280
00281
00282
00283
00284
00285
00286 if (ihihalf_vaddr == (bfd_vma) -1)
00287 abort ();
00288 relent->address = ihihalf_vaddr;
00289 ihihalf_vaddr = (bfd_vma) -1;
00290 relent->addend = reloc->r_symndx;
00291 relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
00292 }
00293 else
00294 {
00295 asymbol *ptr;
00296
00297 relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
00298
00299 ptr = *(relent->sym_ptr_ptr);
00300
00301 if (ptr
00302 && bfd_asymbol_bfd(ptr) == abfd
00303 && ((ptr->flags & BSF_OLD_COMMON) == 0))
00304 relent->addend = 0;
00305 else
00306 relent->addend = 0;
00307
00308 relent->address-= section->vma;
00309 if (reloc->r_type == R_IHIHALF)
00310 ihihalf_vaddr = relent->address;
00311 else if (ihihalf_vaddr != (bfd_vma) -1)
00312 abort ();
00313 }
00314 }
00315
00316
00317
00318 static bfd_boolean
00319 coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
00320 contents, relocs, syms, sections)
00321 bfd *output_bfd ATTRIBUTE_UNUSED;
00322 struct bfd_link_info *info;
00323 bfd *input_bfd;
00324 asection *input_section;
00325 bfd_byte *contents;
00326 struct internal_reloc *relocs;
00327 struct internal_syment *syms;
00328 asection **sections;
00329 {
00330 struct internal_reloc *rel;
00331 struct internal_reloc *relend;
00332 bfd_boolean hihalf;
00333 bfd_vma hihalf_val;
00334
00335
00336
00337
00338 if (info->relocatable)
00339 return TRUE;
00340
00341 hihalf = FALSE;
00342 hihalf_val = 0;
00343
00344 rel = relocs;
00345 relend = rel + input_section->reloc_count;
00346 for (; rel < relend; rel++)
00347 {
00348 long symndx;
00349 bfd_byte *loc;
00350 struct coff_link_hash_entry *h;
00351 struct internal_syment *sym;
00352 asection *sec;
00353 bfd_vma val;
00354 bfd_boolean overflow;
00355 unsigned long insn;
00356 long signed_value;
00357 unsigned long unsigned_value;
00358 bfd_reloc_status_type rstat;
00359
00360 symndx = rel->r_symndx;
00361 loc = contents + rel->r_vaddr - input_section->vma;
00362
00363 if (symndx == -1 || rel->r_type == R_IHCONST)
00364 h = NULL;
00365 else
00366 h = obj_coff_sym_hashes (input_bfd)[symndx];
00367
00368 sym = NULL;
00369 sec = NULL;
00370 val = 0;
00371
00372
00373
00374
00375 if (rel->r_type != R_IHCONST)
00376 {
00377 if (h == NULL)
00378 {
00379 if (symndx == -1)
00380 sec = bfd_abs_section_ptr;
00381 else
00382 {
00383 sym = syms + symndx;
00384 sec = sections[symndx];
00385 val = (sec->output_section->vma
00386 + sec->output_offset
00387 + sym->n_value
00388 - sec->vma);
00389 }
00390 }
00391 else
00392 {
00393 if ( h->root.type == bfd_link_hash_defined
00394 || h->root.type == bfd_link_hash_defweak)
00395 {
00396 sec = h->root.u.def.section;
00397 val = (h->root.u.def.value
00398 + sec->output_section->vma
00399 + sec->output_offset);
00400 }
00401 else
00402 {
00403 if (! ((*info->callbacks->undefined_symbol)
00404 (info, h->root.root.string, input_bfd, input_section,
00405 rel->r_vaddr - input_section->vma, TRUE)))
00406 return FALSE;
00407 }
00408 }
00409
00410 if (hihalf)
00411 {
00412 if (! ((*info->callbacks->reloc_dangerous)
00413 (info, _("missing IHCONST reloc"), input_bfd,
00414 input_section, rel->r_vaddr - input_section->vma)))
00415 return FALSE;
00416 hihalf = FALSE;
00417 }
00418 }
00419
00420 overflow = FALSE;
00421
00422 switch (rel->r_type)
00423 {
00424 default:
00425 bfd_set_error (bfd_error_bad_value);
00426 return FALSE;
00427
00428 case R_IREL:
00429 insn = bfd_get_32 (input_bfd, loc);
00430
00431
00432 signed_value = EXTRACT_HWORD (insn);
00433 signed_value = SIGN_EXTEND_HWORD (signed_value);
00434 signed_value <<= 2;
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
00455 signed_value = 0;
00456
00457
00458 signed_value += val;
00459
00460 if ((signed_value & ~0x3ffff) == 0)
00461 {
00462
00463 insn |= (1 << 24);
00464 }
00465 else
00466 {
00467
00468 signed_value -= (input_section->output_section->vma
00469 + input_section->output_offset
00470 + (rel->r_vaddr - input_section->vma));
00471 if (signed_value > 0x1ffff || signed_value < - 0x20000)
00472 {
00473 overflow = TRUE;
00474 signed_value = 0;
00475 }
00476 }
00477
00478
00479 signed_value >>= 2;
00480 insn = INSERT_HWORD (insn, signed_value);
00481
00482 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
00483 break;
00484
00485 case R_ILOHALF:
00486 insn = bfd_get_32 (input_bfd, loc);
00487 unsigned_value = EXTRACT_HWORD (insn);
00488 unsigned_value += val;
00489 insn = INSERT_HWORD (insn, unsigned_value);
00490 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
00491 break;
00492
00493 case R_IHIHALF:
00494
00495 hihalf = TRUE;
00496 hihalf_val = val;
00497 break;
00498
00499 case R_IHCONST:
00500 if (! hihalf)
00501 {
00502 if (! ((*info->callbacks->reloc_dangerous)
00503 (info, _("missing IHIHALF reloc"), input_bfd,
00504 input_section, rel->r_vaddr - input_section->vma)))
00505 return FALSE;
00506 hihalf_val = 0;
00507 }
00508
00509 insn = bfd_get_32 (input_bfd, loc);
00510 unsigned_value = rel->r_symndx + hihalf_val;
00511 unsigned_value >>= 16;
00512 insn = INSERT_HWORD (insn, unsigned_value);
00513 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
00514
00515 hihalf = FALSE;
00516
00517 break;
00518
00519 case R_BYTE:
00520 case R_HWORD:
00521 case R_WORD:
00522 rstat = _bfd_relocate_contents (howto_table + rel->r_type,
00523 input_bfd, val, loc);
00524 if (rstat == bfd_reloc_overflow)
00525 overflow = TRUE;
00526 else if (rstat != bfd_reloc_ok)
00527 abort ();
00528 break;
00529 }
00530
00531 if (overflow)
00532 {
00533 const char *name;
00534 char buf[SYMNMLEN + 1];
00535
00536 if (symndx == -1)
00537 name = "*ABS*";
00538 else if (h != NULL)
00539 name = NULL;
00540 else if (sym == NULL)
00541 name = "*unknown*";
00542 else if (sym->_n._n_n._n_zeroes == 0
00543 && sym->_n._n_n._n_offset != 0)
00544 name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
00545 else
00546 {
00547 strncpy (buf, sym->_n._n_name, SYMNMLEN);
00548 buf[SYMNMLEN] = '\0';
00549 name = buf;
00550 }
00551
00552 if (! ((*info->callbacks->reloc_overflow)
00553 (info, (h ? &h->root : NULL), name,
00554 howto_table[rel->r_type].name, (bfd_vma) 0, input_bfd,
00555 input_section, rel->r_vaddr - input_section->vma)))
00556 return FALSE;
00557 }
00558 }
00559
00560 return TRUE;
00561 }
00562
00563 #define coff_relocate_section coff_a29k_relocate_section
00564
00565
00566
00567
00568 static bfd_boolean
00569 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
00570 bfd *obfd ATTRIBUTE_UNUSED;
00571 struct bfd_link_info *info ATTRIBUTE_UNUSED;
00572 bfd *ibfd ATTRIBUTE_UNUSED;
00573 asection *sec ATTRIBUTE_UNUSED;
00574 struct internal_reloc *irel;
00575 bfd_boolean *adjustedp;
00576 {
00577 if (irel->r_type == R_IHCONST)
00578 *adjustedp = TRUE;
00579 else
00580 *adjustedp = FALSE;
00581 return TRUE;
00582 }
00583
00584 #define coff_adjust_symndx coff_a29k_adjust_symndx
00585
00586 #include "coffcode.h"
00587
00588 CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL, COFF_SWAP_TABLE)