Wed Jun 14 13:27:22 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    
169 #include <stdio.h>
170 #include <stdlib.h>
171 #include <string.h>
172 #include "getopt.h"
173 #include "bfd.h"
174 int yydebug;
175 char *def_file;
176 char *program_name;
177 char *strrchr ();
178 char *outfile_prefix;
179 char *xmalloc ();
180 char *strdup ();
181
182 static int machine;
183
184 #ifdef DLLTOOL_ARM
185 static char *mname  = "arm";
186 #endif
187
188 #ifdef DLLTOOL_I386
189 static char *mname  = "i386";
190 #endif
191
192 struct mac
193 {
194   char *type;
195   char *how_byte;
196   char *how_short;
197   char *how_long;
198   char *how_asciz;
199   char *how_comment;
200   char *how_jump;
201   char *how_global;
202   char *how_space;
203 } mtable[]
204 = {{"arm",".byte",".short",".long",".asciz","@","bl",".global",".space"},
205    {"i386",".byte",".short",".long",".asciz",";","jmp",".global",".space"},
206  0};
207
208 #define ASM_BYTE        mtable[machine].how_byte
209 #define ASM_SHORT       mtable[machine].how_short
210 #define ASM_LONG        mtable[machine].how_long
211 #define ASM_TEXT        mtable[machine].how_asciz
212 #define ASM_C           mtable[machine].how_comment
213 #define ASM_JUMP        mtable[machine].how_jump
214 #define ASM_GLOBAL      mtable[machine].how_global
215 #define ASM_SPACE       mtable[machine].how_space
216
217 #define PATHMAX 250             /* What's the right name for this ? */
218 static char **oav;
219
220 int i;
221
222 FILE *yyin;                     /* communications with flex */
223 extern int linenumber;
224 void
225 process_def_file (name)
226      char *name;
227 {
228   FILE *f = fopen (name, "r");
229   if (!f)
230     {
231       fprintf (stderr, "Can't open def file %s\n", name);
232       exit (1);
233     }
234
235   yyin = f;
236
237   yyparse ();
238 }
239
240 /**********************************************************************/
241
242 /* Communications with the parser */
243
244
245 typedef struct dlist
246 {
247   char *text;
248   struct dlist *next;
249 } dlist_type;
250
251 typedef struct export
252 {
253   char *name;
254   char *equal;
255   int ordinal;
256   int constant;
257   int noname;
258   struct export *next;
259 }
260 export_type;
261
262 static char *d_name;            /* Arg to NAME or LIBRARY */
263 static int d_nfuncs;            /* Number of functions exported */
264 static int d_ord;               /* Base ordinal index */
265 static export_type *d_exports;  /*list of exported functions */
266 static char *d_suffix = "dll";
267 static dlist_type *d_list; /* Descriptions */
268 static dlist_type *a_list;  /* Stuff to go in directives */
269
270 static int d_is_dll;
271 static int d_is_exe;
272
273 yyerror ()
274 {
275   fprintf (stderr, "Syntax error in def file %s:%d\n",
276            def_file, linenumber);
277 }
278
279 void
280 def_exports (name, equal, ordinal, noname, constant)
281      char *name;
282      char *equal;
283      int ordinal;
284      int noname;
285      int constant;
286 {
287   struct export *p = (struct export *) xmalloc (sizeof (*p));
288
289   p->name = name;
290   p->equal = equal;
291   p->ordinal = ordinal;
292   p->constant = constant;
293   p->noname = noname;
294   p->next = d_exports;
295   d_exports = p;
296   d_nfuncs++;
297
298
299   printf ("EXPORTS %s", name);
300   if (equal)
301     printf ("=%s", equal);
302   if (ordinal > 0)
303     printf ("@%d", ordinal);
304   if (constant)
305     printf (" CONSTANT");
306   printf ("\n");
307 }
308
309 void
310 def_name (name, base)
311      char *name;
312      int base;
313 {
314   printf ("NAME %s base %x\n", name, base);
315   if (d_is_dll)
316     {
317       fprintf (stderr, "Can't have LIBRARY and NAME\n");
318     }
319   d_name = name;
320   if (strchr (d_name, '.'))
321     d_suffix = strdup (strchr (d_name, '.') + 1);
322   d_is_exe = 1;
323 }
324
325 void
326 def_library (name, base)
327      char *name;
328      int base;
329 {
330   printf ("LIBRARY %s base %x\n", name, base);
331   if (d_is_exe)
332     {
333       fprintf (stderr, "Can't have LIBRARY and NAME\n");
334     }
335   d_name = name;
336   if (strchr (d_name, '.'))
337     d_suffix = strdup (strchr (d_name, '.') + 1);
338   d_is_dll = 1;
339 }
340
341 void
342 def_description (desc)
343      char *desc;
344 {
345   dlist_type *d = (dlist_type *)xmalloc(sizeof(dlist_type));
346   d->text = strdup (desc);
347   d->next = d_list;
348   d_list = d;
349 }
350
351 void new_directive(dir)
352 char *dir;
353 {
354   dlist_type *d = (dlist_type *)xmalloc(sizeof(dlist_type));
355   d->text = strdup (dir);
356   d->next = a_list;
357   a_list = d;
358 }
359
360 void
361 def_stacksize (reserve, commit)
362      int reserve;
363      int commit;
364 {
365   char b[200];
366   if (commit>0)
367     sprintf (b,"-stack 0x%x,0x%x ", reserve, commit);
368   else 
369     sprintf (b,"-stack 0x%x ", reserve);
370   new_directive (strdup(b));
371 }
372
373 void
374 def_heapsize (reserve, commit)
375      int reserve;
376      int commit;
377 {
378   char b[200];
379   if (commit>0)
380     sprintf (b,"-heap 0x%x,0x%x ", reserve, commit);
381   else 
382     sprintf (b,"-heap 0x%x ", reserve);
383   new_directive (strdup(b));
384 }
385
386
387 void
388 def_import (internal, module, entry)
389      char *internal;
390      char *module;
391      char *entry;
392 {
393   fprintf (stderr, "IMPORTS are ignored");
394 }
395
396 void
397 def_version (major, minor)
398 {
399   printf ("VERSION %d.%d\n", major, minor);
400 }
401
402
403 void
404 def_section (name, attr)
405      char *name;
406      int attr;
407 {
408   char buf[200];
409   char  atts[5];
410   char *d = atts;
411   if (attr & 1)
412     *d++= 'R';
413
414   if (attr & 2)
415     *d++ = 'W';
416   if (attr & 4)
417     *d++ = 'X';
418   if (attr & 8)
419     *d++ = 'S';
420   *d++ = 0;
421   sprintf (buf, "-attr %s %s", name, atts);
422   new_directive (strdup(buf));
423 }
424 void
425 def_code (attr)
426      int attr;
427 {
428
429 def_section ("CODE", attr);
430 }
431
432 void
433 def_data (attr)
434      int attr;
435 {
436   def_section ("DATA",attr);
437 }
438
439
440 /**********************************************************************/
441
442 void
443 scan_open_obj_file (abfd)
444      bfd *abfd;
445 {
446   /* Look for .drectives */
447   asection *s = bfd_get_section_by_name (abfd, ".drectve");
448   if (s)
449     {
450       int size = bfd_get_section_size_before_reloc (s);
451       char *buf = xmalloc (size);
452       char *p;
453       char *e;
454       bfd_get_section_contents (abfd, s, buf, 0, size);
455       printf ("Sucking in info from %s\n",
456               bfd_get_filename (abfd));
457
458       /* Search for -export: strings */
459       p = buf;
460       e = buf + size;
461       while (p < e)
462         {
463           if (p[0] == '-'
464               && strncmp (p, "-export:", 8) == 0)
465             {
466               char *name;
467               char *c;
468               p += 8;
469               name = p;
470               while (*p != ' ' && *p != '-' && p < e)
471                 p++;
472               c = xmalloc (p - name + 1);
473               memcpy (c, name, p - name);
474               c[p - name] = 0;
475               def_exports (c, 0, -1, 0);
476             }
477           else
478             p++;
479         }
480       free (buf);
481     }
482 }
483
484
485 void
486 scan_obj_file (filename)
487      char *filename;
488 {
489   bfd *f = bfd_openr (filename, 0);
490
491   if (!f)
492     {
493       fprintf (stderr, "Unable to open object file %s\n", filename);
494       exit (1);
495     }
496   if (bfd_check_format (f, bfd_archive))
497     {
498       bfd *arfile = bfd_openr_next_archived_file (f, 0);
499       while (arfile)
500         {
501           if (bfd_check_format (arfile, bfd_object))
502             scan_open_obj_file (arfile);
503           bfd_close (arfile);
504           arfile = bfd_openr_next_archived_file (f, arfile);
505         }
506     }
507
508   if (bfd_check_format (f, bfd_object))
509     {
510       scan_open_obj_file (f);
511     }
512
513   bfd_close (f);
514 }
515
516 /**********************************************************************/
517
518
519 /* return the bit of the name before the last . */
520
521 static
522 char *
523 prefix (name)
524      char *name;
525 {
526   char *res = strdup (name);
527   char *p = strrchr (res, '.');
528   if (p)
529     *p = 0;
530   return res;
531 }
532
533 void
534 dump_def_info (f)
535 FILE *f;
536 {
537   int i;
538   export_type *exp;
539   fprintf(f,"%s ", ASM_C);
540   for (i= 0; oav[i]; i++) 
541     fprintf(f,"%s ", oav[i]);
542   fprintf(f,"\n");
543   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
544     {
545       fprintf (f, "%s  %d %s @ %d %s%s\n",
546                ASM_C,
547                i,
548                exp->name, exp->ordinal,
549                exp->noname ? "NONAME " : "",
550                exp->constant ? "CONSTANT" : "");
551     }
552 }
553 /* Generate the .exp file */
554
555
556 void
557 gen_exp_file ()
558 {
559   FILE *f;
560   char outfile[PATHMAX];
561   int i;
562   export_type *exp;
563   dlist_type *dl;
564   sprintf (outfile, "%s.exp.s", outfile_prefix);
565
566   f = fopen (outfile, "w");
567   if (!f)
568     {
569       fprintf (stderr, "Unable to open output file %s\n", outfile);
570       exit (1);
571     }
572   dump_def_info (f);
573   fprintf (f, "\t.section       .edata\n\n");
574   fprintf (f, "\t%s     0       %s Allways 0\n", ASM_LONG, ASM_C);
575   fprintf (f, "\t%s     %d      %s Time and date\n", ASM_LONG, time (0), ASM_C);
576   fprintf (f, "\t%s     0       %s Major and Minor version\n", ASM_LONG, ASM_C);
577   fprintf (f, "\t%s     name    %s Ptr to name of dll\n", ASM_LONG, ASM_C);
578   fprintf (f, "\t%s     %d      %s Starting ordinal of exports\n", ASM_LONG, d_ord, ASM_C);
579   fprintf (f, "\t%s The next field is documented as being the number of functions\n", ASM_C);
580   fprintf (f, "\t%s yet it doesn't look like that in real PE dlls\n", ASM_C);
581   fprintf (f, "\t%s But it shouldn't be a problem, causes there's\n", ASM_C);
582   fprintf (f, "\t%s always the number of names field\n", ASM_C);
583   fprintf (f, "\t%s     %d      %s Number of functions\n", ASM_LONG, d_nfuncs, ASM_C);
584   fprintf (f, "\t%s     %d      %s Number of names\n", ASM_LONG, d_nfuncs, ASM_C);
585   fprintf (f, "\t%s     afuncs  %s Address of functions\n", ASM_LONG, ASM_C);
586   fprintf (f, "\t%s     anames  %s Address of names\n", ASM_LONG, ASM_C);
587   fprintf (f, "\t%s     anords  %s Address of ordinals\n", ASM_LONG, ASM_C);
588
589   fprintf (f, "name:    %s      \"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
590
591   fprintf (f, "afuncs:\n");
592   i = d_ord;
593   for (exp = d_exports; exp; exp = exp->next)
594     {
595       if (exp->ordinal != i)
596         {
597           fprintf (f, "\t%s\t%d\t@ %d..%d missing\n", ASM_SPACE,
598                    (exp->ordinal - i) * 4,
599                    i, exp->ordinal - 1);
600           i = exp->ordinal;
601         }
602       fprintf (f, "\t%s %s\t%s %d\n", ASM_LONG, exp->name, ASM_C, exp->ordinal);
603       i++;
604     }
605
606
607   fprintf (f, "anames:\n");
608   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
609     if (exp->noname)
610       fprintf (f, "\t%s 0\t%sNoname\n", ASM_LONG, ASM_C);
611     else
612       fprintf (f, "\t%s n%d\n", ASM_LONG, i);
613
614   fprintf (f, "anords:\n");
615   for (exp = d_exports; exp; exp = exp->next)
616     fprintf (f, "\t%s   %d\n", ASM_SHORT, exp->ordinal - d_ord);
617
618   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
619     if (exp->noname)
620       fprintf (f, "@n%d:        %s      \"%s\"\n", i, ASM_TEXT, exp->name);
621     else
622       fprintf (f, "n%d: %s      \"%s\"\n", i, ASM_TEXT, exp->name);
623
624
625   if (a_list)
626     {
627       fprintf(f,"\t.section .drectve\n");
628       for (dl = a_list; dl; dl = dl->next)
629         {
630           fprintf (f,"\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
631         }
632     }
633   if (d_list) 
634     {
635       fprintf(f,"\t.section .rdata\n");
636       for (dl = d_list; dl; dl = dl->next)
637         {
638           char *p;
639           int l;
640           /* We dont output as ascii 'cause there can
641              be quote characters in the string */
642
643           l = 0;
644           for (p = dl->text; *p; p++) {
645             if (l == 0)
646               fprintf(f,"\t%s\t", ASM_BYTE);
647             else
648               fprintf(f,",");
649             fprintf(f,"%d", *p);
650             if (p[1] == 0) {
651               fprintf(f,",0\n");
652               break;
653             }
654             if (++l == 10) {
655               fprintf(f,"\n");
656               l = 0;
657             }
658           }
659         }
660     }
661   fclose (f);
662 }
663
664 /**********************************************************************/
665 gen_lib_file ()
666 {
667   char outfile[PATHMAX];
668   int i;
669   FILE *f;
670   export_type *exp;
671
672   sprintf (outfile, "%s.lib.s", outfile_prefix);
673
674   f = fopen (outfile, "w");
675   if (!f)
676     {
677       fprintf (stderr, "Unable to open output file %s\n", outfile);
678       exit (1);
679     }
680
681
682   dump_def_info (f);
683   fprintf (f, "\t.text\n");
684   fprintf (f, "%s Thunk table\n", ASM_C);
685   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
686     {
687       fprintf (f, "\t%s\t%s\n", ASM_GLOBAL, exp->name);
688       fprintf (f, "\t%s\t__imp__%s\n", ASM_GLOBAL, exp->name);
689     }
690
691   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
692     {
693       fprintf (f, "%s:\t%s\t__imp__%s\n", exp->name, ASM_JUMP, exp->name);
694     }
695
696
697   fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
698   fprintf (f, "\t.section       .idata$2\n");
699   fprintf (f, "\t%s\thname\t%s Ptr to image import by name list\n", ASM_LONG, ASM_C);
700   fprintf (f, "\t%s\t%d\t%s time\n", ASM_LONG, time (0), ASM_C);
701   fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
702   fprintf (f, "\t%s\tiname\t%s imported dll's name\n", ASM_LONG, ASM_C);
703   fprintf (f, "\t%s\tfthunk\t%s pointer to firstthunk\n", ASM_LONG, ASM_C);
704
705   fprintf (f, "\n%s Loader modifies this\n", ASM_C);
706   fprintf (f, "\t.section       .idata$5\n");
707   fprintf (f, "fthunk:\n");
708   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
709     {
710       fprintf (f, "__imp__%s:\n", exp->name);
711       fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
712     }
713
714   fprintf (f, "\n%s Hint name array\n", ASM_C);
715   fprintf (f, "\t.section       .idata$4\n");
716   fprintf (f, "hname:\n");
717   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
718     {
719       fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
720     }
721
722   fprintf (f, "%s Hint/name array storage and import dll name\n", ASM_C);
723   fprintf (f, "\t.section       .idata$6\n");
724
725   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
726     {
727       fprintf (f, "ID%d:\t%s\t%d\n", i, ASM_SHORT, exp->ordinal);
728       fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, exp->name);
729     }
730
731   fprintf (f, "iname:\t%s\t\"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
732   fclose (f);
733 }
734 /**********************************************************************/
735
736 /* Run through the information gathered from the .o files and the
737    .def file and work out the best stuff */
738 int
739 pfunc (a, b)
740      void *a;
741      void *b;
742 {
743   export_type *ap = *(export_type **) a;
744   export_type *bp = *(export_type **) b;
745   if (ap->ordinal == bp->ordinal)
746     return 0;
747
748   /* unset ordinals go to the bottom */
749   if (ap->ordinal == -1)
750     return 1;
751   if (bp->ordinal == -1)
752     return -1;
753   return (ap->ordinal - bp->ordinal);
754 }
755
756
757 int
758 nfunc (a, b)
759      void *a;
760      void *b;
761 {
762   export_type *ap = *(export_type **) a;
763   export_type *bp = *(export_type **) b;
764
765   return (strcmp (ap->name, bp->name));
766 }
767
768 static
769 void
770 remove_null_names (ptr)
771      export_type **ptr;
772 {
773   int src;
774   int dst;
775   for (dst = src = 0; src < d_nfuncs; src++)
776     {
777       if (ptr[src])
778         {
779           ptr[dst] = ptr[src];
780           dst++;
781         }
782     }
783   d_nfuncs = dst;
784 }
785
786 static void
787 dtab (ptr)
788      export_type **ptr;
789 {
790 #ifdef SACDEBUG
791   int i;
792   for (i = 0; i < d_nfuncs; i++)
793     {
794       if (ptr[i])
795         {
796           printf ("%d %s @ %d %s%s\n",
797                   i, ptr[i]->name, ptr[i]->ordinal,
798                   ptr[i]->noname ? "NONAME " : "",
799                   ptr[i]->constant ? "CONSTANT" : "");
800         }
801       else
802         printf ("empty\n");
803     }
804 #endif
805 }
806
807 static void
808 process_duplicates (d_export_vec)
809      export_type **d_export_vec;
810 {
811   int more = 1;
812
813   while (more)
814     {
815       more = 0;
816       /* Remove duplicates */
817       qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
818
819       dtab (d_export_vec);
820       for (i = 0; i < d_nfuncs - 1; i++)
821         {
822           if (strcmp (d_export_vec[i]->name,
823                       d_export_vec[i + 1]->name) == 0)
824             {
825
826               export_type *a = d_export_vec[i];
827               export_type *b = d_export_vec[i + 1];
828
829               more = 1;
830
831               fprintf (stderr, "warning, ignoring duplicate EXPORT %s\n",
832                        a->name);
833               if (a->ordinal != -1
834                   && b->ordinal != -1)
835                 {
836
837                   fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
838                            a->name);
839                   exit (1);
840                 }
841               /* Merge attributes */
842               b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
843               b->constant |= a->constant;
844               b->noname |= a->noname;
845               d_export_vec[i] = 0;
846             }
847
848           dtab (d_export_vec);
849           remove_null_names (d_export_vec);
850           dtab (d_export_vec);
851         }
852     }
853 }
854
855 static void
856 fill_ordinals (d_export_vec)
857      export_type **d_export_vec;
858 {
859   int lowest = 0;
860   qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
861
862   /* fill in the unset ordinals with ones from the minimum */
863   for (i = 0; i < d_nfuncs; i++)
864     {
865       if (d_export_vec[i]->ordinal == -1)
866         {
867           d_export_vec[i]->ordinal = lowest++;
868         }
869       else
870         {
871           if (lowest == d_export_vec[i]->ordinal)
872             {
873               fprintf (stderr, "Warning, Duplicate ordinal %s @ %d\n",
874                        d_export_vec[i]->name,
875                        d_export_vec[i]->ordinal);
876             }
877           lowest = d_export_vec[i]->ordinal + 1;
878         }
879     }
880
881   /* Work out the lowest ordinal number */
882   if (d_export_vec[0])
883     d_ord = d_export_vec[0]->ordinal;
884 }
885 void
886 mangle_defs ()
887 {
888   /* First work out the minimum ordinal chosen */
889
890   export_type *exp;
891   int lowest = 0;
892   int i;
893   export_type **d_export_vec
894   = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
895
896   for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
897     {
898       d_export_vec[i] = exp;
899     }
900
901   process_duplicates (d_export_vec);
902   fill_ordinals (d_export_vec);
903
904   /* Put back the list in the new order */
905   d_exports = 0;
906   for (i = d_nfuncs - 1; i >= 0; i--)
907     {
908       d_export_vec[i]->next = d_exports;
909       d_exports = d_export_vec[i];
910     }
911 }
912
913
914 /**********************************************************************/
915
916 void
917 usage (file, status)
918      FILE *file;
919      int status;
920 {
921   fprintf (file, "Usage %s [-m|--machine machine] [-o outprefix] [-d|--def deffile] [--def deffile]\n", program_name);
922   exit (status);
923 }
924
925 static struct option long_options[] =
926 {
927   {"def", required_argument, NULL, 'd'},
928   {"help", no_argument, NULL, 'h'},
929   {"machine", required_argument, NULL, 'm'},
930   0
931 };
932
933 int
934 main (ac, av)
935      int ac;
936      char **av;
937 {
938   int c;
939   char *firstarg = 0;
940   program_name = av[0];
941   oav = av;
942   
943   while ((c = getopt_long (ac, av, "h?m:o:Dd:", long_options, 0)) != EOF)
944     {
945       switch (c)
946         {
947         case 'h':
948         case '?':
949           usage(stderr,0);
950           break;
951         case 'm':
952           mname = optarg;
953           break;
954         case 'o':
955           outfile_prefix = optarg;
956           break;
957         case 'D':
958           yydebug = 1;
959           break;
960         case 'd':
961           def_file = optarg;
962           break;
963         default:
964           usage (stderr, 1);
965         }
966     }
967
968
969   for (i = 0; mtable[i].type; i++) 
970     {
971       if (strcmp (mtable[i].type, mname) == 0)
972         break;
973     }
974
975   if (!mtable[i].type) 
976     {
977       fprintf(stderr,"Machine not supported\n");
978       exit(1);
979     }
980   machine = i;
981
982
983   if (def_file)
984     {
985
986       process_def_file (def_file);
987     }
988   while (optind < ac)
989     {
990       if (!firstarg)
991         firstarg = av[optind];
992       scan_obj_file (av[optind]);
993       optind++;
994     }
995
996   if (!outfile_prefix)
997     {
998       if (d_name)
999         outfile_prefix = d_name;
1000       else if (def_file)
1001         outfile_prefix = def_file;
1002       else if (firstarg)
1003         outfile_prefix = firstarg;
1004       else
1005         {
1006           fprintf (stderr, "No way to create an output filename\n");
1007           exit (1);
1008         }
1009     }
1010   outfile_prefix = prefix (outfile_prefix);
1011
1012   mangle_defs ();
1013   gen_exp_file ();
1014   gen_lib_file ();
1015   return 0;
1016 }