Wed Oct 11 13:36:13 1995 steve chamberlain <sac@slash.cygnus.com>
[platform/upstream/binutils.git] / binutils / dlltool.c
1 #define show_allnames 0
2
3 /* dlltool.c -- tool to generate stuff for PE style DLLs 
4    Copyright (C) 1995 Free Software Foundation, Inc.
5
6    This file is part of GNU Binutils.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22
23 /*
24    This program allows you to build the files necessary to create
25    DLLs to run on a system which understands PE format image files.
26    (eg, Windows NT)
27
28    A DLL contains an export table which contains the information
29    which the runtime loader needs to tie up references from a
30    referencing program. 
31
32    The export table is generated by this program by reading
33    in a .DEF file or scanning the .a and .o files which will be in the
34    DLL.  A .o file can contain information in special  ".drectve" sections
35    with export information.  
36
37    A DEF file contains any number of the following commands:
38
39
40    NAME <name> [ , <base> ] 
41    The result is going to be <name>.EXE
42
43    LIBRARY <name> [ , <base> ]    
44    The result is going to be <name>.DLL
45
46    EXPORTS  ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) *
47    Declares name1 as an exported symbol from the
48    DLL, with optional ordinal number <integer>
49
50    IMPORTS  ( [ <name> = ] <name> . <name> ) *
51    Ignored for compatibility
52
53    DESCRIPTION <string>
54    Puts <string> into output .exp file in the .rdata section
55
56    [STACKSIZE|HEAPSIZE] <number-reserve> [ , <number-commit> ]
57    Generates --stack|--heap <number-reserve>,<number-commit>
58    in the output .drectve section.  The linker will
59    see this and act upon it.
60
61    [CODE|DATA] <attr>+
62    SECTIONS ( <sectionname> <attr>+ )*
63    <attr> = READ | WRITE | EXECUTE | SHARED
64    Generates --attr <sectionname> <attr> in the output
65    .drectve section.  The linker will see this and act
66    upon it.
67
68
69    A -export:<name> in a .drectve section in an input .o or .a
70    file to this program is equivalent to a EXPORTS <name>
71    in a .DEF file.
72
73
74
75    The program generates output files with the prefix supplied
76    on the command line, or in the def file, or taken from the first 
77    supplied argument.
78
79    The .exp.s file contains the information necessary to export
80    the routines in the DLL.  The .lib.s file contains the information
81    necessary to use the DLL's routines from a referencing program.
82
83
84
85    Example:
86
87    file1.c: 
88    asm (".section .drectve");  
89    asm (".ascii \"-export:adef\"");
90
91    adef(char *s)
92    {
93    printf("hello from the dll %s\n",s);
94    }
95
96    bdef(char *s)
97    {
98    printf("hello from the dll and the other entry point %s\n",s);
99    }
100
101    file2.c:
102    asm (".section .drectve");
103    asm (".ascii \"-export:cdef\"");
104    asm (".ascii \"-export:ddef\"");
105    cdef(char *s)
106    {
107    printf("hello from the dll %s\n",s);
108    }
109
110    ddef(char *s)
111    {
112    printf("hello from the dll and the other entry point %s\n",s);
113    }
114
115    printf()
116    {
117    return 9;
118    }
119
120    main.c
121
122    main()
123    {
124    cdef();
125    }
126
127    thedll.def
128
129    LIBRARY thedll
130    HEAPSIZE 0x40000, 0x2000
131    EXPORTS bdef @ 20
132    cdef @ 30 NONAME 
133
134    SECTIONS donkey READ WRITE
135    aardvark EXECUTE
136
137
138    # compile up the parts of the dll
139
140    gcc -c file1.c       
141    gcc -c file2.c
142
143    # put them in a library (you don't have to, you
144    # could name all the .os on the dlltool line)
145
146    ar  qcv thedll.in file1.o file2.o
147    ranlib thedll.in
148
149    # run this tool over the library and the def file
150    ./dlltool --def thedll.def --output-exp thedll.o --output-lib thedll.a
151
152    # build the dll with the library with file1.o, file2.o and the export table
153    ld -o thedll.dll thedll.o thedll.in
154
155    # build the mainline
156    gcc -c themain.c 
157
158    # link the executable with the import library
159    ld -e main -Tthemain.ld -o themain.exe themain.o thedll.a
160
161  */
162
163 #define PAGE_SIZE 4096
164 #define PAGE_MASK (-PAGE_SIZE)
165 #include "bfd.h"
166 #include "libiberty.h"
167 #include "bucomm.h"
168 #include "getopt.h"
169 #include <sys/types.h>
170 #include "demangle.h"
171
172 #ifdef HAVE_SYS_WAIT_H
173 #include <sys/wait.h>
174 #else
175 #ifndef WIFEXITED
176 #define WIFEXITED(w)    (((w)&0377) == 0)
177 #endif
178 #ifndef WIFSIGNALED
179 #define WIFSIGNALED(w)  (((w)&0377) != 0177 && ((w)&~0377) == 0)
180 #endif
181 #ifndef WTERMSIG
182 #define WTERMSIG(w)     ((w) & 0177)
183 #endif
184 #ifndef WEXITSTATUS
185 #define WEXITSTATUS(w)  (((w) >> 8) & 0377)
186 #endif
187 #endif
188
189
190 char *ar_name = "ar";
191 char *as_name = "as";
192 char *ranlib_name = "ranlib";
193
194 char *exp_name;
195 char *imp_name;
196 char *imp_name_lab;
197 char *dll_name;
198
199 int add_indirect = 0;
200 int add_underscore = 0;
201 int dontdeltemps = 0;
202
203 int yydebug;
204 char *def_file;
205
206 char *program_name;
207 char *strrchr ();
208 char *strdup ();
209
210 static int machine;
211 int killat;
212 static int verbose;
213 FILE *output_def;
214 FILE *base_file;
215 #ifdef DLLTOOL_ARM
216 static char *mname = "arm";
217 #endif
218
219 #ifdef DLLTOOL_I386
220 static char *mname = "i386";
221 #endif
222 #define PATHMAX 250             /* What's the right name for this ? */
223
224 char outfile[PATHMAX];
225 struct mac
226   {
227     char *type;
228     char *how_byte;
229     char *how_short;
230     char *how_long;
231     char *how_asciz;
232     char *how_comment;
233     char *how_jump;
234     char *how_global;
235     char *how_space;
236     char *how_align_short;
237     char *how_align_long;
238   }
239 mtable[]
240 =
241 {
242   {
243 #define MARM 0
244     "arm", ".byte", ".short", ".long", ".asciz", "@", "ldr\tip,[pc]\n\tldr\tpc,[ip]\n\t.long", ".global", ".space", ".align\t2",".align\t4",
245   }
246   ,
247   {
248 #define M386 1
249     "i386", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space", ".align\t2",".align\t4"
250   }
251   ,
252     0
253 };
254
255
256 char *
257 rvaafter (machine)
258      int machine;
259 {
260   switch (machine)
261     {
262     case MARM:
263       return "";
264     case M386:
265       return "";
266     }
267 }
268
269 char *
270 rvabefore (machine)
271      int machine;
272 {
273   switch (machine)
274     {
275     case MARM:
276       return ".rva\t";
277     case M386:
278       return ".rva\t";
279     }
280 }
281
282 char *
283 asm_prefix (machine)
284 {
285   switch (machine)
286     {
287     case MARM:
288       return "";
289     case M386:
290       return "_";
291     }
292 }
293 #define ASM_BYTE        mtable[machine].how_byte
294 #define ASM_SHORT       mtable[machine].how_short
295 #define ASM_LONG        mtable[machine].how_long
296 #define ASM_TEXT        mtable[machine].how_asciz
297 #define ASM_C           mtable[machine].how_comment
298 #define ASM_JUMP        mtable[machine].how_jump
299 #define ASM_GLOBAL      mtable[machine].how_global
300 #define ASM_SPACE       mtable[machine].how_space
301 #define ASM_ALIGN_SHORT mtable[machine].how_align_short
302 #define ASM_RVA_BEFORE  rvabefore(machine)
303 #define ASM_RVA_AFTER   rvaafter(machine)
304 #define ASM_PREFIX      asm_prefix(machine)
305 #define ASM_ALIGN_LONG mtable[machine].how_align_long
306 static char **oav;
307
308
309 FILE *yyin;                     /* communications with flex */
310 extern int linenumber;
311 void
312 process_def_file (name)
313      char *name;
314 {
315   FILE *f = fopen (name, "r");
316   if (!f)
317     {
318       fprintf (stderr, "%s: Can't open def file %s\n", program_name, name);
319       exit (1);
320     }
321
322   yyin = f;
323
324   yyparse ();
325 }
326
327 /**********************************************************************/
328
329 /* Communications with the parser */
330
331
332 typedef struct dlist
333 {
334   char *text;
335   struct dlist *next;
336 }
337 dlist_type;
338
339 typedef struct export
340   {
341     char *name;
342     char *internal_name;
343     int ordinal;
344     int constant;
345     int noname;
346     int hint;
347     struct export *next;
348   }
349 export_type;
350
351 static char *d_name;            /* Arg to NAME or LIBRARY */
352 static int d_nfuncs;            /* Number of functions exported */
353 static int d_named_nfuncs;      /* Number of named functions exported */
354 static int d_low_ord;           /* Lowest ordinal index */
355 static int d_high_ord;          /* Highest ordinal index */
356 static export_type *d_exports;  /*list of exported functions */
357 static export_type **d_exports_lexically;       /* vector of exported functions in alpha order */
358 static dlist_type *d_list;      /* Descriptions */
359 static dlist_type *a_list;      /* Stuff to go in directives */
360
361 static int d_is_dll;
362 static int d_is_exe;
363
364 yyerror ()
365 {
366   fprintf (stderr, "%s: Syntax error in def file %s:%d\n",
367            program_name, def_file, linenumber);
368 }
369
370 void
371 def_exports (name, internal_name, ordinal, noname, constant)
372      char *name;
373      char *internal_name;
374      int ordinal;
375      int noname;
376      int constant;
377 {
378   struct export *p = (struct export *) xmalloc (sizeof (*p));
379
380   p->name = name;
381   p->internal_name = internal_name ? internal_name : name;
382   p->ordinal = ordinal;
383   p->constant = constant;
384   p->noname = noname;
385   p->next = d_exports;
386   d_exports = p;
387   d_nfuncs++;
388 }
389
390
391 void
392 def_name (name, base)
393      char *name;
394      int base;
395 {
396   if (verbose)
397     fprintf (stderr, "%s NAME %s base %x\n", program_name, name, base);
398   if (d_is_dll)
399     {
400       fprintf (stderr, "Can't have LIBRARY and NAME\n");
401     }
402   d_name = name;
403   d_is_exe = 1;
404 }
405
406 void
407 def_library (name, base)
408      char *name;
409      int base;
410 {
411   if (verbose)
412     printf ("%s: LIBRARY %s base %x\n", program_name, name, base);
413   if (d_is_exe)
414     {
415       fprintf (stderr, "%s: Can't have LIBRARY and NAME\n", program_name);
416     }
417   d_name = name;
418   d_is_dll = 1;
419 }
420
421 void
422 def_description (desc)
423      char *desc;
424 {
425   dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type));
426   d->text = strdup (desc);
427   d->next = d_list;
428   d_list = d;
429 }
430
431 void
432 new_directive (dir)
433      char *dir;
434 {
435   dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type));
436   d->text = strdup (dir);
437   d->next = a_list;
438   a_list = d;
439 }
440
441 void
442 def_stacksize (reserve, commit)
443      int reserve;
444      int commit;
445 {
446   char b[200];
447   if (commit > 0)
448     sprintf (b, "-stack 0x%x,0x%x ", reserve, commit);
449   else
450     sprintf (b, "-stack 0x%x ", reserve);
451   new_directive (strdup (b));
452 }
453
454 void
455 def_heapsize (reserve, commit)
456      int reserve;
457      int commit;
458 {
459   char b[200];
460   if (commit > 0)
461     sprintf (b, "-heap 0x%x,0x%x ", reserve, commit);
462   else
463     sprintf (b, "-heap 0x%x ", reserve);
464   new_directive (strdup (b));
465 }
466
467
468 void
469 def_import (internal, module, entry)
470      char *internal;
471      char *module;
472      char *entry;
473 {
474   if (verbose)
475     fprintf (stderr, "%s: IMPORTS are ignored", program_name);
476 }
477
478 void
479 def_version (major, minor)
480 {
481   printf ("VERSION %d.%d\n", major, minor);
482 }
483
484
485 void
486 def_section (name, attr)
487      char *name;
488      int attr;
489 {
490   char buf[200];
491   char atts[5];
492   char *d = atts;
493   if (attr & 1)
494     *d++ = 'R';
495
496   if (attr & 2)
497     *d++ = 'W';
498   if (attr & 4)
499     *d++ = 'X';
500   if (attr & 8)
501     *d++ = 'S';
502   *d++ = 0;
503   sprintf (buf, "-attr %s %s", name, atts);
504   new_directive (strdup (buf));
505 }
506 void
507 def_code (attr)
508      int attr;
509 {
510
511   def_section ("CODE", attr);
512 }
513
514 void
515 def_data (attr)
516      int attr;
517 {
518   def_section ("DATA", attr);
519 }
520
521
522 /**********************************************************************/
523
524 void
525 run (what, args)
526      char *what;
527      char *args;
528 {
529   char *s;
530   int pid;
531   int i;
532   char **argv;
533   extern char **environ;
534   if (verbose)
535     fprintf (stderr, "%s %s\n", what, args);
536
537   /* Count the args */
538   i = 0;
539   for (s = args; *s; s++)
540     if (*s == ' ')
541       i++;
542   i++;
543   argv = alloca (sizeof (char *) * (i + 3));
544   i = 0;
545   argv[i++] = what;
546   s = args;
547   while (1)
548     {
549       argv[i++] = s;
550       while (*s != ' ' && *s != 0)
551         s++;
552       if (*s == 0)
553         break;
554       *s++ = 0;
555     }
556   argv[i++] = 0;
557
558
559   pid = vfork ();
560   if (pid == 0)
561     {
562       execvp (what, argv);
563       fprintf (stderr, "%s: can't exec %s\n", program_name, what);
564       exit (1);
565     }
566   else if (pid == -1)
567     {
568       extern int errno;
569       fprintf (stderr, "%s: vfork failed, %d\n", program_name, errno);
570       exit (1);
571     }
572   else
573     {
574       int status;
575       waitpid (pid, &status, 0);
576       if (status)
577         {
578           if (WIFSIGNALED (status))
579             {
580               fprintf (stderr, "%s: %s %s terminated with signal %d\n",
581                        program_name, what, args, WTERMSIG (status));
582               exit (1);
583             }
584
585           if (WIFEXITED (status))
586             {
587               fprintf (stderr, "%s: %s %s terminated with exit status %d\n",
588                        program_name, what, args, WEXITSTATUS (status));
589               exit (1);
590             }
591         }
592     }
593 }
594
595 /* read in and block out the base relocations */
596 static void
597 basenames (abfd)
598      bfd *abfd;
599 {
600
601
602
603
604 }
605
606 void
607 scan_open_obj_file (abfd)
608      bfd *abfd;
609 {
610   /* Look for .drectve's */
611   asection *s = bfd_get_section_by_name (abfd, ".drectve");
612   if (s)
613     {
614       int size = bfd_get_section_size_before_reloc (s);
615       char *buf = xmalloc (size);
616       char *p;
617       char *e;
618       bfd_get_section_contents (abfd, s, buf, 0, size);
619       if (verbose)
620         fprintf (stderr, "%s: Sucking in info from %s\n",
621                  program_name,
622                  bfd_get_filename (abfd));
623
624       /* Search for -export: strings */
625       p = buf;
626       e = buf + size;
627       while (p < e)
628         {
629           if (p[0] == '-'
630               && strncmp (p, "-export:", 8) == 0)
631             {
632               char *name;
633               char *c;
634               p += 8;
635               name = p;
636               while (*p != ' ' && *p != '-' && p < e)
637                 p++;
638               c = xmalloc (p - name + 1);
639               memcpy (c, name, p - name);
640               c[p - name] = 0;
641               def_exports (c, 0, -1, 0);
642             }
643           else
644             p++;
645         }
646       free (buf);
647     }
648
649   basenames (abfd);
650
651   if (verbose)
652     fprintf (stderr, "%s: Done readin\n",
653              program_name);
654
655 }
656
657
658 void
659 scan_obj_file (filename)
660      char *filename;
661 {
662   bfd *f = bfd_openr (filename, 0);
663
664   if (!f)
665     {
666       fprintf (stderr, "%s: Unable to open object file %s\n",
667                program_name,
668                filename);
669       exit (1);
670     }
671   if (bfd_check_format (f, bfd_archive))
672     {
673       bfd *arfile = bfd_openr_next_archived_file (f, 0);
674       while (arfile)
675         {
676           if (bfd_check_format (arfile, bfd_object))
677             scan_open_obj_file (arfile);
678           bfd_close (arfile);
679           arfile = bfd_openr_next_archived_file (f, arfile);
680         }
681     }
682
683   if (bfd_check_format (f, bfd_object))
684     {
685       scan_open_obj_file (f);
686     }
687
688   bfd_close (f);
689 }
690
691 /**********************************************************************/
692
693
694 /* return the bit of the name before the last . */
695
696 static
697 char *
698 prefix (name)
699      char *name;
700 {
701   char *res = strdup (name);
702   char *p = strrchr (res, '.');
703   if (p)
704     *p = 0;
705   return res;
706 }
707
708 void
709 dump_def_info (f)
710      FILE *f;
711 {
712   int i;
713   export_type *exp;
714   fprintf (f, "%s ", ASM_C);
715   for (i = 0; oav[i]; i++)
716     fprintf (f, "%s ", oav[i]);
717   fprintf (f, "\n");
718   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
719     {
720       fprintf (f, "%s  %d = %s %s @ %d %s%s\n",
721                ASM_C,
722                i,
723                exp->name,
724                exp->internal_name,
725                exp->ordinal,
726                exp->noname ? "NONAME " : "",
727                exp->constant ? "CONSTANT" : "");
728     }
729 }
730 /* Generate the .exp file */
731
732 int
733 sfunc (a, b)
734      long *a;
735      long *b;
736 {
737   return *a - *b;
738 }
739
740
741
742 static void
743 flush_page (f, need, page_addr, on_page)
744      FILE *f;
745      long *need;
746      long page_addr;
747      int on_page;
748 {
749   int i;
750
751   /* Flush this page */
752   fprintf (f, "\t%s\t0x%08x\t%s Starting RVA for chunk\n",
753            ASM_LONG,
754            page_addr,
755            ASM_C);
756   fprintf (f, "\t%s\t0x%x\t%s Size of block\n",
757            ASM_LONG,
758            (on_page * 2) + (on_page & 1) * 2 + 8,
759            ASM_C);
760   for (i = 0; i < on_page; i++)
761     {
762       fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, need[i] - page_addr | 0x3000);
763     }
764   /* And padding */
765   if (on_page & 1)
766     fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, 0 | 0x0000);
767
768 }
769
770
771 void
772 gen_def_file ()
773 {
774   int i;
775   export_type *exp;
776   fprintf (output_def, ";");
777   for (i = 0; oav[i]; i++)
778     fprintf (output_def, " %s", oav[i]);
779
780   fprintf (output_def, "\nEXPORTS\n");
781   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
782     {
783       fprintf (output_def, "\t%s @ %d; %s\n",
784                exp->name,
785                exp->ordinal,
786                cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_PARAMS));
787     }
788 }
789 void
790 gen_exp_file ()
791 {
792   FILE *f;
793   int i;
794   export_type *exp;
795   dlist_type *dl;
796   int had_noname = 0;
797
798   sprintf (outfile, "t%s", exp_name);
799
800   if (verbose)
801     fprintf (stderr, "%s: Generate exp file %s\n",
802              program_name, exp_name);
803
804   f = fopen (outfile, "w");
805   if (!f)
806     {
807       fprintf (stderr, "%s: Unable to open output file %s\n", program_name, outfile);
808       exit (1);
809     }
810   if (verbose)
811     {
812       fprintf (stderr, "%s: Opened file %s\n",
813                program_name, outfile);
814     }
815
816   dump_def_info (f);
817   if (d_exports)
818     {
819       fprintf (f, "\t.section   .edata\n\n");
820       fprintf (f, "\t%s 0       %s Allways 0\n", ASM_LONG, ASM_C);
821       fprintf (f, "\t%s 0       %s Time and date\n", ASM_LONG, ASM_C);
822       fprintf (f, "\t%s 0       %s Major and Minor version\n", ASM_LONG, ASM_C);
823       fprintf (f, "\t%sname%s   %s Ptr to name of dll\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
824       fprintf (f, "\t%s %d      %s Starting ordinal of exports\n", ASM_LONG, d_low_ord, ASM_C);
825
826
827       fprintf (f, "\t%s %d      %s Number of functions\n", ASM_LONG, d_high_ord - d_low_ord + 1, ASM_C);
828       fprintf(f,"\t%s named funcs %d, low ord %d, high ord %d\n",
829               ASM_C,
830               d_named_nfuncs, d_low_ord, d_high_ord);
831       fprintf (f, "\t%s %d      %s Number of names\n", ASM_LONG,
832                show_allnames ? d_high_ord - d_low_ord + 1 : d_named_nfuncs, ASM_C);
833       fprintf (f, "\t%safuncs%s  %s Address of functions\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
834
835       fprintf (f, "\t%sanames%s %s Address of Name Pointer Table\n", 
836                ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
837
838       fprintf (f, "\t%sanords%s %s Address of ordinals\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
839
840       fprintf (f, "name:        %s      \"%s\"\n", ASM_TEXT, dll_name);
841
842
843       fprintf(f,"%s Export address Table\n", ASM_C);
844       fprintf(f,"\t%s\n", ASM_ALIGN_LONG);
845       fprintf (f, "afuncs:\n");
846       i = d_low_ord;
847
848       for (exp = d_exports; exp; exp = exp->next)
849         {
850           if (exp->ordinal != i)
851             {
852 #if 0         
853               fprintf (f, "\t%s\t%d\t%s %d..%d missing\n",
854                        ASM_SPACE,
855                        (exp->ordinal - i) * 4,
856                        ASM_C,
857                        i, exp->ordinal - 1);
858               i = exp->ordinal;
859 #endif
860               while (i < exp->ordinal)
861                 {
862                   fprintf(f,"\t%s\t0\n", ASM_LONG);
863                   i++;
864                 }
865             }
866           fprintf (f, "\t%s%s%s%s\t%s %d\n", ASM_RVA_BEFORE,
867                    ASM_PREFIX,
868                    exp->internal_name, ASM_RVA_AFTER, ASM_C, exp->ordinal);
869           i++;
870         }
871
872       fprintf (f,"%s Export Name Pointer Table\n", ASM_C);
873       fprintf (f, "anames:\n");
874
875       for (i = 0; exp = d_exports_lexically[i]; i++)
876         {
877           if (!exp->noname || show_allnames)
878             fprintf (f, "\t%sn%d%s\n", ASM_RVA_BEFORE, exp->ordinal, ASM_RVA_AFTER);
879         }
880
881       fprintf (f,"%s Export Oridinal Table\n", ASM_C);
882       fprintf (f, "anords:\n");
883       for (i = 0; exp = d_exports_lexically[i]; i++)
884         {
885           if (!exp->noname || show_allnames)
886             fprintf (f, "\t%s   %d\n", ASM_SHORT, exp->ordinal - d_low_ord);
887         }
888
889       fprintf(f,"%s Export Name Table\n", ASM_C);
890       for (i = 0; exp = d_exports_lexically[i]; i++)
891         if (!exp->noname || show_allnames)
892           fprintf (f, "n%d:     %s      \"%s\"\n", exp->ordinal, ASM_TEXT, exp->name);
893
894       if (a_list)
895         {
896           fprintf (f, "\t.section .drectve\n");
897           for (dl = a_list; dl; dl = dl->next)
898             {
899               fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
900             }
901         }
902       if (d_list)
903         {
904           fprintf (f, "\t.section .rdata\n");
905           for (dl = d_list; dl; dl = dl->next)
906             {
907               char *p;
908               int l;
909               /* We dont output as ascii 'cause there can
910                  be quote characters in the string */
911
912               l = 0;
913               for (p = dl->text; *p; p++)
914                 {
915                   if (l == 0)
916                     fprintf (f, "\t%s\t", ASM_BYTE);
917                   else
918                     fprintf (f, ",");
919                   fprintf (f, "%d", *p);
920                   if (p[1] == 0)
921                     {
922                       fprintf (f, ",0\n");
923                       break;
924                     }
925                   if (++l == 10)
926                     {
927                       fprintf (f, "\n");
928                       l = 0;
929                     }
930                 }
931             }
932         }
933     }
934
935
936   /* Add to the output file a way of getting to the exported names
937      without using the import library. */
938   if (add_indirect)
939     {
940       fprintf (f, "\t.section\t.rdata\n");
941       for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
942         if (!exp->noname || show_allnames)
943           {
944             fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
945             fprintf (f, "__imp_%s:\n", exp->name);
946             fprintf (f, "\t%s\t%s\n", ASM_LONG, exp->name);
947           }
948     }
949
950   /* Dump the reloc section if a base file is provided */
951   if (base_file)
952     {
953       int addr;
954       long need[PAGE_SIZE];
955       long page_addr;
956       int numbytes;
957       int num_entries;
958       long *copy;
959       int j;
960       int on_page;
961       fprintf (f, "\t.section\t.init\n");
962       fprintf (f, "lab:\n");
963
964       fseek (base_file, 0, SEEK_END);
965       numbytes = ftell (base_file);
966       fseek (base_file, 0, SEEK_SET);
967       copy = malloc (numbytes);
968       fread (copy, 1, numbytes, base_file);
969       num_entries = numbytes / sizeof (long);
970
971
972       fprintf (f, "\t.section\t.reloc\n");
973       if (num_entries)
974         {
975
976           int src;
977           int dst;
978           int last = -1;
979           qsort (copy, num_entries, sizeof (long), sfunc);
980           /* Delete duplcates */
981           for (src = 0; src < num_entries; src++)
982             {
983               if (last != copy[src]) 
984                 last = copy[dst++] = copy[src];
985             }
986           num_entries = dst;
987           addr = copy[0];
988           page_addr = addr & PAGE_MASK;         /* work out the page addr */
989           on_page = 0;
990           for (j = 0; j < num_entries; j++)
991             {
992               addr = copy[j];
993               if ((addr & PAGE_MASK) != page_addr)
994                 {
995                   flush_page (f, need, page_addr, on_page);
996                   on_page = 0;
997                   page_addr = addr & PAGE_MASK;
998                 }
999               need[on_page++] = addr;
1000             }
1001           flush_page (f, need, page_addr, on_page);
1002
1003           fprintf (f, "\t%s\t0,0\t%s End\n", ASM_LONG, ASM_C);
1004         }
1005     }
1006
1007   fclose (f);
1008
1009   /* assemble the file */
1010   sprintf (outfile, "-o %s t%s", exp_name, exp_name);
1011   run (as_name, outfile);
1012   if (dontdeltemps == 0)
1013     {
1014       sprintf (outfile, "t%s", exp_name);
1015       unlink (outfile);
1016     }
1017 }
1018
1019 static char *
1020 xlate (char *name)
1021 {
1022   if (add_underscore)
1023     {
1024       char *copy = malloc (strlen (name) + 2);
1025       copy[0] = '_';
1026       strcpy (copy + 1, name);
1027       name = copy;
1028     }
1029
1030   if (killat)
1031     {
1032       char *p;
1033       p = strchr (name, '@');
1034       if (p)
1035         *p = 0;
1036     }
1037   return name;
1038 }
1039
1040 /**********************************************************************/
1041
1042 static void dump_iat (f, exp)
1043 FILE *f;
1044 export_type *exp;
1045 {
1046   if (exp->noname && !show_allnames ) 
1047     {
1048       fprintf (f, "\t%s\t0x%08x\n",
1049                ASM_LONG,
1050                exp->ordinal | 0x80000000); /* hint or orindal ?? */
1051     }
1052   else
1053     {
1054       fprintf (f, "\t%sID%d%s\n", ASM_RVA_BEFORE,
1055                exp->ordinal,
1056                ASM_RVA_AFTER);
1057     }
1058 }
1059 static void
1060 gen_lib_file ()
1061 {
1062   int i;
1063   int sol;
1064   FILE *f;
1065   export_type *exp;
1066   char *output_filename;
1067   char prefix[PATHMAX];
1068
1069   sprintf (outfile, "%s", imp_name);
1070   output_filename = strdup (outfile);
1071
1072   unlink (output_filename);
1073
1074   strcpy (prefix, "d");
1075   sprintf (outfile, "%sh.s", prefix);
1076
1077   f = fopen (outfile, "w");
1078
1079   fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
1080   fprintf (f, "\t.section       .idata$2\n");
1081
1082   fprintf (f, "\t%s\t__%s_head\n", ASM_GLOBAL, imp_name_lab);
1083   fprintf (f, "__%s_head:\n", imp_name_lab);
1084
1085   fprintf (f, "\t%shname%s\t%sPtr to image import by name list\n",
1086            ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
1087
1088   fprintf (f, "\t%sthis should be the timestamp, but NT sometimes\n", ASM_C);
1089   fprintf (f, "\t%sdoesn't load DLLs when this is set.\n", ASM_C);
1090   fprintf (f, "\t%s\t0\t%s loaded time\n", ASM_LONG, ASM_C);
1091   fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
1092   fprintf (f, "\t%s__%s_iname%s\t%s imported dll's name\n",
1093            ASM_RVA_BEFORE,
1094            imp_name_lab,
1095            ASM_RVA_AFTER,
1096            ASM_C);
1097   fprintf (f, "\t%sfthunk%s\t%s pointer to firstthunk\n",
1098            ASM_RVA_BEFORE,
1099            ASM_RVA_AFTER, ASM_C);
1100
1101   fprintf (f, "%sStuff for compatibility\n", ASM_C);
1102   fprintf (f, "\t.section\t.idata$5\n");
1103   fprintf (f, "\t%s\t0\n", ASM_LONG);
1104   fprintf (f, "fthunk:\n");
1105   fprintf (f, "\t.section\t.idata$4\n");
1106
1107   fprintf (f, "\t%s\t0\n", ASM_LONG);
1108   fprintf (f, "\t.section       .idata$4\n");
1109   fprintf (f, "hname:\n");
1110
1111   fclose (f);
1112
1113   sprintf (outfile, "-o %sh.o %sh.s", prefix, prefix);
1114   run (as_name, outfile);
1115
1116   for (i = 0; exp = d_exports_lexically[i]; i++)
1117     {
1118       sprintf (outfile, "%ss%d.s", prefix, i);
1119       f = fopen (outfile, "w");
1120       fprintf (f, "\t.text\n");
1121       fprintf (f, "\t%s\t%s%s\n", ASM_GLOBAL, ASM_PREFIX, exp->name);
1122       fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
1123       fprintf (f, "%s%s:\n\t%s\t__imp_%s\n", ASM_PREFIX,
1124                exp->name, ASM_JUMP, exp->name);
1125
1126       fprintf (f, "\t.section\t.idata$7\t%s To force loading of head\n", ASM_C);
1127       fprintf (f, "\t%s\t__%s_head\n", ASM_LONG, imp_name_lab);
1128
1129
1130       fprintf (f,"%s Import Address Table\n", ASM_C);
1131
1132       fprintf (f, "\t.section   .idata$5\n");
1133       fprintf (f, "__imp_%s:\n", exp->name);
1134
1135       dump_iat (f, exp);
1136
1137       fprintf (f, "\n%s Import Lookup Table\n", ASM_C);
1138       fprintf (f, "\t.section   .idata$4\n");
1139
1140       dump_iat (f, exp);
1141
1142       if(!exp->noname || show_allnames) 
1143         {
1144           fprintf (f, "%s Hint/Name table\n", ASM_C);
1145           fprintf (f, "\t.section       .idata$6\n");
1146           fprintf (f, "ID%d:\t%s\t%d\n", exp->ordinal, ASM_SHORT, exp->hint);      
1147           fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name));
1148         }
1149
1150       fclose (f);
1151
1152
1153       sprintf (outfile, "-o %ss%d.o %ss%d.s", prefix, i, prefix, i);
1154       run (as_name, outfile);
1155     }
1156
1157   sprintf (outfile, "%st.s", prefix);
1158   f = fopen (outfile, "w");
1159   fprintf (f, "\t.section       .idata$7\n");
1160   fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab);
1161   fprintf (f, "__%s_iname:\t%s\t\"%s\"\n",
1162            imp_name_lab, ASM_TEXT, dll_name);
1163
1164
1165   fprintf (f, "\t.section       .idata$4\n");
1166   fprintf (f, "\t%s\t0\n", ASM_LONG);
1167
1168   fprintf (f, "\t.section       .idata$5\n");
1169   fprintf (f, "\t%s\t0\n", ASM_LONG);
1170   fclose (f);
1171
1172   sprintf (outfile, "-o %st.o %st.s", prefix, prefix);
1173   run (as_name, outfile);
1174
1175   /* Now stick them all into the archive */
1176
1177
1178   sprintf (outfile, "crs %s %sh.o %st.o", output_filename, prefix, prefix);
1179   run (ar_name, outfile);
1180
1181   /* Do the rest in groups of however many fit into a command line */
1182   sol = 0;
1183   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1184     {
1185       if (sol == 0)
1186         {
1187           sprintf (outfile, "crs %s", output_filename);
1188           sol = strlen (outfile);
1189         }
1190
1191       sprintf (outfile + sol, " %ss%d.o", prefix, i);
1192       sol = strlen (outfile);
1193
1194       if (sol > 100)
1195         {
1196           run (ar_name, outfile);
1197           sol = 0;
1198         }
1199
1200     }
1201   if (sol)
1202     run (ar_name, outfile);
1203
1204   /* Delete all the temp files */
1205
1206   if (dontdeltemps == 0)
1207     {
1208       sprintf (outfile, "%sh.o", prefix);
1209       unlink (outfile);
1210       sprintf (outfile, "%sh.s", prefix);
1211       unlink (outfile);
1212       sprintf (outfile, "%st.o", prefix);
1213       unlink (outfile);
1214       sprintf (outfile, "%st.s", prefix);
1215       unlink (outfile);
1216     }
1217
1218   if (dontdeltemps < 2)
1219     for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1220       {
1221         sprintf (outfile, "%ss%d.o", prefix, i);
1222         unlink (outfile);
1223         sprintf (outfile, "%ss%d.s", prefix, i);
1224         unlink (outfile);
1225       }
1226
1227 }
1228 /**********************************************************************/
1229
1230 /* Run through the information gathered from the .o files and the
1231    .def file and work out the best stuff */
1232 int
1233 pfunc (a, b)
1234      void *a;
1235      void *b;
1236 {
1237   export_type *ap = *(export_type **) a;
1238   export_type *bp = *(export_type **) b;
1239   if (ap->ordinal == bp->ordinal)
1240     return 0;
1241
1242   /* unset ordinals go to the bottom */
1243   if (ap->ordinal == -1)
1244     return 1;
1245   if (bp->ordinal == -1)
1246     return -1;
1247   return (ap->ordinal - bp->ordinal);
1248 }
1249
1250
1251 int
1252 nfunc (a, b)
1253      void *a;
1254      void *b;
1255 {
1256   export_type *ap = *(export_type **) a;
1257   export_type *bp = *(export_type **) b;
1258
1259   return (strcmp (ap->name, bp->name));
1260 }
1261
1262 static
1263 void
1264 remove_null_names (ptr)
1265      export_type **ptr;
1266 {
1267   int src;
1268   int dst;
1269   for (dst = src = 0; src < d_nfuncs; src++)
1270     {
1271       if (ptr[src])
1272         {
1273           ptr[dst] = ptr[src];
1274           dst++;
1275         }
1276     }
1277   d_nfuncs = dst;
1278 }
1279
1280 static void
1281 dtab (ptr)
1282      export_type **ptr;
1283 {
1284 #ifdef SACDEBUG
1285   int i;
1286   for (i = 0; i < d_nfuncs; i++)
1287     {
1288       if (ptr[i])
1289         {
1290           printf ("%d %s @ %d %s%s\n",
1291                   i, ptr[i]->name, ptr[i]->ordinal,
1292                   ptr[i]->noname ? "NONAME " : "",
1293                   ptr[i]->constant ? "CONSTANT" : "");
1294         }
1295       else
1296         printf ("empty\n");
1297     }
1298 #endif
1299 }
1300
1301 static void
1302 process_duplicates (d_export_vec)
1303      export_type **d_export_vec;
1304 {
1305   int more = 1;
1306   int i;  
1307   while (more)
1308     {
1309
1310       more = 0;
1311       /* Remove duplicates */
1312       qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
1313
1314       dtab (d_export_vec);
1315       for (i = 0; i < d_nfuncs - 1; i++)
1316         {
1317           if (strcmp (d_export_vec[i]->name,
1318                       d_export_vec[i + 1]->name) == 0)
1319             {
1320
1321               export_type *a = d_export_vec[i];
1322               export_type *b = d_export_vec[i + 1];
1323
1324               more = 1;
1325               if (verbose)
1326                 fprintf (stderr, "Warning, ignoring duplicate EXPORT %s %d,%d\n",
1327                          a->name,
1328                          a->ordinal,
1329                          b->ordinal);
1330               if (a->ordinal != -1
1331                   && b->ordinal != -1)
1332                 {
1333
1334                   fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
1335                            a->name);
1336                   exit (1);
1337                 }
1338               /* Merge attributes */
1339               b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
1340               b->constant |= a->constant;
1341               b->noname |= a->noname;
1342               d_export_vec[i] = 0;
1343             }
1344
1345           dtab (d_export_vec);
1346           remove_null_names (d_export_vec);
1347           dtab (d_export_vec);
1348         }
1349     }
1350
1351
1352   /* Count the names */
1353   for (i = 0; i < d_nfuncs; i++)
1354     {
1355       if (!d_export_vec[i]->noname)
1356         d_named_nfuncs++;
1357     }
1358 }
1359
1360 static void
1361 fill_ordinals (d_export_vec)
1362      export_type **d_export_vec;
1363 {
1364   int lowest = 0;
1365   int unset = 0;
1366   int hint = 0;
1367   int i;
1368   char *ptr;
1369   qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
1370
1371   /* fill in the unset ordinals with ones from our range */
1372
1373   ptr = (char *) malloc (65536);
1374
1375   memset (ptr, 65536, 0);
1376
1377   /* Mark in our large vector all the numbers that are taken */
1378   for (i = 0; i < d_nfuncs; i++)
1379     {
1380       if (d_export_vec[i]->ordinal != -1)
1381         {
1382           ptr[d_export_vec[i]->ordinal] = 1;
1383           if (lowest == 0)
1384             lowest = d_export_vec[i]->ordinal;
1385         }
1386     }
1387
1388   for (i = 0; i < d_nfuncs; i++)
1389     {
1390       if (d_export_vec[i]->ordinal == -1)
1391         {
1392           int j;
1393           for (j = lowest; j < 65536; j++)
1394             if (ptr[j] == 0)
1395               {
1396                 ptr[j] = 1;
1397                 d_export_vec[i]->ordinal = j;
1398                 goto done;
1399               }
1400
1401           for (j = 1; j < lowest; j++)
1402             if (ptr[j] == 0)
1403               {
1404                 ptr[j] = 1;
1405                 d_export_vec[i]->ordinal = j;
1406                 goto done;
1407               }
1408         done:;
1409
1410         }
1411     }
1412
1413   free (ptr);
1414
1415   /* And resort */
1416
1417   qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
1418
1419
1420   /* Work out the lowest ordinal number */
1421   if (d_export_vec[0])
1422     d_low_ord = d_export_vec[0]->ordinal;
1423   if (d_nfuncs) {
1424   if (d_export_vec[d_nfuncs-1])
1425     d_high_ord = d_export_vec[d_nfuncs-1]->ordinal;
1426 }
1427 }
1428
1429 int alphafunc(av,bv)
1430 void *av;
1431 void *bv;
1432 {
1433   export_type **a = av;
1434   export_type **b = bv;
1435
1436   return strcmp ((*a)->name, (*b)->name);
1437 }
1438
1439 void
1440 mangle_defs ()
1441 {
1442   /* First work out the minimum ordinal chosen */
1443
1444   export_type *exp;
1445   int lowest = 0;
1446   int i;
1447   int hint = 0;
1448   export_type **d_export_vec
1449   = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
1450
1451   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1452     {
1453       d_export_vec[i] = exp;
1454     }
1455
1456   process_duplicates (d_export_vec);
1457   fill_ordinals (d_export_vec);
1458
1459   /* Put back the list in the new order */
1460   d_exports = 0;
1461   for (i = d_nfuncs - 1; i >= 0; i--)
1462     {
1463       d_export_vec[i]->next = d_exports;
1464       d_exports = d_export_vec[i];
1465     }
1466
1467   /* Build list in alpha order */
1468   d_exports_lexically = (export_type **)xmalloc (sizeof(export_type *)*(d_nfuncs+1));
1469
1470   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1471     {
1472       d_exports_lexically[i] = exp;
1473     }
1474   d_exports_lexically[i] = 0;
1475
1476   qsort (d_exports_lexically, i, sizeof (export_type *), alphafunc);
1477
1478   /* Fill exp entries with their hint values */
1479   
1480   for (i = 0; i < d_nfuncs; i++)
1481     {
1482       if (!d_exports_lexically[i]->noname || show_allnames)
1483         d_exports_lexically[i]->hint = hint++;
1484     }
1485
1486 }
1487
1488
1489
1490   /* Work out exec prefix from the name of this file */
1491 void
1492 workout_prefix ()
1493 {
1494   char *ps = 0;
1495   char *s = 0;
1496   char *p;
1497   /* See if we're running in a devo tree */
1498   for (p = program_name; *p; p++)
1499     {
1500       if (*p == '/' || *p == '\\')
1501         {
1502           ps = s;
1503           s = p;
1504         }
1505     }
1506
1507   if (ps && strncmp (ps, "/binutils", 9) == 0)
1508     {
1509       /* running in the binutils directory, the other
1510          executables will be surrounding it in the usual places. */
1511       int len = ps - program_name;
1512       ar_name = xmalloc (len + strlen ("/binutils/ar") + 1);
1513       ranlib_name = xmalloc (len + strlen ("/binutils/ranlib") + 1);
1514       as_name = xmalloc (len + strlen ("/gas/as.new") + 1);
1515
1516       memcpy (ar_name, program_name, len);
1517       strcpy (ar_name + len, "/binutils/ar");
1518       memcpy (ranlib_name, program_name, len);
1519       strcpy (ranlib_name + len, "/binutils/ranlib");
1520       memcpy (as_name, program_name, len);
1521       strcpy (as_name + len, "/gas/as.new");
1522     }
1523   else
1524     {
1525       /* Otherwise chop off any prefix and use it for the rest of the progs,
1526          so i386-win32-dll generates i386-win32-ranlib etc etc */
1527
1528       for (p = program_name; *p; p++)
1529         {
1530           if (strncmp (p, "dlltool", 7) == 0)
1531             {
1532               int len = p - program_name;
1533               ar_name = xmalloc (len + strlen ("ar") + 1);
1534               ranlib_name = xmalloc (len + strlen ("ranlib") + 1);
1535               as_name = xmalloc (len + strlen ("as") + 1);
1536
1537               memcpy (ar_name, program_name, len);
1538               strcpy (ar_name + len, "ar");
1539               memcpy (ranlib_name, program_name, len);
1540               strcpy (ranlib_name + len, "ranlib");
1541               memcpy (as_name, program_name, len);
1542               strcpy (as_name + len, "as");
1543             }
1544         }
1545     }
1546 }
1547
1548
1549 /**********************************************************************/
1550
1551 void
1552 usage (file, status)
1553      FILE *file;
1554      int status;
1555 {
1556   fprintf (file, "Usage %s <options> <object-files>\n", program_name);
1557   fprintf (file, "   --machine <machine>\n");
1558   fprintf (file, "   --output-exp <outname> Generate export file.\n");
1559   fprintf (file, "   --output-lib <outname> Generate input library.\n");
1560   fprintf (file, "   --add-indirect         Add dll indirects to export file.\n");
1561   fprintf (file, "   --dllname <name>       Name of input dll to put into output lib.\n");
1562   fprintf (file, "   --def <deffile>        Name input .def file\n");
1563   fprintf (file, "   --output-def <deffile> Name output .def file\n");
1564   fprintf (file, "   --base-file <basefile> Read linker generated base file\n");
1565   fprintf (file, "   -v                     Verbose\n");
1566   fprintf (file, "   -U                     Add underscores to .lib\n");
1567   fprintf (file, "   -k                     Kill @<n> from exported names\n");
1568   fprintf (file, "   --nodelete             Keep temp files.\n");
1569   exit (status);
1570 }
1571
1572 static struct option long_options[] =
1573 {
1574   {"nodelete", no_argument, NULL, 'n'},
1575   {"dllname", required_argument, NULL, 'D'},
1576   {"output-exp", required_argument, NULL, 'e'},
1577   {"output-def", required_argument, NULL, 'z'},
1578   {"output-lib", required_argument, NULL, 'l'},
1579   {"def", required_argument, NULL, 'd'},
1580   {"add-underscore", no_argument, NULL, 'U'},
1581   {"killat", no_argument, NULL, 'k'},
1582   {"help", no_argument, NULL, 'h'},
1583   {"machine", required_argument, NULL, 'm'},
1584   {"add-indirect", no_argument, NULL, 'a'},
1585   {"base-file", required_argument, NULL, 'b'},
1586   0
1587 };
1588
1589
1590
1591 int
1592 main (ac, av)
1593      int ac;
1594      char **av;
1595 {
1596   int c;
1597   int i;
1598   char *firstarg = 0;
1599   program_name = av[0];
1600   oav = av;
1601
1602   while ((c = getopt_long (ac, av, "uaD:l:e:nkvbUh?m:yd:", long_options, 0)) != EOF)
1603     {
1604       switch (c)
1605         {
1606           /* ignored for compatibility */
1607         case 'u':
1608           break;
1609         case 'a':
1610           add_indirect = 1;
1611           break;
1612         case 'z':
1613           output_def = fopen (optarg, "w");
1614           break;
1615         case 'D':
1616           dll_name = optarg;
1617           break;
1618         case 'l':
1619           imp_name = optarg;
1620           break;
1621         case 'e':
1622           exp_name = optarg;
1623           break;
1624         case 'h':
1625         case '?':
1626           usage (stderr, 0);
1627           break;
1628         case 'm':
1629           mname = optarg;
1630           break;
1631         case 'v':
1632           verbose = 1;
1633           break;
1634         case 'y':
1635           yydebug = 1;
1636           break;
1637         case 'U':
1638           add_underscore = 1;
1639           break;
1640         case 'k':
1641           killat = 1;
1642           break;
1643         case 'd':
1644           def_file = optarg;
1645           break;
1646         case 'n':
1647           dontdeltemps++;
1648           break;
1649         case 'b':
1650           base_file = fopen (optarg, "r");
1651           if (!base_file)
1652             {
1653               fprintf (stderr, "%s: Unable to open base-file %s\n",
1654                        av[0],
1655                        optarg);
1656               exit (1);
1657             }
1658           break;
1659         default:
1660           usage (stderr, 1);
1661         }
1662     }
1663
1664
1665   for (i = 0; mtable[i].type; i++)
1666     {
1667       if (strcmp (mtable[i].type, mname) == 0)
1668         break;
1669     }
1670
1671   if (!mtable[i].type)
1672     {
1673       fprintf (stderr, "Machine not supported\n");
1674       exit (1);
1675     }
1676   machine = i;
1677
1678
1679   if (!dll_name && exp_name)
1680     {
1681       char len = strlen (exp_name) + 5;
1682       dll_name = xmalloc (len);
1683       strcpy (dll_name, exp_name);
1684       strcat (dll_name, ".dll");
1685     }
1686   workout_prefix ();
1687
1688
1689   if (def_file)
1690     {
1691       process_def_file (def_file);
1692     }
1693   while (optind < ac)
1694     {
1695       if (!firstarg)
1696         firstarg = av[optind];
1697       scan_obj_file (av[optind]);
1698       optind++;
1699     }
1700
1701
1702   mangle_defs ();
1703
1704   if (exp_name)
1705     gen_exp_file ();
1706   if (imp_name)
1707     {
1708       /* Make imp_name safe for use as a label. */
1709       char *p;
1710       imp_name_lab = strdup (imp_name);
1711       for (p = imp_name_lab; *p; *p++)
1712         {
1713           if (!isalpha (*p) && !isdigit (*p))
1714             *p = '_';
1715         }
1716       gen_lib_file ();
1717     }
1718   if (output_def)
1719     gen_def_file ();
1720
1721   return 0;
1722 }