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
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 #include "bfd.h"
00203 #include "sysdep.h"
00204 #include "libbfd.h"
00205 #include "libiberty.h"
00206 #include "elf/mmix.h"
00207 #include "opcode/mmix.h"
00208
00209 #define LOP 0x98
00210 #define LOP_QUOTE 0
00211 #define LOP_LOC 1
00212 #define LOP_SKIP 2
00213 #define LOP_FIXO 3
00214 #define LOP_FIXR 4
00215 #define LOP_FIXRX 5
00216 #define LOP_FILE 6
00217 #define LOP_LINE 7
00218 #define LOP_SPEC 8
00219 #define LOP_PRE 9
00220 #define LOP_POST 10
00221 #define LOP_STAB 11
00222 #define LOP_END 12
00223
00224 #define LOP_QUOTE_NEXT ((LOP << 24) | (LOP_QUOTE << 16) | 1)
00225 #define SPEC_DATA_SECTION 80
00226 #define LOP_SPEC_SECTION \
00227 ((LOP << 24) | (LOP_SPEC << 16) | SPEC_DATA_SECTION)
00228
00229
00230
00231 #define MMO_SEC_CONTENTS_CHUNK_SIZE (1 << 15)
00232
00233
00234 #define MAX_SECTION_NAME_SIZE (1024 * 1024)
00235
00236
00237 #define MAX_ARTIFICIAL_SECTION_SIZE (1024 * 1024 * 1024)
00238
00239 #define MMO3_WCHAR 0x80
00240 #define MMO3_LEFT 0x40
00241 #define MMO3_MIDDLE 0x20
00242 #define MMO3_RIGHT 0x10
00243 #define MMO3_TYPEBITS 0xf
00244 #define MMO3_REGQUAL_BITS 0xf
00245 #define MMO3_UNDEF 2
00246 #define MMO3_DATA 8
00247 #define MMO3_SYMBITS 0x2f
00248
00249
00250 #define FATAL_DEBUG \
00251 _bfd_abort (__FILE__, __LINE__, \
00252 "Internal: Non-debugged code (test-case missing)")
00253
00254 #define BAD_CASE(x) \
00255 _bfd_abort (__FILE__, __LINE__, \
00256 "bad case for " #x)
00257
00258 enum mmo_sym_type { mmo_reg_sym, mmo_undef_sym, mmo_data_sym, mmo_abs_sym};
00259
00260
00261
00262
00263
00264 struct mmo_symbol
00265 {
00266 struct mmo_symbol *next;
00267 char *name;
00268 bfd_vma value;
00269 enum mmo_sym_type sym_type;
00270 unsigned int serno;
00271 };
00272
00273 struct mmo_data_list_struct
00274 {
00275 struct mmo_data_list_struct *next;
00276 bfd_vma where;
00277 bfd_size_type size;
00278 bfd_size_type allocated_size;
00279 bfd_byte data[1];
00280 };
00281
00282 typedef struct mmo_data_list_struct mmo_data_list_type;
00283
00284 struct mmo_symbol_trie
00285 {
00286 struct mmo_symbol_trie *left;
00287 struct mmo_symbol_trie *right;
00288 struct mmo_symbol_trie *middle;
00289
00290 bfd_byte symchar;
00291
00292
00293 struct mmo_symbol sym;
00294 };
00295
00296
00297
00298 struct mmo_data_struct
00299 {
00300 struct mmo_symbol *symbols;
00301 struct mmo_symbol *symtail;
00302 asymbol *csymbols;
00303
00304
00305 bfd_byte created[4];
00306
00307
00308
00309 bfd_boolean have_error;
00310
00311
00312
00313
00314 int max_symbol_length;
00315
00316
00317 char *lop_stab_symbol;
00318
00319
00320
00321 int symbol_position;
00322
00323
00324 int sec_no;
00325
00326
00327
00328 int byte_no;
00329
00330
00331 bfd_byte buf[4];
00332 };
00333
00334 typedef struct mmo_data_struct tdata_type;
00335
00336 struct mmo_section_data_struct
00337 {
00338 mmo_data_list_type *head;
00339 mmo_data_list_type *tail;
00340 };
00341
00342 #define mmo_section_data(sec) \
00343 ((struct mmo_section_data_struct *) (sec)->used_by_bfd)
00344
00345
00346
00347
00348
00349 struct mmo_write_sec_info
00350 {
00351 asection *reg_section;
00352 bfd_boolean retval;
00353 };
00354
00355
00356 struct mmo_find_sec_info
00357 {
00358 asection *sec;
00359 bfd_vma addr;
00360 };
00361
00362 static bfd_boolean mmo_bfd_copy_private_bfd_data (bfd *, bfd *);
00363 static void mmo_write_section_unless_reg_contents (bfd *, asection *, void *);
00364 static void mmo_find_sec_w_addr (bfd *, asection *, void *);
00365 static void mmo_find_sec_w_addr_grow (bfd *, asection *, void *);
00366 static asection *mmo_make_section (bfd *, const char *);
00367 static void mmo_get_symbol_info (bfd *, asymbol *, symbol_info *);
00368 static void mmo_print_symbol (bfd *, void *, asymbol *,
00369 bfd_print_symbol_type);
00370 static void mmo_init (void);
00371 static bfd_boolean mmo_mkobject (bfd *);
00372 static bfd_boolean mmo_scan (bfd *);
00373 static asection *mmo_decide_section (bfd *, bfd_vma);
00374 static asection *mmo_get_generic_spec_data_section (bfd *, int);
00375 static asection *mmo_get_spec_section (bfd *, int);
00376 static INLINE bfd_byte *mmo_get_loc (asection *, bfd_vma, int);
00377 static void mmo_xore_64 (asection *, bfd_vma vma, bfd_vma value);
00378 static void mmo_xore_32 (asection *, bfd_vma vma, unsigned int);
00379 static void mmo_xore_16 (asection *, bfd_vma vma, unsigned int);
00380 static const bfd_target *mmo_object_p (bfd *);
00381 static void mmo_map_set_sizes (bfd *, asection *, void *);
00382 static bfd_boolean mmo_get_symbols (bfd *);
00383 static bfd_boolean mmo_create_symbol (bfd *, const char *, bfd_vma,
00384 enum mmo_sym_type, unsigned int);
00385 static bfd_boolean mmo_get_section_contents (bfd *, asection *, void *,
00386 file_ptr, bfd_size_type);
00387 static long mmo_get_symtab_upper_bound (bfd *);
00388 static long mmo_canonicalize_symtab (bfd *, asymbol **);
00389 static void mmo_get_symbol_info (bfd *, asymbol *, symbol_info *);
00390 static void mmo_print_symbol (bfd *, void *, asymbol *,
00391 bfd_print_symbol_type);
00392 static bfd_boolean mmo_set_section_contents (bfd *, sec_ptr, const void *,
00393 file_ptr, bfd_size_type);
00394 static int mmo_sizeof_headers (bfd *, bfd_boolean);
00395 static long mmo_get_reloc_upper_bound (bfd *, asection *);
00396 static bfd_boolean mmo_internal_write_header (bfd *);
00397 static bfd_boolean mmo_internal_write_post (bfd *, int, asection *);
00398 static bfd_boolean mmo_internal_add_3_sym (bfd *, struct mmo_symbol_trie *,
00399 const struct mmo_symbol *);
00400 static unsigned int mmo_internal_3_length (bfd *, struct mmo_symbol_trie *);
00401 static void mmo_internal_3_dump (bfd *, struct mmo_symbol_trie *);
00402 static void mmo_beb128_out (bfd *, int, int);
00403 static bfd_boolean mmo_internal_write_section (bfd *, asection *);
00404 static void mmo_write_tetra (bfd *, unsigned int);
00405 static void mmo_write_tetra_raw (bfd *, unsigned int);
00406 static void mmo_write_octa (bfd *, bfd_vma);
00407 static void mmo_write_octa_raw (bfd *, bfd_vma);
00408 static bfd_boolean mmo_write_chunk (bfd *, const bfd_byte *, unsigned int);
00409 static bfd_boolean mmo_flush_chunk (bfd *);
00410 static bfd_boolean mmo_write_loc_chunk (bfd *, bfd_vma, const bfd_byte *,
00411 unsigned int, bfd_vma *);
00412 static bfd_boolean mmo_write_chunk_list (bfd *, mmo_data_list_type *);
00413 static bfd_boolean mmo_write_loc_chunk_list (bfd *, mmo_data_list_type *);
00414 static bfd_boolean mmo_write_symbols_and_terminator (bfd *);
00415 static flagword mmo_sec_flags_from_bfd_flags (flagword);
00416 static flagword bfd_sec_flags_from_mmo_flags (flagword);
00417 static bfd_byte mmo_get_byte (bfd *);
00418 static void mmo_write_byte (bfd *, bfd_byte);
00419 static bfd_boolean mmo_new_section_hook (bfd *, asection *);
00420 static int mmo_sort_mmo_symbols (const void *, const void *);
00421 static bfd_boolean mmo_write_object_contents (bfd *);
00422 static long mmo_canonicalize_reloc (bfd *, sec_ptr, arelent **, asymbol **);
00423 static bfd_boolean mmo_write_section_description (bfd *, asection *);
00424 static bfd_boolean mmo_has_leading_or_trailing_zero_tetra_p (bfd *,
00425 asection *);
00426
00427
00428
00429
00430
00431 static
00432 char valid_mmo_symbol_character_set[
00433
00434 + 'Z' - 'A' + 1 + 'z' - 'a' + 1
00435
00436 + 10
00437
00438 + 1 + 1
00439
00440 + 256 - 126
00441
00442 + 1];
00443
00444
00445
00446
00447
00448 static asection *
00449 mmo_make_section (bfd *abfd, const char *secname)
00450 {
00451 asection *sec = bfd_get_section_by_name (abfd, secname);
00452
00453 if (sec == NULL)
00454 {
00455 char *newsecname = strdup (secname);
00456
00457 if (newsecname == NULL)
00458 {
00459 (*_bfd_error_handler)
00460 (_("%s: No core to allocate section name %s\n"),
00461 bfd_get_filename (abfd), secname);
00462 bfd_set_error (bfd_error_system_call);
00463 return NULL;
00464 }
00465 sec = bfd_make_section (abfd, newsecname);
00466 }
00467
00468 return sec;
00469 }
00470
00471
00472
00473
00474
00475 static void
00476 mmo_init (void)
00477 {
00478 static bfd_boolean inited = FALSE;
00479 int i = 0;
00480 int j = 0;
00481 static const char letters[]
00482 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:_";
00483
00484 if (inited)
00485 return;
00486 inited = TRUE;
00487
00488
00489 strcpy (valid_mmo_symbol_character_set, letters);
00490 i = strlen (letters);
00491
00492 for (j = 126; j < 256; j++)
00493 valid_mmo_symbol_character_set[i++] = j;
00494 }
00495
00496
00497
00498 static const bfd_target *
00499 mmo_object_p (bfd *abfd)
00500 {
00501 struct stat statbuf;
00502 bfd_byte b[4];
00503
00504 mmo_init ();
00505
00506 if (bfd_stat (abfd, &statbuf) < 0
00507 || bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
00508 || bfd_bread (b, 4, abfd) != 4)
00509 goto bad_final;
00510
00511
00512
00513 if ((statbuf.st_size % 4) != 0
00514 || b[0] != LOP || b[1] != LOP_PRE || b[2] != 1)
00515 goto bad_format;
00516
00517
00518 if (bfd_seek (abfd, (file_ptr) statbuf.st_size - 4, SEEK_SET) != 0
00519 || bfd_bread (b, 4, abfd) != 4)
00520 goto bad_final;
00521
00522
00523 if (b[0] != LOP || b[1] != LOP_END || ! mmo_mkobject (abfd))
00524 goto bad_format;
00525
00526
00527
00528 abfd->tdata.mmo_data->max_symbol_length = (b[2] * 256 + b[3]) * 4;
00529 abfd->tdata.mmo_data->lop_stab_symbol
00530 = bfd_malloc (abfd->tdata.mmo_data->max_symbol_length + 1);
00531
00532 if (abfd->tdata.mmo_data->lop_stab_symbol == NULL)
00533 {
00534 (*_bfd_error_handler)
00535 (_("%s: No core to allocate a symbol %d bytes long\n"),
00536 bfd_get_filename (abfd), abfd->tdata.mmo_data->max_symbol_length);
00537 goto bad_final;
00538 }
00539
00540
00541 if (! mmo_scan (abfd))
00542 goto bad_format_free;
00543
00544 if (abfd->symcount > 0)
00545 abfd->flags |= HAS_SYMS;
00546
00547
00548
00549
00550 if (! bfd_default_set_arch_mach (abfd, bfd_arch_mmix, 0))
00551 goto bad_format_free;
00552
00553 return abfd->xvec;
00554
00555 bad_format_free:
00556 free (abfd->tdata.mmo_data->lop_stab_symbol);
00557 bad_format:
00558 bfd_set_error (bfd_error_wrong_format);
00559 bad_final:
00560 return NULL;
00561 }
00562
00563
00564
00565 static bfd_boolean
00566 mmo_mkobject (bfd *abfd)
00567 {
00568 mmo_init ();
00569
00570 if (abfd->tdata.mmo_data == NULL)
00571 {
00572 time_t created;
00573
00574
00575
00576 tdata_type *tdata = (tdata_type *) bfd_zmalloc (sizeof (tdata_type));
00577 if (tdata == NULL)
00578 return FALSE;
00579
00580 created = time (NULL);
00581 bfd_put_32 (abfd, created, tdata->created);
00582
00583 abfd->tdata.mmo_data = tdata;
00584 }
00585
00586 return TRUE;
00587 }
00588
00589 static bfd_boolean
00590 mmo_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
00591 {
00592 if (bfd_get_flavour (ibfd) != bfd_target_mmo_flavour
00593 || bfd_get_flavour (obfd) != bfd_target_mmo_flavour)
00594 return TRUE;
00595
00596
00597
00598
00599 memcpy (obfd->tdata.mmo_data->created, ibfd->tdata.mmo_data->created,
00600 sizeof (obfd->tdata.mmo_data->created));
00601 return TRUE;
00602 }
00603
00604
00605
00606
00607 static void
00608 mmo_find_sec_w_addr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *p)
00609 {
00610 struct mmo_find_sec_info *infop = (struct mmo_find_sec_info *) p;
00611 bfd_vma vma = bfd_get_section_vma (abfd, sec);
00612
00613
00614 if ((bfd_get_section_flags (abfd, sec) & (SEC_LOAD | SEC_ALLOC))
00615 != (SEC_LOAD | SEC_ALLOC))
00616 return;
00617
00618 if (infop->addr >= vma && infop->addr < vma + sec->size)
00619 infop->sec = sec;
00620 }
00621
00622 static void
00623 mmo_find_sec_w_addr_grow (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *p)
00624 {
00625 struct mmo_find_sec_info *infop = (struct mmo_find_sec_info *) p;
00626 bfd_vma vma = bfd_get_section_vma (abfd, sec);
00627
00628
00629 if ((bfd_get_section_flags (abfd, sec) & (SEC_LOAD | SEC_ALLOC))
00630 != (SEC_LOAD | SEC_ALLOC))
00631 return;
00632
00633 if (infop->addr >= vma && infop->addr < vma + MAX_ARTIFICIAL_SECTION_SIZE)
00634 infop->sec = sec;
00635 }
00636
00637
00638
00639
00640
00641
00642 static asection *
00643 mmo_decide_section (bfd *abfd, bfd_vma vma)
00644 {
00645 asection *sec = NULL;
00646 char sec_name[sizeof (".MMIX.sec.") + 20];
00647 struct mmo_find_sec_info info;
00648
00649 info.addr = vma;
00650 info.sec = NULL;
00651
00652
00653 bfd_map_over_sections (abfd, mmo_find_sec_w_addr, &info);
00654
00655 if (info.sec != NULL)
00656 return info.sec;
00657
00658
00659
00660
00661
00662 if ((vma >> 56) == 0)
00663 {
00664 sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
00665
00666 if (sec == NULL)
00667 return NULL;
00668
00669 if (! sec->user_set_vma)
00670 bfd_set_section_vma (abfd, sec, vma);
00671 if (! bfd_set_section_flags (abfd, sec,
00672 bfd_get_section_flags (abfd, sec)
00673 | SEC_CODE | SEC_LOAD | SEC_ALLOC))
00674 return NULL;
00675 }
00676 else if ((vma >> 56) == 0x20)
00677 {
00678 sec = bfd_make_section_old_way (abfd, MMO_DATA_SECTION_NAME);
00679
00680 if (sec == NULL)
00681 return NULL;
00682
00683 if (! sec->user_set_vma)
00684 bfd_set_section_vma (abfd, sec, vma);
00685 if (! bfd_set_section_flags (abfd, sec,
00686 bfd_get_section_flags (abfd, sec)
00687 | SEC_LOAD | SEC_ALLOC))
00688 return NULL;
00689 }
00690
00691 bfd_map_over_sections (abfd, mmo_find_sec_w_addr_grow, &info);
00692
00693 if (info.sec != NULL)
00694 return info.sec;
00695
00696
00697 sprintf (sec_name, ".MMIX.sec.%d", abfd->tdata.mmo_data->sec_no++);
00698 sec = mmo_make_section (abfd, sec_name);
00699 if (! sec->user_set_vma)
00700 bfd_set_section_vma (abfd, sec, vma);
00701
00702 if (! bfd_set_section_flags (abfd, sec,
00703 bfd_get_section_flags (abfd, sec)
00704 | SEC_LOAD | SEC_ALLOC))
00705 return NULL;
00706 return sec;
00707 }
00708
00709
00710
00711 static INLINE void
00712 mmo_xore_64 (asection *sec, bfd_vma vma, bfd_vma value)
00713 {
00714 bfd_byte *loc = mmo_get_loc (sec, vma, 8);
00715 bfd_vma prev = bfd_get_64 (sec->owner, loc);
00716
00717 value ^= prev;
00718 bfd_put_64 (sec->owner, value, loc);
00719 }
00720
00721
00722
00723 static INLINE void
00724 mmo_xore_32 (asection *sec, bfd_vma vma, unsigned int value)
00725 {
00726 bfd_byte *loc = mmo_get_loc (sec, vma, 4);
00727 unsigned int prev = bfd_get_32 (sec->owner, loc);
00728
00729 value ^= prev;
00730 bfd_put_32 (sec->owner, value, loc);
00731 }
00732
00733
00734
00735 static INLINE void
00736 mmo_xore_16 (asection *sec, bfd_vma vma, unsigned int value)
00737 {
00738 bfd_byte *loc = mmo_get_loc (sec, vma, 2);
00739 unsigned int prev = bfd_get_16 (sec->owner, loc);
00740
00741 value ^= prev;
00742 bfd_put_16 (sec->owner, value, loc);
00743 }
00744
00745
00746
00747 static INLINE void
00748 mmo_write_tetra_raw (bfd *abfd, unsigned int value)
00749 {
00750 bfd_byte buf[4];
00751
00752 bfd_put_32 (abfd, value, buf);
00753
00754 if (bfd_bwrite (buf, 4, abfd) != 4)
00755 abfd->tdata.mmo_data->have_error = TRUE;
00756 }
00757
00758
00759
00760 static INLINE void
00761 mmo_write_tetra (bfd *abfd, unsigned int value)
00762 {
00763 if (((value >> 24) & 0xff) == LOP)
00764 mmo_write_tetra_raw (abfd, LOP_QUOTE_NEXT);
00765
00766 mmo_write_tetra_raw (abfd, value);
00767 }
00768
00769
00770
00771 static INLINE void
00772 mmo_write_octa (bfd *abfd, bfd_vma value)
00773 {
00774 mmo_write_tetra (abfd, (unsigned int) (value >> 32));
00775 mmo_write_tetra (abfd, (unsigned int) value);
00776 }
00777
00778
00779
00780 static INLINE void
00781 mmo_write_octa_raw (bfd *abfd, bfd_vma value)
00782 {
00783 mmo_write_tetra_raw (abfd, (unsigned int) (value >> 32));
00784 mmo_write_tetra_raw (abfd, (unsigned int) value);
00785 }
00786
00787
00788
00789
00790 static INLINE bfd_boolean
00791 mmo_write_chunk (bfd *abfd, const bfd_byte *loc, unsigned int len)
00792 {
00793 bfd_boolean retval = TRUE;
00794
00795
00796 if (abfd->tdata.mmo_data->byte_no != 0)
00797 {
00798 while (abfd->tdata.mmo_data->byte_no < 4 && len != 0)
00799 {
00800 abfd->tdata.mmo_data->buf[abfd->tdata.mmo_data->byte_no++] = *loc++;
00801 len--;
00802 }
00803
00804 if (abfd->tdata.mmo_data->byte_no == 4)
00805 {
00806 mmo_write_tetra (abfd,
00807 bfd_get_32 (abfd, abfd->tdata.mmo_data->buf));
00808 abfd->tdata.mmo_data->byte_no = 0;
00809 }
00810 }
00811
00812 while (len >= 4)
00813 {
00814 if (loc[0] == LOP)
00815 mmo_write_tetra_raw (abfd, LOP_QUOTE_NEXT);
00816
00817 retval = (retval
00818 && ! abfd->tdata.mmo_data->have_error
00819 && 4 == bfd_bwrite (loc, 4, abfd));
00820
00821 loc += 4;
00822 len -= 4;
00823 }
00824
00825 if (len)
00826 {
00827 memcpy (abfd->tdata.mmo_data->buf, loc, len);
00828 abfd->tdata.mmo_data->byte_no = len;
00829 }
00830
00831 if (! retval)
00832 abfd->tdata.mmo_data->have_error = TRUE;
00833 return retval;
00834 }
00835
00836
00837
00838
00839 static INLINE bfd_boolean
00840 mmo_flush_chunk (bfd *abfd)
00841 {
00842 if (abfd->tdata.mmo_data->byte_no != 0)
00843 {
00844 memset (abfd->tdata.mmo_data->buf + abfd->tdata.mmo_data->byte_no,
00845 0, 4 - abfd->tdata.mmo_data->byte_no);
00846 mmo_write_tetra (abfd,
00847 bfd_get_32 (abfd, abfd->tdata.mmo_data->buf));
00848 abfd->tdata.mmo_data->byte_no = 0;
00849 }
00850
00851 return ! abfd->tdata.mmo_data->have_error;
00852 }
00853
00854
00855
00856 static INLINE bfd_boolean
00857 mmo_write_chunk_list (bfd *abfd, mmo_data_list_type *datap)
00858 {
00859 for (; datap != NULL; datap = datap->next)
00860 if (! mmo_write_chunk (abfd, datap->data, datap->size))
00861 return FALSE;
00862
00863 return mmo_flush_chunk (abfd);
00864 }
00865
00866
00867
00868
00869
00870 static bfd_boolean
00871 mmo_write_loc_chunk (bfd *abfd, bfd_vma vma, const bfd_byte *loc,
00872 unsigned int len, bfd_vma *last_vmap)
00873 {
00874
00875
00876
00877
00878
00879
00880
00881
00882 if (abfd->tdata.mmo_data->byte_no == 0 || vma != *last_vmap)
00883 {
00884 while (len >= 4 && bfd_get_32 (abfd, loc) == 0)
00885 {
00886 vma += 4;
00887 len -= 4;
00888 loc += 4;
00889 }
00890
00891 while (len >= 4 && bfd_get_32 (abfd, loc + len - 4) == 0)
00892 len -= 4;
00893 }
00894
00895
00896
00897 if (vma != *last_vmap)
00898 {
00899
00900 mmo_flush_chunk (abfd);
00901
00902
00903
00904 mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_LOC << 16) | 2);
00905 mmo_write_octa_raw (abfd, vma);
00906 }
00907
00908
00909 *last_vmap = vma + len;
00910
00911 return (! abfd->tdata.mmo_data->have_error
00912 && mmo_write_chunk (abfd, loc, len));
00913 }
00914
00915
00916
00917 static INLINE bfd_boolean
00918 mmo_write_loc_chunk_list (bfd *abfd, mmo_data_list_type *datap)
00919 {
00920
00921 bfd_vma last_vma = datap ? datap->where - 1 : 0;
00922
00923 for (; datap != NULL; datap = datap->next)
00924 if (! mmo_write_loc_chunk (abfd, datap->where, datap->data, datap->size,
00925 &last_vma))
00926 return FALSE;
00927
00928 return mmo_flush_chunk (abfd);
00929 }
00930
00931
00932
00933 static asection *
00934 mmo_get_generic_spec_data_section (bfd *abfd, int spec_data_number)
00935 {
00936 asection *sec;
00937 char secname[sizeof (MMIX_OTHER_SPEC_SECTION_PREFIX) + 20]
00938 = MMIX_OTHER_SPEC_SECTION_PREFIX;
00939
00940 sprintf (secname + strlen (MMIX_OTHER_SPEC_SECTION_PREFIX),
00941 "%d", spec_data_number);
00942
00943 sec = mmo_make_section (abfd, secname);
00944
00945 return sec;
00946 }
00947
00948
00949
00950
00951 static asection *
00952 mmo_get_spec_section (bfd *abfd, int spec_data_number)
00953 {
00954 char *secname;
00955 asection *sec;
00956 bfd_byte buf[4];
00957 unsigned int secname_length;
00958 unsigned int i;
00959 bfd_vma section_length;
00960 bfd_vma section_vma;
00961 mmo_data_list_type *loc;
00962 flagword flags;
00963 long orig_pos;
00964
00965
00966
00967 if (spec_data_number != SPEC_DATA_SECTION)
00968 return mmo_get_generic_spec_data_section (abfd, spec_data_number);
00969
00970
00971 orig_pos = bfd_tell (abfd);
00972
00973
00974 if (bfd_bread (buf, 4, abfd) != 4)
00975 goto format_error;
00976
00977 if (buf[0] == LOP)
00978 {
00979 if (buf[1] != LOP_QUOTE)
00980 goto format_error;
00981
00982 if (bfd_bread (buf, 4, abfd) != 4)
00983 goto format_error;
00984 }
00985
00986
00987
00988 secname_length = bfd_get_32 (abfd, buf) * 4;
00989
00990
00991 if (secname_length > MAX_SECTION_NAME_SIZE)
00992 goto format_error;
00993
00994
00995 secname = bfd_malloc (secname_length + 1);
00996 secname[secname_length] = 0;
00997
00998 for (i = 0; i < secname_length / 4; i++)
00999 {
01000 if (bfd_bread (secname + i * 4, 4, abfd) != 4)
01001 goto format_error_free;
01002
01003 if (secname[i * 4] == (char) LOP)
01004 {
01005
01006
01007 if (secname[i * 4 + 1] != LOP_QUOTE
01008 || bfd_bread (secname + i * 4, 4, abfd) != 4)
01009
01010
01011
01012 goto format_error_free;
01013 }
01014 }
01015
01016
01017 if (bfd_bread (buf, 4, abfd) != 4
01018 || (buf[0] == LOP
01019 && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
01020 goto format_error_free;
01021
01022 flags = bfd_get_32 (abfd, buf);
01023
01024
01025 if (bfd_bread (buf, 4, abfd) != 4
01026 || (buf[0] == LOP
01027 && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
01028 goto format_error_free;
01029
01030 section_length = (bfd_vma) bfd_get_32 (abfd, buf) << 32;
01031
01032
01033
01034 if (bfd_bread (buf, 4, abfd) != 4
01035 || (buf[0] == LOP
01036 && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
01037 goto format_error_free;
01038
01039 section_length |= (bfd_vma) bfd_get_32 (abfd, buf);
01040
01041
01042 if (section_length > MAX_ARTIFICIAL_SECTION_SIZE)
01043 goto format_error_free;
01044
01045
01046 if (bfd_bread (buf, 4, abfd) != 4
01047 || (buf[0] == LOP
01048 && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
01049 goto format_error_free;
01050
01051 section_vma = (bfd_vma) bfd_get_32 (abfd, buf) << 32;
01052
01053
01054 if (bfd_bread (buf, 4, abfd) != 4
01055 || (buf[0] == LOP
01056 && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
01057 goto format_error_free;
01058
01059 section_vma |= (bfd_vma) bfd_get_32 (abfd, buf);
01060
01061 sec = mmo_make_section (abfd, secname);
01062 free (secname);
01063 if (sec == NULL)
01064 goto format_error;
01065
01066
01067
01068 loc = bfd_zmalloc (section_length + 3
01069 + sizeof (struct mmo_data_list_struct));
01070 if (loc == NULL)
01071 goto format_error;
01072
01073
01074
01075 loc->size = (section_length + 3) & ~3;
01076
01077
01078
01079 if (! bfd_set_section_flags (abfd, sec,
01080 bfd_sec_flags_from_mmo_flags (flags)
01081 | bfd_get_section_flags (abfd, sec)
01082 | (section_length != 0 ? SEC_HAS_CONTENTS : 0))
01083 || ! bfd_set_section_size (abfd, sec, sec->size + section_length)
01084
01085 || (! sec->user_set_vma
01086 && ! bfd_set_section_vma (abfd, sec, section_vma)))
01087 {
01088
01089
01090 return NULL;
01091 }
01092
01093 loc->next = NULL;
01094 if (mmo_section_data (sec)->tail != NULL)
01095 mmo_section_data (sec)->tail->next = loc;
01096 else
01097 mmo_section_data (sec)->head = loc;
01098 mmo_section_data (sec)->tail = loc;
01099 loc->where = section_vma;
01100
01101 return sec;
01102
01103 format_error_free:
01104 free (secname);
01105 format_error:
01106 if (bfd_seek (abfd, orig_pos, SEEK_SET) != 0)
01107 return NULL;
01108
01109 return mmo_get_generic_spec_data_section (abfd, spec_data_number);
01110 }
01111
01112
01113
01114 static bfd_byte
01115 mmo_get_byte (bfd *abfd)
01116 {
01117 bfd_byte retval;
01118
01119 if (abfd->tdata.mmo_data->byte_no == 0)
01120 {
01121 if (! abfd->tdata.mmo_data->have_error
01122 && bfd_bread (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
01123 {
01124 abfd->tdata.mmo_data->have_error = TRUE;
01125
01126
01127
01128 return 128;
01129 }
01130 }
01131
01132 retval = abfd->tdata.mmo_data->buf[abfd->tdata.mmo_data->byte_no];
01133 abfd->tdata.mmo_data->byte_no = (abfd->tdata.mmo_data->byte_no + 1) % 4;
01134
01135 return retval;
01136 }
01137
01138
01139
01140 static void
01141 mmo_write_byte (bfd *abfd, bfd_byte value)
01142 {
01143 abfd->tdata.mmo_data->buf[(abfd->tdata.mmo_data->byte_no++ % 4)] = value;
01144 if ((abfd->tdata.mmo_data->byte_no % 4) == 0)
01145 {
01146 if (! abfd->tdata.mmo_data->have_error
01147 && bfd_bwrite (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
01148 abfd->tdata.mmo_data->have_error = TRUE;
01149 }
01150 }
01151
01152
01153
01154 static bfd_boolean
01155 mmo_create_symbol (bfd *abfd, const char *symname, bfd_vma addr, enum
01156 mmo_sym_type sym_type, unsigned int serno)
01157 {
01158 struct mmo_symbol *n;
01159
01160 n = (struct mmo_symbol *) bfd_alloc (abfd, sizeof (struct mmo_symbol));
01161 if (n == NULL)
01162 return FALSE;
01163
01164 n->name = bfd_alloc (abfd, strlen (symname) + 1);
01165 if (n->name == NULL)
01166 return FALSE;
01167
01168 strcpy (n->name, symname);
01169
01170 n->value = addr;
01171 n->sym_type = sym_type;
01172 n->serno = serno;
01173
01174 if (abfd->tdata.mmo_data->symbols == NULL)
01175 abfd->tdata.mmo_data->symbols = n;
01176 else
01177 abfd->tdata.mmo_data->symtail->next = n;
01178 abfd->tdata.mmo_data->symtail = n;
01179 n->next = NULL;
01180
01181 ++abfd->symcount;
01182
01183
01184
01185
01186
01187 if (strcmp (symname, MMIX_START_SYMBOL_NAME) == 0
01188 && bfd_get_start_address (abfd) != addr)
01189 {
01190 (*_bfd_error_handler)
01191 (_("%s: invalid mmo file: initialization value for $255 is not `Main'\n"),
01192 bfd_get_filename (abfd));
01193 bfd_set_error (bfd_error_bad_value);
01194 return FALSE;
01195 }
01196
01197 return TRUE;
01198 }
01199
01200
01201
01202 static bfd_boolean
01203 mmo_get_symbols (bfd *abfd)
01204 {
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304 bfd_byte m = mmo_get_byte (abfd);
01305
01306
01307 if (abfd->tdata.mmo_data->have_error)
01308 return FALSE;
01309
01310 if (m & MMO3_LEFT)
01311
01312 mmo_get_symbols (abfd);
01313
01314 if (m & MMO3_SYMBITS)
01315 {
01316 bfd_byte c = mmo_get_byte (abfd);
01317 bfd_byte j = m & MMO3_TYPEBITS;
01318 bfd_vma addr = 0;
01319 enum mmo_sym_type sym_type;
01320 unsigned int serno = 0;
01321 bfd_byte k;
01322
01323 if (m & MMO3_WCHAR)
01324 {
01325 bfd_byte c2 = mmo_get_byte (abfd);
01326
01327
01328
01329
01330 if (c != 0)
01331 {
01332 abfd->tdata.mmo_data->lop_stab_symbol
01333 [abfd->tdata.mmo_data->symbol_position] = 0;
01334
01335 (*_bfd_error_handler)
01336 (_("%s: unsupported wide character sequence"
01337 " 0x%02X 0x%02X after symbol name starting with `%s'\n"),
01338 bfd_get_filename (abfd), c, c2,
01339 abfd->tdata.mmo_data->lop_stab_symbol);
01340 bfd_set_error (bfd_error_bad_value);
01341 abfd->tdata.mmo_data->have_error = TRUE;
01342 return FALSE;
01343 }
01344 else
01345 c = c2;
01346 }
01347
01348 abfd->tdata.mmo_data->lop_stab_symbol[abfd->tdata.mmo_data->symbol_position++] = c;
01349 abfd->tdata.mmo_data->lop_stab_symbol[abfd->tdata.mmo_data->symbol_position] = 0;
01350
01351 if (j & MMO3_REGQUAL_BITS)
01352 {
01353 if (j == MMO3_REGQUAL_BITS)
01354 {
01355 sym_type = mmo_reg_sym;
01356 addr = mmo_get_byte (abfd);
01357 }
01358 else if (j <= 8)
01359 {
01360 unsigned int i;
01361
01362 for (i = 0; i < j; i++)
01363 addr = (addr << 8) + mmo_get_byte (abfd);
01364
01365 if (addr == 0 && j == MMO3_UNDEF)
01366 sym_type = mmo_undef_sym;
01367 else
01368 sym_type = mmo_abs_sym;
01369 }
01370 else
01371 {
01372 unsigned int i;
01373
01374 for (i = MMO3_DATA; i < j; i++)
01375 addr = (addr << 8) + mmo_get_byte (abfd);
01376
01377 addr += (bfd_vma) 0x20 << 56;
01378 sym_type = mmo_data_sym;
01379 }
01380
01381
01382 do
01383 {
01384 k = mmo_get_byte (abfd);
01385 serno = (serno << 7) + k;
01386 }
01387 while (k < 128);
01388 serno -= 128;
01389
01390
01391 if (! abfd->tdata.mmo_data->have_error
01392 && ! mmo_create_symbol (abfd,
01393 abfd->tdata.mmo_data->lop_stab_symbol
01394 + 1,
01395 addr, sym_type, serno))
01396 abfd->tdata.mmo_data->have_error = TRUE;
01397 }
01398
01399 if (m & MMO3_MIDDLE)
01400
01401 mmo_get_symbols (abfd);
01402
01403 abfd->tdata.mmo_data->symbol_position--;
01404 }
01405
01406 if (m & MMO3_RIGHT)
01407
01408 mmo_get_symbols (abfd);
01409
01410 return ! abfd->tdata.mmo_data->have_error;
01411 }
01412
01413
01414
01415
01416
01417
01418 static INLINE bfd_byte *
01419 mmo_get_loc (asection *sec, bfd_vma vma, int size)
01420 {
01421 bfd_size_type allocated_size;
01422 struct mmo_section_data_struct *sdatap = mmo_section_data (sec);
01423 struct mmo_data_list_struct *datap = sdatap->head;
01424 struct mmo_data_list_struct *entry;
01425
01426
01427
01428 for (; datap != NULL; datap = datap->next)
01429 {
01430 if (datap->where <= vma
01431 && datap->where + datap->size >= vma + size)
01432 return datap->data + vma - datap->where;
01433 else if (datap->where <= vma
01434 && datap->where + datap->allocated_size >= vma + size
01435
01436
01437 && (datap->next == NULL || datap->next->where >= vma + size))
01438 {
01439
01440
01441 datap->size += (vma + size) - (datap->where + datap->size);
01442
01443
01444
01445
01446
01447
01448 if (vma + size > sec->vma + sec->size)
01449 sec->size += (vma + size) - (sec->vma + sec->size);
01450
01451 return datap->data + vma - datap->where;
01452 }
01453 }
01454
01455
01456
01457
01458
01459
01460
01461 for (datap = sdatap->head; datap != NULL; datap = datap->next)
01462 if ((datap->where <= vma && datap->where + datap->size > vma)
01463 || (datap->where < vma + size
01464 && datap->where + datap->size >= vma + size))
01465 return NULL;
01466
01467 allocated_size
01468 = (size + MMO_SEC_CONTENTS_CHUNK_SIZE - 1) & ~(MMO_SEC_CONTENTS_CHUNK_SIZE - 1);
01469 entry = (mmo_data_list_type *)
01470 bfd_zalloc (sec->owner, sizeof (mmo_data_list_type) + allocated_size);
01471 if (entry == NULL)
01472 return NULL;
01473 entry->where = vma;
01474 entry->size = size;
01475 entry->allocated_size = allocated_size;
01476
01477 datap = sdatap->head;
01478
01479
01480
01481 if (sdatap->tail != NULL && entry->where >= sdatap->tail->where)
01482 {
01483 sdatap->tail->next = entry;
01484 entry->next = NULL;
01485 sdatap->tail = entry;
01486 }
01487 else
01488 {
01489 mmo_data_list_type **look;
01490 for (look = &sdatap->head;
01491 *look != NULL && (*look)->where < entry->where;
01492 look = &(*look)->next)
01493 ;
01494 entry->next = *look;
01495 *look = entry;
01496 if (entry->next == NULL)
01497 {
01498 sdatap->tail = entry;
01499
01500
01501
01502 if (! bfd_set_section_flags (sec->owner, sec,
01503 bfd_get_section_flags (sec->owner, sec)
01504 | SEC_HAS_CONTENTS))
01505 return NULL;
01506 }
01507 }
01508
01509
01510
01511 if (vma + size > sec->vma + sec->size)
01512 sec->size += (vma + size) - (sec->vma + sec->size);
01513 return entry->data;
01514 }
01515
01516
01517
01518 static void
01519 mmo_map_set_sizes (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
01520 void *ignored ATTRIBUTE_UNUSED)
01521 {
01522 sec->lma = sec->vma;
01523 }
01524
01525
01526
01527 static bfd_boolean
01528 mmo_scan (bfd *abfd)
01529 {
01530 unsigned int i;
01531 unsigned int lineno = 1;
01532 bfd_boolean error = FALSE;
01533 bfd_vma vma = 0;
01534 asection *sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
01535 asection *non_spec_sec = NULL;
01536 bfd_vma non_spec_vma = 0;
01537 char *current_filename = NULL;
01538 bfd_size_type nbytes_read = 0;
01539
01540 bfd_byte buf[8];
01541 long stab_loc = -1;
01542 char *file_names[256];
01543
01544 memset (file_names, 0, sizeof (file_names));
01545
01546 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
01547 goto error_return;
01548
01549 while ((nbytes_read = bfd_bread (buf, 4, abfd)) == 4)
01550 {
01551 if (buf[0] == LOP)
01552 {
01553 unsigned int y = bfd_get_8 (abfd, buf + 2);
01554 unsigned int z = bfd_get_8 (abfd, buf + 3);
01555
01556
01557
01558 if ((buf[1] != LOP_QUOTE || y != 0 || z != 1)
01559 && non_spec_sec != NULL)
01560 {
01561 sec = non_spec_sec;
01562 vma = non_spec_vma;
01563 non_spec_sec = NULL;
01564 }
01565
01566 switch (buf[1])
01567 {
01568 default:
01569 (*_bfd_error_handler)
01570 (_("%s: invalid mmo file: unsupported lopcode `%d'\n"),
01571 bfd_get_filename (abfd), buf[1]);
01572 bfd_set_error (bfd_error_bad_value);
01573 goto error_return;
01574
01575 case LOP_QUOTE:
01576
01577 if (y != 0 || z != 1)
01578 {
01579 (*_bfd_error_handler)
01580 (_("%s: invalid mmo file: expected YZ = 1 got YZ = %d for lop_quote\n"),
01581 bfd_get_filename (abfd), y*256+z);
01582 bfd_set_error (bfd_error_bad_value);
01583 goto error_return;
01584 }
01585 if (bfd_bread (buf, 4, abfd) != 4)
01586 goto error_return;
01587
01588 mmo_xore_32 (sec, vma, bfd_get_32 (abfd, buf));
01589 vma += 4;
01590 vma &= ~3;
01591 lineno++;
01592 break;
01593
01594 case LOP_LOC:
01595
01596 vma = (bfd_vma) y << 56;
01597 if (z == 1)
01598 {
01599
01600 if (bfd_bread (buf, 4, abfd) != 4)
01601 goto error_return;
01602
01603 vma += bfd_get_32 (abfd, buf);
01604 }
01605 else if (z == 2)
01606 {
01607
01608 if (bfd_bread (buf, 8, abfd) != 8)
01609 goto error_return;
01610
01611 vma += bfd_get_64 (abfd, buf);
01612 }
01613 else
01614 {
01615 (*_bfd_error_handler)
01616 (_("%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_loc\n"),
01617 bfd_get_filename (abfd), z);
01618 bfd_set_error (bfd_error_bad_value);
01619 goto error_return;
01620 }
01621
01622 sec = mmo_decide_section (abfd, vma);
01623 if (sec == NULL)
01624 goto error_return;
01625 break;
01626
01627 case LOP_SKIP:
01628
01629 vma += y * 256 + z;
01630
01631 sec = mmo_decide_section (abfd, vma);
01632 if (sec == NULL)
01633 goto error_return;
01634 break;
01635
01636 case LOP_FIXO:
01637
01638
01639 {
01640 bfd_vma p = (bfd_vma) y << 56;
01641 asection *fixosec;
01642
01643 if (z == 1)
01644 {
01645
01646 if (bfd_bread (buf, 4, abfd) != 4)
01647 goto error_return;
01648
01649 p += bfd_get_32 (abfd, buf);
01650 }
01651 else if (z == 2)
01652 {
01653
01654 if (bfd_bread (buf, 8, abfd) != 8)
01655 goto error_return;
01656
01657 p += bfd_get_64 (abfd, buf);
01658 }
01659 else
01660 {
01661 (*_bfd_error_handler)
01662 (_("%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_fixo\n"),
01663 bfd_get_filename (abfd), z);
01664 bfd_set_error (bfd_error_bad_value);
01665 goto error_return;
01666 }
01667
01668
01669
01670 fixosec = mmo_decide_section (abfd, p);
01671 if (fixosec == NULL)
01672 goto error_return;
01673 mmo_xore_64 (fixosec, p, vma);
01674 }
01675 break;
01676
01677 case LOP_FIXR:
01678
01679 {
01680 unsigned int yz = (y * 256 + z);
01681 bfd_vma p = vma + 2 - 4 * yz;
01682 asection *fixrsec = mmo_decide_section (abfd, p);
01683 if (fixrsec == NULL)
01684 goto error_return;
01685 mmo_xore_16 (fixrsec, p, yz);
01686 }
01687 break;
01688
01689 case LOP_FIXRX:
01690
01691
01692
01693 {
01694 bfd_vma delta;
01695 bfd_vma p;
01696 asection *fixrsec;
01697
01698 if (y != 0)
01699 {
01700 (*_bfd_error_handler)
01701 (_("%s: invalid mmo file: expected y = 0, got y = %d for lop_fixrx\n"),
01702 bfd_get_filename (abfd), y);
01703 bfd_set_error (bfd_error_bad_value);
01704 goto error_return;
01705 }
01706
01707 if (z != 16 && z != 24)
01708 {
01709 (*_bfd_error_handler)
01710 (_("%s: invalid mmo file: expected z = 16 or z = 24, got z = %d for lop_fixrx\n"),
01711 bfd_get_filename (abfd), z);
01712 bfd_set_error (bfd_error_bad_value);
01713 goto error_return;
01714 }
01715
01716
01717 if (bfd_bread (buf, 4, abfd) != 4)
01718 goto error_return;
01719
01720 delta = bfd_get_32 (abfd, buf);
01721
01722
01723
01724
01725
01726 if (buf[0] == 0)
01727 p = vma - 4 * delta;
01728 else if (buf[0] == 1)
01729 p = vma - 4 * ((delta & 0xffffff) - (1 << z));
01730 else
01731 {
01732 (*_bfd_error_handler)
01733 (_("%s: invalid mmo file: leading byte of operand word must be 0 or 1, got %d for lop_fixrx\n"),
01734 bfd_get_filename (abfd), buf[0]);
01735 bfd_set_error (bfd_error_bad_value);
01736 goto error_return;
01737 }
01738
01739 fixrsec = mmo_decide_section (abfd, vma);
01740 if (fixrsec == NULL)
01741 goto error_return;
01742 mmo_xore_32 (fixrsec, p, delta);
01743 }
01744 break;
01745
01746 case LOP_FILE:
01747
01748
01749 if (z != 0)
01750 {
01751 char *fname = bfd_malloc (z * 4 + 1);
01752
01753 if (fname == NULL)
01754 {
01755 (*_bfd_error_handler)
01756 (_("%s: cannot allocate file name for file number %d, %d bytes\n"),
01757 bfd_get_filename (abfd), y, z * 4 + 1);
01758 bfd_set_error (bfd_error_system_call);
01759 goto error_return;
01760 }
01761
01762 fname[z * 4] = 0;
01763
01764 for (i = 0; i < z; i++)
01765 {
01766 if (bfd_bread (fname + i * 4, 4, abfd) != 4)
01767 {
01768 free (fname);
01769 goto error_return;
01770 }
01771 }
01772
01773 if (file_names[y] != NULL)
01774 {
01775 (*_bfd_error_handler)
01776 (_("%s: invalid mmo file: file number %d `%s',"
01777 " was already entered as `%s'\n"),
01778 bfd_get_filename (abfd), y, fname, file_names[y]);
01779 bfd_set_error (bfd_error_bad_value);
01780 goto error_return;
01781 }
01782
01783 file_names[y] = fname;
01784 }
01785
01786 if (file_names[y] == NULL)
01787 {
01788 (*_bfd_error_handler)
01789 (_("%s: invalid mmo file: file name for number %d"
01790 " was not specified before use\n"),
01791 bfd_get_filename (abfd), y);
01792 bfd_set_error (bfd_error_bad_value);
01793 goto error_return;
01794 }
01795
01796 current_filename = file_names[y];
01797 lineno = 0;
01798 break;
01799
01800 case LOP_LINE:
01801
01802 lineno = y * 256 + z;
01803
01804
01805
01806 break;
01807
01808 case LOP_SPEC:
01809
01810
01811 non_spec_sec = sec;
01812 non_spec_vma = vma;
01813 sec = mmo_get_spec_section (abfd, y * 256 + z);
01814 if (sec == NULL)
01815 goto error_return;
01816
01817 vma = sec->vma;
01818 break;
01819
01820 case LOP_PRE:
01821 {
01822
01823
01824
01825 if (z >= 1
01826 && bfd_bread (abfd->tdata.mmo_data->created, 4,
01827 abfd) != 4)
01828 goto error_return;
01829
01830 for (i = 1; i < z; i++)
01831 if (bfd_bread (buf, 4, abfd) != 4)
01832 goto error_return;
01833 }
01834 break;
01835
01836 case LOP_POST:
01837
01838
01839
01840 {
01841 asection *rsec;
01842 bfd_byte *loc;
01843 bfd_vma first_octa;
01844 bfd_vma startaddr_octa;
01845
01846
01847
01848 if (bfd_bread (buf, 8, abfd) != 8)
01849 goto error_return;
01850
01851 first_octa = bfd_get_64 (abfd, buf);
01852
01853
01854
01855 if (z != 255)
01856 {
01857 rsec
01858 = bfd_make_section_old_way (abfd,
01859 MMIX_REG_CONTENTS_SECTION_NAME);
01860 rsec->vma = z * 8;
01861 loc = mmo_get_loc (rsec, z * 8, (255 - z) * 8);
01862 bfd_put_64 (abfd, first_octa, loc);
01863
01864 for (i = z + 1; i < 255; i++)
01865 {
01866 if (bfd_bread (loc + (i - z) * 8, 8, abfd) != 8)
01867 goto error_return;
01868 }
01869
01870
01871
01872 if (bfd_bread (buf, 8, abfd) != 8)
01873 goto error_return;
01874
01875 startaddr_octa = bfd_get_64 (abfd, buf);
01876 }
01877 else
01878 startaddr_octa = first_octa;
01879
01880 if (! bfd_set_start_address (abfd, startaddr_octa))
01881 {
01882
01883
01884 bfd_set_error (bfd_error_bad_value);
01885 goto error_return;
01886 }
01887 }
01888 break;
01889
01890 case LOP_STAB:
01891
01892 if (y != 0 || z != 0)
01893 {
01894 (*_bfd_error_handler)
01895 (_("%s: invalid mmo file: fields y and z of lop_stab"
01896 " non-zero, y: %d, z: %d\n"),
01897 bfd_get_filename (abfd), y, z);
01898 bfd_set_error (bfd_error_bad_value);
01899 goto error_return;
01900 }
01901
01902
01903
01904 stab_loc = bfd_tell (abfd);
01905
01906
01907
01908
01909
01910
01911
01912
01913 if (abfd->tdata.mmo_data->max_symbol_length != 0
01914 && ! mmo_get_symbols (abfd))
01915 goto error_return;
01916 break;
01917
01918 case LOP_END:
01919 {
01920
01921
01922 struct stat statbuf;
01923 long curpos = bfd_tell (abfd);
01924
01925 if (bfd_stat (abfd, &statbuf) < 0)
01926 goto error_return;
01927
01928 if (statbuf.st_size != curpos)
01929 {
01930 (*_bfd_error_handler)
01931 (_("%s: invalid mmo file: lop_end not last item in"
01932 " file\n"),
01933 bfd_get_filename (abfd));
01934 bfd_set_error (bfd_error_bad_value);
01935 goto error_return;
01936 }
01937
01938
01939
01940
01941 if ((long) (y * 256 + z) * 4 != (curpos - stab_loc) - 4)
01942 {
01943 (*_bfd_error_handler)
01944 (_("%s: invalid mmo file: YZ of lop_end (%ld)"
01945 " not equal to the number of tetras to the preceding"
01946 " lop_stab (%ld)\n"),
01947 bfd_get_filename (abfd), (long) (y * 256 + z),
01948 (curpos - stab_loc - 4)/4);
01949 bfd_set_error (bfd_error_bad_value);
01950 goto error_return;
01951 }
01952
01953 bfd_map_over_sections (abfd, mmo_map_set_sizes, NULL);
01954 goto done;
01955 }
01956 }
01957 }
01958 else
01959 {
01960
01961 mmo_xore_32 (sec, vma & ~3, bfd_get_32 (abfd, buf));
01962 vma += 4;
01963 vma &= ~3;
01964 lineno++;
01965 }
01966 }
01967
01968
01969
01970
01971
01972
01973
01974 if (nbytes_read != 0)
01975 bfd_set_error (bfd_error_system_call);
01976 else
01977 bfd_set_error (bfd_error_bad_value);
01978
01979 error_return:
01980 error = TRUE;
01981 done:
01982
01983
01984
01985
01986 sec = bfd_get_section_by_name (abfd, MMO_TEXT_SECTION_NAME);
01987 if (sec != NULL
01988 && (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
01989 && ! bfd_set_section_flags (abfd, sec,
01990 bfd_get_section_flags (abfd, sec)
01991 | SEC_ALLOC | SEC_LOAD | SEC_CODE))
01992 error = TRUE;
01993
01994 sec = bfd_get_section_by_name (abfd, MMO_DATA_SECTION_NAME);
01995 if (sec != NULL
01996 && (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
01997 && ! bfd_set_section_flags (abfd, sec,
01998 bfd_get_section_flags (abfd, sec)
01999 | SEC_ALLOC | SEC_LOAD))
02000 error = TRUE;
02001
02002
02003 for (i = 0; i < sizeof (file_names) / sizeof (file_names[0]); i++)
02004 if (file_names[i])
02005 free (file_names[i]);
02006 return ! error;
02007 }
02008
02009
02010
02011
02012 static bfd_boolean
02013 mmo_new_section_hook (bfd *abfd ATTRIBUTE_UNUSED, asection *newsect)
02014 {
02015
02016
02017 newsect->used_by_bfd =
02018 bfd_zalloc (abfd, sizeof (struct mmo_section_data_struct));
02019
02020 if (!newsect->used_by_bfd)
02021 return FALSE;
02022
02023
02024 newsect->alignment_power = 2;
02025 return TRUE;
02026 }
02027
02028
02029
02030
02031 static bfd_boolean
02032 mmo_get_section_contents (bfd *abfd ATTRIBUTE_UNUSED,
02033 asection *sec,
02034 void * location,
02035 file_ptr offset,
02036 bfd_size_type bytes_to_do)
02037 {
02038
02039
02040 while (bytes_to_do)
02041 {
02042
02043
02044
02045 int chunk_size
02046 = (int) bytes_to_do != 0 ? bytes_to_do : MMO_SEC_CONTENTS_CHUNK_SIZE;
02047 bfd_byte *loc;
02048
02049 do
02050 loc = mmo_get_loc (sec, sec->vma + offset, chunk_size);
02051 while (loc == NULL && (chunk_size /= 2) != 0);
02052
02053 if (chunk_size == 0)
02054 return FALSE;
02055
02056 memcpy (location, loc, chunk_size);
02057
02058 location += chunk_size;
02059 bytes_to_do -= chunk_size;
02060 offset += chunk_size;
02061 }
02062 return TRUE;
02063 }
02064
02065
02066
02067 static long
02068 mmo_get_symtab_upper_bound (bfd *abfd)
02069 {
02070 return (abfd->symcount + 1) * sizeof (asymbol *);
02071 }
02072
02073
02074
02075 static int
02076 mmo_sort_mmo_symbols (const void *arg1, const void *arg2)
02077 {
02078 const struct mmo_symbol *sym1 = *(const struct mmo_symbol **) arg1;
02079 const struct mmo_symbol *sym2 = *(const struct mmo_symbol **) arg2;
02080
02081
02082 if (sym1->serno < sym2->serno)
02083 return -1;
02084 else if (sym1->serno > sym2->serno)
02085 return 1;
02086
02087
02088 return ((const char *) arg1 - (const char *) arg2);
02089 }
02090
02091
02092
02093 static long
02094 mmo_canonicalize_symtab (bfd *abfd, asymbol **alocation)
02095 {
02096 unsigned int symcount = bfd_get_symcount (abfd);
02097 asymbol *csymbols;
02098 unsigned int i;
02099
02100 csymbols = abfd->tdata.mmo_data->csymbols;
02101 if (csymbols == NULL)
02102 {
02103 asymbol *c;
02104 struct mmo_symbol *s;
02105 struct mmo_symbol **msp;
02106
02107
02108
02109
02110
02111 for (s = abfd->tdata.mmo_data->symbols,
02112 msp = (struct mmo_symbol **) alocation;
02113 s != NULL;
02114 s = s->next, ++msp)
02115 *msp = s;
02116
02117 *msp = NULL;
02118
02119 qsort (alocation, symcount, sizeof (struct mmo_symbol *),
02120 mmo_sort_mmo_symbols);
02121
02122 csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol));
02123 if (csymbols == NULL && symcount != 0)
02124 return FALSE;
02125 abfd->tdata.mmo_data->csymbols = csymbols;
02126
02127 for (msp = (struct mmo_symbol **) alocation, c = csymbols;
02128 *msp != NULL;
02129 msp++, ++c)
02130 {
02131 s = *msp;
02132 c->the_bfd = abfd;
02133 c->name = s->name;
02134 c->value = s->value;
02135 c->flags = BSF_GLOBAL;
02136
02137 if (s->sym_type == mmo_data_sym)
02138 {
02139 c->section
02140 = bfd_get_section_by_name (abfd, MMO_DATA_SECTION_NAME);
02141
02142 if (c->section == NULL)
02143 c->section = bfd_abs_section_ptr;
02144 else
02145 c->value -= c->section->vma;
02146 }
02147 else if (s->sym_type == mmo_undef_sym)
02148 c->section = bfd_und_section_ptr;
02149 else if (s->sym_type == mmo_reg_sym)
02150 {
02151 c->section
02152 = bfd_make_section_old_way (abfd, MMIX_REG_SECTION_NAME);
02153 }
02154 else
02155 {
02156 asection *textsec
02157 = bfd_get_section_by_name (abfd, MMO_TEXT_SECTION_NAME);
02158 asection *datasec;
02159
02160 if (textsec != NULL
02161 && c->value >= textsec->vma
02162 && c->value <= textsec->vma + textsec->size)
02163 {
02164 c->section = textsec;
02165 c->value -= c->section->vma;
02166 }
02167
02168
02169
02170
02171
02172
02173
02174 else if ((datasec
02175 = bfd_get_section_by_name (abfd,
02176 MMO_DATA_SECTION_NAME))
02177 != NULL
02178 && c->value >= datasec->vma
02179 && c->value <= datasec->vma + datasec->size)
02180 {
02181 c->section = datasec;
02182 c->value -= c->section->vma;
02183 }
02184 else
02185 c->section = bfd_abs_section_ptr;
02186 }
02187
02188 c->udata.p = NULL;
02189 }
02190 }
02191
02192
02193 for (i = 0; i < symcount; i++)
02194 *alocation++ = csymbols++;
02195 *alocation = NULL;
02196
02197 return symcount;
02198 }
02199
02200
02201
02202 static void
02203 mmo_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
02204 asymbol *symbol, symbol_info *ret)
02205 {
02206 bfd_symbol_info (symbol, ret);
02207 }
02208
02209 static void
02210 mmo_print_symbol (bfd *abfd, void *afile, asymbol *symbol,
02211 bfd_print_symbol_type how)
02212 {
02213 FILE *file = (FILE *) afile;
02214
02215 switch (how)
02216 {
02217 case bfd_print_symbol_name:
02218 fprintf (file, "%s", symbol->name);
02219 break;
02220 default:
02221 bfd_print_symbol_vandf (abfd, file, symbol);
02222
02223 fprintf (file, " %-5s %s",
02224 symbol->section->name,
02225 symbol->name);
02226 }
02227 }
02228
02229
02230
02231
02232 static int
02233 mmo_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
02234 bfd_boolean exec ATTRIBUTE_UNUSED)
02235 {
02236 return 0;
02237 }
02238
02239
02240
02241 static bfd_boolean
02242 mmo_internal_write_header (bfd *abfd)
02243 {
02244 const char lop_pre_bfd[] = { LOP, LOP_PRE, 1, 1};
02245
02246 if (bfd_bwrite (lop_pre_bfd, 4, abfd) != 4)
02247 return FALSE;
02248
02249
02250 if (bfd_bwrite (abfd->tdata.mmo_data->created, 4, abfd) != 4)
02251 return FALSE;
02252
02253 return TRUE;
02254 }
02255
02256
02257
02258
02259
02260
02261 static bfd_boolean
02262 mmo_internal_write_post (bfd *abfd, int z, asection *sec)
02263 {
02264 int i;
02265 bfd_byte buf[8];
02266 mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_POST << 16) | z);
02267
02268 for (i = z; i < 255; i++)
02269 {
02270 bfd_byte *data = mmo_get_loc (sec, i * 8, 8);
02271
02272 if (bfd_bwrite (data, 8, abfd) != 8)
02273 return FALSE;
02274 }
02275
02276
02277
02278
02279 bfd_put_64 (abfd, bfd_get_start_address (abfd), buf);
02280
02281 return ! abfd->tdata.mmo_data->have_error && bfd_bwrite (buf, 8, abfd) == 8;
02282 }
02283
02284
02285
02286
02287 static flagword
02288 mmo_sec_flags_from_bfd_flags (flagword flags)
02289 {
02290 flagword oflags = 0;
02291
02292 if (flags & SEC_ALLOC)
02293 oflags |= MMO_SEC_ALLOC;
02294 if (flags & SEC_LOAD)
02295 oflags |= MMO_SEC_LOAD;
02296 if (flags & SEC_RELOC)
02297 oflags |= MMO_SEC_RELOC;
02298 if (flags & SEC_READONLY)
02299 oflags |= MMO_SEC_READONLY;
02300 if (flags & SEC_CODE)
02301 oflags |= MMO_SEC_CODE;
02302 if (flags & SEC_DATA)
02303 oflags |= MMO_SEC_DATA;
02304 if (flags & SEC_NEVER_LOAD)
02305 oflags |= MMO_SEC_NEVER_LOAD;
02306 if (flags & SEC_IS_COMMON)
02307 oflags |= MMO_SEC_IS_COMMON;
02308 if (flags & SEC_DEBUGGING)
02309 oflags |= MMO_SEC_DEBUGGING;
02310
02311 return oflags;
02312 }
02313
02314 static flagword
02315 bfd_sec_flags_from_mmo_flags (flagword flags)
02316 {
02317 flagword oflags = 0;
02318
02319 if (flags & MMO_SEC_ALLOC)
02320 oflags |= SEC_ALLOC;
02321 if (flags & MMO_SEC_LOAD)
02322 oflags |= SEC_LOAD;
02323 if (flags & MMO_SEC_RELOC)
02324 oflags |= SEC_RELOC;
02325 if (flags & MMO_SEC_READONLY)
02326 oflags |= SEC_READONLY;
02327 if (flags & MMO_SEC_CODE)
02328 oflags |= SEC_CODE;
02329 if (flags & MMO_SEC_DATA)
02330 oflags |= SEC_DATA;
02331 if (flags & MMO_SEC_NEVER_LOAD)
02332 oflags |= SEC_NEVER_LOAD;
02333 if (flags & MMO_SEC_IS_COMMON)
02334 oflags |= SEC_IS_COMMON;
02335 if (flags & MMO_SEC_DEBUGGING)
02336 oflags |= SEC_DEBUGGING;
02337
02338 return oflags;
02339 }
02340
02341
02342
02343
02344 static bfd_boolean
02345 mmo_has_leading_or_trailing_zero_tetra_p (bfd *abfd, asection *sec)
02346 {
02347 bfd_vma secaddr = bfd_get_section_vma (abfd, sec);
02348
02349 if (sec->size < 4)
02350 return FALSE;
02351
02352 if (bfd_get_32 (abfd, mmo_get_loc (sec, secaddr, 4)) == 0
02353 && bfd_get_32 (abfd,
02354 mmo_get_loc (sec, secaddr + sec->size - 4, 4)) == 0)
02355 return TRUE;
02356
02357 return FALSE;
02358 }
02359
02360
02361
02362 static bfd_boolean
02363 mmo_internal_write_section (bfd *abfd, asection *sec)
02364 {
02365
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377 if (strcmp (sec->name, MMO_TEXT_SECTION_NAME) == 0)
02378 {
02379 bfd_vma secaddr = bfd_get_section_vma (abfd, sec);
02380
02381
02382
02383
02384
02385 if (sec->size != 0
02386 && (secaddr + sec->size >= (bfd_vma) 1 << 56
02387 || (secaddr & 3) != 0
02388 || (sec->size & 3) != 0
02389 || mmo_has_leading_or_trailing_zero_tetra_p (abfd, sec)))
02390 {
02391 if (!mmo_write_section_description (abfd, sec))
02392 return FALSE;
02393 }
02394
02395
02396 return mmo_write_loc_chunk_list (abfd, mmo_section_data (sec)->head);
02397 }
02398 else if (strcmp (sec->name, MMO_DATA_SECTION_NAME) == 0)
02399 {
02400 bfd_vma secaddr = bfd_get_section_vma (abfd, sec);
02401
02402
02403 if (sec->size != 0
02404 && (secaddr < (bfd_vma) 0x20 << 56
02405 || secaddr + sec->size >= (bfd_vma) 0x21 << 56
02406 || (secaddr & 3) != 0
02407 || (sec->size & 3) != 0
02408 || mmo_has_leading_or_trailing_zero_tetra_p (abfd, sec)))
02409 {
02410 if (!mmo_write_section_description (abfd, sec))
02411 return FALSE;
02412 }
02413
02414 return mmo_write_loc_chunk_list (abfd, mmo_section_data (sec)->head);
02415 }
02416 else if (strcmp (sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0)
02417
02418 {
02419
02420
02421 bfd_set_error (bfd_error_bad_value);
02422 return FALSE;
02423 }
02424 else if (strncmp (sec->name, MMIX_OTHER_SPEC_SECTION_PREFIX,
02425 strlen (MMIX_OTHER_SPEC_SECTION_PREFIX)) == 0)
02426 {
02427 int n = atoi (sec->name + strlen (MMIX_OTHER_SPEC_SECTION_PREFIX));
02428 mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_SPEC << 16) | n);
02429 return (! abfd->tdata.mmo_data->have_error
02430 && mmo_write_chunk_list (abfd, mmo_section_data (sec)->head));
02431 }
02432
02433
02434 else if ((bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS) != 0
02435 && sec->size != 0)
02436 {
02437 if (!mmo_write_section_description (abfd, sec))
02438 return FALSE;
02439
02440
02441
02442 if (bfd_get_section_flags (abfd, sec) & SEC_LOAD)
02443 return (! abfd->tdata.mmo_data->have_error
02444 && mmo_write_loc_chunk_list (abfd,
02445 mmo_section_data (sec)->head));
02446 return (! abfd->tdata.mmo_data->have_error
02447 && mmo_write_chunk_list (abfd, mmo_section_data (sec)->head));
02448 }
02449
02450
02451 return TRUE;
02452 }
02453
02454
02455
02456 static bfd_boolean
02457 mmo_write_section_description (bfd *abfd, asection *sec)
02458 {
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552 mmo_write_tetra_raw (abfd, LOP_SPEC_SECTION);
02553 mmo_write_tetra (abfd, (strlen (sec->name) + 3) / 4);
02554 mmo_write_chunk (abfd, (bfd_byte *) sec->name, strlen (sec->name));
02555 mmo_flush_chunk (abfd);
02556
02557
02558
02559
02560 mmo_write_tetra (abfd,
02561 mmo_sec_flags_from_bfd_flags
02562 (bfd_get_section_flags (abfd, sec)));
02563 mmo_write_octa (abfd, sec->size);
02564 mmo_write_octa (abfd, bfd_get_section_vma (abfd, sec));
02565 return TRUE;
02566 }
02567
02568
02569
02570 static bfd_boolean
02571 mmo_set_section_contents (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
02572 const void *location, file_ptr offset,
02573 bfd_size_type bytes_to_do)
02574 {
02575
02576 while (bytes_to_do)
02577 {
02578
02579
02580
02581 int chunk_size
02582 = (int) bytes_to_do != 0 ? bytes_to_do : MMO_SEC_CONTENTS_CHUNK_SIZE;
02583 bfd_byte *loc;
02584
02585 do
02586 loc = mmo_get_loc (sec, sec->vma + offset, chunk_size);
02587 while (loc == NULL && (chunk_size /= 2) != 0);
02588
02589 if (chunk_size == 0)
02590 return FALSE;
02591
02592 memcpy (loc, location, chunk_size);
02593
02594 location += chunk_size;
02595 bytes_to_do -= chunk_size;
02596 offset += chunk_size;
02597 }
02598 return TRUE;
02599 }
02600
02601
02602
02603 static bfd_boolean
02604 mmo_internal_add_3_sym (bfd *abfd, struct mmo_symbol_trie *rootp,
02605 const struct mmo_symbol *symp)
02606 {
02607 const char *name = symp->name;
02608 struct mmo_symbol_trie *trie = rootp;
02609 struct mmo_symbol_trie **triep = NULL;
02610
02611 while (*name && trie != NULL)
02612 {
02613 if (*name < trie->symchar)
02614 {
02615 triep = &trie->left;
02616 trie = trie->left;
02617 }
02618 else if (*name > trie->symchar)
02619 {
02620 triep = &trie->right;
02621 trie = trie->right;
02622 }
02623 else if (*name == trie->symchar)
02624 {
02625 triep = &trie->middle;
02626 name++;
02627
02628
02629
02630
02631
02632 if (*name)
02633 trie = trie->middle;
02634 }
02635 }
02636
02637 while (*name != 0)
02638 {
02639
02640 trie = bfd_zalloc (abfd, sizeof (struct mmo_symbol_trie));
02641 *triep = trie;
02642 trie->symchar = *name++;
02643 triep = &trie->middle;
02644 }
02645
02646
02647
02648 if (trie->sym.name != NULL)
02649 {
02650 (*_bfd_error_handler)
02651 (_("%s: invalid symbol table: duplicate symbol `%s'\n"),
02652 bfd_get_filename (abfd), trie->sym.name);
02653 bfd_set_error (bfd_error_bad_value);
02654 return FALSE;
02655 }
02656
02657 memcpy (&trie->sym, symp, sizeof *symp);
02658 return TRUE;
02659 }
02660
02661
02662
02663 static unsigned int
02664 mmo_internal_3_length (bfd *abfd, struct mmo_symbol_trie *trie)
02665 {
02666
02667 unsigned int length = 1;
02668
02669 if (trie == NULL)
02670 return 0;
02671
02672
02673 length += mmo_internal_3_length (abfd, trie->left);
02674
02675
02676 length += 1 + mmo_internal_3_length (abfd, trie->middle);
02677
02678
02679 length += mmo_internal_3_length (abfd, trie->right);
02680
02681
02682 if (trie->sym.name != NULL)
02683 {
02684 unsigned int serno = trie->sym.serno;
02685
02686
02687 if (trie->sym.sym_type == mmo_reg_sym)
02688 length++;
02689 else if (trie->sym.sym_type == mmo_undef_sym)
02690 length += 2;
02691 else
02692 {
02693 bfd_vma value = trie->sym.value;
02694
02695
02696 if (trie->sym.sym_type == mmo_data_sym)
02697 value -= (bfd_vma) 0x20 << 56;
02698
02699 do
02700 {
02701 value >>= 8;
02702 length++;
02703 }
02704 while (value != 0);
02705 }
02706
02707
02708 do
02709 {
02710 serno >>= 7;
02711 length++;
02712 }
02713 while (serno != 0);
02714 }
02715
02716 return length;
02717 }
02718
02719
02720
02721
02722
02723 static void
02724 mmo_beb128_out (bfd *abfd, int serno, int marker)
02725 {
02726 if (serno & ~0x7f)
02727 mmo_beb128_out (abfd, serno >> 7, 0);
02728 mmo_write_byte (abfd, marker | (serno & 0x7f));
02729 }
02730
02731
02732
02733 static void
02734 mmo_internal_3_dump (bfd *abfd, struct mmo_symbol_trie *trie)
02735 {
02736 bfd_byte control = 0;
02737
02738 if (trie == NULL)
02739 return;
02740
02741 if (trie->left)
02742 control |= MMO3_LEFT;
02743
02744 if (trie->middle)
02745 control |= MMO3_MIDDLE;
02746
02747 if (trie->right)
02748 control |= MMO3_RIGHT;
02749
02750 if (trie->sym.name != NULL)
02751 {
02752
02753 if (trie->sym.sym_type == mmo_reg_sym)
02754 control |= MMO3_REGQUAL_BITS;
02755 else if (trie->sym.sym_type == mmo_undef_sym)
02756 control |= MMO3_UNDEF;
02757 else
02758 {
02759 bfd_vma value = trie->sym.value;
02760
02761
02762 if (trie->sym.sym_type == mmo_data_sym)
02763 {
02764 control |= MMO3_DATA;
02765 value -= (bfd_vma) 0x20 << 56;
02766 }
02767
02768 do
02769 {
02770 value >>= 8;
02771 control++;
02772 }
02773 while (value != 0);
02774 }
02775 }
02776
02777
02778 mmo_write_byte (abfd, control);
02779
02780 mmo_internal_3_dump (abfd, trie->left);
02781
02782 if (control & MMO3_SYMBITS)
02783 {
02784 mmo_write_byte (abfd, trie->symchar);
02785
02786 if (trie->sym.name != NULL)
02787 {
02788 if (trie->sym.sym_type == mmo_reg_sym)
02789 mmo_write_byte (abfd, trie->sym.value);
02790 else if (trie->sym.sym_type == mmo_undef_sym)
02791 {
02792 mmo_write_byte (abfd, 0);
02793 mmo_write_byte (abfd, 0);
02794 }
02795 else
02796 {
02797 bfd_vma value = trie->sym.value;
02798
02799 bfd_byte byte_n = control & 15;
02800
02801
02802
02803 if (trie->sym.sym_type == mmo_data_sym)
02804 {
02805 value -= (bfd_vma) 0x20 << 56;
02806 byte_n -= 8;
02807 }
02808
02809 do
02810 {
02811 mmo_write_byte (abfd, (value >> ((byte_n - 1) * 8)) & 0xff);
02812 byte_n--;
02813 }
02814 while (byte_n != 0);
02815 }
02816
02817 mmo_beb128_out (abfd, trie->sym.serno, 128);
02818 }
02819 mmo_internal_3_dump (abfd, trie->middle);
02820 }
02821 mmo_internal_3_dump (abfd, trie->right);
02822 }
02823
02824
02825
02826 static bfd_boolean
02827 mmo_write_symbols_and_terminator (bfd *abfd)
02828 {
02829 int count = bfd_get_symcount (abfd);
02830 asymbol *maintable[2];
02831 asymbol **table;
02832 asymbol **orig_table = bfd_get_outsymbols (abfd);
02833 int serno;
02834 struct mmo_symbol_trie root;
02835 int trie_len;
02836 int i;
02837 bfd_byte buf[4];
02838
02839
02840 asymbol *fakemain = bfd_make_empty_symbol (abfd);
02841
02842 fakemain->flags = BSF_GLOBAL;
02843 fakemain->value = bfd_get_start_address (abfd);
02844 fakemain->name = MMIX_START_SYMBOL_NAME;
02845 fakemain->section = bfd_abs_section_ptr;
02846 maintable[0] = fakemain;
02847 maintable[1] = NULL;
02848
02849 memset (&root, 0, sizeof (root));
02850
02851
02852 root.symchar = 0xff;
02853
02854
02855
02856 table = bfd_alloc (abfd, (count + 1) * sizeof (asymbol *));
02857 if (table == NULL)
02858 return FALSE;
02859
02860 memcpy (table, orig_table, count * sizeof (asymbol *));
02861
02862
02863
02864
02865
02866
02867 for (i = 0; i < count; i++)
02868 if (table[i] != NULL
02869 && strcmp (table[i]->name, MMIX_START_SYMBOL_NAME) == 0
02870 && (table[i]->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL)
02871 {
02872 asymbol *mainsym = table[i];
02873 memcpy (table + 1, orig_table, i * sizeof (asymbol *));
02874 table[0] = mainsym;
02875
02876
02877
02878
02879 if ((mainsym->value
02880 + mainsym->section->output_section->vma
02881 + mainsym->section->output_offset)
02882 != bfd_get_start_address (abfd))
02883 {
02884
02885
02886 char vmas_main[40];
02887 char vmas_start[40];
02888 bfd_vma vma_start = bfd_get_start_address (abfd);
02889
02890 sprintf_vma (vmas_main, mainsym->value);
02891 sprintf_vma (vmas_start, vma_start);
02892
02893 (*_bfd_error_handler)
02894 (_("%s: Bad symbol definition: `Main' set to %s rather"
02895 " than the start address %s\n"),
02896 bfd_get_filename (abfd), vmas_main, vmas_start);
02897 bfd_set_error (bfd_error_bad_value);
02898 return FALSE;
02899 }
02900 break;
02901 }
02902 if (i == count && count != 0)
02903 {
02904
02905
02906 memcpy (table + 1, orig_table, count * sizeof (asymbol *));
02907 table[0] = fakemain;
02908 count++;
02909 }
02910
02911 for (i = 0, serno = 1; i < count && table[i] != NULL; i++)
02912 {
02913 asymbol *s = table[i];
02914
02915
02916
02917
02918
02919
02920 if ((s->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL
02921 && strspn (s->name,
02922 valid_mmo_symbol_character_set) == strlen (s->name))
02923 {
02924 struct mmo_symbol sym;
02925 memset (&sym, 0, sizeof (sym));
02926
02927
02928
02929 sym.name = (char *) s->name;
02930 sym.value =
02931 s->value
02932 + s->section->output_section->vma
02933 + s->section->output_offset;
02934
02935 if (bfd_is_und_section (s->section))
02936 sym.sym_type = mmo_undef_sym;
02937 else if (strcmp (s->section->name, MMO_DATA_SECTION_NAME) == 0
02938
02939
02940
02941
02942 && (sym.value >> 48) == 0x2000)
02943 sym.sym_type = mmo_data_sym;
02944 else if (strcmp (s->section->name, MMIX_REG_SECTION_NAME) == 0)
02945 sym.sym_type = mmo_reg_sym;
02946 else if (strcmp (s->section->name,
02947 MMIX_REG_CONTENTS_SECTION_NAME) == 0)
02948 {
02949 sym.sym_type = mmo_reg_sym;
02950 sym.value /= 8;
02951 }
02952 else
02953 sym.sym_type = mmo_abs_sym;
02954
02955
02956
02957
02958
02959
02960 sym.serno = serno++;
02961
02962 if (! mmo_internal_add_3_sym (abfd, &root, &sym))
02963 return FALSE;
02964 }
02965 }
02966
02967
02968 root.symchar = ':';
02969 root.middle = root.left;
02970 root.right = NULL;
02971 root.left = NULL;
02972
02973
02974
02975
02976 trie_len = (mmo_internal_3_length (abfd, &root) + 3)/4;
02977
02978 if (trie_len > 0xffff)
02979 {
02980
02981
02982
02983 struct mmo_symbol sym;
02984
02985 (*_bfd_error_handler)
02986 (_("%s: warning: symbol table too large for mmo, larger than 65535"
02987 " 32-bit words: %d. Only `Main' will be emitted.\n"),
02988 bfd_get_filename (abfd), trie_len);
02989
02990 memset (&sym, 0, sizeof (sym));
02991 sym.sym_type = mmo_abs_sym;
02992 sym.name = MMIX_START_SYMBOL_NAME;
02993 sym.serno = 1;
02994 sym.value = bfd_get_start_address (abfd);
02995
02996
02997 memset (&root, 0, sizeof (root));
02998 root.left = root.middle;
02999 root.symchar = 0xff;
03000 root.middle = NULL;
03001 root.right = NULL;
03002
03003 if (! mmo_internal_add_3_sym (abfd, &root, &sym))
03004 return FALSE;
03005
03006 root.symchar = ':';
03007 root.middle = root.left;
03008 root.right = NULL;
03009 root.left = NULL;
03010
03011 trie_len = (mmo_internal_3_length (abfd, &root) + 3)/4;
03012 }
03013
03014
03015 abfd->tdata.mmo_data->byte_no = 0;
03016
03017
03018 bfd_put_32 (abfd, (LOP << 24) | (LOP_STAB << 16), buf);
03019 if (bfd_bwrite (buf, 4, abfd) != 4)
03020 return FALSE;
03021
03022
03023 mmo_internal_3_dump (abfd, &root);
03024
03025 if (trie_len != (abfd->tdata.mmo_data->byte_no + 3)/4)
03026 {
03027
03028
03029
03030 (*_bfd_error_handler)
03031 (_("%s: internal error, symbol table changed size from %d to %d"
03032 " words\n"),
03033 bfd_get_filename (abfd), trie_len,
03034 (abfd->tdata.mmo_data->byte_no + 3)/4);
03035 bfd_set_error (bfd_error_bad_value);
03036 return FALSE;
03037 }
03038
03039
03040
03041 if ((abfd->tdata.mmo_data->byte_no % 4) != 0
03042 || abfd->tdata.mmo_data->have_error)
03043 {
03044 memset (abfd->tdata.mmo_data->buf + (abfd->tdata.mmo_data->byte_no % 4),
03045 0, 4 - (abfd->tdata.mmo_data->byte_no % 4));
03046
03047 if (abfd->tdata.mmo_data->have_error
03048 || bfd_bwrite (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
03049 return FALSE;
03050 }
03051
03052 bfd_put_32 (abfd, (LOP << 24) | (LOP_END << 16) | trie_len, buf);
03053 return bfd_bwrite (buf, 4, abfd) == 4;
03054 }
03055
03056
03057
03058
03059
03060 static void
03061 mmo_write_section_unless_reg_contents (bfd *abfd, asection *sec, void *p)
03062 {
03063 struct mmo_write_sec_info *infop = (struct mmo_write_sec_info *) p;
03064
03065 if (! infop->retval)
03066 return;
03067
03068 if (strcmp (sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0)
03069 {
03070 infop->reg_section = sec;
03071 return;
03072 }
03073
03074
03075 if (strcmp (sec->name, MMIX_REG_SECTION_NAME) == 0)
03076 {
03077 if (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
03078 {
03079
03080
03081
03082 (*_bfd_error_handler)
03083 (_("%s: internal error, internal register section %s had"
03084 " contents\n"),
03085 bfd_get_filename (abfd), sec->name);
03086 bfd_set_error (bfd_error_bad_value);
03087 infop->retval = FALSE;
03088 return;
03089 }
03090
03091 return;
03092 }
03093
03094 infop->retval = mmo_internal_write_section (abfd, sec);
03095 }
03096
03097
03098
03099
03100 static bfd_boolean
03101 mmo_write_object_contents (bfd *abfd)
03102 {
03103 struct mmo_write_sec_info wsecinfo;
03104
03105
03106 if (! mmo_internal_write_header (abfd))
03107 return FALSE;
03108
03109 wsecinfo.reg_section = NULL;
03110 wsecinfo.retval = TRUE;
03111
03112 bfd_map_over_sections (abfd, mmo_write_section_unless_reg_contents,
03113 &wsecinfo);
03114
03115 if (! wsecinfo.retval)
03116 return FALSE;
03117
03118 if (wsecinfo.reg_section != NULL)
03119 {
03120 asection *sec = wsecinfo.reg_section;
03121 unsigned int z = (unsigned int) (sec->vma / 8);
03122
03123
03124
03125
03126 if (z < 32 || z >= 255 || (sec->vma & 7) != 0
03127 || sec->vma != 256 * 8 - sec->size - 8)
03128 {
03129 bfd_set_error (bfd_error_bad_value);
03130
03131 if (sec->size == 0)
03132
03133 (*_bfd_error_handler)
03134 (_("%s: no initialized registers; section length 0\n"),
03135 bfd_get_filename (abfd));
03136 else if (sec->vma > (256 - 32) * 8)
03137
03138
03139 (*_bfd_error_handler)
03140 (_("%s: too many initialized registers; section length %ld\n"),
03141 bfd_get_filename (abfd),
03142 (long) sec->size);
03143 else
03144 (*_bfd_error_handler)
03145 (_("%s: invalid start address for initialized registers of"
03146 " length %ld: 0x%lx%08lx\n"),
03147 bfd_get_filename (abfd),
03148 (long) sec->size,
03149 (unsigned long) (sec->vma >> 32), (unsigned long) (sec->vma));
03150
03151 return FALSE;
03152 }
03153
03154 if (! mmo_internal_write_post (abfd, z, sec))
03155 return FALSE;
03156 }
03157 else
03158 if (! mmo_internal_write_post (abfd, 255, NULL))
03159 return FALSE;
03160
03161 return mmo_write_symbols_and_terminator (abfd);
03162 }
03163
03164
03165
03166
03167 static long
03168 mmo_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED,
03169 asection *sec ATTRIBUTE_UNUSED)
03170 {
03171 return sizeof (void *);
03172 }
03173
03174
03175
03176
03177 long
03178 mmo_canonicalize_reloc (bfd *abfd ATTRIBUTE_UNUSED,
03179 sec_ptr section ATTRIBUTE_UNUSED, arelent **relptr,
03180 asymbol **symbols ATTRIBUTE_UNUSED)
03181 {
03182 *relptr = NULL;
03183 return 0;
03184 }
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194 #define mmo_close_and_cleanup _bfd_generic_close_and_cleanup
03195 #define mmo_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
03196
03197
03198
03199 #define mmo_bfd_is_local_label_name bfd_generic_is_local_label_name
03200 #define mmo_bfd_is_target_special_symbol \
03201 ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
03202
03203
03204 #define mmo_get_lineno _bfd_nosymbols_get_lineno
03205
03206
03207
03208 #define mmo_find_nearest_line _bfd_nosymbols_find_nearest_line
03209 #define mmo_make_empty_symbol _bfd_generic_make_empty_symbol
03210 #define mmo_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
03211 #define mmo_read_minisymbols _bfd_generic_read_minisymbols
03212 #define mmo_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
03213
03214 #define mmo_get_section_contents_in_window \
03215 _bfd_generic_get_section_contents_in_window
03216 #define mmo_bfd_get_relocated_section_contents \
03217 bfd_generic_get_relocated_section_contents
03218 #define mmo_bfd_gc_sections bfd_generic_gc_sections
03219 #define mmo_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
03220 #define mmo_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
03221 #define mmo_bfd_link_add_symbols _bfd_generic_link_add_symbols
03222 #define mmo_bfd_link_just_syms _bfd_generic_link_just_syms
03223 #define mmo_bfd_final_link _bfd_generic_final_link
03224 #define mmo_bfd_link_split_section _bfd_generic_link_split_section
03225
03226
03227
03228 #define mmo_set_arch_mach bfd_default_set_arch_mach
03229 #define mmo_bfd_relax_section bfd_generic_relax_section
03230 #define mmo_bfd_merge_sections bfd_generic_merge_sections
03231 #define mmo_bfd_is_group_section bfd_generic_is_group_section
03232 #define mmo_bfd_discard_group bfd_generic_discard_group
03233 #define mmo_section_already_linked \
03234 _bfd_generic_section_already_linked
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246 #define mmo_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
03247
03248
03249
03250 #define mmo_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
03251 #define mmo_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
03252 #define mmo_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
03253 #define mmo_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
03254 #define mmo_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
03255 #define mmo_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data
03256
03257 const bfd_target bfd_mmo_vec =
03258 {
03259 "mmo",
03260 bfd_target_mmo_flavour,
03261 BFD_ENDIAN_BIG,
03262 BFD_ENDIAN_BIG,
03263
03264
03265 (HAS_RELOC | EXEC_P |
03266 HAS_LINENO | HAS_DEBUG |
03267 HAS_SYMS | HAS_LOCALS | WP_TEXT),
03268
03269
03270 (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
03271 | SEC_READONLY | SEC_EXCLUDE | SEC_DEBUGGING | SEC_IN_MEMORY),
03272
03273 0,
03274 ' ',
03275 16,
03276 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
03277 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
03278 bfd_getb16, bfd_getb_signed_16, bfd_putb16,
03279 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
03280 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
03281 bfd_getb16, bfd_getb_signed_16, bfd_putb16,
03282
03283 {
03284 _bfd_dummy_target,
03285 mmo_object_p,
03286 _bfd_dummy_target,
03287 _bfd_dummy_target,
03288 },
03289 {
03290 bfd_false,
03291 mmo_mkobject,
03292 bfd_false,
03293 bfd_false,
03294 },
03295 {
03296 bfd_false,
03297 mmo_write_object_contents,
03298 bfd_false,
03299 bfd_false,
03300 },
03301
03302 BFD_JUMP_TABLE_GENERIC (mmo),
03303 BFD_JUMP_TABLE_COPY (mmo),
03304 BFD_JUMP_TABLE_CORE (_bfd_nocore),
03305 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
03306 BFD_JUMP_TABLE_SYMBOLS (mmo),
03307
03308
03309 BFD_JUMP_TABLE_RELOCS (mmo),
03310 BFD_JUMP_TABLE_WRITE (mmo),
03311 BFD_JUMP_TABLE_LINK (mmo),
03312 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
03313
03314 NULL,
03315
03316 NULL
03317 };