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