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