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