Mon Jul 3 14:16:47 1995 Steve Chamberlain <sac@slash.cygnus.com>
[platform/upstream/binutils.git] / binutils / dlltool.c
1 /* dlltool.c -- tool to generate stuff for PE style DLLs 
2    Copyright (C) 1995 Free Software Foundation, Inc.
3
4    This file is part of GNU Binutils.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20
21 /*
22    This program allows you to build the files necessary to create
23    DLLs to run on a system which understands PE format image files.
24    (eg, Windows NT)
25
26    A DLL contains an export table which contains the information
27    which the runtime loader needs to tie up references from a
28    referencing program. 
29
30    The export table is generated by this program by reading
31    in a .DEF file or scanning the .a and .o files which will be in the
32    DLL.  A .o file can contain information in special  ".drective" sections
33    with export information.  
34
35    A DEF file contains any number of the following commands:
36
37
38    NAME <name> [ , <base> ] 
39    The result is going to be <name>.EXE
40
41    LIBRARY <name> [ , <base> ]    
42    The result is going to be <name>.DLL
43
44    EXPORTS  ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) *
45    Declares name1 as an exported symbol from the
46    DLL, with optional ordinal number <integer>
47
48    IMPORTS  ( [ <name> = ] <name> . <name> ) *
49    Ignored for compatibility
50
51    DESCRIPTION <string>
52    Puts <string> into output .exp file in the .rdata section
53
54    [STACKSIZE|HEAPSIZE] <number-reserve> [ , <number-commit> ]
55    Generates --stack|--heap <number-reserve>,<number-commit>
56    in the output .drective section.  The linker will
57    see this and act upon it.
58
59    [CODE|DATA] <attr>+
60    SECTIONS ( <sectionname> <attr>+ )*
61    <attr> = READ | WRITE | EXECUTE | SHARED
62    Generates --attr <sectionname> <attr> in the output
63    .drective section.  The linker will see this and act
64    upon it.
65
66
67    A -export:<name> in a .drective section in an input .o or .a
68    file to this program is equivalent to a EXPORTS <name>
69    in a .DEF file.
70
71
72
73    The program generates output files with the prefix supplied
74    on the command line, or in the def file, or taken from the first 
75    supplied argument.
76
77    The output files are <prefix>-exp.s and <prefix>-lib.s
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 -o thedll -d thedll.def thedll.in
151
152    # build the export table for the dll
153    as -o thedll.exp thedll-exp.s
154    # build the dll with the library with file1.o, file2.o and the export table
155    ld -o thedll.dll thedll.exp thedll.in
156
157    # build the import table for the executable
158    as -o thedll.lib thedll-lib.s
159
160    # build the mainline
161    gcc -c themain.c 
162
163    # link the executable with the import library
164    ld -e main -Tthemain.ld -o themain.exe themain.o thedll.lib
165
166  */
167
168 #define PAGE_SIZE 4096
169 #define PAGE_MASK (-PAGE_SIZE)
170 #include <stdio.h>
171 #include <stdlib.h>
172 #include <string.h>
173 #include "getopt.h"
174 #include "bfd.h"
175 int yydebug;
176 char *def_file;
177 char *program_name;
178 char *strrchr ();
179 char *outfile_prefix;
180 char *xmalloc ();
181 char *strdup ();
182
183 static int machine;
184 int suckunderscore;
185 int killat;
186 static int verbose;
187 FILE *base_file;
188 #ifdef DLLTOOL_ARM
189 static char *mname = "arm";
190 #endif
191
192 #ifdef DLLTOOL_I386
193 static char *mname = "i386";
194 #endif
195 #define PATHMAX 250             /* What's the right name for this ? */
196
197 char outfile[PATHMAX];
198 struct mac
199   {
200     char *type;
201     char *how_byte;
202     char *how_short;
203     char *how_long;
204     char *how_asciz;
205     char *how_comment;
206     char *how_jump;
207     char *how_global;
208     char *how_space;
209   }
210 mtable[]
211 =
212 {
213   {
214     "arm", ".byte", ".short", ".long", ".asciz", "@", "ldr\tip,[pc]\n\tldr\tpc,[ip]\n\t.long", ".global", ".space"
215   }
216   ,
217   {
218     "i386", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space"
219   }
220   ,
221     0
222 };
223
224 #define ASM_BYTE        mtable[machine].how_byte
225 #define ASM_SHORT       mtable[machine].how_short
226 #define ASM_LONG        mtable[machine].how_long
227 #define ASM_TEXT        mtable[machine].how_asciz
228 #define ASM_C           mtable[machine].how_comment
229 #define ASM_JUMP        mtable[machine].how_jump
230 #define ASM_GLOBAL      mtable[machine].how_global
231 #define ASM_SPACE       mtable[machine].how_space
232
233
234 static char **oav;
235
236 int i;
237
238 FILE *yyin;                     /* communications with flex */
239 extern int linenumber;
240 void
241 process_def_file (name)
242      char *name;
243 {
244   FILE *f = fopen (name, "r");
245   if (!f)
246     {
247       fprintf (stderr, "%s: Can't open def file %s\n", program_name, name);
248       exit (1);
249     }
250
251   yyin = f;
252
253   yyparse ();
254 }
255
256 /**********************************************************************/
257
258 /* Communications with the parser */
259
260
261 typedef struct dlist
262 {
263   char *text;
264   struct dlist *next;
265 }
266 dlist_type;
267
268 typedef struct export
269   {
270     char *name;
271     char *internal_name;
272     int ordinal;
273     int constant;
274     int noname;
275     struct export *next;
276   }
277 export_type;
278
279 static char *d_name;            /* Arg to NAME or LIBRARY */
280 static int d_nfuncs;            /* Number of functions exported */
281 static int d_ord;               /* Base ordinal index */
282 static export_type *d_exports;  /*list of exported functions */
283 static char *d_suffix = "dll";
284 static dlist_type *d_list;      /* Descriptions */
285 static dlist_type *a_list;      /* Stuff to go in directives */
286
287 static int d_is_dll;
288 static int d_is_exe;
289
290 yyerror ()
291 {
292   fprintf (stderr, "%s: Syntax error in def file %s:%d\n",
293            program_name, def_file, linenumber);
294 }
295
296 void
297 def_exports (name, internal_name, ordinal, noname, constant)
298      char *name;
299      char *internal_name;
300      int ordinal;
301      int noname;
302      int constant;
303 {
304   struct export *p = (struct export *) xmalloc (sizeof (*p));
305
306   p->name = name;
307   p->internal_name = internal_name ? internal_name : name;
308   p->ordinal = ordinal;
309   p->constant = constant;
310   p->noname = noname;
311   p->next = d_exports;
312   d_exports = p;
313   d_nfuncs++;
314 }
315
316
317 void
318 def_name (name, base)
319      char *name;
320      int base;
321 {
322   if (verbose)
323     fprintf (stderr, "%s NAME %s base %x\n", program_name, name, base);
324   if (d_is_dll)
325     {
326       fprintf (stderr, "Can't have LIBRARY and NAME\n");
327     }
328   d_name = name;
329   if (strchr (d_name, '.'))
330     d_suffix = strdup (strchr (d_name, '.') + 1);
331   d_is_exe = 1;
332 }
333
334 void
335 def_library (name, base)
336      char *name;
337      int base;
338 {
339   if (verbose)
340     printf ("%s: LIBRARY %s base %x\n", program_name, name, base);
341   if (d_is_exe)
342     {
343       fprintf (stderr, "%s: Can't have LIBRARY and NAME\n", program_name);
344     }
345   d_name = name;
346   if (strchr (d_name, '.'))
347     d_suffix = strdup (strchr (d_name, '.') + 1);
348   d_is_dll = 1;
349 }
350
351 void
352 def_description (desc)
353      char *desc;
354 {
355   dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type));
356   d->text = strdup (desc);
357   d->next = d_list;
358   d_list = d;
359 }
360
361 void 
362 new_directive (dir)
363      char *dir;
364 {
365   dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type));
366   d->text = strdup (dir);
367   d->next = a_list;
368   a_list = d;
369 }
370
371 void
372 def_stacksize (reserve, commit)
373      int reserve;
374      int commit;
375 {
376   char b[200];
377   if (commit > 0)
378     sprintf (b, "-stack 0x%x,0x%x ", reserve, commit);
379   else
380     sprintf (b, "-stack 0x%x ", reserve);
381   new_directive (strdup (b));
382 }
383
384 void
385 def_heapsize (reserve, commit)
386      int reserve;
387      int commit;
388 {
389   char b[200];
390   if (commit > 0)
391     sprintf (b, "-heap 0x%x,0x%x ", reserve, commit);
392   else
393     sprintf (b, "-heap 0x%x ", reserve);
394   new_directive (strdup (b));
395 }
396
397
398 void
399 def_import (internal, module, entry)
400      char *internal;
401      char *module;
402      char *entry;
403 {
404   if (verbose)
405     fprintf (stderr, "%s: IMPORTS are ignored", program_name);
406 }
407
408 void
409 def_version (major, minor)
410 {
411   printf ("VERSION %d.%d\n", major, minor);
412 }
413
414
415 void
416 def_section (name, attr)
417      char *name;
418      int attr;
419 {
420   char buf[200];
421   char atts[5];
422   char *d = atts;
423   if (attr & 1)
424     *d++ = 'R';
425
426   if (attr & 2)
427     *d++ = 'W';
428   if (attr & 4)
429     *d++ = 'X';
430   if (attr & 8)
431     *d++ = 'S';
432   *d++ = 0;
433   sprintf (buf, "-attr %s %s", name, atts);
434   new_directive (strdup (buf));
435 }
436 void
437 def_code (attr)
438      int attr;
439 {
440
441   def_section ("CODE", attr);
442 }
443
444 void
445 def_data (attr)
446      int attr;
447 {
448   def_section ("DATA", attr);
449 }
450
451
452 /**********************************************************************/
453
454 /* read in and block out the base relocations */
455 static void 
456 basenames (abfd)
457      bfd *abfd;
458 {
459
460
461
462
463 }
464
465 void
466 scan_open_obj_file (abfd)
467      bfd *abfd;
468 {
469   /* Look for .drectives */
470   asection *s = bfd_get_section_by_name (abfd, ".drectve");
471   if (s)
472     {
473       int size = bfd_get_section_size_before_reloc (s);
474       char *buf = xmalloc (size);
475       char *p;
476       char *e;
477       bfd_get_section_contents (abfd, s, buf, 0, size);
478       if (verbose)
479         fprintf (stderr, "%s: Sucking in info from %s\n",
480                  program_name,
481                  bfd_get_filename (abfd));
482
483       /* Search for -export: strings */
484       p = buf;
485       e = buf + size;
486       while (p < e)
487         {
488           if (p[0] == '-'
489               && strncmp (p, "-export:", 8) == 0)
490             {
491               char *name;
492               char *c;
493               p += 8;
494               name = p;
495               while (*p != ' ' && *p != '-' && p < e)
496                 p++;
497               c = xmalloc (p - name + 1);
498               memcpy (c, name, p - name);
499               c[p - name] = 0;
500               def_exports (c, 0, -1, 0);
501             }
502           else
503             p++;
504         }
505       free (buf);
506     }
507
508   basenames (abfd);
509
510   if (verbose)
511     fprintf (stderr, "%s: Done readin\n",
512              program_name);
513
514 }
515
516
517 void
518 scan_obj_file (filename)
519      char *filename;
520 {
521   bfd *f = bfd_openr (filename, 0);
522
523   if (!f)
524     {
525       fprintf (stderr, "%s: Unable to open object file %s\n", 
526                program_name, 
527                filename);
528       exit (1);
529     }
530   if (bfd_check_format (f, bfd_archive))
531     {
532       bfd *arfile = bfd_openr_next_archived_file (f, 0);
533       while (arfile)
534         {
535           if (bfd_check_format (arfile, bfd_object))
536             scan_open_obj_file (arfile);
537           bfd_close (arfile);
538           arfile = bfd_openr_next_archived_file (f, arfile);
539         }
540     }
541
542   if (bfd_check_format (f, bfd_object))
543     {
544       scan_open_obj_file (f);
545     }
546
547   bfd_close (f);
548 }
549
550 /**********************************************************************/
551
552
553 /* return the bit of the name before the last . */
554
555 static
556 char *
557 prefix (name)
558      char *name;
559 {
560   char *res = strdup (name);
561   char *p = strrchr (res, '.');
562   if (p)
563     *p = 0;
564   return res;
565 }
566
567 void
568 dump_def_info (f)
569      FILE *f;
570 {
571   int i;
572   export_type *exp;
573   fprintf (f, "%s ", ASM_C);
574   for (i = 0; oav[i]; i++)
575     fprintf (f, "%s ", oav[i]);
576   fprintf (f, "\n");
577   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
578     {
579       fprintf (f, "%s  %d = %s %s @ %d %s%s\n",
580                ASM_C,
581                i,
582                exp->name,
583                exp->internal_name,
584                exp->ordinal,
585                exp->noname ? "NONAME " : "",
586                exp->constant ? "CONSTANT" : "");
587     }
588 }
589 /* Generate the .exp file */
590
591 int
592 sfunc (a, b)
593      long *a;
594      long *b;
595 {
596   return *a - *b;
597 }
598
599 static void 
600 flush_page (f, need, page_addr, on_page)
601      FILE *f;
602      long *need;
603      long page_addr;
604      int on_page;
605 {
606   int i;
607   /* Flush this page */
608   fprintf (f, "\t%s\t0x%x\t%s Starting RVA for chunk\n",
609            ASM_LONG,
610            page_addr,
611            ASM_C);
612   fprintf (f, "\t%s\t0x%x\t%s Size of block\n",
613            ASM_LONG,
614            (on_page * 2) + (on_page & 1) * 2 + 8,
615            ASM_C);
616   for (i = 0; i < on_page; i++)
617     {
618       fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, need[i] - page_addr | 0x3000);
619     }
620   /* And padding */
621   if (on_page & 1)
622     fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, 0 | 0x0000);
623
624 }
625
626
627 void
628 gen_exp_file ()
629 {
630   FILE *f;
631   int i;
632   export_type *exp;
633   dlist_type *dl;
634   int had_noname = 0;
635
636   sprintf (outfile, "%s-exp.s", outfile_prefix);
637
638   if (verbose)
639     fprintf (stderr, "%s: Generate exp file %s\n",
640              program_name, outfile_prefix);
641
642   f = fopen (outfile, "w");
643   if (!f)
644     {
645       fprintf (stderr, "%s: Unable to open output file %s\n", program_name, outfile);
646       exit (1);
647     }
648   if (verbose)
649     {
650       fprintf (stderr, "%s: Opened file %s\n",
651                program_name, outfile);
652     }
653
654   dump_def_info (f);
655   fprintf (f, "\t.section       .edata\n\n");
656   fprintf (f, "\t%s     0       %s Allways 0\n", ASM_LONG, ASM_C);
657   fprintf (f, "\t%s     %d      %s Time and date\n", ASM_LONG, time (0), ASM_C);
658   fprintf (f, "\t%s     0       %s Major and Minor version\n", ASM_LONG, ASM_C);
659   fprintf (f, "\t%s     name    %s Ptr to name of dll\n", ASM_LONG, ASM_C);
660   fprintf (f, "\t%s     %d      %s Starting ordinal of exports\n", ASM_LONG, d_ord, ASM_C);
661   fprintf (f, "\t%s The next field is documented as being the number of functions\n", ASM_C);
662   fprintf (f, "\t%s yet it doesn't look like that in real PE dlls\n", ASM_C);
663   fprintf (f, "\t%s But it shouldn't be a problem, causes there's\n", ASM_C);
664   fprintf (f, "\t%s always the number of names field\n", ASM_C);
665   fprintf (f, "\t%s     %d      %s Number of functions\n", ASM_LONG, d_nfuncs, ASM_C);
666   fprintf (f, "\t%s     %d      %s Number of names\n", ASM_LONG, d_nfuncs, ASM_C);
667   fprintf (f, "\t%s     afuncs  %s Address of functions\n", ASM_LONG, ASM_C);
668   fprintf (f, "\t%s     anames  %s Address of names\n", ASM_LONG, ASM_C);
669   fprintf (f, "\t%s     anords  %s Address of ordinals\n", ASM_LONG, ASM_C);
670
671   fprintf (f, "name:    %s      \"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
672
673   fprintf (f, "afuncs:\n");
674   i = d_ord;
675   for (exp = d_exports; exp; exp = exp->next)
676     {
677 #if 0
678       /* This seems necessary in the doc, but in real
679          life it's not used.. */
680       if (exp->ordinal != i)
681         {
682           fprintf (f, "%s\t%s\t%d\t@ %d..%d missing\n", ASM_C, ASM_SPACE,
683                    (exp->ordinal - i) * 4,
684                    i, exp->ordinal - 1);
685           i = exp->ordinal;
686         }
687 #endif
688       fprintf (f, "\t%s %s\t%s %d\n", ASM_LONG, exp->internal_name, ASM_C, exp->ordinal);
689       i++;
690     }
691
692
693   fprintf (f, "anames:\n");
694   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
695     {
696       if (exp->noname)
697         {
698           had_noname = 1;
699           fprintf (f, "\t%s     nNoname\n", ASM_LONG, ASM_C);
700         }
701       else
702         {
703           fprintf (f, "\t%s     n%d\n", ASM_LONG, i);
704         }
705     }
706
707   fprintf (f, "anords:\n");
708   for (exp = d_exports; exp; exp = exp->next)
709     fprintf (f, "\t%s   %d\n", ASM_SHORT, exp->ordinal - d_ord);
710
711   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
712     if (exp->noname)
713       fprintf (f, "@n%d:        %s      \"%s\"\n", i, ASM_TEXT, exp->name);
714     else
715       fprintf (f, "n%d: %s      \"%s\"\n", i, ASM_TEXT, exp->name);
716
717   if (had_noname)
718     fprintf (f, "nNoname:       %s      \"__noname__\"\n", ASM_TEXT);
719
720   if (a_list)
721     {
722       fprintf (f, "\t.section .drectve\n");
723       for (dl = a_list; dl; dl = dl->next)
724         {
725           fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
726         }
727     }
728   if (d_list)
729     {
730       fprintf (f, "\t.section .rdata\n");
731       for (dl = d_list; dl; dl = dl->next)
732         {
733           char *p;
734           int l;
735           /* We dont output as ascii 'cause there can
736              be quote characters in the string */
737
738           l = 0;
739           for (p = dl->text; *p; p++)
740             {
741               if (l == 0)
742                 fprintf (f, "\t%s\t", ASM_BYTE);
743               else
744                 fprintf (f, ",");
745               fprintf (f, "%d", *p);
746               if (p[1] == 0)
747                 {
748                   fprintf (f, ",0\n");
749                   break;
750                 }
751               if (++l == 10)
752                 {
753                   fprintf (f, "\n");
754                   l = 0;
755                 }
756             }
757         }
758     }
759
760   /* Dump the reloc section if a base file is provided */
761   if (base_file)
762     {
763       int addr;
764       long need[PAGE_SIZE];
765       long page_addr;
766       int numbytes;
767       int num_entries;
768       long *copy;
769       int j;
770       int on_page;
771       fprintf (f, "\t.section\t.reloc\n");
772       fseek (base_file, 0, SEEK_END);
773       numbytes = ftell (base_file);
774       fseek (base_file, 0, SEEK_SET);
775       copy = malloc (numbytes);
776       fread (copy, 1, numbytes, base_file);
777       num_entries = numbytes / sizeof (long);
778
779       qsort (copy, num_entries, sizeof (long), sfunc);
780
781       addr = copy[0];
782       page_addr = addr & PAGE_MASK;     /* work out the page addr */
783       on_page = 0;
784       for (j = 0; j < num_entries; j++)
785         {
786           addr = copy[j];
787           if ((addr & PAGE_MASK) != page_addr)
788             {
789               flush_page (f, need, page_addr, on_page);
790               on_page = 0;
791               page_addr = addr & PAGE_MASK;
792             }
793           need[on_page++] = addr;
794         }
795       flush_page (f, need, page_addr, on_page);
796     }
797
798   fclose (f);
799 }
800
801 static char *
802 xlate (char *name)
803 {
804
805   if (!suckunderscore)
806     return name;
807
808   if (name[0] == '_')
809     name++;
810   if (killat) {
811     char *p;
812     p = strchr (name, '@');
813     if (p)
814       *p = 0;
815   }
816   return name;
817 }
818
819 /**********************************************************************/
820 gen_lib_file ()
821 {
822   int i;
823   FILE *f;
824   export_type *exp;
825
826   sprintf (outfile, "%s-lib.s", outfile_prefix);
827
828   f = fopen (outfile, "w");
829   if (!f)
830     {
831       fprintf (stderr, "Unable to open output file %s\n", outfile);
832       exit (1);
833     }
834
835
836   dump_def_info (f);
837   fprintf (f, "\t.text\n");
838   fprintf (f, "%s Thunk table\n", ASM_C);
839   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
840     {
841       fprintf (f, "\t%s\t%s\n", ASM_GLOBAL, exp->name);
842       fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
843     }
844
845   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
846     {
847       fprintf (f, "%s:\t%s\t__imp_%s\n", exp->name, ASM_JUMP, exp->name);
848     }
849
850
851   fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
852   fprintf (f, "\t.section       .idata$2\n");
853   fprintf (f, "\t%s\thname\t%s Ptr to image import by name list\n", ASM_LONG, ASM_C);
854   fprintf (f, "\t%s\t%d\t%s time\n", ASM_LONG, time (0), ASM_C);
855   fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
856   fprintf (f, "\t%s\tiname\t%s imported dll's name\n", ASM_LONG, ASM_C);
857   fprintf (f, "\t%s\tfthunk\t%s pointer to firstthunk\n", ASM_LONG, ASM_C);
858
859   fprintf (f, "%sStuff for compatibility\n", ASM_C);
860   fprintf (f, "\t.section\t.idata$3\n");
861   fprintf (f, "\t%s\t0\n", ASM_LONG);
862   fprintf (f, "\t%s\t0\n", ASM_LONG);
863   fprintf (f, "\t%s\t0\n", ASM_LONG);
864   fprintf (f, "\t%s\t0\n", ASM_LONG);
865   fprintf (f, "\t%s\t0\n", ASM_LONG);
866   fprintf (f, "\t.section\t.idata$5\n");
867   fprintf (f, "\t%s\t0\n", ASM_LONG);
868
869   fprintf (f, "\t.section\t.idata$4\n");
870   fprintf (f, "\t%s\t0\n", ASM_LONG);
871
872   fprintf (f, "\n%s Loader modifies this\n", ASM_C);
873   fprintf (f, "\t.section       .idata$5\n");
874   fprintf (f, "fthunk:\n");
875   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
876     {
877       fprintf (f, "__imp_%s:\n", exp->name);
878       fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
879     }
880   fprintf (f, "\t%s\t0\n", ASM_LONG);
881
882   fprintf (f, "\n%s Hint name array\n", ASM_C);
883   fprintf (f, "\t.section       .idata$4\n");
884   fprintf (f, "hname:\n");
885   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
886     {
887       fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
888     }
889
890   fprintf (f, "\t%s\t0\n", ASM_LONG);
891   fprintf (f, "%s Hint/name array storage and import dll name\n", ASM_C);
892   fprintf (f, "\t.section       .idata$6\n");
893
894   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
895     {
896       fprintf (f, "ID%d:\t%s\t%d\n", i, ASM_SHORT, exp->ordinal);
897       fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name));
898     }
899   fprintf (f, "\t%s\t0\n", ASM_LONG);
900   fprintf (f, "iname:\t%s\t\"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
901   fclose (f);
902 }
903 /**********************************************************************/
904
905 /* Run through the information gathered from the .o files and the
906    .def file and work out the best stuff */
907 int
908 pfunc (a, b)
909      void *a;
910      void *b;
911 {
912   export_type *ap = *(export_type **) a;
913   export_type *bp = *(export_type **) b;
914   if (ap->ordinal == bp->ordinal)
915     return 0;
916
917   /* unset ordinals go to the bottom */
918   if (ap->ordinal == -1)
919     return 1;
920   if (bp->ordinal == -1)
921     return -1;
922   return (ap->ordinal - bp->ordinal);
923 }
924
925
926 int
927 nfunc (a, b)
928      void *a;
929      void *b;
930 {
931   export_type *ap = *(export_type **) a;
932   export_type *bp = *(export_type **) b;
933
934   return (strcmp (ap->name, bp->name));
935 }
936
937 static
938 void
939 remove_null_names (ptr)
940      export_type **ptr;
941 {
942   int src;
943   int dst;
944   for (dst = src = 0; src < d_nfuncs; src++)
945     {
946       if (ptr[src])
947         {
948           ptr[dst] = ptr[src];
949           dst++;
950         }
951     }
952   d_nfuncs = dst;
953 }
954
955 static void
956 dtab (ptr)
957      export_type **ptr;
958 {
959 #ifdef SACDEBUG
960   int i;
961   for (i = 0; i < d_nfuncs; i++)
962     {
963       if (ptr[i])
964         {
965           printf ("%d %s @ %d %s%s\n",
966                   i, ptr[i]->name, ptr[i]->ordinal,
967                   ptr[i]->noname ? "NONAME " : "",
968                   ptr[i]->constant ? "CONSTANT" : "");
969         }
970       else
971         printf ("empty\n");
972     }
973 #endif
974 }
975
976 static void
977 process_duplicates (d_export_vec)
978      export_type **d_export_vec;
979 {
980   int more = 1;
981
982   while (more)
983     {
984       more = 0;
985       /* Remove duplicates */
986       qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
987
988       dtab (d_export_vec);
989       for (i = 0; i < d_nfuncs - 1; i++)
990         {
991           if (strcmp (d_export_vec[i]->name,
992                       d_export_vec[i + 1]->name) == 0)
993             {
994
995               export_type *a = d_export_vec[i];
996               export_type *b = d_export_vec[i + 1];
997
998               more = 1;
999               if (verbose)
1000                 fprintf (stderr, "Warning, ignoring duplicate EXPORT %s %d,%d\n",
1001                          a->name,
1002                          a->ordinal,
1003                          b->ordinal);
1004               if (a->ordinal != -1
1005                   && b->ordinal != -1)
1006                 {
1007
1008                   fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
1009                            a->name);
1010                   exit (1);
1011                 }
1012               /* Merge attributes */
1013               b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
1014               b->constant |= a->constant;
1015               b->noname |= a->noname;
1016               d_export_vec[i] = 0;
1017             }
1018
1019           dtab (d_export_vec);
1020           remove_null_names (d_export_vec);
1021           dtab (d_export_vec);
1022         }
1023     }
1024 }
1025
1026 static void
1027 fill_ordinals (d_export_vec)
1028      export_type **d_export_vec;
1029 {
1030   int lowest = 0;
1031   int unset = 0;
1032   char *ptr;
1033   qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
1034
1035   /* fill in the unset ordinals with ones from our range */
1036
1037   ptr = (char *) malloc (65536);
1038
1039   memset (ptr, 65536, 0);
1040
1041   /* Mark in our large vector all the numbers that are taken */
1042   for (i = 0; i < d_nfuncs; i++)
1043     {
1044       if (d_export_vec[i]->ordinal != -1)
1045         {
1046           ptr[d_export_vec[i]->ordinal] = 1;
1047           if (lowest == 0)
1048             lowest = d_export_vec[i]->ordinal;
1049         }
1050     }
1051
1052   for (i = 0; i < d_nfuncs; i++)
1053     {
1054       if (d_export_vec[i]->ordinal == -1)
1055         {
1056           int j;
1057           for (j = lowest; j < 65536; j++)
1058             if (ptr[j] == 0)
1059               {
1060                 ptr[j] = 1;
1061                 d_export_vec[i]->ordinal = j;
1062                 goto done;
1063               }
1064
1065           for (j = 1; j < lowest; j++)
1066             if (ptr[j] == 0)
1067               {
1068                 ptr[j] = 1;
1069                 d_export_vec[i]->ordinal = j;
1070                 goto done;
1071               }
1072         done:;
1073
1074         }
1075     }
1076
1077   free (ptr);
1078
1079   /* And resort */
1080
1081   qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
1082
1083   /* Work out the lowest ordinal number */
1084   if (d_export_vec[0])
1085     d_ord = d_export_vec[0]->ordinal;
1086 }
1087 void
1088 mangle_defs ()
1089 {
1090   /* First work out the minimum ordinal chosen */
1091
1092   export_type *exp;
1093   int lowest = 0;
1094   int i;
1095   export_type **d_export_vec
1096   = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
1097
1098   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1099     {
1100       d_export_vec[i] = exp;
1101     }
1102
1103   process_duplicates (d_export_vec);
1104   fill_ordinals (d_export_vec);
1105
1106   /* Put back the list in the new order */
1107   d_exports = 0;
1108   for (i = d_nfuncs - 1; i >= 0; i--)
1109     {
1110       d_export_vec[i]->next = d_exports;
1111       d_exports = d_export_vec[i];
1112     }
1113 }
1114
1115
1116 /**********************************************************************/
1117
1118 void
1119 usage (file, status)
1120      FILE *file;
1121      int status;
1122 {
1123   fprintf (file, "Usage %s <options> <object-files>\n", program_name);
1124   fprintf (file, "\t -m <machine>           Generate code for <machine>\n");
1125   fprintf (file, "\t --machine <machine>\n");
1126   fprintf (file, "\t -o <outprefix>         Set output prefix\n");
1127   fprintf (file, "\t -d <deffile>           Name input .def file\n");
1128   fprintf (file, "\t --def <deffile> \n");
1129   fprintf (file, "\t --base-file <basefile> Read linker generated base file\n");
1130   fprintf (file, "\t -b <basefile> \n");
1131   fprintf (file, "\t -v                     Verbose\n");
1132   fprintf (file, "\t -u                     Remove leading underscore from .lib\n");
1133   fprintf (file, "\t -k                     Kill @<n> from exported names\n");
1134   exit (status);
1135 }
1136
1137 static struct option long_options[] =
1138 {
1139   {"def", required_argument, NULL, 'd'},
1140   {"underscore", no_argument, NULL, 'u'},
1141   {"killat", no_argument, NULL, 'k'},
1142   {"help", no_argument, NULL, 'h'},
1143   {"machine", required_argument, NULL, 'm'},
1144   {"base-file", required_argument, NULL, 'b'},
1145   0
1146 };
1147
1148 int
1149 main (ac, av)
1150      int ac;
1151      char **av;
1152 {
1153   int c;
1154   char *firstarg = 0;
1155   program_name = av[0];
1156   oav = av;
1157
1158   while ((c = getopt_long (ac, av, "kvbuh?m:o:Dd:", long_options, 0)) != EOF)
1159     {
1160       switch (c)
1161         {
1162         case 'h':
1163         case '?':
1164           usage (stderr, 0);
1165           break;
1166         case 'm':
1167           mname = optarg;
1168           break;
1169         case 'o':
1170           outfile_prefix = optarg;
1171           break;
1172         case 'v':
1173           verbose = 1;
1174           break;
1175         case 'D':
1176           yydebug = 1;
1177           break;
1178         case 'u':
1179           suckunderscore = 1;
1180           break;
1181         case 'k':
1182           killat = 1;
1183           break;
1184         case 'd':
1185           def_file = optarg;
1186           break;
1187         case 'b':
1188           base_file = fopen (optarg, "r");
1189           if (!base_file)
1190             {
1191               fprintf (stderr, "%s: Unable to open base-file %s\n",
1192                        av[0],
1193                        optarg);
1194               exit (1);
1195             }
1196           break;
1197         default:
1198           usage (stderr, 1);
1199         }
1200     }
1201
1202
1203   for (i = 0; mtable[i].type; i++)
1204     {
1205       if (strcmp (mtable[i].type, mname) == 0)
1206         break;
1207     }
1208
1209   if (!mtable[i].type)
1210     {
1211       fprintf (stderr, "Machine not supported\n");
1212       exit (1);
1213     }
1214   machine = i;
1215
1216
1217   if (def_file)
1218     {
1219       process_def_file (def_file);
1220     }
1221   while (optind < ac)
1222     {
1223       if (!firstarg)
1224         firstarg = av[optind];
1225       scan_obj_file (av[optind]);
1226       optind++;
1227     }
1228
1229   if (!outfile_prefix)
1230     {
1231       if (d_name)
1232         outfile_prefix = d_name;
1233       else if (def_file)
1234         outfile_prefix = def_file;
1235       else if (firstarg)
1236         outfile_prefix = firstarg;
1237       else
1238         {
1239           fprintf (stderr, "No way to create an output filename\n");
1240           exit (1);
1241         }
1242     }
1243   outfile_prefix = prefix (outfile_prefix);
1244
1245   if (verbose)
1246     fprintf (stderr, "%s: Outfile prefix is %s\n",
1247              program_name, outfile_prefix);
1248   mangle_defs ();
1249
1250   gen_exp_file ();
1251
1252
1253   gen_lib_file ();
1254
1255   return 0;
1256 }