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