* 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.
This commit is contained in:
DJ Delorie 1998-11-17 03:18:06 +00:00
parent 67c72211ac
commit d3ca9a538c
3 changed files with 497 additions and 7 deletions

View file

@ -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>.

View file

@ -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

View file

@ -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++;
}
@ -894,6 +896,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