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