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