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