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