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