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 #define TARGET_PAGE_SIZE 4096
00026 #define ZMAGIC_DISK_BLOCK_SIZE 1024
00027 #define SEGMENT_SIZE TARGET_PAGE_SIZE
00028 #define TEXT_START_ADDR 0x0
00029 #define N_SHARED_LIB(x) 0
00030
00031 #define MACHTYPE_OK(mtype) ((mtype) == M_68020 || (mtype) == M_UNKNOWN)
00032
00033 #include "bfd.h"
00034 #include "sysdep.h"
00035 #include "libbfd.h"
00036 #include "aout/aout64.h"
00037 #include "aout/stab_gnu.h"
00038 #include "aout/ar.h"
00039 #include "libaout.h"
00040
00041 #define TARGET_IS_BIG_ENDIAN_P
00042 #define DEFAULT_ARCH bfd_arch_m68k
00043
00044
00045
00046
00047 #define MY(OP) CONCAT2 (m68klinux_,OP)
00048 #define TARGETNAME "a.out-m68k-linux"
00049
00050 extern const bfd_target MY(vec);
00051
00052
00053
00054
00055
00056 static void MY_final_link_callback
00057 PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
00058 static bfd_boolean m68klinux_bfd_final_link
00059 PARAMS ((bfd *, struct bfd_link_info *));
00060 static bfd_boolean m68klinux_write_object_contents PARAMS ((bfd *));
00061
00062 static bfd_boolean
00063 m68klinux_bfd_final_link (abfd, info)
00064 bfd *abfd;
00065 struct bfd_link_info *info;
00066 {
00067 obj_aout_subformat (abfd) = q_magic_format;
00068 return NAME(aout,final_link) (abfd, info, MY_final_link_callback);
00069 }
00070
00071 #define MY_bfd_final_link m68klinux_bfd_final_link
00072
00073
00074
00075 static bfd_boolean
00076 m68klinux_write_object_contents (abfd)
00077 bfd *abfd;
00078 {
00079 struct external_exec exec_bytes;
00080 struct internal_exec *execp = exec_hdr (abfd);
00081
00082 N_SET_MACHTYPE (*execp, M_68020);
00083
00084 obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
00085
00086 WRITE_HEADERS(abfd, execp);
00087
00088 return TRUE;
00089 }
00090
00091 #define MY_write_object_contents m68klinux_write_object_contents
00092
00093
00094
00095
00096
00097 #ifndef GOT_REF_PREFIX
00098 #define GOT_REF_PREFIX "__GOT_"
00099 #endif
00100
00101 #define IS_GOT_SYM(name) \
00102 (strncmp (name, GOT_REF_PREFIX, sizeof GOT_REF_PREFIX - 1) == 0)
00103
00104
00105
00106 #ifndef PLT_REF_PREFIX
00107 #define PLT_REF_PREFIX "__PLT_"
00108 #endif
00109
00110 #define IS_PLT_SYM(name) \
00111 (strncmp (name, PLT_REF_PREFIX, sizeof PLT_REF_PREFIX - 1) == 0)
00112
00113
00114
00115 #ifndef NEEDS_SHRLIB
00116 #define NEEDS_SHRLIB "__NEEDS_SHRLIB_"
00117 #endif
00118
00119
00120
00121
00122
00123
00124
00125
00126 #ifndef SHARABLE_CONFLICTS
00127 #define SHARABLE_CONFLICTS "__SHARABLE_CONFLICTS__"
00128 #endif
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 struct fixup
00141 {
00142 struct fixup *next;
00143 struct linux_link_hash_entry *h;
00144 bfd_vma value;
00145
00146
00147
00148 char jump;
00149
00150 char builtin;
00151 };
00152
00153
00154
00155
00156
00157 struct linux_link_hash_entry
00158 {
00159 struct aout_link_hash_entry root;
00160 };
00161
00162 struct linux_link_hash_table
00163 {
00164 struct aout_link_hash_table root;
00165
00166
00167 bfd *dynobj;
00168
00169
00170 size_t fixup_count;
00171
00172
00173 size_t local_builtins;
00174
00175
00176 struct fixup *fixup_list;
00177 };
00178
00179 static struct bfd_hash_entry *linux_link_hash_newfunc
00180 PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
00181 static struct bfd_link_hash_table *linux_link_hash_table_create
00182 PARAMS ((bfd *));
00183 static struct fixup *new_fixup
00184 PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *,
00185 bfd_vma, int));
00186 static bfd_boolean linux_link_create_dynamic_sections
00187 PARAMS ((bfd *, struct bfd_link_info *));
00188 static bfd_boolean linux_add_one_symbol
00189 PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *,
00190 bfd_vma, const char *, bfd_boolean, bfd_boolean,
00191 struct bfd_link_hash_entry **));
00192 static bfd_boolean linux_tally_symbols
00193 PARAMS ((struct linux_link_hash_entry *, PTR));
00194 static bfd_boolean linux_finish_dynamic_link
00195 PARAMS ((bfd *, struct bfd_link_info *));
00196
00197
00198
00199 static struct bfd_hash_entry *
00200 linux_link_hash_newfunc (entry, table, string)
00201 struct bfd_hash_entry *entry;
00202 struct bfd_hash_table *table;
00203 const char *string;
00204 {
00205 struct linux_link_hash_entry *ret = (struct linux_link_hash_entry *) entry;
00206
00207
00208
00209 if (ret == (struct linux_link_hash_entry *) NULL)
00210 ret = ((struct linux_link_hash_entry *)
00211 bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry)));
00212 if (ret == NULL)
00213 return (struct bfd_hash_entry *) ret;
00214
00215
00216 ret = ((struct linux_link_hash_entry *)
00217 NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret,
00218 table, string));
00219 if (ret != NULL)
00220 {
00221
00222 }
00223
00224 return (struct bfd_hash_entry *) ret;
00225 }
00226
00227
00228
00229 static struct bfd_link_hash_table *
00230 linux_link_hash_table_create (abfd)
00231 bfd *abfd;
00232 {
00233 struct linux_link_hash_table *ret;
00234 bfd_size_type amt = sizeof (struct linux_link_hash_table);
00235
00236 ret = (struct linux_link_hash_table *) bfd_malloc (amt);
00237 if (ret == (struct linux_link_hash_table *) NULL)
00238 {
00239 bfd_set_error (bfd_error_no_memory);
00240 return (struct bfd_link_hash_table *) NULL;
00241 }
00242 if (! NAME(aout,link_hash_table_init) (&ret->root, abfd,
00243 linux_link_hash_newfunc))
00244 {
00245 free (ret);
00246 return (struct bfd_link_hash_table *) NULL;
00247 }
00248
00249 ret->dynobj = NULL;
00250 ret->fixup_count = 0;
00251 ret->local_builtins = 0;
00252 ret->fixup_list = NULL;
00253
00254 return &ret->root.root;
00255 }
00256
00257
00258
00259 #define linux_link_hash_lookup(table, string, create, copy, follow) \
00260 ((struct linux_link_hash_entry *) \
00261 aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\
00262 (follow)))
00263
00264
00265
00266 #define linux_link_hash_traverse(table, func, info) \
00267 (aout_link_hash_traverse \
00268 (&(table)->root, \
00269 (bfd_boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \
00270 (info)))
00271
00272
00273
00274
00275 #define linux_hash_table(p) ((struct linux_link_hash_table *) ((p)->hash))
00276
00277
00278
00279 static struct fixup *
00280 new_fixup (info, h, value, builtin)
00281 struct bfd_link_info *info;
00282 struct linux_link_hash_entry *h;
00283 bfd_vma value;
00284 int builtin;
00285 {
00286 struct fixup *f;
00287
00288 f = (struct fixup *) bfd_hash_allocate (&info->hash->table,
00289 sizeof (struct fixup));
00290 if (f == NULL)
00291 return f;
00292 f->next = linux_hash_table (info)->fixup_list;
00293 linux_hash_table (info)->fixup_list = f;
00294 f->h = h;
00295 f->value = value;
00296 f->builtin = builtin;
00297 f->jump = 0;
00298 ++linux_hash_table (info)->fixup_count;
00299 return f;
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309 static bfd_boolean
00310 linux_link_create_dynamic_sections (abfd, info)
00311 bfd *abfd;
00312 struct bfd_link_info *info ATTRIBUTE_UNUSED;
00313 {
00314 flagword flags;
00315 register asection *s;
00316
00317
00318 flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
00319
00320
00321
00322 s = bfd_make_section (abfd, ".linux-dynamic");
00323 if (s == NULL
00324 || ! bfd_set_section_flags (abfd, s, flags)
00325 || ! bfd_set_section_alignment (abfd, s, 2))
00326 return FALSE;
00327 s->size = 0;
00328 s->contents = 0;
00329
00330 return TRUE;
00331 }
00332
00333
00334
00335
00336
00337 static bfd_boolean
00338 linux_add_one_symbol (info, abfd, name, flags, section, value, string,
00339 copy, collect, hashp)
00340 struct bfd_link_info *info;
00341 bfd *abfd;
00342 const char *name;
00343 flagword flags;
00344 asection *section;
00345 bfd_vma value;
00346 const char *string;
00347 bfd_boolean copy;
00348 bfd_boolean collect;
00349 struct bfd_link_hash_entry **hashp;
00350 {
00351 struct linux_link_hash_entry *h;
00352 bfd_boolean insert;
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 insert = FALSE;
00363
00364 if (! info->relocatable
00365 && linux_hash_table (info)->dynobj == NULL
00366 && strcmp (name, SHARABLE_CONFLICTS) == 0
00367 && (flags & BSF_CONSTRUCTOR) != 0
00368 && abfd->xvec == info->hash->creator)
00369 {
00370 if (! linux_link_create_dynamic_sections (abfd, info))
00371 return FALSE;
00372 linux_hash_table (info)->dynobj = abfd;
00373 insert = TRUE;
00374 }
00375
00376 if (bfd_is_abs_section (section)
00377 && abfd->xvec == info->hash->creator)
00378 {
00379 h = linux_link_hash_lookup (linux_hash_table (info), name, FALSE,
00380 FALSE, FALSE);
00381 if (h != NULL
00382 && (h->root.root.type == bfd_link_hash_defined
00383 || h->root.root.type == bfd_link_hash_defweak))
00384 {
00385 struct fixup *f;
00386
00387 if (hashp != NULL)
00388 *hashp = (struct bfd_link_hash_entry *) h;
00389
00390 f = new_fixup (info, h, value, ! IS_PLT_SYM (name));
00391 if (f == NULL)
00392 return FALSE;
00393 f->jump = IS_PLT_SYM (name);
00394
00395 return TRUE;
00396 }
00397 }
00398
00399
00400 if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
00401 value, string, copy, collect,
00402 hashp))
00403 return FALSE;
00404
00405
00406
00407 if (insert)
00408 {
00409 asection *s;
00410
00411
00412
00413 s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
00414 ".linux-dynamic");
00415 BFD_ASSERT (s != NULL);
00416
00417 if (! (_bfd_generic_link_add_one_symbol
00418 (info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS,
00419 BSF_GLOBAL | BSF_CONSTRUCTOR, s, (bfd_vma) 0, NULL,
00420 FALSE, FALSE, NULL)))
00421 return FALSE;
00422 }
00423
00424 return TRUE;
00425 }
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 static bfd_boolean
00438 linux_tally_symbols (h, data)
00439 struct linux_link_hash_entry *h;
00440 PTR data;
00441 {
00442 struct bfd_link_info *info = (struct bfd_link_info *) data;
00443 struct fixup *f, *f1;
00444 int is_plt;
00445 struct linux_link_hash_entry *h1, *h2;
00446 bfd_boolean exists;
00447
00448 if (h->root.root.type == bfd_link_hash_warning)
00449 h = (struct linux_link_hash_entry *) h->root.root.u.i.link;
00450
00451 if (h->root.root.type == bfd_link_hash_undefined
00452 && strncmp (h->root.root.root.string, NEEDS_SHRLIB,
00453 sizeof NEEDS_SHRLIB - 1) == 0)
00454 {
00455 const char *name;
00456 char *p;
00457 char *alloc = NULL;
00458
00459 name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1;
00460 p = strrchr (name, '_');
00461 if (p != NULL)
00462 alloc = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 1);
00463
00464 if (p == NULL || alloc == NULL)
00465 (*_bfd_error_handler) (_("Output file requires shared library `%s'\n"),
00466 name);
00467 else
00468 {
00469 strcpy (alloc, name);
00470 p = strrchr (alloc, '_');
00471 *p++ = '\0';
00472 (*_bfd_error_handler)
00473 (_("Output file requires shared library `%s.so.%s'\n"),
00474 alloc, p);
00475 free (alloc);
00476 }
00477
00478 abort ();
00479 }
00480
00481
00482 is_plt = IS_PLT_SYM (h->root.root.root.string);
00483
00484 if (is_plt || IS_GOT_SYM (h->root.root.root.string))
00485 {
00486
00487
00488
00489 h1 = linux_link_hash_lookup (linux_hash_table (info),
00490 (h->root.root.root.string
00491 + sizeof PLT_REF_PREFIX - 1),
00492 FALSE, FALSE, TRUE);
00493
00494 h2 = linux_link_hash_lookup (linux_hash_table (info),
00495 (h->root.root.root.string
00496 + sizeof PLT_REF_PREFIX - 1),
00497 FALSE, FALSE, FALSE);
00498
00499
00500
00501
00502
00503
00504
00505 if (h1 != NULL
00506 && (((h1->root.root.type == bfd_link_hash_defined
00507 || h1->root.root.type == bfd_link_hash_defweak)
00508 && ! bfd_is_abs_section (h1->root.root.u.def.section))
00509 || h2->root.root.type == bfd_link_hash_indirect))
00510 {
00511
00512
00513
00514
00515 exists = FALSE;
00516 for (f1 = linux_hash_table (info)->fixup_list;
00517 f1 != NULL;
00518 f1 = f1->next)
00519 {
00520 if ((f1->h != h && f1->h != h1)
00521 || (! f1->builtin && ! f1->jump))
00522 continue;
00523 if (f1->h == h1)
00524 exists = TRUE;
00525 if (! exists
00526 && bfd_is_abs_section (h->root.root.u.def.section))
00527 {
00528 f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0);
00529 f->jump = is_plt;
00530 }
00531 f1->h = h1;
00532 f1->jump = is_plt;
00533 f1->builtin = 0;
00534 exists = TRUE;
00535 }
00536 if (! exists
00537 && bfd_is_abs_section (h->root.root.u.def.section))
00538 {
00539 f = new_fixup (info, h1, h->root.root.u.def.value, 0);
00540 if (f == NULL)
00541 {
00542
00543 abort ();
00544 }
00545 f->jump = is_plt;
00546 }
00547 }
00548
00549
00550
00551 if (bfd_is_abs_section (h->root.root.u.def.section))
00552 h->root.written = TRUE;
00553 }
00554
00555 return TRUE;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564 bfd_boolean
00565 bfd_m68klinux_size_dynamic_sections (output_bfd, info)
00566 bfd *output_bfd;
00567 struct bfd_link_info *info;
00568 {
00569 struct fixup *f;
00570 asection *s;
00571
00572 if (output_bfd->xvec != &MY(vec))
00573 return TRUE;
00574
00575
00576 linux_link_hash_traverse (linux_hash_table (info),
00577 linux_tally_symbols,
00578 (PTR) info);
00579
00580
00581
00582
00583 for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
00584 {
00585 if (f->builtin)
00586 {
00587 ++linux_hash_table (info)->fixup_count;
00588 ++linux_hash_table (info)->local_builtins;
00589 break;
00590 }
00591 }
00592
00593 if (linux_hash_table (info)->dynobj == NULL)
00594 {
00595 if (linux_hash_table (info)->fixup_count > 0)
00596 abort ();
00597 return TRUE;
00598 }
00599
00600
00601 s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
00602 ".linux-dynamic");
00603 if (s != NULL)
00604 {
00605 s->size = linux_hash_table (info)->fixup_count + 1;
00606 s->size *= 8;
00607 s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->size);
00608 if (s->contents == NULL)
00609 {
00610 bfd_set_error (bfd_error_no_memory);
00611 return FALSE;
00612 }
00613 }
00614
00615 return TRUE;
00616 }
00617
00618
00619
00620
00621
00622 static bfd_boolean
00623 linux_finish_dynamic_link (output_bfd, info)
00624 bfd *output_bfd;
00625 struct bfd_link_info *info;
00626 {
00627 asection *s, *os, *is;
00628 bfd_byte *fixup_table;
00629 struct linux_link_hash_entry *h;
00630 struct fixup *f;
00631 unsigned int new_addr;
00632 int section_offset;
00633 unsigned int fixups_written;
00634
00635 if (linux_hash_table (info)->dynobj == NULL)
00636 return TRUE;
00637
00638 s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
00639 ".linux-dynamic");
00640 BFD_ASSERT (s != NULL);
00641 os = s->output_section;
00642 fixups_written = 0;
00643
00644 #ifdef LINUX_LINK_DEBUG
00645 printf ("Fixup table file offset: %x VMA: %x\n",
00646 os->filepos + s->output_offset,
00647 os->vma + s->output_offset);
00648 #endif
00649
00650 fixup_table = s->contents;
00651 bfd_put_32 (output_bfd, (bfd_vma) linux_hash_table (info)->fixup_count,
00652 fixup_table);
00653 fixup_table += 4;
00654
00655
00656 for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
00657 {
00658 if (f->builtin)
00659 continue;
00660
00661 if (f->h->root.root.type != bfd_link_hash_defined
00662 && f->h->root.root.type != bfd_link_hash_defweak)
00663 {
00664 (*_bfd_error_handler)
00665 (_("Symbol %s not defined for fixups\n"),
00666 f->h->root.root.root.string);
00667 continue;
00668 }
00669
00670 is = f->h->root.root.u.def.section;
00671 section_offset = is->output_section->vma + is->output_offset;
00672 new_addr = f->h->root.root.u.def.value + section_offset;
00673
00674 #ifdef LINUX_LINK_DEBUG
00675 printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string,
00676 new_addr, f->value);
00677 #endif
00678
00679 if (f->jump)
00680 {
00681 bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
00682 fixup_table += 4;
00683 bfd_put_32 (output_bfd, f->value + 2, fixup_table);
00684 fixup_table += 4;
00685 }
00686 else
00687 {
00688 bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
00689 fixup_table += 4;
00690 bfd_put_32 (output_bfd, f->value, fixup_table);
00691 fixup_table += 4;
00692 }
00693 ++fixups_written;
00694 }
00695
00696 if (linux_hash_table (info)->local_builtins != 0)
00697 {
00698
00699 bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
00700 fixup_table += 4;
00701 bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
00702 fixup_table += 4;
00703 ++fixups_written;
00704 for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
00705 {
00706 if (! f->builtin)
00707 continue;
00708
00709 if (f->h->root.root.type != bfd_link_hash_defined
00710 && f->h->root.root.type != bfd_link_hash_defweak)
00711 {
00712 (*_bfd_error_handler)
00713 (_("Symbol %s not defined for fixups\n"),
00714 f->h->root.root.root.string);
00715 continue;
00716 }
00717
00718 is = f->h->root.root.u.def.section;
00719 section_offset = is->output_section->vma + is->output_offset;
00720 new_addr = f->h->root.root.u.def.value + section_offset;
00721
00722 #ifdef LINUX_LINK_DEBUG
00723 printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string,
00724 new_addr, f->value);
00725 #endif
00726
00727 bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
00728 fixup_table += 4;
00729 bfd_put_32 (output_bfd, f->value, fixup_table);
00730 fixup_table += 4;
00731 ++fixups_written;
00732 }
00733 }
00734
00735 if (linux_hash_table (info)->fixup_count != fixups_written)
00736 {
00737 (*_bfd_error_handler) (_("Warning: fixup count mismatch\n"));
00738 while (linux_hash_table (info)->fixup_count > fixups_written)
00739 {
00740 bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
00741 fixup_table += 4;
00742 bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
00743 fixup_table += 4;
00744 ++fixups_written;
00745 }
00746 }
00747
00748 h = linux_link_hash_lookup (linux_hash_table (info),
00749 "__BUILTIN_FIXUPS__",
00750 FALSE, FALSE, FALSE);
00751
00752 if (h != NULL
00753 && (h->root.root.type == bfd_link_hash_defined
00754 || h->root.root.type == bfd_link_hash_defweak))
00755 {
00756 is = h->root.root.u.def.section;
00757 section_offset = is->output_section->vma + is->output_offset;
00758 new_addr = h->root.root.u.def.value + section_offset;
00759
00760 #ifdef LINUX_LINK_DEBUG
00761 printf ("Builtin fixup table at %x\n", new_addr);
00762 #endif
00763
00764 bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
00765 }
00766 else
00767 bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
00768
00769 if (bfd_seek (output_bfd, (file_ptr) (os->filepos + s->output_offset),
00770 SEEK_SET) != 0)
00771 return FALSE;
00772
00773 if (bfd_bwrite ((PTR) s->contents, s->size, output_bfd) != s->size)
00774 return FALSE;
00775
00776 return TRUE;
00777 }
00778
00779 #define MY_bfd_link_hash_table_create linux_link_hash_table_create
00780 #define MY_add_one_symbol linux_add_one_symbol
00781 #define MY_finish_dynamic_link linux_finish_dynamic_link
00782
00783 #define MY_zmagic_contiguous 1
00784
00785 #include "aout-target.h"