]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - binutils/dlltool.c
* dlltool.c (mtable): New fields.
[thirdparty/binutils-gdb.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 static char *rva_n (long addr)
610 {
611 char b[20];
612 sprintf (b, "0x%08x - __rva");
613 return strdup (b);
614 }
615
616 static char *rva_s (char *s)
617 {
618 char b[20];
619 sprintf (b, "0x%08x - __rva");
620 return strdup (b);
621 }
622
623 static void
624 flush_page (f, need, page_addr, on_page)
625 FILE *f;
626 long *need;
627 long page_addr;
628 int on_page;
629 {
630 int i;
631 /* Flush this page */
632 fprintf (f, "\t%s\t%s\t%s Starting RVA for chunk\n",
633 ASM_LONG,
634 rva_n(page_addr),
635 ASM_C);
636 fprintf (f, "\t%s\t0x%x\t%s Size of block\n",
637 ASM_LONG,
638 (on_page * 2) + (on_page & 1) * 2 + 8,
639 ASM_C);
640 for (i = 0; i < on_page; i++)
641 {
642 fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, need[i] - page_addr | 0x3000);
643 }
644 /* And padding */
645 if (on_page & 1)
646 fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, 0 | 0x0000);
647
648 }
649
650
651 void
652 gen_exp_file ()
653 {
654 FILE *f;
655 int i;
656 export_type *exp;
657 dlist_type *dl;
658 int had_noname = 0;
659
660 sprintf (outfile, "%s-exp.s", outfile_prefix);
661
662 if (verbose)
663 fprintf (stderr, "%s: Generate exp file %s\n",
664 program_name, outfile_prefix);
665
666 f = fopen (outfile, "w");
667 if (!f)
668 {
669 fprintf (stderr, "%s: Unable to open output file %s\n", program_name, outfile);
670 exit (1);
671 }
672 if (verbose)
673 {
674 fprintf (stderr, "%s: Opened file %s\n",
675 program_name, outfile);
676 }
677
678 dump_def_info (f);
679 fprintf (f, "\t.section .edata\n\n");
680 fprintf (f, "\t%s 0 %s Allways 0\n", ASM_LONG, ASM_C);
681 fprintf (f, "\t%s %d %s Time and date\n", ASM_LONG, time (0), ASM_C);
682 fprintf (f, "\t%s 0 %s Major and Minor version\n", ASM_LONG, ASM_C);
683 fprintf (f, "\t%s name %s Ptr to name of dll\n", ASM_LONG, ASM_C);
684 fprintf (f, "\t%s %d %s Starting ordinal of exports\n", ASM_LONG, d_ord, ASM_C);
685 fprintf (f, "\t%s The next field is documented as being the number of functions\n", ASM_C);
686 fprintf (f, "\t%s yet it doesn't look like that in real PE dlls\n", ASM_C);
687 fprintf (f, "\t%s But it shouldn't be a problem, causes there's\n", ASM_C);
688 fprintf (f, "\t%s always the number of names field\n", ASM_C);
689 fprintf (f, "\t%s %d %s Number of functions\n", ASM_LONG, d_nfuncs, ASM_C);
690 fprintf (f, "\t%s %d %s Number of names\n", ASM_LONG, d_nfuncs, ASM_C);
691 fprintf (f, "\t%s afuncs %s Address of functions\n", ASM_LONG, ASM_C);
692 fprintf (f, "\t%s anames %s Address of names\n", ASM_LONG, ASM_C);
693 fprintf (f, "\t%s anords %s Address of ordinals\n", ASM_LONG, ASM_C);
694
695 fprintf (f, "name: %s \"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
696
697 fprintf (f, "afuncs:\n");
698 i = d_ord;
699 for (exp = d_exports; exp; exp = exp->next)
700 {
701 #if 0
702 /* This seems necessary in the doc, but in real
703 life it's not used.. */
704 if (exp->ordinal != i)
705 {
706 fprintf (f, "%s\t%s\t%d\t@ %d..%d missing\n", ASM_C, ASM_SPACE,
707 (exp->ordinal - i) * 4,
708 i, exp->ordinal - 1);
709 i = exp->ordinal;
710 }
711 #endif
712 fprintf (f, "\t%s %s\t%s %d\n", ASM_LONG, exp->internal_name, ASM_C, exp->ordinal);
713 i++;
714 }
715
716
717 fprintf (f, "anames:\n");
718 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
719 {
720 if (exp->noname)
721 {
722 had_noname = 1;
723 fprintf (f, "\t%s nNoname\n", ASM_LONG, ASM_C);
724 }
725 else
726 {
727 fprintf (f, "\t%s n%d\n", ASM_LONG, i);
728 }
729 }
730
731 fprintf (f, "anords:\n");
732 for (exp = d_exports; exp; exp = exp->next)
733 fprintf (f, "\t%s %d\n", ASM_SHORT, exp->ordinal - d_ord);
734
735 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
736 if (exp->noname)
737 fprintf (f, "@n%d: %s \"%s\"\n", i, ASM_TEXT, exp->name);
738 else
739 fprintf (f, "n%d: %s \"%s\"\n", i, ASM_TEXT, exp->name);
740
741 if (had_noname)
742 fprintf (f, "nNoname: %s \"__noname__\"\n", ASM_TEXT);
743
744 if (a_list)
745 {
746 fprintf (f, "\t.section .drectve\n");
747 for (dl = a_list; dl; dl = dl->next)
748 {
749 fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
750 }
751 }
752 if (d_list)
753 {
754 fprintf (f, "\t.section .rdata\n");
755 for (dl = d_list; dl; dl = dl->next)
756 {
757 char *p;
758 int l;
759 /* We dont output as ascii 'cause there can
760 be quote characters in the string */
761
762 l = 0;
763 for (p = dl->text; *p; p++)
764 {
765 if (l == 0)
766 fprintf (f, "\t%s\t", ASM_BYTE);
767 else
768 fprintf (f, ",");
769 fprintf (f, "%d", *p);
770 if (p[1] == 0)
771 {
772 fprintf (f, ",0\n");
773 break;
774 }
775 if (++l == 10)
776 {
777 fprintf (f, "\n");
778 l = 0;
779 }
780 }
781 }
782 }
783
784 /* Dump the reloc section if a base file is provided */
785 if (base_file)
786 {
787 int addr;
788 long need[PAGE_SIZE];
789 long page_addr;
790 int numbytes;
791 int num_entries;
792 long *copy;
793 int j;
794 int on_page;
795 fprintf (f, "\t.section\t.reloc\n");
796 fseek (base_file, 0, SEEK_END);
797 numbytes = ftell (base_file);
798 fseek (base_file, 0, SEEK_SET);
799 copy = malloc (numbytes);
800 fread (copy, 1, numbytes, base_file);
801 num_entries = numbytes / sizeof (long);
802
803 qsort (copy, num_entries, sizeof (long), sfunc);
804
805 addr = copy[0];
806 page_addr = addr & PAGE_MASK; /* work out the page addr */
807 on_page = 0;
808 for (j = 0; j < num_entries; j++)
809 {
810 addr = copy[j];
811 if ((addr & PAGE_MASK) != page_addr)
812 {
813 flush_page (f, need, page_addr, on_page);
814 on_page = 0;
815 page_addr = addr & PAGE_MASK;
816 }
817 need[on_page++] = addr;
818 }
819 flush_page (f, need, page_addr, on_page);
820 }
821
822 fclose (f);
823 }
824
825 static char *
826 xlate (char *name)
827 {
828
829 if (!suckunderscore)
830 return name;
831
832 if (name[0] == '_')
833 name++;
834 if (killat) {
835 char *p;
836 p = strchr (name, '@');
837 if (p)
838 *p = 0;
839 }
840 return name;
841 }
842
843 /**********************************************************************/
844 gen_lib_file ()
845 {
846 int i;
847 FILE *f;
848 export_type *exp;
849
850 sprintf (outfile, "%s-lib.s", outfile_prefix);
851
852 f = fopen (outfile, "w");
853 if (!f)
854 {
855 fprintf (stderr, "Unable to open output file %s\n", outfile);
856 exit (1);
857 }
858
859
860 dump_def_info (f);
861 fprintf (f, "\t.text\n");
862 fprintf (f, "%s Thunk table\n", ASM_C);
863 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
864 {
865 fprintf (f, "\t%s\t%s\n", ASM_GLOBAL, exp->name);
866 fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
867 }
868
869 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
870 {
871 fprintf (f, "%s:\t%s\t__imp_%s\n", exp->name, ASM_JUMP, exp->name);
872 }
873
874
875 fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
876 fprintf (f, "\t.section .idata$2\n");
877 fprintf (f, "\t%s\t%shname%s\t%sPtr to image import by name list\n", ASM_LONG,
878 ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
879 fprintf (f, "\t%s\t%d\t%s time\n", ASM_LONG, time (0), ASM_C);
880 fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
881 fprintf (f, "\t%s\t%siname%s\t%s imported dll's name\n", ASM_LONG,
882 ASM_RVA_BEFORE,
883 ASM_RVA_AFTER,
884 ASM_C);
885 fprintf (f, "\t%s\t%sfthunk%s\t%s pointer to firstthunk\n", ASM_LONG,
886 ASM_RVA_BEFORE,
887 ASM_RVA_AFTER, ASM_C);
888
889 fprintf (f, "%sStuff for compatibility\n", ASM_C);
890 #if 0
891 fprintf (f, "\t.section\t.idata$3\n");
892 fprintf (f, "\t%s\t0\n", ASM_LONG);
893 fprintf (f, "\t%s\t0\n", ASM_LONG);
894 fprintf (f, "\t%s\t0\n", ASM_LONG);
895 fprintf (f, "\t%s\t0\n", ASM_LONG);
896 fprintf (f, "\t%s\t0\n", ASM_LONG);
897 #endif
898
899 fprintf (f, "\t.section\t.idata$5\n");
900 fprintf (f, "\t%s\t0\n", ASM_LONG);
901
902 fprintf (f, "\t.section\t.idata$4\n");
903 fprintf (f, "\t%s\t0\n", ASM_LONG);
904
905 fprintf (f, "\n%s Loader modifies this\n", ASM_C);
906 fprintf (f, "\t.section .idata$5\n");
907 fprintf (f, "fthunk:\n");
908 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
909 {
910 fprintf (f, "__imp_%s:\n", exp->name);
911 fprintf (f, "\t%s\t%sID%d%s\n", ASM_LONG,
912 ASM_RVA_BEFORE,
913 i,
914 ASM_RVA_AFTER);
915 }
916 fprintf (f, "\t%s\t0\n", ASM_LONG);
917
918 fprintf (f, "\n%s Hint name array\n", ASM_C);
919 fprintf (f, "\t.section .idata$4\n");
920 fprintf (f, "hname:\n");
921 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
922 {
923 fprintf (f, "\t%s\t%sID%d%s\n", ASM_LONG, ASM_RVA_BEFORE,
924 i,
925 ASM_RVA_AFTER);
926 }
927
928 fprintf (f, "\t%s\t0\n", ASM_LONG);
929 fprintf (f, "%s Hint/name array storage and import dll name\n", ASM_C);
930 fprintf (f, "\t.section .idata$6\n");
931
932 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
933 {
934 fprintf (f,"\t%s\n", ASM_ALIGN_SHORT);
935 fprintf (f, "ID%d:\t%s\t%d\n", i, ASM_SHORT, exp->ordinal);
936 fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name));
937 }
938 fprintf (f, "\t%s\t0\n", ASM_LONG);
939 fprintf (f, "iname:\t%s\t\"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
940 fclose (f);
941 }
942 /**********************************************************************/
943
944 /* Run through the information gathered from the .o files and the
945 .def file and work out the best stuff */
946 int
947 pfunc (a, b)
948 void *a;
949 void *b;
950 {
951 export_type *ap = *(export_type **) a;
952 export_type *bp = *(export_type **) b;
953 if (ap->ordinal == bp->ordinal)
954 return 0;
955
956 /* unset ordinals go to the bottom */
957 if (ap->ordinal == -1)
958 return 1;
959 if (bp->ordinal == -1)
960 return -1;
961 return (ap->ordinal - bp->ordinal);
962 }
963
964
965 int
966 nfunc (a, b)
967 void *a;
968 void *b;
969 {
970 export_type *ap = *(export_type **) a;
971 export_type *bp = *(export_type **) b;
972
973 return (strcmp (ap->name, bp->name));
974 }
975
976 static
977 void
978 remove_null_names (ptr)
979 export_type **ptr;
980 {
981 int src;
982 int dst;
983 for (dst = src = 0; src < d_nfuncs; src++)
984 {
985 if (ptr[src])
986 {
987 ptr[dst] = ptr[src];
988 dst++;
989 }
990 }
991 d_nfuncs = dst;
992 }
993
994 static void
995 dtab (ptr)
996 export_type **ptr;
997 {
998 #ifdef SACDEBUG
999 int i;
1000 for (i = 0; i < d_nfuncs; i++)
1001 {
1002 if (ptr[i])
1003 {
1004 printf ("%d %s @ %d %s%s\n",
1005 i, ptr[i]->name, ptr[i]->ordinal,
1006 ptr[i]->noname ? "NONAME " : "",
1007 ptr[i]->constant ? "CONSTANT" : "");
1008 }
1009 else
1010 printf ("empty\n");
1011 }
1012 #endif
1013 }
1014
1015 static void
1016 process_duplicates (d_export_vec)
1017 export_type **d_export_vec;
1018 {
1019 int more = 1;
1020
1021 while (more)
1022 {
1023 more = 0;
1024 /* Remove duplicates */
1025 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
1026
1027 dtab (d_export_vec);
1028 for (i = 0; i < d_nfuncs - 1; i++)
1029 {
1030 if (strcmp (d_export_vec[i]->name,
1031 d_export_vec[i + 1]->name) == 0)
1032 {
1033
1034 export_type *a = d_export_vec[i];
1035 export_type *b = d_export_vec[i + 1];
1036
1037 more = 1;
1038 if (verbose)
1039 fprintf (stderr, "Warning, ignoring duplicate EXPORT %s %d,%d\n",
1040 a->name,
1041 a->ordinal,
1042 b->ordinal);
1043 if (a->ordinal != -1
1044 && b->ordinal != -1)
1045 {
1046
1047 fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
1048 a->name);
1049 exit (1);
1050 }
1051 /* Merge attributes */
1052 b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
1053 b->constant |= a->constant;
1054 b->noname |= a->noname;
1055 d_export_vec[i] = 0;
1056 }
1057
1058 dtab (d_export_vec);
1059 remove_null_names (d_export_vec);
1060 dtab (d_export_vec);
1061 }
1062 }
1063 }
1064
1065 static void
1066 fill_ordinals (d_export_vec)
1067 export_type **d_export_vec;
1068 {
1069 int lowest = 0;
1070 int unset = 0;
1071 char *ptr;
1072 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
1073
1074 /* fill in the unset ordinals with ones from our range */
1075
1076 ptr = (char *) malloc (65536);
1077
1078 memset (ptr, 65536, 0);
1079
1080 /* Mark in our large vector all the numbers that are taken */
1081 for (i = 0; i < d_nfuncs; i++)
1082 {
1083 if (d_export_vec[i]->ordinal != -1)
1084 {
1085 ptr[d_export_vec[i]->ordinal] = 1;
1086 if (lowest == 0)
1087 lowest = d_export_vec[i]->ordinal;
1088 }
1089 }
1090
1091 for (i = 0; i < d_nfuncs; i++)
1092 {
1093 if (d_export_vec[i]->ordinal == -1)
1094 {
1095 int j;
1096 for (j = lowest; j < 65536; j++)
1097 if (ptr[j] == 0)
1098 {
1099 ptr[j] = 1;
1100 d_export_vec[i]->ordinal = j;
1101 goto done;
1102 }
1103
1104 for (j = 1; j < lowest; j++)
1105 if (ptr[j] == 0)
1106 {
1107 ptr[j] = 1;
1108 d_export_vec[i]->ordinal = j;
1109 goto done;
1110 }
1111 done:;
1112
1113 }
1114 }
1115
1116 free (ptr);
1117
1118 /* And resort */
1119
1120 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
1121
1122 /* Work out the lowest ordinal number */
1123 if (d_export_vec[0])
1124 d_ord = d_export_vec[0]->ordinal;
1125 }
1126 void
1127 mangle_defs ()
1128 {
1129 /* First work out the minimum ordinal chosen */
1130
1131 export_type *exp;
1132 int lowest = 0;
1133 int i;
1134 export_type **d_export_vec
1135 = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
1136
1137 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1138 {
1139 d_export_vec[i] = exp;
1140 }
1141
1142 process_duplicates (d_export_vec);
1143 fill_ordinals (d_export_vec);
1144
1145 /* Put back the list in the new order */
1146 d_exports = 0;
1147 for (i = d_nfuncs - 1; i >= 0; i--)
1148 {
1149 d_export_vec[i]->next = d_exports;
1150 d_exports = d_export_vec[i];
1151 }
1152 }
1153
1154
1155 /**********************************************************************/
1156
1157 void
1158 usage (file, status)
1159 FILE *file;
1160 int status;
1161 {
1162 fprintf (file, "Usage %s <options> <object-files>\n", program_name);
1163 fprintf (file, "\t -m <machine> Generate code for <machine>\n");
1164 fprintf (file, "\t --machine <machine>\n");
1165 fprintf (file, "\t -o <outprefix> Set output prefix\n");
1166 fprintf (file, "\t -d <deffile> Name input .def file\n");
1167 fprintf (file, "\t --def <deffile> \n");
1168 fprintf (file, "\t --base-file <basefile> Read linker generated base file\n");
1169 fprintf (file, "\t -b <basefile> \n");
1170 fprintf (file, "\t -v Verbose\n");
1171 fprintf (file, "\t -u Remove leading underscore from .lib\n");
1172 fprintf (file, "\t -k Kill @<n> from exported names\n");
1173 exit (status);
1174 }
1175
1176 static struct option long_options[] =
1177 {
1178 {"def", required_argument, NULL, 'd'},
1179 {"underscore", no_argument, NULL, 'u'},
1180 {"killat", no_argument, NULL, 'k'},
1181 {"help", no_argument, NULL, 'h'},
1182 {"machine", required_argument, NULL, 'm'},
1183 {"base-file", required_argument, NULL, 'b'},
1184 0
1185 };
1186
1187 int
1188 main (ac, av)
1189 int ac;
1190 char **av;
1191 {
1192 int c;
1193 char *firstarg = 0;
1194 program_name = av[0];
1195 oav = av;
1196
1197 while ((c = getopt_long (ac, av, "kvbuh?m:o:Dd:", long_options, 0)) != EOF)
1198 {
1199 switch (c)
1200 {
1201 case 'h':
1202 case '?':
1203 usage (stderr, 0);
1204 break;
1205 case 'm':
1206 mname = optarg;
1207 break;
1208 case 'o':
1209 outfile_prefix = optarg;
1210 break;
1211 case 'v':
1212 verbose = 1;
1213 break;
1214 case 'D':
1215 yydebug = 1;
1216 break;
1217 case 'u':
1218 suckunderscore = 1;
1219 break;
1220 case 'k':
1221 killat = 1;
1222 break;
1223 case 'd':
1224 def_file = optarg;
1225 break;
1226 case 'b':
1227 base_file = fopen (optarg, "r");
1228 if (!base_file)
1229 {
1230 fprintf (stderr, "%s: Unable to open base-file %s\n",
1231 av[0],
1232 optarg);
1233 exit (1);
1234 }
1235 break;
1236 default:
1237 usage (stderr, 1);
1238 }
1239 }
1240
1241
1242 for (i = 0; mtable[i].type; i++)
1243 {
1244 if (strcmp (mtable[i].type, mname) == 0)
1245 break;
1246 }
1247
1248 if (!mtable[i].type)
1249 {
1250 fprintf (stderr, "Machine not supported\n");
1251 exit (1);
1252 }
1253 machine = i;
1254
1255
1256 if (def_file)
1257 {
1258 process_def_file (def_file);
1259 }
1260 while (optind < ac)
1261 {
1262 if (!firstarg)
1263 firstarg = av[optind];
1264 scan_obj_file (av[optind]);
1265 optind++;
1266 }
1267
1268 if (!outfile_prefix)
1269 {
1270 if (d_name)
1271 outfile_prefix = d_name;
1272 else if (def_file)
1273 outfile_prefix = def_file;
1274 else if (firstarg)
1275 outfile_prefix = firstarg;
1276 else
1277 {
1278 fprintf (stderr, "No way to create an output filename\n");
1279 exit (1);
1280 }
1281 }
1282 outfile_prefix = prefix (outfile_prefix);
1283
1284 if (verbose)
1285 fprintf (stderr, "%s: Outfile prefix is %s\n",
1286 program_name, outfile_prefix);
1287 mangle_defs ();
1288
1289 gen_exp_file ();
1290
1291
1292 gen_lib_file ();
1293
1294 return 0;
1295 }