Document the .idata section.
[deliverable/binutils-gdb.git] / binutils / dlltool.c
1 #define show_allnames 0
2
3 /* dlltool.c -- tool to generate stuff for PE style DLLs
4 Copyright (C) 1995 Free Software Foundation, Inc.
5
6 This file is part of GNU Binutils.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22
23 /*
24 This program allows you to build the files necessary to create
25 DLLs to run on a system which understands PE format image files.
26 (eg, Windows NT)
27
28 A DLL contains an export table which contains the information
29 which the runtime loader needs to tie up references from a
30 referencing program.
31
32 The export table is generated by this program by reading
33 in a .DEF file or scanning the .a and .o files which will be in the
34 DLL. A .o file can contain information in special ".drectve" sections
35 with export information.
36
37 A DEF file contains any number of the following commands:
38
39
40 NAME <name> [ , <base> ]
41 The result is going to be <name>.EXE
42
43 LIBRARY <name> [ , <base> ]
44 The result is going to be <name>.DLL
45
46 EXPORTS ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) *
47 Declares name1 as an exported symbol from the
48 DLL, with optional ordinal number <integer>
49
50 IMPORTS ( [ <name> = ] <name> . <name> ) *
51 Ignored for compatibility
52
53 DESCRIPTION <string>
54 Puts <string> into output .exp file in the .rdata section
55
56 [STACKSIZE|HEAPSIZE] <number-reserve> [ , <number-commit> ]
57 Generates --stack|--heap <number-reserve>,<number-commit>
58 in the output .drectve section. The linker will
59 see this and act upon it.
60
61 [CODE|DATA] <attr>+
62 SECTIONS ( <sectionname> <attr>+ )*
63 <attr> = READ | WRITE | EXECUTE | SHARED
64 Generates --attr <sectionname> <attr> in the output
65 .drectve section. The linker will see this and act
66 upon it.
67
68
69 A -export:<name> in a .drectve section in an input .o or .a
70 file to this program is equivalent to a EXPORTS <name>
71 in a .DEF file.
72
73
74
75 The program generates output files with the prefix supplied
76 on the command line, or in the def file, or taken from the first
77 supplied argument.
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 --def thedll.def --output-exp thedll.o --output-lib thedll.a
151
152 # build the dll with the library with file1.o, file2.o and the export table
153 ld -o thedll.dll thedll.o thedll.in
154
155 # build the mainline
156 gcc -c themain.c
157
158 # link the executable with the import library
159 ld -e main -Tthemain.ld -o themain.exe themain.o thedll.a
160
161 */
162
163 /* .idata section description
164
165 The .idata section is the import table. It is a collection of several
166 subsections used to keep the pieces for each dll together: .idata$[234567].
167 IE: Each dll's .idata$2's are catenated together, each .idata$3's, etc.
168
169 .idata$2 = Import Directory Table
170 = array of IMAGE_IMPORT_DESCRIPTOR's.
171 There is one for each dll imported from plus a trailing null copy.
172
173 DWORD Characteristics; - pointer to .idata$4
174 DWORD TimeDateStamp; - currently always 0
175 DWORD ForwarderChain; - currently always 0
176 DWORD Name; - pointer to dll's name
177 PIMAGE_THUNK_DATA FirstThunk; - pointer to .idata$5
178
179 .idata$3 = ppc's way of null terminating .idata$2. Jeepers creepers,
180 can we have some consistency here???
181
182 .idata$4 = Import Lookup Table
183 = array of array of pointers to hint name table.
184 There is one for each dll being imported from, and each dll's set is
185 terminated by a trailing NULL.
186
187 .idata$5 = Import Address Table
188 = array of array of pointers to hint name table.
189 There is one for each dll being imported from, and each dll's set is
190 terminated by a trailing NULL.
191 Initially, this table is identical to the Import Lookup Table. However,
192 at load time, the loader overwrites the entries with the address of the
193 function.
194
195 .idata$6 = Hint Name Table
196 = Array of { short, asciz } entries, one for each imported function.
197 The `short' is the function's ordinal number.
198
199 .idata$7 = dll name (eg: "kernel32.dll"). (.idata$6 for ppc)
200 */
201
202 #define PAGE_SIZE 4096
203 #define PAGE_MASK (-PAGE_SIZE)
204 #include "bfd.h"
205 #include "libiberty.h"
206 #include "bucomm.h"
207 #include "getopt.h"
208 #include "demangle.h"
209 #include <ctype.h>
210 #ifdef HAVE_SYS_WAIT_H
211 #include <sys/wait.h>
212 #else
213 #ifndef WIFEXITED
214 #define WIFEXITED(w) (((w)&0377) == 0)
215 #endif
216 #ifndef WIFSIGNALED
217 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
218 #endif
219 #ifndef WTERMSIG
220 #define WTERMSIG(w) ((w) & 0177)
221 #endif
222 #ifndef WEXITSTATUS
223 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
224 #endif
225 #endif
226
227
228
229 char *as_name = "as";
230
231 static int no_idata4;
232 static int no_idata5;
233 static char *exp_name;
234 static char *imp_name;
235 static char *head_label;
236 static char *imp_name_lab;
237 static char *dll_name;
238
239 static int add_indirect = 0;
240 static int add_underscore = 0;
241 static int dontdeltemps = 0;
242
243 int yyparse();
244 int yydebug;
245 static char *def_file;
246
247 static char *program_name;
248 char *strrchr ();
249 char *strdup ();
250
251 static int machine;
252 int killat;
253 static int verbose;
254 FILE *output_def;
255 FILE *base_file;
256
257 #ifdef DLLTOOL_ARM
258 static char *mname = "arm";
259 #endif
260
261 #ifdef DLLTOOL_I386
262 static char *mname = "i386";
263 #endif
264
265 #ifdef DLLTOOL_PPC
266 static char *mname = "ppc";
267 #endif
268
269 #define PATHMAX 250 /* What's the right name for this ? */
270
271 /* This bit of assemly does jmp * ....
272 s set how_jtab_roff to mark where the 32bit abs branch should go */
273 unsigned char i386_jtab[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90};
274
275
276 unsigned char arm_jtab[] = { 0x00, 0xc0, 0x9f, 0xe5,
277 0x00, 0xf0, 0x9c, 0xe5,
278 0, 0, 0, 0};
279
280 /* This is the glue sequence for PowerPC PE. There is a */
281 /* tocrel16-tocdefn reloc against the first instruction. */
282 /* We also need a IMGLUE reloc against the glue function */
283 /* to restore the toc saved by the third instruction in */
284 /* the glue. */
285 unsigned char ppc_jtab[] =
286 {
287 0x00, 0x00, 0x62, 0x81, /* lwz r11,0(r2) */
288 /* Reloc TOCREL16 __imp_xxx */
289 0x00, 0x00, 0x8B, 0x81, /* lwz r12,0(r11) */
290 0x04, 0x00, 0x41, 0x90, /* stw r2,4(r1) */
291 0xA6, 0x03, 0x89, 0x7D, /* mtctr r12 */
292 0x04, 0x00, 0x4B, 0x80, /* lwz r2,4(r11) */
293 0x20, 0x04, 0x80, 0x4E /* bctr */
294 };
295
296 /* the glue instruction, picks up the toc from the stw in */
297 /* the above code: "lwz r2,4(r1)" */
298 bfd_vma ppc_glue_insn = 0x80410004;
299
300
301 char outfile[PATHMAX];
302 struct mac
303 {
304 char *type;
305 char *how_byte;
306 char *how_short;
307 char *how_long;
308 char *how_asciz;
309 char *how_comment;
310 char *how_jump;
311 char *how_global;
312 char *how_space;
313 char *how_align_short;
314 char *how_align_long;
315 char *how_bfd_target;
316 enum bfd_architecture how_bfd_arch;
317 unsigned char *how_jtab;
318 int how_jtab_size; /* size of the jtab entry */
319 int how_jtab_roff; /* offset into it for the ind 32 reloc into idata 5 */
320 }
321 mtable[]
322 =
323 {
324 {
325 #define MARM 0
326 "arm", ".byte", ".short", ".long", ".asciz", "@",
327 "ldr\tip,[pc]\n\tldr\tpc,[ip]\n\t.long",
328 ".global", ".space", ".align\t2",".align\t4","pe-arm-little", bfd_arch_arm,
329 arm_jtab, sizeof(arm_jtab),8
330 }
331 ,
332 {
333 #define M386 1
334 "i386", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space", ".align\t2",".align\t4","pe-i386",bfd_arch_i386,
335 i386_jtab,sizeof(i386_jtab),2,
336 }
337 ,
338 {
339 #define MPPC 2
340 "ppc", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space", ".align\t2",".align\t4","pe-powerpcle",bfd_arch_powerpc,
341 ppc_jtab,sizeof(ppc_jtab),0,
342 }
343 ,
344 { 0}
345 };
346
347
348 char *
349 rvaafter (machine)
350 int machine;
351 {
352 switch (machine)
353 {
354 case MARM:
355 return "";
356 case M386:
357 return "";
358 case MPPC:
359 return "";
360 }
361 return "";
362 }
363
364 char *
365 rvabefore (machine)
366 int machine;
367 {
368 switch (machine)
369 {
370 case MARM:
371 return ".rva\t";
372 case M386:
373 return ".rva\t";
374 case MPPC:
375 return ".rva\t";
376 }
377 return "";
378 }
379
380 char *
381 asm_prefix (machine)
382 int machine;
383 {
384 switch (machine)
385 {
386 case MARM:
387 return "";
388 case M386:
389 return "_";
390 case MPPC:
391 return "";
392 }
393 return "";
394 }
395 #define ASM_BYTE mtable[machine].how_byte
396 #define ASM_SHORT mtable[machine].how_short
397 #define ASM_LONG mtable[machine].how_long
398 #define ASM_TEXT mtable[machine].how_asciz
399 #define ASM_C mtable[machine].how_comment
400 #define ASM_JUMP mtable[machine].how_jump
401 #define ASM_GLOBAL mtable[machine].how_global
402 #define ASM_SPACE mtable[machine].how_space
403 #define ASM_ALIGN_SHORT mtable[machine].how_align_short
404 #define ASM_RVA_BEFORE rvabefore(machine)
405 #define ASM_RVA_AFTER rvaafter(machine)
406 #define ASM_PREFIX asm_prefix(machine)
407 #define ASM_ALIGN_LONG mtable[machine].how_align_long
408 #define HOW_BFD_TARGET 0 /* always default*/
409 #define HOW_BFD_ARCH mtable[machine].how_bfd_arch
410 #define HOW_JTAB mtable[machine].how_jtab
411 #define HOW_JTAB_SIZE mtable[machine].how_jtab_size
412 #define HOW_JTAB_ROFF mtable[machine].how_jtab_roff
413 static char **oav;
414
415
416 FILE *yyin; /* communications with flex */
417 extern int linenumber;
418 void
419 process_def_file (name)
420 char *name;
421 {
422 FILE *f = fopen (name, FOPEN_RT);
423 if (!f)
424 {
425 fprintf (stderr, "%s: Can't open def file %s\n", program_name, name);
426 exit (1);
427 }
428
429 yyin = f;
430
431 yyparse ();
432 }
433
434 /**********************************************************************/
435
436 /* Communications with the parser */
437
438
439 typedef struct dlist
440 {
441 char *text;
442 struct dlist *next;
443 }
444 dlist_type;
445
446 typedef struct export
447 {
448 char *name;
449 char *internal_name;
450 int ordinal;
451 int constant;
452 int noname;
453 int hint;
454 struct export *next;
455 }
456 export_type;
457
458 static char *d_name; /* Arg to NAME or LIBRARY */
459 static int d_nfuncs; /* Number of functions exported */
460 static int d_named_nfuncs; /* Number of named functions exported */
461 static int d_low_ord; /* Lowest ordinal index */
462 static int d_high_ord; /* Highest ordinal index */
463 static export_type *d_exports; /*list of exported functions */
464 static export_type **d_exports_lexically; /* vector of exported functions in alpha order */
465 static dlist_type *d_list; /* Descriptions */
466 static dlist_type *a_list; /* Stuff to go in directives */
467
468 static int d_is_dll;
469 static int d_is_exe;
470
471 int
472 yyerror ()
473 {
474 fprintf (stderr, "%s: Syntax error in def file %s:%d\n",
475 program_name, def_file, linenumber);
476 return 0;
477 }
478
479 void
480 def_exports (name, internal_name, ordinal, noname, constant)
481 char *name;
482 char *internal_name;
483 int ordinal;
484 int noname;
485 int constant;
486 {
487 struct export *p = (struct export *) xmalloc (sizeof (*p));
488
489 p->name = name;
490 p->internal_name = internal_name ? internal_name : name;
491 p->ordinal = ordinal;
492 p->constant = constant;
493 p->noname = noname;
494 p->next = d_exports;
495 d_exports = p;
496 d_nfuncs++;
497 }
498
499
500 void
501 def_name (name, base)
502 char *name;
503 int base;
504 {
505 if (verbose)
506 fprintf (stderr, "%s NAME %s base %x\n", program_name, name, base);
507 if (d_is_dll)
508 {
509 fprintf (stderr, "Can't have LIBRARY and NAME\n");
510 }
511 d_name = name;
512 d_is_exe = 1;
513 }
514
515 void
516 def_library (name, base)
517 char *name;
518 int base;
519 {
520 if (verbose)
521 printf ("%s: LIBRARY %s base %x\n", program_name, name, base);
522 if (d_is_exe)
523 {
524 fprintf (stderr, "%s: Can't have LIBRARY and NAME\n", program_name);
525 }
526 d_name = name;
527 d_is_dll = 1;
528 }
529
530 void
531 def_description (desc)
532 char *desc;
533 {
534 dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type));
535 d->text = strdup (desc);
536 d->next = d_list;
537 d_list = d;
538 }
539
540 void
541 new_directive (dir)
542 char *dir;
543 {
544 dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type));
545 d->text = strdup (dir);
546 d->next = a_list;
547 a_list = d;
548 }
549
550 void
551 def_stacksize (reserve, commit)
552 int reserve;
553 int commit;
554 {
555 char b[200];
556 if (commit > 0)
557 sprintf (b, "-stack 0x%x,0x%x ", reserve, commit);
558 else
559 sprintf (b, "-stack 0x%x ", reserve);
560 new_directive (strdup (b));
561 }
562
563 void
564 def_heapsize (reserve, commit)
565 int reserve;
566 int commit;
567 {
568 char b[200];
569 if (commit > 0)
570 sprintf (b, "-heap 0x%x,0x%x ", reserve, commit);
571 else
572 sprintf (b, "-heap 0x%x ", reserve);
573 new_directive (strdup (b));
574 }
575
576
577 void
578 def_import (internal, module, entry)
579 char *internal;
580 char *module;
581 char *entry;
582 {
583 if (verbose)
584 fprintf (stderr, "%s: IMPORTS are ignored", program_name);
585 }
586
587 void
588 def_version (major, minor)
589 int major;
590 int minor;
591 {
592 printf ("VERSION %d.%d\n", major, minor);
593 }
594
595
596 void
597 def_section (name, attr)
598 char *name;
599 int attr;
600 {
601 char buf[200];
602 char atts[5];
603 char *d = atts;
604 if (attr & 1)
605 *d++ = 'R';
606
607 if (attr & 2)
608 *d++ = 'W';
609 if (attr & 4)
610 *d++ = 'X';
611 if (attr & 8)
612 *d++ = 'S';
613 *d++ = 0;
614 sprintf (buf, "-attr %s %s", name, atts);
615 new_directive (strdup (buf));
616 }
617 void
618 def_code (attr)
619 int attr;
620 {
621
622 def_section ("CODE", attr);
623 }
624
625 void
626 def_data (attr)
627 int attr;
628 {
629 def_section ("DATA", attr);
630 }
631
632
633 /**********************************************************************/
634
635 void
636 run (what, args)
637 char *what;
638 char *args;
639 {
640 char *s;
641 int pid;
642 int i;
643 char **argv;
644 extern char **environ;
645 if (verbose)
646 fprintf (stderr, "%s %s\n", what, args);
647
648 /* Count the args */
649 i = 0;
650 for (s = args; *s; s++)
651 if (*s == ' ')
652 i++;
653 i++;
654 argv = alloca (sizeof (char *) * (i + 3));
655 i = 0;
656 argv[i++] = what;
657 s = args;
658 while (1)
659 {
660 argv[i++] = s;
661 while (*s != ' ' && *s != 0)
662 s++;
663 if (*s == 0)
664 break;
665 *s++ = 0;
666 }
667 argv[i++] = 0;
668
669
670 pid = vfork ();
671
672 if (pid == 0)
673 {
674 execvp (what, argv);
675 fprintf (stderr, "%s: can't exec %s\n", program_name, what);
676 exit (1);
677 }
678 else if (pid == -1)
679 {
680 extern int errno;
681 fprintf (stderr, "%s: vfork failed, %d\n", program_name, errno);
682 exit (1);
683 }
684 else
685 {
686 int status;
687 waitpid (pid, &status, 0);
688 if (status)
689 {
690 if (WIFSIGNALED (status))
691 {
692 fprintf (stderr, "%s: %s %s terminated with signal %d\n",
693 program_name, what, args, WTERMSIG (status));
694 exit (1);
695 }
696
697 if (WIFEXITED (status))
698 {
699 fprintf (stderr, "%s: %s %s terminated with exit status %d\n",
700 program_name, what, args, WEXITSTATUS (status));
701 exit (1);
702 }
703 }
704 }
705 }
706
707 /* read in and block out the base relocations */
708 static void
709 basenames (abfd)
710 bfd *abfd;
711 {
712
713
714
715
716 }
717
718 void
719 scan_open_obj_file (abfd)
720 bfd *abfd;
721 {
722 /* Look for .drectve's */
723 asection *s = bfd_get_section_by_name (abfd, ".drectve");
724 if (s)
725 {
726 int size = bfd_get_section_size_before_reloc (s);
727 char *buf = xmalloc (size);
728 char *p;
729 char *e;
730 bfd_get_section_contents (abfd, s, buf, 0, size);
731 if (verbose)
732 fprintf (stderr, "%s: Sucking in info from %s\n",
733 program_name,
734 bfd_get_filename (abfd));
735
736 /* Search for -export: strings */
737 p = buf;
738 e = buf + size;
739 while (p < e)
740 {
741 if (p[0] == '-'
742 && strncmp (p, "-export:", 8) == 0)
743 {
744 char *name;
745 char *c;
746 p += 8;
747 name = p;
748 while (*p != ' ' && *p != '-' && p < e)
749 p++;
750 c = xmalloc (p - name + 1);
751 memcpy (c, name, p - name);
752 c[p - name] = 0;
753 def_exports (c, 0, -1, 0);
754 }
755 else
756 p++;
757 }
758 free (buf);
759 }
760
761 basenames (abfd);
762
763 if (verbose)
764 fprintf (stderr, "%s: Done readin\n",
765 program_name);
766
767 }
768
769
770 void
771 scan_obj_file (filename)
772 char *filename;
773 {
774 bfd *f = bfd_openr (filename, 0);
775
776 if (!f)
777 {
778 fprintf (stderr, "%s: Unable to open object file %s\n",
779 program_name,
780 filename);
781 exit (1);
782 }
783 if (bfd_check_format (f, bfd_archive))
784 {
785 bfd *arfile = bfd_openr_next_archived_file (f, 0);
786 while (arfile)
787 {
788 if (bfd_check_format (arfile, bfd_object))
789 scan_open_obj_file (arfile);
790 bfd_close (arfile);
791 arfile = bfd_openr_next_archived_file (f, arfile);
792 }
793 }
794 else if (bfd_check_format (f, bfd_object))
795 {
796 scan_open_obj_file (f);
797 }
798
799 bfd_close (f);
800 }
801
802 /**********************************************************************/
803
804
805
806 void
807 dump_def_info (f)
808 FILE *f;
809 {
810 int i;
811 export_type *exp;
812 fprintf (f, "%s ", ASM_C);
813 for (i = 0; oav[i]; i++)
814 fprintf (f, "%s ", oav[i]);
815 fprintf (f, "\n");
816 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
817 {
818 fprintf (f, "%s %d = %s %s @ %d %s%s\n",
819 ASM_C,
820 i,
821 exp->name,
822 exp->internal_name,
823 exp->ordinal,
824 exp->noname ? "NONAME " : "",
825 exp->constant ? "CONSTANT" : "");
826 }
827 }
828 /* Generate the .exp file */
829
830 int
831 sfunc (a, b)
832 long *a;
833 long *b;
834 {
835 return *a - *b;
836 }
837
838
839
840 static void
841 flush_page (f, need, page_addr, on_page)
842 FILE *f;
843 int *need;
844 int page_addr;
845 int on_page;
846 {
847 int i;
848
849 /* Flush this page */
850 fprintf (f, "\t%s\t0x%08x\t%s Starting RVA for chunk\n",
851 ASM_LONG,
852 page_addr,
853 ASM_C);
854 fprintf (f, "\t%s\t0x%x\t%s Size of block\n",
855 ASM_LONG,
856 (on_page * 2) + (on_page & 1) * 2 + 8,
857 ASM_C);
858 for (i = 0; i < on_page; i++)
859 {
860 fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, (need[i] - page_addr) | 0x3000);
861 }
862 /* And padding */
863 if (on_page & 1)
864 fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, 0 | 0x0000);
865
866 }
867
868
869 void
870 gen_def_file ()
871 {
872 int i;
873 export_type *exp;
874
875 fprintf (output_def, ";");
876 for (i = 0; oav[i]; i++)
877 fprintf (output_def, " %s", oav[i]);
878
879 fprintf (output_def, "\nEXPORTS\n");
880
881 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
882 {
883 char *quote = strchr (exp->name, '.') ? "\"" : "";
884 fprintf (output_def, "\t%s%s%s @ %d%s ; %s\n",
885 quote,
886 exp->name,
887 quote,
888 exp->ordinal,
889 exp->noname ? " NONAME" : "",
890 cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_PARAMS));
891 }
892 }
893 void
894 gen_exp_file ()
895 {
896 FILE *f;
897 int i;
898 export_type *exp;
899 dlist_type *dl;
900
901
902 sprintf (outfile, "t%s", exp_name);
903
904 if (verbose)
905 fprintf (stderr, "%s: Generate exp file %s\n",
906 program_name, exp_name);
907
908 f = fopen (outfile, FOPEN_WT);
909 if (!f)
910 {
911 fprintf (stderr, "%s: Unable to open output file %s\n", program_name, outfile);
912 exit (1);
913 }
914 if (verbose)
915 {
916 fprintf (stderr, "%s: Opened file %s\n",
917 program_name, outfile);
918 }
919
920 dump_def_info (f);
921 if (d_exports)
922 {
923 fprintf (f, "\t.section .edata\n\n");
924 fprintf (f, "\t%s 0 %s Allways 0\n", ASM_LONG, ASM_C);
925 fprintf (f, "\t%s 0x%x %s Time and date\n", ASM_LONG, time(0),ASM_C);
926 fprintf (f, "\t%s 0 %s Major and Minor version\n", ASM_LONG, ASM_C);
927 fprintf (f, "\t%sname%s %s Ptr to name of dll\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
928 fprintf (f, "\t%s %d %s Starting ordinal of exports\n", ASM_LONG, d_low_ord, ASM_C);
929
930
931 fprintf (f, "\t%s %d %s Number of functions\n", ASM_LONG, d_high_ord - d_low_ord + 1, ASM_C);
932 fprintf(f,"\t%s named funcs %d, low ord %d, high ord %d\n",
933 ASM_C,
934 d_named_nfuncs, d_low_ord, d_high_ord);
935 fprintf (f, "\t%s %d %s Number of names\n", ASM_LONG,
936 show_allnames ? d_high_ord - d_low_ord + 1 : d_named_nfuncs, ASM_C);
937 fprintf (f, "\t%safuncs%s %s Address of functions\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
938
939 fprintf (f, "\t%sanames%s %s Address of Name Pointer Table\n",
940 ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
941
942 fprintf (f, "\t%sanords%s %s Address of ordinals\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
943
944 fprintf (f, "name: %s \"%s\"\n", ASM_TEXT, dll_name);
945
946
947 fprintf(f,"%s Export address Table\n", ASM_C);
948 fprintf(f,"\t%s\n", ASM_ALIGN_LONG);
949 fprintf (f, "afuncs:\n");
950 i = d_low_ord;
951
952 for (exp = d_exports; exp; exp = exp->next)
953 {
954 if (exp->ordinal != i)
955 {
956 #if 0
957 fprintf (f, "\t%s\t%d\t%s %d..%d missing\n",
958 ASM_SPACE,
959 (exp->ordinal - i) * 4,
960 ASM_C,
961 i, exp->ordinal - 1);
962 i = exp->ordinal;
963 #endif
964 while (i < exp->ordinal)
965 {
966 fprintf(f,"\t%s\t0\n", ASM_LONG);
967 i++;
968 }
969 }
970 fprintf (f, "\t%s%s%s%s\t%s %d\n", ASM_RVA_BEFORE,
971 ASM_PREFIX,
972 exp->internal_name, ASM_RVA_AFTER, ASM_C, exp->ordinal);
973 i++;
974 }
975
976 fprintf (f,"%s Export Name Pointer Table\n", ASM_C);
977 fprintf (f, "anames:\n");
978
979 for (i = 0; (exp = d_exports_lexically[i]); i++)
980 {
981 if (!exp->noname || show_allnames)
982 fprintf (f, "\t%sn%d%s\n", ASM_RVA_BEFORE, exp->ordinal, ASM_RVA_AFTER);
983 }
984
985 fprintf (f,"%s Export Oridinal Table\n", ASM_C);
986 fprintf (f, "anords:\n");
987 for (i = 0; (exp = d_exports_lexically[i]); i++)
988 {
989 if (!exp->noname || show_allnames)
990 fprintf (f, "\t%s %d\n", ASM_SHORT, exp->ordinal - d_low_ord);
991 }
992
993 fprintf(f,"%s Export Name Table\n", ASM_C);
994 for (i = 0; (exp = d_exports_lexically[i]); i++)
995 if (!exp->noname || show_allnames)
996 fprintf (f, "n%d: %s \"%s\"\n", exp->ordinal, ASM_TEXT, exp->name);
997
998 if (a_list)
999 {
1000 fprintf (f, "\t.section .drectve\n");
1001 for (dl = a_list; dl; dl = dl->next)
1002 {
1003 fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
1004 }
1005 }
1006 if (d_list)
1007 {
1008 fprintf (f, "\t.section .rdata\n");
1009 for (dl = d_list; dl; dl = dl->next)
1010 {
1011 char *p;
1012 int l;
1013 /* We dont output as ascii 'cause there can
1014 be quote characters in the string */
1015
1016 l = 0;
1017 for (p = dl->text; *p; p++)
1018 {
1019 if (l == 0)
1020 fprintf (f, "\t%s\t", ASM_BYTE);
1021 else
1022 fprintf (f, ",");
1023 fprintf (f, "%d", *p);
1024 if (p[1] == 0)
1025 {
1026 fprintf (f, ",0\n");
1027 break;
1028 }
1029 if (++l == 10)
1030 {
1031 fprintf (f, "\n");
1032 l = 0;
1033 }
1034 }
1035 }
1036 }
1037 }
1038
1039
1040 /* Add to the output file a way of getting to the exported names
1041 without using the import library. */
1042 if (add_indirect)
1043 {
1044 fprintf (f, "\t.section\t.rdata\n");
1045 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1046 if (!exp->noname || show_allnames)
1047 {
1048 fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
1049 fprintf (f, "__imp_%s:\n", exp->name);
1050 fprintf (f, "\t%s\t%s\n", ASM_LONG, exp->name);
1051 }
1052 }
1053
1054 /* Dump the reloc section if a base file is provided */
1055 if (base_file)
1056 {
1057 int addr;
1058 long need[PAGE_SIZE];
1059 long page_addr;
1060 int numbytes;
1061 int num_entries;
1062 long *copy;
1063 int j;
1064 int on_page;
1065 fprintf (f, "\t.section\t.init\n");
1066 fprintf (f, "lab:\n");
1067
1068 fseek (base_file, 0, SEEK_END);
1069 numbytes = ftell (base_file);
1070 fseek (base_file, 0, SEEK_SET);
1071 copy = malloc (numbytes);
1072 fread (copy, 1, numbytes, base_file);
1073 num_entries = numbytes / sizeof (long);
1074
1075
1076 fprintf (f, "\t.section\t.reloc\n");
1077 if (num_entries)
1078 {
1079
1080 int src;
1081 int dst = 0;
1082 int last = -1;
1083 qsort (copy, num_entries, sizeof (long), sfunc);
1084 /* Delete duplcates */
1085 for (src = 0; src < num_entries; src++)
1086 {
1087 if (last != copy[src])
1088 last = copy[dst++] = copy[src];
1089 }
1090 num_entries = dst;
1091 addr = copy[0];
1092 page_addr = addr & PAGE_MASK; /* work out the page addr */
1093 on_page = 0;
1094 for (j = 0; j < num_entries; j++)
1095 {
1096 addr = copy[j];
1097 if ((addr & PAGE_MASK) != page_addr)
1098 {
1099 flush_page (f, need, page_addr, on_page);
1100 on_page = 0;
1101 page_addr = addr & PAGE_MASK;
1102 }
1103 need[on_page++] = addr;
1104 }
1105 flush_page (f, need, page_addr, on_page);
1106
1107 /* fprintf (f, "\t%s\t0,0\t%s End\n", ASM_LONG, ASM_C);*/
1108 }
1109 }
1110
1111 fclose (f);
1112
1113 /* assemble the file */
1114 sprintf (outfile, "-o %s t%s", exp_name, exp_name);
1115 run (as_name, outfile);
1116 if (dontdeltemps == 0)
1117 {
1118 sprintf (outfile, "t%s", exp_name);
1119 unlink (outfile);
1120 }
1121 }
1122
1123 static char *
1124 xlate (char *name)
1125 {
1126 if (add_underscore)
1127 {
1128 char *copy = malloc (strlen (name) + 2);
1129 copy[0] = '_';
1130 strcpy (copy + 1, name);
1131 name = copy;
1132 }
1133
1134 if (killat)
1135 {
1136 char *p;
1137 p = strchr (name, '@');
1138 if (p)
1139 *p = 0;
1140 }
1141 return name;
1142 }
1143
1144 /**********************************************************************/
1145
1146 static void dump_iat (f, exp)
1147 FILE *f;
1148 export_type *exp;
1149 {
1150 if (exp->noname && !show_allnames )
1151 {
1152 fprintf (f, "\t%s\t0x%08x\n",
1153 ASM_LONG,
1154 exp->ordinal | 0x80000000); /* hint or orindal ?? */
1155 }
1156 else
1157 {
1158 fprintf (f, "\t%sID%d%s\n", ASM_RVA_BEFORE,
1159 exp->ordinal,
1160 ASM_RVA_AFTER);
1161 }
1162 }
1163
1164
1165
1166 typedef struct
1167 {
1168 int id;
1169 const char *name;
1170 int flags;
1171 int align;
1172 asection *sec;
1173 asymbol *sym;
1174 asymbol **sympp;
1175 int size;
1176 unsigned char *data;
1177 } sinfo;
1178
1179
1180 #ifndef DLLTOOL_PPC
1181
1182 #define TEXT 0
1183 #define DATA 1
1184 #define BSS 2
1185 #define IDATA7 3
1186 #define IDATA5 4
1187 #define IDATA4 5
1188 #define IDATA6 6
1189 #define PDATA 7
1190 #define RDATA 8
1191
1192 #define NSECS 7
1193
1194
1195 static sinfo secdata[NSECS] =
1196 {
1197 { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS, 3},
1198 { DATA, ".data", SEC_DATA, 2},
1199 { BSS, ".bss", 0, 2},
1200 { IDATA7, ".idata$7", SEC_HAS_CONTENTS, 2},
1201 { IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2},
1202 { IDATA4, ".idata$4", SEC_HAS_CONTENTS, 2},
1203 { IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1}
1204 };
1205
1206 #else
1207
1208 /* Sections numbered to make the order the same as other PowerPC NT */
1209 /* compilers. This also keeps funny alignment thingies from happening. */
1210 #define TEXT 0
1211 #define PDATA 1
1212 #define RDATA 2
1213 #define IDATA5 3
1214 #define IDATA4 4
1215 #define IDATA6 5
1216 #define IDATA7 6
1217 #define DATA 7
1218 #define BSS 8
1219
1220 #define NSECS 9
1221
1222 static sinfo secdata[NSECS] =
1223 {
1224 { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS, 3},
1225 { PDATA, ".pdata", SEC_HAS_CONTENTS, 2},
1226 { RDATA, ".rdata", SEC_HAS_CONTENTS, 2},
1227 { IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2},
1228 { IDATA4, ".idata$4", SEC_HAS_CONTENTS, 2},
1229 { IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1},
1230 { IDATA7, ".idata$7", SEC_HAS_CONTENTS, 2},
1231 { DATA, ".data", SEC_DATA, 2},
1232 { BSS, ".bss", 0, 2}
1233 };
1234
1235 #endif
1236
1237 /*
1238 This is what we're trying to make
1239
1240 .text
1241 .global _GetFileVersionInfoSizeW@8
1242 .global __imp_GetFileVersionInfoSizeW@8
1243 _GetFileVersionInfoSizeW@8:
1244 jmp * __imp_GetFileVersionInfoSizeW@8
1245 .section .idata$7 # To force loading of head
1246 .long __version_a_head
1247 # Import Address Table
1248 .section .idata$5
1249 __imp_GetFileVersionInfoSizeW@8:
1250 .rva ID2
1251
1252 # Import Lookup Table
1253 .section .idata$4
1254 .rva ID2
1255 # Hint/Name table
1256 .section .idata$6
1257 ID2: .short 2
1258 .asciz "GetFileVersionInfoSizeW"
1259
1260
1261 For the PowerPC, here's the variation on the above scheme:
1262
1263 # Rather than a simple "jmp *", the code to get to the dll function
1264 # looks like:
1265 .text
1266 lwz r11,[tocv]__imp_function_name(r2)
1267 # RELOC: 00000000 TOCREL16,TOCDEFN __imp_function_name
1268 lwz r12,0(r11)
1269 stw r2,4(r1)
1270 mtctr r12
1271 lwz r2,4(r11)
1272 bctr
1273 */
1274
1275 static char *
1276 make_label (prefix, name)
1277 const char *prefix;
1278 const char *name;
1279 {
1280 int len = strlen (ASM_PREFIX) + strlen (prefix) + strlen (name);
1281 char *copy = xmalloc (len +1 );
1282 strcpy (copy, ASM_PREFIX);
1283 strcat (copy, prefix);
1284 strcat (copy, name);
1285 return copy;
1286 }
1287
1288 static bfd *
1289 make_one_lib_file (exp, i)
1290 export_type *exp;
1291 int i;
1292 {
1293 if (0)
1294 {
1295 FILE *f;
1296 char *prefix="d";
1297 sprintf (outfile, "%ss%d.s", prefix, i);
1298 f = fopen (outfile, FOPEN_WT);
1299 fprintf (f, "\t.text\n");
1300 fprintf (f, "\t%s\t%s%s\n", ASM_GLOBAL, ASM_PREFIX, exp->name);
1301 fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
1302 fprintf (f, "%s%s:\n\t%s\t__imp_%s\n", ASM_PREFIX,
1303 exp->name, ASM_JUMP, exp->name);
1304
1305 fprintf (f, "\t.section\t.idata$7\t%s To force loading of head\n", ASM_C);
1306 fprintf (f, "\t%s\t%s\n", ASM_LONG, head_label);
1307
1308
1309 fprintf (f,"%s Import Address Table\n", ASM_C);
1310
1311 fprintf (f, "\t.section .idata$5\n");
1312 fprintf (f, "__imp_%s:\n", exp->name);
1313
1314 dump_iat (f, exp);
1315
1316 fprintf (f, "\n%s Import Lookup Table\n", ASM_C);
1317 fprintf (f, "\t.section .idata$4\n");
1318
1319 dump_iat (f, exp);
1320
1321 if(!exp->noname || show_allnames)
1322 {
1323 fprintf (f, "%s Hint/Name table\n", ASM_C);
1324 fprintf (f, "\t.section .idata$6\n");
1325 fprintf (f, "ID%d:\t%s\t%d\n", exp->ordinal, ASM_SHORT, exp->hint);
1326 fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name));
1327 }
1328
1329 fclose (f);
1330
1331
1332 sprintf (outfile, "-o %ss%d.o %ss%d.s", prefix, i, prefix, i);
1333
1334 run (as_name, outfile);
1335
1336 }
1337 else
1338 {
1339
1340 bfd *abfd;
1341
1342 asymbol *exp_label;
1343 asymbol *iname;
1344 asymbol *iname_lab;
1345 asymbol **iname_lab_pp;
1346 asymbol **iname_pp;
1347
1348 /* Extra Symbols for PPC */
1349 #ifdef DLLTOOL_PPC
1350 #define EXTRA 2
1351 #else
1352 #define EXTRA 0
1353 #endif
1354
1355 asymbol *function_name; /* ".." functionName */
1356 asymbol **fn_pp;
1357 asymbol *toc_symbol; /* The .toc symbol */
1358 asymbol **toc_pp;
1359
1360 /* one symbol for each section, 2 extra + a null */
1361 asymbol *ptrs[NSECS+3+EXTRA+1];
1362
1363 char *outname = xmalloc (10);
1364 int oidx = 0;
1365 sprintf (outname, "ds%d.o", i);
1366 abfd = bfd_openw (outname, HOW_BFD_TARGET);
1367 if (!abfd)
1368 {
1369 fprintf (stderr, "%s: bfd_open failed open output file %s\n",
1370 program_name, outname);
1371 exit (1);
1372 }
1373
1374 bfd_set_format (abfd, bfd_object);
1375 bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
1376
1377
1378 /* First make symbols for the sections */
1379 for (i = 0; i < NSECS; i++)
1380 {
1381 sinfo *si = secdata + i;
1382 if (si->id != i)
1383 abort();
1384 si->sec = bfd_make_section_old_way (abfd, si->name);
1385 bfd_set_section_flags (abfd,
1386 si->sec,
1387 si->flags);
1388
1389 bfd_set_section_alignment(abfd, si->sec, si->align);
1390 si->sec->output_section = si->sec;
1391 si->sym = bfd_make_empty_symbol(abfd);
1392 si->sym->name = si->sec->name;
1393 si->sym->section = si->sec;
1394 si->sym->flags = BSF_LOCAL;
1395 si->sym->value = 0;
1396 ptrs[oidx] = si->sym;
1397 si->sympp = ptrs + oidx;
1398
1399 oidx++;
1400 }
1401
1402 exp_label = bfd_make_empty_symbol(abfd);
1403 exp_label->name = make_label ("",exp->name);
1404
1405 /* On PowerPC, the function name points to a descriptor in the
1406 rdata section, the first element of which is a pointer to the
1407 code (..function_name), and the second points to the .toc
1408 */
1409 if (machine == MPPC)
1410 exp_label->section = secdata[RDATA].sec;
1411 else
1412 exp_label->section = secdata[TEXT].sec;
1413
1414 exp_label->flags = BSF_GLOBAL;
1415 exp_label->value = 0;
1416
1417 ptrs[oidx++] = exp_label;
1418
1419 iname = bfd_make_empty_symbol(abfd);
1420 iname->name = make_label ("__imp_", exp->name);
1421 iname->section = secdata[IDATA5].sec;
1422 iname->flags = BSF_GLOBAL;
1423 iname->value = 0;
1424
1425
1426 iname_lab = bfd_make_empty_symbol(abfd);
1427
1428 iname_lab->name = head_label;
1429 iname_lab->section = (asection *)&bfd_und_section;
1430 iname_lab->flags = 0;
1431 iname_lab->value = 0;
1432
1433
1434 iname_pp = ptrs + oidx;
1435 ptrs[oidx++] = iname;
1436
1437 iname_lab_pp = ptrs + oidx;
1438 ptrs[oidx++] = iname_lab;
1439
1440 #ifdef DLLTOOL_PPC
1441 /* The symbol refering to the code (.text) */
1442 function_name = bfd_make_empty_symbol(abfd);
1443 function_name->name = make_label ("..", exp->name);
1444 function_name->section = secdata[TEXT].sec;
1445 function_name->flags = BSF_GLOBAL;
1446 function_name->value = 0;
1447
1448 fn_pp = ptrs + oidx;
1449 ptrs[oidx++] = function_name;
1450
1451 /* The .toc symbol */
1452 toc_symbol = bfd_make_empty_symbol(abfd);
1453 toc_symbol->name = make_label (".", "toc");
1454 toc_symbol->section = (asection *)&bfd_und_section;
1455 toc_symbol->flags = BSF_GLOBAL;
1456 toc_symbol->value = 0;
1457
1458 toc_pp = ptrs + oidx;
1459 ptrs[oidx++] = toc_symbol;
1460 #endif
1461
1462 ptrs[oidx] = 0;
1463
1464 for (i = 0; i < NSECS; i++)
1465 {
1466 sinfo *si = secdata + i;
1467 asection *sec = si->sec;
1468 arelent *rel;
1469 arelent **rpp;
1470
1471 switch (i)
1472 {
1473 case TEXT:
1474 si->size = HOW_JTAB_SIZE;
1475 si->data = xmalloc (HOW_JTAB_SIZE);
1476 memcpy (si->data, HOW_JTAB, HOW_JTAB_SIZE);
1477
1478 /* add the reloc into idata$5 */
1479 rel = xmalloc (sizeof (arelent));
1480 rpp = xmalloc (sizeof (arelent *) * 2);
1481 rpp[0] = rel;
1482 rpp[1] = 0;
1483 rel->address = HOW_JTAB_ROFF;
1484 rel->addend = 0;
1485
1486 if (machine == MPPC)
1487 {
1488 rel->howto = bfd_reloc_type_lookup (abfd,
1489 BFD_RELOC_16_GOTOFF);
1490 rel->sym_ptr_ptr = iname_pp;
1491 }
1492 else
1493 {
1494 rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1495 rel->sym_ptr_ptr = secdata[IDATA5].sympp;
1496 }
1497 sec->orelocation = rpp;
1498 sec->reloc_count = 1;
1499 break;
1500 case IDATA4:
1501 case IDATA5:
1502 /* An idata$4 or idata$5 is one word long, and has an
1503 rva to idata$6 */
1504
1505 si->data = xmalloc (4);
1506 si->size = 4;
1507
1508 if (exp->noname)
1509 {
1510 si->data[0] = exp->ordinal ;
1511 si->data[1] = exp->ordinal >> 8;
1512 si->data[2] = exp->ordinal >> 16;
1513 si->data[3] = 0x80;
1514 }
1515 else
1516 {
1517 sec->reloc_count = 1;
1518 memset (si->data, 0, si->size);
1519 rel = xmalloc (sizeof (arelent));
1520 rpp = xmalloc (sizeof (arelent *) * 2);
1521 rpp[0] = rel;
1522 rpp[1] = 0;
1523 rel->address = 0;
1524 rel->addend = 0;
1525 rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA);
1526 rel->sym_ptr_ptr = secdata[IDATA6].sympp;
1527 sec->orelocation = rpp;
1528 }
1529
1530 break;
1531
1532 case IDATA6:
1533 if (!exp->noname)
1534 {
1535 int idx = exp->hint + 1;
1536 si->size = strlen (xlate (exp->name)) + 3;
1537 si->data = xmalloc (si->size);
1538 si->data[0] = idx & 0xff;
1539 si->data[1] = idx >> 8;
1540 strcpy (si->data + 2, xlate (exp->name));
1541 }
1542 break;
1543 case IDATA7:
1544 si->size = 4;
1545 si->data =xmalloc(4);
1546 memset (si->data, 0, si->size);
1547 rel = xmalloc (sizeof (arelent));
1548 rpp = xmalloc (sizeof (arelent *) * 2);
1549 rpp[0] = rel;
1550 rel->address = 0;
1551 rel->addend = 0;
1552 rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1553 rel->sym_ptr_ptr = iname_lab_pp;
1554 sec->orelocation = rpp;
1555 sec->reloc_count = 1;
1556 break;
1557
1558 case PDATA:
1559 {
1560 /* The .pdata section is 5 words long. */
1561 /* Think of it as: */
1562 /* struct */
1563 /* { */
1564 /* bfd_vma BeginAddress, [0x00] */
1565 /* EndAddress, [0x04] */
1566 /* ExceptionHandler, [0x08] */
1567 /* HandlerData, [0x0c] */
1568 /* PrologEndAddress; [0x10] */
1569 /* }; */
1570
1571 /* So this pdata section setups up this as a glue linkage to
1572 a dll routine. There are a number of house keeping things
1573 we need to do:
1574
1575 1. In the name of glue trickery, the ADDR32 relocs for 0,
1576 4, and 0x10 are set to point to the same place:
1577 "..function_name".
1578 2. There is one more reloc needed in the pdata section.
1579 The actual glue instruction to restore the toc on
1580 return is saved as the offset in an IMGLUE reloc.
1581 So we need a total of four relocs for this section.
1582
1583 3. Lastly, the HandlerData field is set to 0x03, to indicate
1584 that this is a glue routine.
1585 */
1586 arelent *imglue, *ba_rel, *ea_rel, *pea_rel;
1587
1588 /* alignment must be set to 2**2 or you get extra stuff */
1589 bfd_set_section_alignment(abfd, sec, 2);
1590
1591 si->size = 4 * 5;
1592 si->data =xmalloc(4 * 5);
1593 memset (si->data, 0, si->size);
1594 rpp = xmalloc (sizeof (arelent *) * 5);
1595 rpp[0] = imglue = xmalloc (sizeof (arelent));
1596 rpp[1] = ba_rel = xmalloc (sizeof (arelent));
1597 rpp[2] = ea_rel = xmalloc (sizeof (arelent));
1598 rpp[3] = pea_rel = xmalloc (sizeof (arelent));
1599 rpp[4] = 0;
1600
1601 /* stick the toc reload instruction in the glue reloc */
1602 bfd_put_32(abfd, ppc_glue_insn, (char *) &imglue->address);
1603
1604 imglue->addend = 0;
1605 imglue->howto = bfd_reloc_type_lookup (abfd,
1606 BFD_RELOC_32_GOTOFF);
1607 imglue->sym_ptr_ptr = fn_pp;
1608
1609 ba_rel->address = 0;
1610 ba_rel->addend = 0;
1611 ba_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1612 ba_rel->sym_ptr_ptr = fn_pp;
1613
1614 bfd_put_32(abfd, 0x18, si->data + 0x04);
1615 ea_rel->address = 4;
1616 ea_rel->addend = 0;
1617 ea_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1618 ea_rel->sym_ptr_ptr = fn_pp;
1619
1620 /* mark it as glue */
1621 bfd_put_32(abfd, 0x03, si->data + 0x0c);
1622
1623 /* mark the prolog end address */
1624 bfd_put_32(abfd, 0x0D, si->data + 0x10);
1625 pea_rel->address = 0x10;
1626 pea_rel->addend = 0;
1627 pea_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1628 pea_rel->sym_ptr_ptr = fn_pp;
1629
1630 sec->orelocation = rpp;
1631 sec->reloc_count = 4;
1632 break;
1633 }
1634 case RDATA:
1635 /* Each external function in a PowerPC PE file has a two word
1636 descriptor consisting of:
1637 1. The address of the code.
1638 2. The address of the appropriate .toc
1639 We use relocs to build this.
1640 */
1641
1642 si->size = 8;
1643 si->data =xmalloc(8);
1644 memset (si->data, 0, si->size);
1645
1646 rpp = xmalloc (sizeof (arelent *) * 3);
1647 rpp[0] = rel = xmalloc (sizeof (arelent));
1648 rpp[1] = xmalloc (sizeof (arelent));
1649 rpp[2] = 0;
1650
1651 rel->address = 0;
1652 rel->addend = 0;
1653 rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1654 rel->sym_ptr_ptr = fn_pp;
1655
1656 rel = rpp[1];
1657
1658 rel->address = 4;
1659 rel->addend = 0;
1660 rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
1661 rel->sym_ptr_ptr = toc_pp;
1662
1663 sec->orelocation = rpp;
1664 sec->reloc_count = 2;
1665 break;
1666 }
1667 }
1668
1669 {
1670 bfd_vma vma = 0;
1671 /* Size up all the sections */
1672 for (i = 0; i < NSECS; i++)
1673 {
1674 sinfo *si = secdata + i;
1675
1676 bfd_set_section_size (abfd, si->sec, si->size);
1677 bfd_set_section_vma (abfd, si->sec, vma);
1678
1679 /* vma += si->size;*/
1680 }
1681 }
1682 /* Write them out */
1683 for (i = 0; i < NSECS; i++)
1684 {
1685 sinfo *si = secdata + i;
1686
1687 if (i == IDATA5 && no_idata5)
1688 continue;
1689
1690 if (i == IDATA4 && no_idata4)
1691 continue;
1692
1693 bfd_set_section_contents (abfd, si->sec,
1694 si->data, 0,
1695 si->size);
1696 }
1697
1698 bfd_set_symtab (abfd, ptrs, oidx);
1699 bfd_close (abfd);
1700 abfd = bfd_openr (outname, HOW_BFD_TARGET);
1701 return abfd;
1702 }
1703
1704 }
1705
1706
1707 static bfd *
1708 make_head()
1709 {
1710 FILE * f = fopen ("dh.s", FOPEN_WT);
1711
1712 fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
1713 fprintf (f, "\t.section .idata$2\n");
1714
1715 fprintf(f,"\t%s\t%s\n", ASM_GLOBAL,head_label);
1716
1717 fprintf (f, "%s:\n", head_label);
1718
1719 fprintf (f, "\t%shname%s\t%sPtr to image import by name list\n",
1720 ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
1721
1722 fprintf (f, "\t%sthis should be the timestamp, but NT sometimes\n", ASM_C);
1723 fprintf (f, "\t%sdoesn't load DLLs when this is set.\n", ASM_C);
1724 fprintf (f, "\t%s\t0\t%s loaded time\n", ASM_LONG, ASM_C);
1725 fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
1726 fprintf (f, "\t%s__%s_iname%s\t%s imported dll's name\n",
1727 ASM_RVA_BEFORE,
1728 imp_name_lab,
1729 ASM_RVA_AFTER,
1730 ASM_C);
1731 fprintf (f, "\t%sfthunk%s\t%s pointer to firstthunk\n",
1732 ASM_RVA_BEFORE,
1733 ASM_RVA_AFTER, ASM_C);
1734
1735 fprintf (f, "%sStuff for compatibility\n", ASM_C);
1736
1737 if (!no_idata5)
1738 {
1739 fprintf (f, "\t.section\t.idata$5\n");
1740 fprintf (f, "\t%s\t0\n", ASM_LONG);
1741 fprintf (f, "fthunk:\n");
1742 }
1743 if (!no_idata4)
1744 {
1745 fprintf (f, "\t.section\t.idata$4\n");
1746
1747 fprintf (f, "\t%s\t0\n", ASM_LONG);
1748 fprintf (f, "\t.section .idata$4\n");
1749 fprintf (f, "hname:\n");
1750 }
1751 fclose (f);
1752
1753 sprintf (outfile, "-o dh.o dh.s");
1754 run (as_name, outfile);
1755
1756 return bfd_openr ("dh.o", HOW_BFD_TARGET);
1757 }
1758
1759 static bfd *
1760 make_tail()
1761 {
1762 FILE * f = fopen ("dt.s", FOPEN_WT);
1763
1764 #ifdef DLLTOOL_PPC
1765 /* Other PowerPC NT compilers use idata$6 for the dllname, so I
1766 do too. Original, huh? */
1767 fprintf (f, "\t.section .idata$6\n");
1768 #else
1769 fprintf (f, "\t.section .idata$7\n");
1770 #endif
1771
1772 fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab);
1773 fprintf (f, "__%s_iname:\t%s\t\"%s\"\n",
1774 imp_name_lab, ASM_TEXT, dll_name);
1775
1776 if (!no_idata4)
1777 {
1778 fprintf (f, "\t.section .idata$4\n");
1779 fprintf (f, "\t%s\t0\n", ASM_LONG);
1780 }
1781 if (!no_idata5)
1782 {
1783 fprintf (f, "\t.section .idata$5\n");
1784 fprintf (f, "\t%s\t0\n", ASM_LONG);
1785 }
1786
1787
1788 #ifdef DLLTOOL_PPC
1789 /* Normally, we need to see a null descriptor built in idata$3 to
1790 act as the terminator for the list. The ideal way, I suppose,
1791 would be to mark this section as a comdat type 2 section, so
1792 only one would appear in the final .exe (if our linker supported
1793 comdat, that is) or cause it to be inserted by something else (say
1794 crt0)
1795 */
1796
1797 fprintf (f, "\t.section .idata$3\n");
1798 fprintf (f, "\t%s\t0\n", ASM_LONG);
1799 fprintf (f, "\t%s\t0\n", ASM_LONG);
1800 fprintf (f, "\t%s\t0\n", ASM_LONG);
1801 fprintf (f, "\t%s\t0\n", ASM_LONG);
1802 fprintf (f, "\t%s\t0\n", ASM_LONG);
1803 #endif
1804
1805 fclose (f);
1806
1807 sprintf (outfile, "-o dt.o dt.s");
1808 run (as_name, outfile);
1809 return bfd_openr ("dt.o", HOW_BFD_TARGET);
1810 }
1811
1812 static void
1813 gen_lib_file ()
1814 {
1815 int i;
1816 export_type *exp;
1817 bfd *ar_head;
1818 bfd *ar_tail;
1819 bfd *outarch;
1820 bfd * head = 0;
1821
1822 unlink (imp_name);
1823
1824 outarch = bfd_openw (imp_name, HOW_BFD_TARGET);
1825
1826 if (!outarch)
1827 {
1828 fprintf (stderr, "%s: Can't open .lib file %s\n", program_name, imp_name);
1829 exit (1);
1830 }
1831 bfd_set_format (outarch, bfd_archive);
1832 outarch->has_armap = 1;
1833
1834 /* Work out a reasonable size of things to put onto one line. */
1835
1836
1837
1838 ar_head = make_head ();
1839 ar_tail = make_tail();
1840
1841 for (i = 0; (exp = d_exports_lexically[i]); i++)
1842 {
1843 bfd *n = make_one_lib_file (exp, i);
1844 n->next = head;
1845 head = n;
1846 }
1847
1848
1849 /* Now stick them all into the archive */
1850
1851 ar_head->next = head;
1852 ar_tail->next = ar_head;
1853 head = ar_tail;
1854
1855 bfd_set_archive_head (outarch, head);
1856 bfd_close (outarch);
1857
1858 /* Delete all the temp files */
1859
1860 if (dontdeltemps == 0)
1861 {
1862 sprintf (outfile, "dh.o");
1863 unlink (outfile);
1864 sprintf (outfile, "dh.s");
1865 unlink (outfile);
1866 sprintf (outfile, "dt.o");
1867 unlink (outfile);
1868 sprintf (outfile, "dt.s");
1869 unlink (outfile);
1870 }
1871
1872 if (dontdeltemps < 2)
1873 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
1874 {
1875 sprintf (outfile, "ds%d.o",i);
1876 unlink (outfile);
1877 }
1878
1879 }
1880 /**********************************************************************/
1881
1882 /* Run through the information gathered from the .o files and the
1883 .def file and work out the best stuff */
1884 int
1885 pfunc (a, b)
1886 void *a;
1887 void *b;
1888 {
1889 export_type *ap = *(export_type **) a;
1890 export_type *bp = *(export_type **) b;
1891 if (ap->ordinal == bp->ordinal)
1892 return 0;
1893
1894 /* unset ordinals go to the bottom */
1895 if (ap->ordinal == -1)
1896 return 1;
1897 if (bp->ordinal == -1)
1898 return -1;
1899 return (ap->ordinal - bp->ordinal);
1900 }
1901
1902
1903 int
1904 nfunc (a, b)
1905 void *a;
1906 void *b;
1907 {
1908 export_type *ap = *(export_type **) a;
1909 export_type *bp = *(export_type **) b;
1910
1911 return (strcmp (ap->name, bp->name));
1912 }
1913
1914 static
1915 void
1916 remove_null_names (ptr)
1917 export_type **ptr;
1918 {
1919 int src;
1920 int dst;
1921 for (dst = src = 0; src < d_nfuncs; src++)
1922 {
1923 if (ptr[src])
1924 {
1925 ptr[dst] = ptr[src];
1926 dst++;
1927 }
1928 }
1929 d_nfuncs = dst;
1930 }
1931
1932 static void
1933 dtab (ptr)
1934 export_type **ptr;
1935 {
1936 #ifdef SACDEBUG
1937 int i;
1938 for (i = 0; i < d_nfuncs; i++)
1939 {
1940 if (ptr[i])
1941 {
1942 printf ("%d %s @ %d %s%s\n",
1943 i, ptr[i]->name, ptr[i]->ordinal,
1944 ptr[i]->noname ? "NONAME " : "",
1945 ptr[i]->constant ? "CONSTANT" : "");
1946 }
1947 else
1948 printf ("empty\n");
1949 }
1950 #endif
1951 }
1952
1953 static void
1954 process_duplicates (d_export_vec)
1955 export_type **d_export_vec;
1956 {
1957 int more = 1;
1958 int i;
1959 while (more)
1960 {
1961
1962 more = 0;
1963 /* Remove duplicates */
1964 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
1965
1966 dtab (d_export_vec);
1967 for (i = 0; i < d_nfuncs - 1; i++)
1968 {
1969 if (strcmp (d_export_vec[i]->name,
1970 d_export_vec[i + 1]->name) == 0)
1971 {
1972
1973 export_type *a = d_export_vec[i];
1974 export_type *b = d_export_vec[i + 1];
1975
1976 more = 1;
1977 if (verbose)
1978 fprintf (stderr, "Warning, ignoring duplicate EXPORT %s %d,%d\n",
1979 a->name,
1980 a->ordinal,
1981 b->ordinal);
1982 if (a->ordinal != -1
1983 && b->ordinal != -1)
1984 {
1985
1986 fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
1987 a->name);
1988 exit (1);
1989 }
1990 /* Merge attributes */
1991 b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
1992 b->constant |= a->constant;
1993 b->noname |= a->noname;
1994 d_export_vec[i] = 0;
1995 }
1996
1997 dtab (d_export_vec);
1998 remove_null_names (d_export_vec);
1999 dtab (d_export_vec);
2000 }
2001 }
2002
2003
2004 /* Count the names */
2005 for (i = 0; i < d_nfuncs; i++)
2006 {
2007 if (!d_export_vec[i]->noname)
2008 d_named_nfuncs++;
2009 }
2010 }
2011
2012 static void
2013 fill_ordinals (d_export_vec)
2014 export_type **d_export_vec;
2015 {
2016 int lowest = 0;
2017
2018 int i;
2019 char *ptr;
2020 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
2021
2022 /* fill in the unset ordinals with ones from our range */
2023
2024 ptr = (char *) malloc (65536);
2025
2026 memset (ptr, 0, 65536);
2027
2028 /* Mark in our large vector all the numbers that are taken */
2029 for (i = 0; i < d_nfuncs; i++)
2030 {
2031 if (d_export_vec[i]->ordinal != -1)
2032 {
2033 ptr[d_export_vec[i]->ordinal] = 1;
2034 if (lowest == 0)
2035 lowest = d_export_vec[i]->ordinal;
2036 }
2037 }
2038
2039 /* Start at 1 for compatibility with MS toolchain. */
2040 if (lowest == 0)
2041 lowest = 1;
2042
2043 for (i = 0; i < d_nfuncs; i++)
2044 {
2045 if (d_export_vec[i]->ordinal == -1)
2046 {
2047 int j;
2048 for (j = lowest; j < 65536; j++)
2049 if (ptr[j] == 0)
2050 {
2051 ptr[j] = 1;
2052 d_export_vec[i]->ordinal = j;
2053 goto done;
2054 }
2055
2056 for (j = 1; j < lowest; j++)
2057 if (ptr[j] == 0)
2058 {
2059 ptr[j] = 1;
2060 d_export_vec[i]->ordinal = j;
2061 goto done;
2062 }
2063 done:;
2064
2065 }
2066 }
2067
2068 free (ptr);
2069
2070 /* And resort */
2071
2072 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
2073
2074 /* Work out the lowest and highest ordinal numbers. */
2075 if (d_nfuncs)
2076 {
2077 if (d_export_vec[0])
2078 d_low_ord = d_export_vec[0]->ordinal;
2079 if (d_export_vec[d_nfuncs-1])
2080 d_high_ord = d_export_vec[d_nfuncs-1]->ordinal;
2081 }
2082 }
2083
2084 int alphafunc(av,bv)
2085 void *av;
2086 void *bv;
2087 {
2088 export_type **a = av;
2089 export_type **b = bv;
2090
2091 return strcmp ((*a)->name, (*b)->name);
2092 }
2093
2094 void
2095 mangle_defs ()
2096 {
2097 /* First work out the minimum ordinal chosen */
2098
2099 export_type *exp;
2100
2101 int i;
2102 int hint = 0;
2103 export_type **d_export_vec
2104 = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
2105
2106 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
2107 {
2108 d_export_vec[i] = exp;
2109 }
2110
2111 process_duplicates (d_export_vec);
2112 fill_ordinals (d_export_vec);
2113
2114 /* Put back the list in the new order */
2115 d_exports = 0;
2116 for (i = d_nfuncs - 1; i >= 0; i--)
2117 {
2118 d_export_vec[i]->next = d_exports;
2119 d_exports = d_export_vec[i];
2120 }
2121
2122 /* Build list in alpha order */
2123 d_exports_lexically = (export_type **)xmalloc (sizeof(export_type *)*(d_nfuncs+1));
2124
2125 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
2126 {
2127 d_exports_lexically[i] = exp;
2128 }
2129 d_exports_lexically[i] = 0;
2130
2131 qsort (d_exports_lexically, i, sizeof (export_type *), alphafunc);
2132
2133 /* Fill exp entries with their hint values */
2134
2135 for (i = 0; i < d_nfuncs; i++)
2136 {
2137 if (!d_exports_lexically[i]->noname || show_allnames)
2138 d_exports_lexically[i]->hint = hint++;
2139 }
2140
2141 }
2142
2143
2144
2145
2146
2147
2148 /**********************************************************************/
2149
2150 void
2151 usage (file, status)
2152 FILE *file;
2153 int status;
2154 {
2155 fprintf (file, "Usage %s <options> <object-files>\n", program_name);
2156 fprintf (file, " --machine <machine>\n");
2157 fprintf (file, " --output-exp <outname> Generate export file.\n");
2158 fprintf (file, " --output-lib <outname> Generate input library.\n");
2159 fprintf (file, " --add-indirect Add dll indirects to export file.\n");
2160 fprintf (file, " --dllname <name> Name of input dll to put into output lib.\n");
2161 fprintf (file, " --def <deffile> Name input .def file\n");
2162 fprintf (file, " --output-def <deffile> Name output .def file\n");
2163 fprintf (file, " --base-file <basefile> Read linker generated base file\n");
2164 fprintf (file, " --no-idata4 Don't generate idata$4 section\n");
2165 fprintf (file, " --no-idata5 Don't generate idata$5 section\n");
2166 fprintf (file, " -v Verbose\n");
2167 fprintf (file, " -U Add underscores to .lib\n");
2168 fprintf (file, " -k Kill @<n> from exported names\n");
2169 fprintf (file, " --as <name> Use <name> for assembler\n");
2170 fprintf (file, " --nodelete Keep temp files.\n");
2171 exit (status);
2172 }
2173
2174 #define OPTION_NO_IDATA4 'x'
2175 #define OPTION_NO_IDATA5 'c'
2176 static struct option long_options[] =
2177 {
2178 {"nodelete", no_argument, NULL, 'n'},
2179 {"dllname", required_argument, NULL, 'D'},
2180 {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
2181 {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
2182 {"output-exp", required_argument, NULL, 'e'},
2183 {"output-def", required_argument, NULL, 'z'},
2184 {"output-lib", required_argument, NULL, 'l'},
2185 {"def", required_argument, NULL, 'd'},
2186 {"add-underscore", no_argument, NULL, 'U'},
2187 {"killat", no_argument, NULL, 'k'},
2188 {"help", no_argument, NULL, 'h'},
2189 {"machine", required_argument, NULL, 'm'},
2190 {"add-indirect", no_argument, NULL, 'a'},
2191 {"base-file", required_argument, NULL, 'b'},
2192 {"as", required_argument, NULL, 'S'},
2193 {0}
2194 };
2195
2196
2197
2198 int
2199 main (ac, av)
2200 int ac;
2201 char **av;
2202 {
2203 int c;
2204 int i;
2205 char *firstarg = 0;
2206 program_name = av[0];
2207 oav = av;
2208
2209 while ((c = getopt_long (ac, av, "xcz:S:R:A:puaD:l:e:nkvbUh?m:yd:", long_options, 0))
2210 != EOF)
2211 {
2212 switch (c)
2213 {
2214 case OPTION_NO_IDATA4:
2215 no_idata4 = 1;
2216 break;
2217 case OPTION_NO_IDATA5:
2218 no_idata5 = 1;
2219 break;
2220 case 'S':
2221 as_name = optarg;
2222 break;
2223
2224 /* ignored for compatibility */
2225 case 'u':
2226 break;
2227 case 'a':
2228 add_indirect = 1;
2229 break;
2230 case 'z':
2231 output_def = fopen (optarg, FOPEN_WT);
2232 break;
2233 case 'D':
2234 dll_name = optarg;
2235 break;
2236 case 'l':
2237 imp_name = optarg;
2238 break;
2239 case 'e':
2240 exp_name = optarg;
2241 break;
2242 case 'h':
2243 case '?':
2244 usage (stderr, 0);
2245 break;
2246 case 'm':
2247 mname = optarg;
2248 break;
2249 case 'v':
2250 verbose = 1;
2251 break;
2252 case 'y':
2253 yydebug = 1;
2254 break;
2255 case 'U':
2256 add_underscore = 1;
2257 break;
2258 case 'k':
2259 killat = 1;
2260 break;
2261 case 'd':
2262 def_file = optarg;
2263 break;
2264 case 'n':
2265 dontdeltemps++;
2266 break;
2267 case 'b':
2268 base_file = fopen (optarg, FOPEN_RB);
2269 if (!base_file)
2270 {
2271 fprintf (stderr, "%s: Unable to open base-file %s\n",
2272 av[0],
2273 optarg);
2274 exit (1);
2275 }
2276 break;
2277 default:
2278 usage (stderr, 1);
2279 }
2280 }
2281
2282
2283 for (i = 0; mtable[i].type; i++)
2284 {
2285 if (strcmp (mtable[i].type, mname) == 0)
2286 break;
2287 }
2288
2289 if (!mtable[i].type)
2290 {
2291 fprintf (stderr, "Machine not supported\n");
2292 exit (1);
2293 }
2294 machine = i;
2295
2296
2297 if (!dll_name && exp_name)
2298 {
2299 char len = strlen (exp_name) + 5;
2300 dll_name = xmalloc (len);
2301 strcpy (dll_name, exp_name);
2302 strcat (dll_name, ".dll");
2303 }
2304
2305 if (def_file)
2306 {
2307 process_def_file (def_file);
2308 }
2309 while (optind < ac)
2310 {
2311 if (!firstarg)
2312 firstarg = av[optind];
2313 scan_obj_file (av[optind]);
2314 optind++;
2315 }
2316
2317
2318 mangle_defs ();
2319
2320 if (exp_name)
2321 gen_exp_file ();
2322 if (imp_name)
2323 {
2324 /* Make imp_name safe for use as a label. */
2325 char *p;
2326 imp_name_lab = strdup (imp_name);
2327 for (p = imp_name_lab; *p; *p++)
2328 {
2329 if (!isalpha (*p) && !isdigit (*p))
2330 *p = '_';
2331 }
2332 head_label = make_label("_head_", imp_name_lab);
2333 gen_lib_file ();
2334 }
2335 if (output_def)
2336 gen_def_file ();
2337
2338 return 0;
2339 }
This page took 0.082712 seconds and 5 git commands to generate.