aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>1998-11-17 03:18:06 +0000
committerDJ Delorie <dj@redhat.com>1998-11-17 03:18:06 +0000
commitd3ca9a538c9305de81734d296c5ddcca8e5fa3ed (patch)
treeba98ae83b0f44041a57758dcf0a426a3e66d18a9 /ld
parent67c72211ac4c9251a34a81ae8f0a14b85257aea8 (diff)
downloadgdb-d3ca9a538c9305de81734d296c5ddcca8e5fa3ed.zip
gdb-d3ca9a538c9305de81734d296c5ddcca8e5fa3ed.tar.gz
gdb-d3ca9a538c9305de81734d296c5ddcca8e5fa3ed.tar.bz2
* emultempl/pe.em (gld_i386_finish): generate import library
* deffile.h: add hint member. * pe-dll.c (pe_dll_generate_implib): New function with helpers; generates the import library directly from the export table. (fill_edata): remember the actual hint for the import library.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog8
-rw-r--r--ld/emultempl/pe.em27
-rw-r--r--ld/pe-dll.c469
3 files changed, 497 insertions, 7 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index d1ce60a..52e1866 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,11 @@
+Mon Nov 16 22:14:07 1998 DJ Delorie <dj@cygnus.com>
+
+ * emultempl/pe.em (gld_i386_finish): generate import library
+ * deffile.h: add hint member.
+ * pe-dll.c (pe_dll_generate_implib): New function with helpers;
+ generates the import library directly from the export table.
+ (fill_edata): remember the actual hint for the import library.
+
Sat Nov 14 14:36:24 1998 Ian Lance Taylor <ian@cygnus.com>
* ld.1: Some cleanups from NOKUBI Hirotaka <hnokubi@yyy.or.jp>.
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 34f6f7a..d241837 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -70,6 +70,7 @@ int pe_dll_do_default_excludes = 1;
int pe_dll_kill_ats = 0;
int pe_dll_stdcall_aliases = 0;
int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */
+static char *pe_implib_filename = 0;
extern const char *output_filename;
@@ -108,6 +109,7 @@ gld_${EMULATION_NAME}_before_parse()
#define OPTION_STDCALL_ALIASES (OPTION_KILL_ATS + 1)
#define OPTION_ENABLE_STDCALL_FIXUP (OPTION_STDCALL_ALIASES + 1)
#define OPTION_DISABLE_STDCALL_FIXUP (OPTION_ENABLE_STDCALL_FIXUP + 1)
+#define OPTION_IMPLIB_FILENAME (OPTION_DISABLE_STDCALL_FIXUP + 1)
static struct option longopts[] =
{
@@ -127,6 +129,7 @@ static struct option longopts[] =
{"stack", required_argument, NULL, OPTION_STACK},
{"subsystem", required_argument, NULL, OPTION_SUBSYSTEM},
{"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE},
+#ifdef TARGET_IS_i386pe
/* getopt allows abbreviations, so we do this to stop it from treating -o
as an abbreviation for this option */
{"output-def", required_argument, NULL, OPTION_OUT_DEF},
@@ -137,6 +140,8 @@ static struct option longopts[] =
{"add-stdcall-alias", no_argument, NULL, OPTION_STDCALL_ALIASES},
{"enable-stdcall-fixup", no_argument, NULL, OPTION_ENABLE_STDCALL_FIXUP},
{"disable-stdcall-fixup", no_argument, NULL, OPTION_DISABLE_STDCALL_FIXUP},
+ {"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME},
+#endif
{NULL, no_argument, NULL, 0}
};
@@ -198,13 +203,16 @@ gld_${EMULATION_NAME}_list_options (file)
fprintf (file, _(" --stack <size> Set size of the initial stack\n"));
fprintf (file, _(" --subsystem <name>[:<version>] Set required OS subsystem [& version]\n"));
fprintf (file, _(" --support-old-code Support interworking with old code\n"));
- fprintf (file, _(" --output-def <file> Generate a .DEF file for the built DLL\n"));
- fprintf (file, _(" --export-all-symbols Automatically export all globals to DLL\n"));
- fprintf (file, _(" --exclude-symbols sym,sym,... Exclude symbols from automatic export\n"));
- fprintf (file, _(" --kill-at Remove @nn from exported symbols\n"));
+#ifdef TARGET_IS_i386pe
fprintf (file, _(" --add-stdcall-alias Export symbols with and without @nn\n"));
- fprintf (file, _(" --enable-stdcall-fixup Link _sym to _sym@nn without warnings\n"));
fprintf (file, _(" --disable-stdcall-fixup Don't link _sym to _sym@nn\n"));
+ fprintf (file, _(" --enable-stdcall-fixup Link _sym to _sym@nn without warnings\n"));
+ fprintf (file, _(" --exclude-symbols sym,sym,... Exclude symbols from automatic export\n"));
+ fprintf (file, _(" --export-all-symbols Automatically export all globals to DLL\n"));
+ fprintf (file, _(" --kill-at Remove @nn from exported symbols\n"));
+ fprintf (file, _(" --out-implib <file> Generate import library\n"));
+ fprintf (file, _(" --output-def <file> Generate a .DEF file for the built DLL\n"));
+#endif
}
static void
@@ -424,6 +432,9 @@ gld_${EMULATION_NAME}_parse_args(argc, argv)
case OPTION_DISABLE_STDCALL_FIXUP:
pe_enable_stdcall_fixup = 0;
break;
+ case OPTION_IMPLIB_FILENAME:
+ pe_implib_filename = xstrdup (optarg);
+ break;
}
return 1;
}
@@ -773,7 +784,11 @@ gld_${EMULATION_NAME}_finish ()
{
#ifdef TARGET_IS_i386pe
if (link_info.shared)
- pe_dll_fill_sections (output_bfd, &link_info);
+ {
+ pe_dll_fill_sections (output_bfd, &link_info);
+ if (pe_implib_filename)
+ pe_dll_generate_implib (pe_def_file, pe_implib_filename);
+ }
if (pe_out_def_filename)
pe_dll_generate_def_file (pe_out_def_filename);
#endif
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index 51520c4..fddf42f 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -515,7 +515,7 @@ fill_edata (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
- int i;
+ int i, hint;
unsigned char *edirectory;
unsigned long *eaddresses;
unsigned long *enameptrs;
@@ -550,6 +550,7 @@ fill_edata (abfd, info)
bfd_put_32 (abfd, ERVA (eordinals), edata_d + 36);
/* Ok, now for the filling in part */
+ hint = 0;
for (i = 0; i < export_table_size; i++)
{
int s = exported_symbols[i];
@@ -569,6 +570,7 @@ fill_edata (abfd, info)
enamestr += strlen (enamestr) + 1;
bfd_put_16 (abfd, i, (void *) eordinals);
enameptrs++;
+ pe_def_file->exports[s].hint = hint++;
}
eordinals++;
}
@@ -896,6 +898,471 @@ pe_dll_generate_def_file (pe_out_def_filename)
/************************************************************************
+ Generate the import library
+
+ ************************************************************************/
+
+static asymbol **symtab;
+static int symptr;
+static int tmp_seq;
+static const char *dll_filename;
+static char *dll_symname;
+
+static asection *
+quick_section(abfd, name, flags, align)
+ bfd *abfd;
+ const char *name;
+ int flags;
+ int align;
+{
+ asection *sec;
+ asymbol *sym;
+
+ sec = bfd_make_section_old_way(abfd, name);
+ sec->output_section = sec;
+ bfd_set_section_flags (abfd, sec, flags);
+ bfd_set_section_alignment (abfd, sec, align);
+
+ sym = bfd_make_empty_symbol(abfd);
+ symtab[symptr++] = sym;
+ sym->name = sec->name;
+ sym->section = sec;
+ sym->flags = BSF_LOCAL;
+ sym->value = 0;
+
+ return sec;
+}
+
+static void
+quick_symbol (abfd, n1, n2, n3, sec, flags, addr)
+ bfd *abfd;
+ char *n1;
+ char *n2;
+ char *n3;
+ asection *sec;
+ int flags;
+ int addr;
+{
+ asymbol *sym = bfd_make_empty_symbol(abfd);
+ char *name = (char *) xmalloc (strlen(n1) + strlen(n2) + strlen(n3) + 1);
+ strcpy (name, n1);
+ strcat (name, n2);
+ strcat (name, n3);
+ sym->name = name;
+ sym->section = sec;
+ sym->flags = flags;
+ sym->value = addr;
+ symtab[symptr++] = sym;
+}
+
+static arelent **reltab = 0;
+static int relcount = 0, relsize = 0;
+
+static void
+quick_reloc (abfd, address, which_howto, symidx)
+ bfd *abfd;
+ int address;
+ int which_howto;
+ int symidx;
+{
+ if (relcount >= (relsize-1))
+ {
+ relsize += 10;
+ if (reltab)
+ reltab = (arelent **) xrealloc (reltab, relsize * sizeof (arelent *));
+ else
+ reltab = (arelent **) xmalloc (relsize * sizeof (arelent *));
+ }
+ reltab[relcount] = (arelent *) xmalloc (sizeof (arelent));
+ reltab[relcount]->address = address;
+ reltab[relcount]->addend = 0;
+ reltab[relcount]->howto = bfd_reloc_type_lookup (abfd, which_howto);
+ reltab[relcount]->sym_ptr_ptr = symtab + symidx;
+ relcount++;
+}
+
+static void
+save_relocs (asection *sec)
+{
+ reltab[relcount] = 0;
+ sec->orelocation = reltab;
+ sec->reloc_count = relcount;
+ reltab = 0;
+ relcount = relsize = 0;
+}
+
+#define UNDSEC (asection *) &bfd_und_section
+
+/*
+ * .section .idata$2
+ * .global __head_my_dll
+ * __head_my_dll:
+ * .rva hname
+ * .long 0
+ * .long 0
+ * .rva __my_dll_iname
+ * .rva fthunk
+ *
+ * .section .idata$5
+ * .long 0
+ * fthunk:
+ *
+ * .section .idata$4
+ * .long 0
+ * hname:
+ */
+
+#define BFD_OPEN_OLDWAY 0
+
+bfd *
+make_head (parent)
+ bfd *parent;
+{
+ asection *id2, *id5, *id4;
+ unsigned char *d2, *d5, *d4;
+
+#if BFD_OPEN_OLDWAY
+ bfd *abfd = bfd_openw ("dh.o", 0);
+#else
+ bfd *abfd = bfd_create ("dh.o", parent);
+ bfd_make_writable (abfd);
+#endif
+ bfd_set_format (abfd, bfd_object);
+ bfd_set_arch_mach (abfd, bfd_arch_i386, 0);
+
+ symptr = 0;
+ symtab = (asymbol **) xmalloc (6 * sizeof (asymbol *));
+ id2 = quick_section(abfd, ".idata$2", SEC_HAS_CONTENTS, 2);
+ id5 = quick_section(abfd, ".idata$5", SEC_HAS_CONTENTS, 2);
+ id4 = quick_section(abfd, ".idata$4", SEC_HAS_CONTENTS, 2);
+ quick_symbol (abfd, "__head_", dll_symname, "", id2, BSF_GLOBAL, 0);
+ quick_symbol (abfd, "_", dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0);
+
+ bfd_set_section_size(abfd, id2, 20);
+ d2 = (unsigned char *) xmalloc (20);
+ memset (d2, 0, 20);
+ d2[0] = d2[16] = 4; /* reloc addend */
+ quick_reloc(abfd, 0, BFD_RELOC_RVA, 2);
+ quick_reloc(abfd, 12, BFD_RELOC_RVA, 4);
+ quick_reloc(abfd, 16, BFD_RELOC_RVA, 1);
+ save_relocs(id2);
+
+ bfd_set_section_size (abfd, id5, 4);
+ d5 = (unsigned char *) xmalloc (4);
+ memset (d5, 0, 4);
+
+ bfd_set_section_size (abfd, id4, 4);
+ d4 = (unsigned char *) xmalloc (4);
+ memset (d4, 0, 4);
+
+ bfd_set_symtab(abfd, symtab, symptr);
+
+ bfd_set_section_contents(abfd, id2, d2, 0, 20);
+ bfd_set_section_contents(abfd, id5, d5, 0, 4);
+ bfd_set_section_contents(abfd, id4, d4, 0, 4);
+
+#if BFD_OPEN_OLDWAY
+ bfd_close (abfd);
+ return bfd_openr("dh.o", 0);
+#else
+ bfd_make_readable (abfd);
+ return abfd;
+#endif
+}
+
+/*
+ * .section .idata$4
+ * .long 0
+ * .section .idata$5
+ * .long 0
+ * .section idata$7
+ * .global __my_dll_iname
+ *__my_dll_iname:
+ * .asciz "my.dll"
+ */
+
+bfd *
+make_tail (parent)
+ bfd *parent;
+{
+ asection *id4, *id5, *id7;
+ unsigned char *d4, *d5, *d7;
+ int len;
+
+#if BFD_OPEN_OLDWAY
+ bfd *abfd = bfd_openw ("dt.o", 0);
+#else
+ bfd *abfd = bfd_create ("dt.o", parent);
+ bfd_make_writable (abfd);
+#endif
+ bfd_set_format (abfd, bfd_object);
+ bfd_set_arch_mach (abfd, bfd_arch_i386, 0);
+
+ symptr = 0;
+ symtab = (asymbol **) xmalloc (5 * sizeof (asymbol *));
+ id4 = quick_section(abfd, ".idata$4", SEC_HAS_CONTENTS, 2);
+ id5 = quick_section(abfd, ".idata$5", SEC_HAS_CONTENTS, 2);
+ id7 = quick_section(abfd, ".idata$7", SEC_HAS_CONTENTS, 2);
+ quick_symbol (abfd, "_", dll_symname, "_iname", id7, BSF_GLOBAL, 0);
+
+ bfd_set_section_size(abfd, id4, 4);
+ d4 = (unsigned char *) xmalloc (4);
+ memset (d4, 0, 4);
+
+ bfd_set_section_size (abfd, id5, 4);
+ d5 = (unsigned char *) xmalloc (4);
+ memset (d5, 0, 4);
+
+ len = strlen(dll_filename)+1;
+ if (len & 1)
+ len ++;
+ bfd_set_section_size (abfd, id7, len);
+ d7 = (unsigned char *) xmalloc (len);
+ strcpy (d7, dll_filename);
+
+ bfd_set_symtab(abfd, symtab, symptr);
+
+ bfd_set_section_contents(abfd, id4, d4, 0, 4);
+ bfd_set_section_contents(abfd, id5, d5, 0, 4);
+ bfd_set_section_contents(abfd, id7, d7, 0, len);
+
+#if BFD_OPEN_OLDWAY
+ bfd_close (abfd);
+ return bfd_openr ("dt.o", 0);
+#else
+ bfd_make_readable (abfd);
+ return abfd;
+#endif
+}
+
+/*
+ * .text
+ * .global _function
+ * .global ___imp_function
+ * .global __imp__function
+ *_function:
+ * jmp *__imp__function:
+ *
+ * .section idata$7
+ * .long __head_my_dll
+ *
+ * .section .idata$5
+ *___imp_function:
+ *__imp__function:
+ *iat?
+ * .section .idata$4
+ *iat?
+ * .section .idata$6
+ *ID<ordinal>:
+ * .short <hint>
+ * .asciz "function" xlate? (add underscore, kill at)
+ */
+
+unsigned char jmp_ix86_bytes[] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90
+};
+
+
+bfd *
+make_one (exp, parent)
+ def_file_export *exp;
+ bfd *parent;
+{
+ asection *tx, *id7, *id5, *id4, *id6;
+ unsigned char *td, *d7, *d5, *d4, *d6;
+ int len;
+ char *oname;
+ bfd *abfd;
+
+ oname = (char *) xmalloc (20);
+ sprintf(oname, "ds%d.o", tmp_seq);
+ tmp_seq++;
+#if BFD_OPEN_OLDWAY
+ abfd = bfd_openw (oname, 0);
+#else
+ abfd = bfd_create (oname, parent);
+ bfd_make_writable (abfd);
+#endif
+ bfd_set_format (abfd, bfd_object);
+ bfd_set_arch_mach (abfd, bfd_arch_i386, 0);
+
+ symptr = 0;
+ symtab = (asymbol **) xmalloc (10 * sizeof (asymbol *));
+ tx = quick_section(abfd, ".text", SEC_CODE|SEC_HAS_CONTENTS, 2);
+ id7 = quick_section(abfd, ".idata$7", SEC_HAS_CONTENTS, 2);
+ id5 = quick_section(abfd, ".idata$5", SEC_HAS_CONTENTS, 2);
+ id4 = quick_section(abfd, ".idata$4", SEC_HAS_CONTENTS, 2);
+ id6 = quick_section(abfd, ".idata$6", SEC_HAS_CONTENTS, 2);
+ quick_symbol (abfd, "_", exp->name, "", tx, BSF_GLOBAL, 0);
+ quick_symbol (abfd, "__head_", dll_symname, "", UNDSEC, BSF_GLOBAL, 0);
+ quick_symbol (abfd, "___imp_", exp->name, "", id5, BSF_GLOBAL, 0);
+ quick_symbol (abfd, "__imp__", exp->name, "", id5, BSF_GLOBAL, 0);
+
+ bfd_set_section_size (abfd, tx, 8);
+ td = (unsigned char *) xmalloc (8);
+ memcpy (td, jmp_ix86_bytes, 8);
+ quick_reloc (abfd, 2, BFD_RELOC_32, 2);
+ save_relocs (tx);
+
+ bfd_set_section_size(abfd, id7, 4);
+ d7 = (unsigned char *) xmalloc (4);
+ memset (d7, 0, 4);
+ quick_reloc (abfd, 0, BFD_RELOC_RVA, 6);
+ save_relocs (id7);
+
+ bfd_set_section_size (abfd, id5, 4);
+ d5 = (unsigned char *) xmalloc (4);
+ memset (d5, 0, 4);
+ if (exp->flag_noname)
+ {
+ d5[0] = exp->ordinal;
+ d5[1] = exp->ordinal >> 8;
+ d5[3] = 0x80;
+ }
+ else
+ {
+ quick_reloc (abfd, 0, BFD_RELOC_RVA, 4);
+ save_relocs (id5);
+ }
+
+ bfd_set_section_size (abfd, id4, 4);
+ d4 = (unsigned char *) xmalloc (4);
+ memset (d4, 0, 4);
+ if (exp->flag_noname)
+ {
+ d5[0] = exp->ordinal;
+ d5[1] = exp->ordinal >> 8;
+ d5[3] = 0x80;
+ }
+ else
+ {
+ quick_reloc (abfd, 0, BFD_RELOC_RVA, 4);
+ save_relocs (id4);
+ }
+
+ if (exp->flag_noname)
+ {
+ len = 0;
+ bfd_set_section_size(abfd, id6, 0);
+ }
+ else
+ {
+ len = strlen(exp->name) + 3;
+ if (len & 1)
+ len++;
+ bfd_set_section_size(abfd, id6, len);
+ d6 = (unsigned char *) xmalloc (len);
+ memset (d6, 0, len);
+ d6[0] = exp->hint & 0xff;
+ d6[1] = exp->hint >> 8;
+ strcpy(d6+2, exp->name);
+ }
+
+ bfd_set_symtab(abfd, symtab, symptr);
+
+ bfd_set_section_contents(abfd, tx, td, 0, 8);
+ bfd_set_section_contents(abfd, id7, d7, 0, 4);
+ bfd_set_section_contents(abfd, id5, d5, 0, 4);
+ bfd_set_section_contents(abfd, id4, d4, 0, 4);
+ bfd_set_section_contents(abfd, id6, d6, 0, len);
+
+#if BFD_OPEN_OLDWAY
+ bfd_close(abfd);
+ return bfd_openr(oname, 0);
+#else
+ bfd_make_readable (abfd);
+ return abfd;
+#endif
+}
+
+void
+pe_dll_generate_implib (def, impfilename)
+ def_file *def;
+ char *impfilename;
+{
+ int i;
+ /*export_type *exp;*/
+ bfd *ar_head;
+ bfd *ar_tail;
+ bfd *outarch;
+ bfd * head = 0;
+
+ dll_filename = def->name;
+ if (dll_filename == 0)
+ {
+ dll_filename = dll_name;
+ for (i=0; impfilename[i]; i++)
+ if (impfilename[i] == '/' || impfilename[i] == '\\')
+ dll_filename = impfilename+1;
+ }
+ dll_symname = xstrdup (dll_filename);
+ for (i=0; dll_symname[i]; i++)
+ if (!isalnum (dll_symname[i]))
+ dll_symname[i] = '_';
+
+ unlink (impfilename);
+
+ outarch = bfd_openw (impfilename, 0);
+
+ if (!outarch)
+ {
+ /* xgettext:c-format */
+ einfo (_("%XCan't open .lib file: %s\n"), impfilename);
+ return;
+ }
+
+ /* xgettext:c-format */
+ einfo (_("Creating library file: %s\n"), impfilename);
+
+ bfd_set_format (outarch, bfd_archive);
+ outarch->has_armap = 1;
+
+ /* Work out a reasonable size of things to put onto one line. */
+
+ ar_head = make_head (outarch);
+ ar_tail = make_tail (outarch);
+
+ if (ar_head == NULL || ar_tail == NULL)
+ return;
+
+ for (i = 0; i<def->num_exports; i++)
+ {
+ bfd *n = make_one (def->exports+i, outarch);
+ n->next = head;
+ head = n;
+ }
+
+ /* Now stick them all into the archive */
+
+ ar_head->next = head;
+ ar_tail->next = ar_head;
+ head = ar_tail;
+
+ if (! bfd_set_archive_head (outarch, head))
+ einfo ("%Xbfd_set_archive_head: %s\n", bfd_errmsg (bfd_get_error ()));
+
+ if (! bfd_close (outarch))
+ einfo ("%Xbfd_close %s: %s\n", impfilename, bfd_errmsg (bfd_get_error ()));
+
+ while (head != NULL)
+ {
+ bfd *n = head->next;
+ bfd_close (head);
+ head = n;
+ }
+
+ unlink ("dh.o");
+ unlink ("dt.o");
+ for (i=0; i<tmp_seq; i++)
+ {
+ char buf[20];
+ sprintf (buf, "ds%d.o", i);
+ unlink (buf);
+ }
+}
+
+/************************************************************************
+
These are the main functions, called from the emulation. The first
is called after the bfds are read, so we can guess at how much space
we need. The second is called after everything is placed, so we