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