Wed Jun 14 13:27:22 1995 Steve Chamberlain <sac@slash.cygnus.com>
authorSteve Chamberlain <sac@cygnus>
Wed, 14 Jun 1995 20:28:36 +0000 (20:28 +0000)
committerSteve Chamberlain <sac@cygnus>
Wed, 14 Jun 1995 20:28:36 +0000 (20:28 +0000)
* deflex.l, defparse.y, dlltool.c: New files.
* Makefile.in, configure.in: Support for them.

Mon Jun 12 11:27:54 1995  Steve Chamberlain  <sac@slash.cygnus.com>

* sysdump.c: Include sysdep.h
(main): Open input with FOPEN_RB.  binutils/7137

binutils/.Sanitize
binutils/ChangeLog
binutils/defparse.y [new file with mode: 0644]
binutils/dlltool.c [new file with mode: 0644]

index df81854..197cced 100644 (file)
@@ -45,6 +45,9 @@ config
 configure.bat
 configure.in
 cxxfilt.man
+dlltool.c
+defparse.y
+deflex.l
 filemode.c
 gmalloc.c
 is-ranlib.c
index 04840a8..8661090 100644 (file)
@@ -1,3 +1,13 @@
+Wed Jun 14 13:27:22 1995  Steve Chamberlain  <sac@slash.cygnus.com>
+
+       * deflex.l, defparse.y, dlltool.c: New files.
+       * Makefile.in, configure.in: Support for them.
+
+Mon Jun 12 11:27:54 1995  Steve Chamberlain  <sac@slash.cygnus.com>
+
+       * sysdump.c: Include sysdep.h
+       (main): Open input with FOPEN_RB.  binutils/7137
+
 Fri Jun  9 17:26:11 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
 
        * objdump.c (wide_output): New flag variable.
diff --git a/binutils/defparse.y b/binutils/defparse.y
new file mode 100644 (file)
index 0000000..4a9ca39
--- /dev/null
@@ -0,0 +1,135 @@
+{
+/* defparse.y - parser for .def files */
+
+/*   Copyright (C) 1995 Free Software Foundation, Inc.
+
+This file is part of GNU Binutils.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+%union {
+  char *id;
+  int number;
+char *string;
+};
+
+%token NAME, LIBRARY, DESCRIPTION, STACKSIZE, HEAPSIZE, CODE, DATA
+%token SECTIONS, EXPORTS, IMPORTS, VERSION, BASE, CONSTANT
+%token READ WRITE EXECUTE SHARED NONAME
+%token <id> ID
+%token <string> STRING
+%token <number> NUMBER
+%type  <number> opt_base opt_ordinal opt_NONAME opt_CONSTANT attr attr_list opt_number
+%type  <id> opt_name opt_equal_name 
+
+%%
+
+start: start command
+       | command
+       ;
+
+command: 
+               NAME opt_name opt_base { def_name ($2, $3); }
+       |       LIBRARY opt_name opt_base { def_library ($2, $3); }
+       |       EXPORTS explist 
+       |       DESCRIPTION STRING { def_description ($2);}
+       |       STACKSIZE NUMBER opt_number { def_stacksize ($2, $3);}
+       |       HEAPSIZE NUMBER opt_number { def_heapsize ($2, $3);}
+       |       CODE attr_list { def_code ($2);}
+       |       DATA attr_list  { def_data ($2);}
+       |       SECTIONS seclist
+       |       IMPORTS implist
+       |       VERSION NUMBER { def_version ($2,0);}
+       |       VERSION NUMBER '.' NUMBER { def_version ($2,$4);}
+       ;
+
+
+explist:
+               explist expline
+       |       expline
+       ;
+
+expline:
+               ID opt_equal_name opt_ordinal opt_NONAME opt_CONSTANT
+                       { def_exports ($1, $2, $3, $4, $5);}
+       ;
+implist:       
+               implist impline
+       |       impline
+       ;
+
+impline:
+               ID '=' ID '.' ID { def_import ($1,$3,$5);}
+       |       ID '.' ID        { def_import (0, $1,$3);}
+       ;
+seclist:
+               seclist secline
+       |       secline
+       ;
+
+secline:
+       ID attr_list { def_section ($1,$2);}
+       ;
+
+attr_list:
+       attr_list opt_comma attr
+       | attr
+       ;
+
+opt_comma:
+       ','
+       | 
+       ;
+opt_number: ',' NUMBER { $$=$2;}
+       |          { $$=-1;}
+       ;
+       
+attr:
+               READ { $$ = 1;}
+       |       WRITE { $$ = 2;}        
+       |       EXECUTE { $$=4;}
+       |       SHARED { $$=8;}
+       ;
+
+opt_CONSTANT:
+               CONSTANT {$$=1;}
+       |                {$$=0;}
+       ;
+opt_NONAME:
+               NONAME {$$=1;}
+       |                {$$=0;}
+       ;
+
+opt_name: ID           { $$ =$1; }
+       |               { $$=""; }
+       ;
+
+opt_ordinal: 
+         '@' NUMBER     { $$=$2;}
+       |                { $$=-1;}
+       ;
+
+opt_equal_name:
+          '=' ID       { $$ = $2; }
+        |              { $$ =  0; }                     
+       ;
+
+opt_base: BASE '=' NUMBER      { $$= $3;}
+       |       { $$=-1;}
+       ;
+
+       
+
diff --git a/binutils/dlltool.c b/binutils/dlltool.c
new file mode 100644 (file)
index 0000000..69fe91f
--- /dev/null
@@ -0,0 +1,1016 @@
+/* dlltool.c -- tool to generate stuff for PE style DLLs 
+   Copyright (C) 1995 Free Software Foundation, Inc.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/*
+   This program allows you to build the files necessary to create
+   DLLs to run on a system which understands PE format image files.
+   (eg, Windows NT)
+
+   A DLL contains an export table which contains the information
+   which the runtime loader needs to tie up references from a
+   referencing program. 
+
+   The export table is generated by this program by reading
+   in a .DEF file or scanning the .a and .o files which will be in the
+   DLL.  A .o file can contain information in special  ".drective" sections
+   with export information.  
+
+   A DEF file contains any number of the following commands:
+
+
+   NAME <name> [ , <base> ] 
+                The result is going to be <name>.EXE
+
+   LIBRARY <name> [ , <base> ]    
+                The result is going to be <name>.DLL
+
+   EXPORTS  ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) *
+                Declares name1 as an exported symbol from the
+               DLL, with optional ordinal number <integer>
+
+   IMPORTS  ( [ <name> = ] <name> . <name> ) *
+               Ignored for compatibility
+
+   DESCRIPTION <string>
+               Puts <string> into output .exp file in the .rdata section
+
+   [STACKSIZE|HEAPSIZE] <number-reserve> [ , <number-commit> ]
+               Generates --stack|--heap <number-reserve>,<number-commit>
+               in the output .drective section.  The linker will
+               see this and act upon it.
+
+   [CODE|DATA] <attr>+
+   SECTIONS ( <sectionname> <attr>+ )*
+     <attr> = READ | WRITE | EXECUTE | SHARED
+               Generates --attr <sectionname> <attr> in the output
+               .drective section.  The linker will see this and act
+               upon it.
+
+
+   A -export:<name> in a .drective section in an input .o or .a
+   file to this program is equivalent to a EXPORTS <name>
+   in a .DEF file.
+
+
+
+  The program generates output files with the prefix supplied
+  on the command line, or in the def file, or taken from the first 
+  supplied argument.
+
+  The output files are <prefix>.exp.s and <prefix>.lib.s
+
+  The .exp.s file contains the information necessary to export
+  the routines in the DLL.  The .lib.s file contains the information
+  necessary to use the DLL's routines from a referencing program.
+
+
+
+Example:
+
+file1.c: 
+       asm (".section .drectve");  
+       asm (".ascii \"-export:adef\"");
+
+       adef(char *s)
+         {
+         printf("hello from the dll %s\n",s);
+         }
+
+        bdef(char *s)
+         {
+         printf("hello from the dll and the other entry point %s\n",s);
+        }
+
+file2.c:
+       asm (".section .drectve");
+       asm (".ascii \"-export:cdef\"");
+       asm (".ascii \"-export:ddef\"");
+       cdef(char *s)
+       {
+       printf("hello from the dll %s\n",s);
+       }
+
+       ddef(char *s)
+       {
+       printf("hello from the dll and the other entry point %s\n",s);
+       }
+
+       printf()
+       {
+       return 9;
+       }
+
+main.c
+
+       main()
+       {
+         cdef();
+       }
+
+thedll.def
+
+       LIBRARY thedll
+       HEAPSIZE 0x40000, 0x2000
+       EXPORTS bdef @ 20
+               cdef @ 30 NONAME 
+
+       SECTIONS donkey READ WRITE
+                aardvark EXECUTE
+
+
+# compile up the parts of the dll
+
+gcc -c file1.c 
+gcc -c file2.c
+
+# put them in a library (you don't have to, you
+# could name all the .os on the dlltool line)
+
+ar  qcv thedll.in file1.o file2.o
+ranlib thedll.in
+
+# run this tool over the library and the def file
+./dlltool -o thedll -d thedll.def thedll.in
+
+# build the export table for the dll
+as -o thedll.exp thedll.exp.s
+# build the dll with the library with file1.o, file2.o and the export table
+ld -o thedll.dll thedll.exp thedll.in
+
+# build the import table for the executable
+as -o thedll.lib thedll.lib.s
+
+# build the mainline
+gcc -c themain.c 
+
+# link the executable with the import library
+ld -e main -Tthemain.ld -o themain.exe themain.o thedll.lib
+
+
+*/
+   
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+#include "bfd.h"
+int yydebug;
+char *def_file;
+char *program_name;
+char *strrchr ();
+char *outfile_prefix;
+char *xmalloc ();
+char *strdup ();
+
+static int machine;
+
+#ifdef DLLTOOL_ARM
+static char *mname  = "arm";
+#endif
+
+#ifdef DLLTOOL_I386
+static char *mname  = "i386";
+#endif
+
+struct mac
+{
+  char *type;
+  char *how_byte;
+  char *how_short;
+  char *how_long;
+  char *how_asciz;
+  char *how_comment;
+  char *how_jump;
+  char *how_global;
+  char *how_space;
+} mtable[]
+= {{"arm",".byte",".short",".long",".asciz","@","bl",".global",".space"},
+   {"i386",".byte",".short",".long",".asciz",";","jmp",".global",".space"},
+ 0};
+
+#define ASM_BYTE       mtable[machine].how_byte
+#define ASM_SHORT      mtable[machine].how_short
+#define ASM_LONG       mtable[machine].how_long
+#define ASM_TEXT       mtable[machine].how_asciz
+#define ASM_C          mtable[machine].how_comment
+#define ASM_JUMP       mtable[machine].how_jump
+#define ASM_GLOBAL     mtable[machine].how_global
+#define ASM_SPACE      mtable[machine].how_space
+
+#define PATHMAX 250            /* What's the right name for this ? */
+static char **oav;
+
+int i;
+
+FILE *yyin;                    /* communications with flex */
+extern int linenumber;
+void
+process_def_file (name)
+     char *name;
+{
+  FILE *f = fopen (name, "r");
+  if (!f)
+    {
+      fprintf (stderr, "Can't open def file %s\n", name);
+      exit (1);
+    }
+
+  yyin = f;
+
+  yyparse ();
+}
+
+/**********************************************************************/
+
+/* Communications with the parser */
+
+
+typedef struct dlist
+{
+  char *text;
+  struct dlist *next;
+} dlist_type;
+
+typedef struct export
+{
+  char *name;
+  char *equal;
+  int ordinal;
+  int constant;
+  int noname;
+  struct export *next;
+}
+export_type;
+
+static char *d_name;           /* Arg to NAME or LIBRARY */
+static int d_nfuncs;           /* Number of functions exported */
+static int d_ord;              /* Base ordinal index */
+static export_type *d_exports; /*list of exported functions */
+static char *d_suffix = "dll";
+static dlist_type *d_list; /* Descriptions */
+static dlist_type *a_list;  /* Stuff to go in directives */
+
+static int d_is_dll;
+static int d_is_exe;
+
+yyerror ()
+{
+  fprintf (stderr, "Syntax error in def file %s:%d\n",
+          def_file, linenumber);
+}
+
+void
+def_exports (name, equal, ordinal, noname, constant)
+     char *name;
+     char *equal;
+     int ordinal;
+     int noname;
+     int constant;
+{
+  struct export *p = (struct export *) xmalloc (sizeof (*p));
+
+  p->name = name;
+  p->equal = equal;
+  p->ordinal = ordinal;
+  p->constant = constant;
+  p->noname = noname;
+  p->next = d_exports;
+  d_exports = p;
+  d_nfuncs++;
+
+
+  printf ("EXPORTS %s", name);
+  if (equal)
+    printf ("=%s", equal);
+  if (ordinal > 0)
+    printf ("@%d", ordinal);
+  if (constant)
+    printf (" CONSTANT");
+  printf ("\n");
+}
+
+void
+def_name (name, base)
+     char *name;
+     int base;
+{
+  printf ("NAME %s base %x\n", name, base);
+  if (d_is_dll)
+    {
+      fprintf (stderr, "Can't have LIBRARY and NAME\n");
+    }
+  d_name = name;
+  if (strchr (d_name, '.'))
+    d_suffix = strdup (strchr (d_name, '.') + 1);
+  d_is_exe = 1;
+}
+
+void
+def_library (name, base)
+     char *name;
+     int base;
+{
+  printf ("LIBRARY %s base %x\n", name, base);
+  if (d_is_exe)
+    {
+      fprintf (stderr, "Can't have LIBRARY and NAME\n");
+    }
+  d_name = name;
+  if (strchr (d_name, '.'))
+    d_suffix = strdup (strchr (d_name, '.') + 1);
+  d_is_dll = 1;
+}
+
+void
+def_description (desc)
+     char *desc;
+{
+  dlist_type *d = (dlist_type *)xmalloc(sizeof(dlist_type));
+  d->text = strdup (desc);
+  d->next = d_list;
+  d_list = d;
+}
+
+void new_directive(dir)
+char *dir;
+{
+  dlist_type *d = (dlist_type *)xmalloc(sizeof(dlist_type));
+  d->text = strdup (dir);
+  d->next = a_list;
+  a_list = d;
+}
+
+void
+def_stacksize (reserve, commit)
+     int reserve;
+     int commit;
+{
+  char b[200];
+  if (commit>0)
+    sprintf (b,"-stack 0x%x,0x%x ", reserve, commit);
+  else 
+    sprintf (b,"-stack 0x%x ", reserve);
+  new_directive (strdup(b));
+}
+
+void
+def_heapsize (reserve, commit)
+     int reserve;
+     int commit;
+{
+  char b[200];
+  if (commit>0)
+    sprintf (b,"-heap 0x%x,0x%x ", reserve, commit);
+  else 
+    sprintf (b,"-heap 0x%x ", reserve);
+  new_directive (strdup(b));
+}
+
+
+void
+def_import (internal, module, entry)
+     char *internal;
+     char *module;
+     char *entry;
+{
+  fprintf (stderr, "IMPORTS are ignored");
+}
+
+void
+def_version (major, minor)
+{
+  printf ("VERSION %d.%d\n", major, minor);
+}
+
+
+void
+def_section (name, attr)
+     char *name;
+     int attr;
+{
+  char buf[200];
+  char  atts[5];
+  char *d = atts;
+  if (attr & 1)
+    *d++= 'R';
+
+  if (attr & 2)
+    *d++ = 'W';
+  if (attr & 4)
+    *d++ = 'X';
+  if (attr & 8)
+    *d++ = 'S';
+  *d++ = 0;
+  sprintf (buf, "-attr %s %s", name, atts);
+  new_directive (strdup(buf));
+}
+void
+def_code (attr)
+     int attr;
+{
+
+def_section ("CODE", attr);
+}
+
+void
+def_data (attr)
+     int attr;
+{
+  def_section ("DATA",attr);
+}
+
+
+/**********************************************************************/
+
+void
+scan_open_obj_file (abfd)
+     bfd *abfd;
+{
+  /* Look for .drectives */
+  asection *s = bfd_get_section_by_name (abfd, ".drectve");
+  if (s)
+    {
+      int size = bfd_get_section_size_before_reloc (s);
+      char *buf = xmalloc (size);
+      char *p;
+      char *e;
+      bfd_get_section_contents (abfd, s, buf, 0, size);
+      printf ("Sucking in info from %s\n",
+             bfd_get_filename (abfd));
+
+      /* Search for -export: strings */
+      p = buf;
+      e = buf + size;
+      while (p < e)
+       {
+         if (p[0] == '-'
+             && strncmp (p, "-export:", 8) == 0)
+           {
+             char *name;
+             char *c;
+             p += 8;
+             name = p;
+             while (*p != ' ' && *p != '-' && p < e)
+               p++;
+             c = xmalloc (p - name + 1);
+             memcpy (c, name, p - name);
+             c[p - name] = 0;
+             def_exports (c, 0, -1, 0);
+           }
+         else
+           p++;
+       }
+      free (buf);
+    }
+}
+
+
+void
+scan_obj_file (filename)
+     char *filename;
+{
+  bfd *f = bfd_openr (filename, 0);
+
+  if (!f)
+    {
+      fprintf (stderr, "Unable to open object file %s\n", filename);
+      exit (1);
+    }
+  if (bfd_check_format (f, bfd_archive))
+    {
+      bfd *arfile = bfd_openr_next_archived_file (f, 0);
+      while (arfile)
+       {
+         if (bfd_check_format (arfile, bfd_object))
+           scan_open_obj_file (arfile);
+         bfd_close (arfile);
+         arfile = bfd_openr_next_archived_file (f, arfile);
+       }
+    }
+
+  if (bfd_check_format (f, bfd_object))
+    {
+      scan_open_obj_file (f);
+    }
+
+  bfd_close (f);
+}
+
+/**********************************************************************/
+
+
+/* return the bit of the name before the last . */
+
+static
+char *
+prefix (name)
+     char *name;
+{
+  char *res = strdup (name);
+  char *p = strrchr (res, '.');
+  if (p)
+    *p = 0;
+  return res;
+}
+
+void
+dump_def_info (f)
+FILE *f;
+{
+  int i;
+  export_type *exp;
+  fprintf(f,"%s ", ASM_C);
+  for (i= 0; oav[i]; i++) 
+    fprintf(f,"%s ", oav[i]);
+  fprintf(f,"\n");
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      fprintf (f, "%s  %d %s @ %d %s%s\n",
+              ASM_C,
+              i,
+              exp->name, exp->ordinal,
+              exp->noname ? "NONAME " : "",
+              exp->constant ? "CONSTANT" : "");
+    }
+}
+/* Generate the .exp file */
+
+
+void
+gen_exp_file ()
+{
+  FILE *f;
+  char outfile[PATHMAX];
+  int i;
+  export_type *exp;
+  dlist_type *dl;
+  sprintf (outfile, "%s.exp.s", outfile_prefix);
+
+  f = fopen (outfile, "w");
+  if (!f)
+    {
+      fprintf (stderr, "Unable to open output file %s\n", outfile);
+      exit (1);
+    }
+  dump_def_info (f);
+  fprintf (f, "\t.section      .edata\n\n");
+  fprintf (f, "\t%s    0       %s Allways 0\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s    %d      %s Time and date\n", ASM_LONG, time (0), ASM_C);
+  fprintf (f, "\t%s    0       %s Major and Minor version\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s    name    %s Ptr to name of dll\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s    %d      %s Starting ordinal of exports\n", ASM_LONG, d_ord, ASM_C);
+  fprintf (f, "\t%s The next field is documented as being the number of functions\n", ASM_C);
+  fprintf (f, "\t%s yet it doesn't look like that in real PE dlls\n", ASM_C);
+  fprintf (f, "\t%s But it shouldn't be a problem, causes there's\n", ASM_C);
+  fprintf (f, "\t%s always the number of names field\n", ASM_C);
+  fprintf (f, "\t%s    %d      %s Number of functions\n", ASM_LONG, d_nfuncs, ASM_C);
+  fprintf (f, "\t%s    %d      %s Number of names\n", ASM_LONG, d_nfuncs, ASM_C);
+  fprintf (f, "\t%s    afuncs  %s Address of functions\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s    anames  %s Address of names\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s    anords  %s Address of ordinals\n", ASM_LONG, ASM_C);
+
+  fprintf (f, "name:   %s      \"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
+
+  fprintf (f, "afuncs:\n");
+  i = d_ord;
+  for (exp = d_exports; exp; exp = exp->next)
+    {
+      if (exp->ordinal != i)
+       {
+         fprintf (f, "\t%s\t%d\t@ %d..%d missing\n", ASM_SPACE,
+                  (exp->ordinal - i) * 4,
+                  i, exp->ordinal - 1);
+         i = exp->ordinal;
+       }
+      fprintf (f, "\t%s        %s\t%s %d\n", ASM_LONG, exp->name, ASM_C, exp->ordinal);
+      i++;
+    }
+
+
+  fprintf (f, "anames:\n");
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    if (exp->noname)
+      fprintf (f, "\t%s        0\t%sNoname\n", ASM_LONG, ASM_C);
+    else
+      fprintf (f, "\t%s        n%d\n", ASM_LONG, i);
+
+  fprintf (f, "anords:\n");
+  for (exp = d_exports; exp; exp = exp->next)
+    fprintf (f, "\t%s  %d\n", ASM_SHORT, exp->ordinal - d_ord);
+
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    if (exp->noname)
+      fprintf (f, "@n%d:       %s      \"%s\"\n", i, ASM_TEXT, exp->name);
+    else
+      fprintf (f, "n%d:        %s      \"%s\"\n", i, ASM_TEXT, exp->name);
+
+
+  if (a_list)
+    {
+      fprintf(f,"\t.section .drectve\n");
+      for (dl = a_list; dl; dl = dl->next)
+       {
+         fprintf (f,"\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
+       }
+    }
+  if (d_list) 
+    {
+      fprintf(f,"\t.section .rdata\n");
+      for (dl = d_list; dl; dl = dl->next)
+       {
+         char *p;
+         int l;
+         /* We dont output as ascii 'cause there can
+            be quote characters in the string */
+
+         l = 0;
+         for (p = dl->text; *p; p++) {
+           if (l == 0)
+             fprintf(f,"\t%s\t", ASM_BYTE);
+           else
+             fprintf(f,",");
+           fprintf(f,"%d", *p);
+           if (p[1] == 0) {
+             fprintf(f,",0\n");
+             break;
+           }
+           if (++l == 10) {
+             fprintf(f,"\n");
+             l = 0;
+           }
+         }
+       }
+    }
+  fclose (f);
+}
+
+/**********************************************************************/
+gen_lib_file ()
+{
+  char outfile[PATHMAX];
+  int i;
+  FILE *f;
+  export_type *exp;
+
+  sprintf (outfile, "%s.lib.s", outfile_prefix);
+
+  f = fopen (outfile, "w");
+  if (!f)
+    {
+      fprintf (stderr, "Unable to open output file %s\n", outfile);
+      exit (1);
+    }
+
+
+  dump_def_info (f);
+  fprintf (f, "\t.text\n");
+  fprintf (f, "%s Thunk table\n", ASM_C);
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      fprintf (f, "\t%s\t%s\n", ASM_GLOBAL, exp->name);
+      fprintf (f, "\t%s\t__imp__%s\n", ASM_GLOBAL, exp->name);
+    }
+
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      fprintf (f, "%s:\t%s\t__imp__%s\n", exp->name, ASM_JUMP, exp->name);
+    }
+
+
+  fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
+  fprintf (f, "\t.section      .idata$2\n");
+  fprintf (f, "\t%s\thname\t%s Ptr to image import by name list\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s\t%d\t%s time\n", ASM_LONG, time (0), ASM_C);
+  fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s\tiname\t%s imported dll's name\n", ASM_LONG, ASM_C);
+  fprintf (f, "\t%s\tfthunk\t%s pointer to firstthunk\n", ASM_LONG, ASM_C);
+
+  fprintf (f, "\n%s Loader modifies this\n", ASM_C);
+  fprintf (f, "\t.section      .idata$5\n");
+  fprintf (f, "fthunk:\n");
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      fprintf (f, "__imp__%s:\n", exp->name);
+      fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
+    }
+
+  fprintf (f, "\n%s Hint name array\n", ASM_C);
+  fprintf (f, "\t.section      .idata$4\n");
+  fprintf (f, "hname:\n");
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
+    }
+
+  fprintf (f, "%s Hint/name array storage and import dll name\n", ASM_C);
+  fprintf (f, "\t.section      .idata$6\n");
+
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      fprintf (f, "ID%d:\t%s\t%d\n", i, ASM_SHORT, exp->ordinal);
+      fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, exp->name);
+    }
+
+  fprintf (f, "iname:\t%s\t\"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
+  fclose (f);
+}
+/**********************************************************************/
+
+/* Run through the information gathered from the .o files and the
+   .def file and work out the best stuff */
+int
+pfunc (a, b)
+     void *a;
+     void *b;
+{
+  export_type *ap = *(export_type **) a;
+  export_type *bp = *(export_type **) b;
+  if (ap->ordinal == bp->ordinal)
+    return 0;
+
+  /* unset ordinals go to the bottom */
+  if (ap->ordinal == -1)
+    return 1;
+  if (bp->ordinal == -1)
+    return -1;
+  return (ap->ordinal - bp->ordinal);
+}
+
+
+int
+nfunc (a, b)
+     void *a;
+     void *b;
+{
+  export_type *ap = *(export_type **) a;
+  export_type *bp = *(export_type **) b;
+
+  return (strcmp (ap->name, bp->name));
+}
+
+static
+void
+remove_null_names (ptr)
+     export_type **ptr;
+{
+  int src;
+  int dst;
+  for (dst = src = 0; src < d_nfuncs; src++)
+    {
+      if (ptr[src])
+       {
+         ptr[dst] = ptr[src];
+         dst++;
+       }
+    }
+  d_nfuncs = dst;
+}
+
+static void
+dtab (ptr)
+     export_type **ptr;
+{
+#ifdef SACDEBUG
+  int i;
+  for (i = 0; i < d_nfuncs; i++)
+    {
+      if (ptr[i])
+       {
+         printf ("%d %s @ %d %s%s\n",
+                 i, ptr[i]->name, ptr[i]->ordinal,
+                 ptr[i]->noname ? "NONAME " : "",
+                 ptr[i]->constant ? "CONSTANT" : "");
+       }
+      else
+       printf ("empty\n");
+    }
+#endif
+}
+
+static void
+process_duplicates (d_export_vec)
+     export_type **d_export_vec;
+{
+  int more = 1;
+
+  while (more)
+    {
+      more = 0;
+      /* Remove duplicates */
+      qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
+
+      dtab (d_export_vec);
+      for (i = 0; i < d_nfuncs - 1; i++)
+       {
+         if (strcmp (d_export_vec[i]->name,
+                     d_export_vec[i + 1]->name) == 0)
+           {
+
+             export_type *a = d_export_vec[i];
+             export_type *b = d_export_vec[i + 1];
+
+             more = 1;
+
+             fprintf (stderr, "warning, ignoring duplicate EXPORT %s\n",
+                      a->name);
+             if (a->ordinal != -1
+                 && b->ordinal != -1)
+               {
+
+                 fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
+                          a->name);
+                 exit (1);
+               }
+             /* Merge attributes */
+             b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
+             b->constant |= a->constant;
+             b->noname |= a->noname;
+             d_export_vec[i] = 0;
+           }
+
+         dtab (d_export_vec);
+         remove_null_names (d_export_vec);
+         dtab (d_export_vec);
+       }
+    }
+}
+
+static void
+fill_ordinals (d_export_vec)
+     export_type **d_export_vec;
+{
+  int lowest = 0;
+  qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
+
+  /* fill in the unset ordinals with ones from the minimum */
+  for (i = 0; i < d_nfuncs; i++)
+    {
+      if (d_export_vec[i]->ordinal == -1)
+       {
+         d_export_vec[i]->ordinal = lowest++;
+       }
+      else
+       {
+         if (lowest == d_export_vec[i]->ordinal)
+           {
+             fprintf (stderr, "Warning, Duplicate ordinal %s @ %d\n",
+                      d_export_vec[i]->name,
+                      d_export_vec[i]->ordinal);
+           }
+         lowest = d_export_vec[i]->ordinal + 1;
+       }
+    }
+
+  /* Work out the lowest ordinal number */
+  if (d_export_vec[0])
+    d_ord = d_export_vec[0]->ordinal;
+}
+void
+mangle_defs ()
+{
+  /* First work out the minimum ordinal chosen */
+
+  export_type *exp;
+  int lowest = 0;
+  int i;
+  export_type **d_export_vec
+  = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
+
+  for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
+    {
+      d_export_vec[i] = exp;
+    }
+
+  process_duplicates (d_export_vec);
+  fill_ordinals (d_export_vec);
+
+  /* Put back the list in the new order */
+  d_exports = 0;
+  for (i = d_nfuncs - 1; i >= 0; i--)
+    {
+      d_export_vec[i]->next = d_exports;
+      d_exports = d_export_vec[i];
+    }
+}
+
+
+/**********************************************************************/
+
+void
+usage (file, status)
+     FILE *file;
+     int status;
+{
+  fprintf (file, "Usage %s [-m|--machine machine] [-o outprefix] [-d|--def deffile] [--def deffile]\n", program_name);
+  exit (status);
+}
+
+static struct option long_options[] =
+{
+  {"def", required_argument, NULL, 'd'},
+  {"help", no_argument, NULL, 'h'},
+  {"machine", required_argument, NULL, 'm'},
+  0
+};
+
+int
+main (ac, av)
+     int ac;
+     char **av;
+{
+  int c;
+  char *firstarg = 0;
+  program_name = av[0];
+  oav = av;
+  
+  while ((c = getopt_long (ac, av, "h?m:o:Dd:", long_options, 0)) != EOF)
+    {
+      switch (c)
+       {
+       case 'h':
+       case '?':
+         usage(stderr,0);
+         break;
+       case 'm':
+         mname = optarg;
+         break;
+       case 'o':
+         outfile_prefix = optarg;
+         break;
+       case 'D':
+         yydebug = 1;
+         break;
+       case 'd':
+         def_file = optarg;
+         break;
+       default:
+         usage (stderr, 1);
+       }
+    }
+
+
+  for (i = 0; mtable[i].type; i++) 
+    {
+      if (strcmp (mtable[i].type, mname) == 0)
+       break;
+    }
+
+  if (!mtable[i].type) 
+    {
+      fprintf(stderr,"Machine not supported\n");
+      exit(1);
+    }
+  machine = i;
+
+
+  if (def_file)
+    {
+
+      process_def_file (def_file);
+    }
+  while (optind < ac)
+    {
+      if (!firstarg)
+       firstarg = av[optind];
+      scan_obj_file (av[optind]);
+      optind++;
+    }
+
+  if (!outfile_prefix)
+    {
+      if (d_name)
+       outfile_prefix = d_name;
+      else if (def_file)
+       outfile_prefix = def_file;
+      else if (firstarg)
+       outfile_prefix = firstarg;
+      else
+       {
+         fprintf (stderr, "No way to create an output filename\n");
+         exit (1);
+       }
+    }
+  outfile_prefix = prefix (outfile_prefix);
+
+  mangle_defs ();
+  gen_exp_file ();
+  gen_lib_file ();
+  return 0;
+}