1 /* dlltool.c -- tool to generate stuff for PE style DLLs
2 Copyright (C) 1995 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
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.
26 A DLL contains an export table which contains the information
27 which the runtime loader needs to tie up references from a
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.
35 A DEF file contains any number of the following commands:
38 NAME <name> [ , <base> ]
39 The result is going to be <name>.EXE
41 LIBRARY <name> [ , <base> ]
42 The result is going to be <name>.DLL
44 EXPORTS ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) *
45 Declares name1 as an exported symbol from the
46 DLL, with optional ordinal number <integer>
48 IMPORTS ( [ <name> = ] <name> . <name> ) *
49 Ignored for compatibility
52 Puts <string> into output .exp file in the .rdata section
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.
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
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>
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
77 The output files are <prefix>.exp.s and <prefix>.lib.s
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.
88 asm (".section .drectve");
89 asm (".ascii \"-export:adef\"");
93 printf("hello from the dll %s\n",s);
98 printf("hello from the dll and the other entry point %s\n",s);
102 asm (".section .drectve");
103 asm (".ascii \"-export:cdef\"");
104 asm (".ascii \"-export:ddef\"");
107 printf("hello from the dll %s\n",s);
112 printf("hello from the dll and the other entry point %s\n",s);
130 HEAPSIZE 0x40000, 0x2000
134 SECTIONS donkey READ WRITE
138 # compile up the parts of the dll
143 # put them in a library (you don't have to, you
144 # could name all the .os on the dlltool line)
146 ar qcv thedll.in file1.o file2.o
149 # run this tool over the library and the def file
150 ./dlltool -o thedll -d thedll.def thedll.in
152 # build the export table for the dll
153 as -o thedll.exp thedll.exp.s
154 # build the dll with the library with file1.o, file2.o and the export table
155 ld -o thedll.dll thedll.exp thedll.in
157 # build the import table for the executable
158 as -o thedll.lib thedll.lib.s
163 # link the executable with the import library
164 ld -e main -Tthemain.ld -o themain.exe themain.o thedll.lib
178 char *outfile_prefix;
185 static char *mname = "arm";
189 static char *mname = "i386";
204 = {{"arm",".byte",".short",".long",".asciz","@","bl",".global",".space"},
205 {"i386",".byte",".short",".long",".asciz",";","jmp",".global",".space"},
208 #define ASM_BYTE mtable[machine].how_byte
209 #define ASM_SHORT mtable[machine].how_short
210 #define ASM_LONG mtable[machine].how_long
211 #define ASM_TEXT mtable[machine].how_asciz
212 #define ASM_C mtable[machine].how_comment
213 #define ASM_JUMP mtable[machine].how_jump
214 #define ASM_GLOBAL mtable[machine].how_global
215 #define ASM_SPACE mtable[machine].how_space
217 #define PATHMAX 250 /* What's the right name for this ? */
222 FILE *yyin; /* communications with flex */
223 extern int linenumber;
225 process_def_file (name)
228 FILE *f = fopen (name, "r");
231 fprintf (stderr, "Can't open def file %s\n", name);
240 /**********************************************************************/
242 /* Communications with the parser */
251 typedef struct export
262 static char *d_name; /* Arg to NAME or LIBRARY */
263 static int d_nfuncs; /* Number of functions exported */
264 static int d_ord; /* Base ordinal index */
265 static export_type *d_exports; /*list of exported functions */
266 static char *d_suffix = "dll";
267 static dlist_type *d_list; /* Descriptions */
268 static dlist_type *a_list; /* Stuff to go in directives */
275 fprintf (stderr, "Syntax error in def file %s:%d\n",
276 def_file, linenumber);
280 def_exports (name, equal, ordinal, noname, constant)
287 struct export *p = (struct export *) xmalloc (sizeof (*p));
291 p->ordinal = ordinal;
292 p->constant = constant;
299 printf ("EXPORTS %s", name);
301 printf ("=%s", equal);
303 printf ("@%d", ordinal);
305 printf (" CONSTANT");
310 def_name (name, base)
314 printf ("NAME %s base %x\n", name, base);
317 fprintf (stderr, "Can't have LIBRARY and NAME\n");
320 if (strchr (d_name, '.'))
321 d_suffix = strdup (strchr (d_name, '.') + 1);
326 def_library (name, base)
330 printf ("LIBRARY %s base %x\n", name, base);
333 fprintf (stderr, "Can't have LIBRARY and NAME\n");
336 if (strchr (d_name, '.'))
337 d_suffix = strdup (strchr (d_name, '.') + 1);
342 def_description (desc)
345 dlist_type *d = (dlist_type *)xmalloc(sizeof(dlist_type));
346 d->text = strdup (desc);
351 void new_directive(dir)
354 dlist_type *d = (dlist_type *)xmalloc(sizeof(dlist_type));
355 d->text = strdup (dir);
361 def_stacksize (reserve, commit)
367 sprintf (b,"-stack 0x%x,0x%x ", reserve, commit);
369 sprintf (b,"-stack 0x%x ", reserve);
370 new_directive (strdup(b));
374 def_heapsize (reserve, commit)
380 sprintf (b,"-heap 0x%x,0x%x ", reserve, commit);
382 sprintf (b,"-heap 0x%x ", reserve);
383 new_directive (strdup(b));
388 def_import (internal, module, entry)
393 fprintf (stderr, "IMPORTS are ignored");
397 def_version (major, minor)
399 printf ("VERSION %d.%d\n", major, minor);
404 def_section (name, attr)
421 sprintf (buf, "-attr %s %s", name, atts);
422 new_directive (strdup(buf));
429 def_section ("CODE", attr);
436 def_section ("DATA",attr);
440 /**********************************************************************/
443 scan_open_obj_file (abfd)
446 /* Look for .drectives */
447 asection *s = bfd_get_section_by_name (abfd, ".drectve");
450 int size = bfd_get_section_size_before_reloc (s);
451 char *buf = xmalloc (size);
454 bfd_get_section_contents (abfd, s, buf, 0, size);
455 printf ("Sucking in info from %s\n",
456 bfd_get_filename (abfd));
458 /* Search for -export: strings */
464 && strncmp (p, "-export:", 8) == 0)
470 while (*p != ' ' && *p != '-' && p < e)
472 c = xmalloc (p - name + 1);
473 memcpy (c, name, p - name);
475 def_exports (c, 0, -1, 0);
486 scan_obj_file (filename)
489 bfd *f = bfd_openr (filename, 0);
493 fprintf (stderr, "Unable to open object file %s\n", filename);
496 if (bfd_check_format (f, bfd_archive))
498 bfd *arfile = bfd_openr_next_archived_file (f, 0);
501 if (bfd_check_format (arfile, bfd_object))
502 scan_open_obj_file (arfile);
504 arfile = bfd_openr_next_archived_file (f, arfile);
508 if (bfd_check_format (f, bfd_object))
510 scan_open_obj_file (f);
516 /**********************************************************************/
519 /* return the bit of the name before the last . */
526 char *res = strdup (name);
527 char *p = strrchr (res, '.');
539 fprintf(f,"%s ", ASM_C);
540 for (i= 0; oav[i]; i++)
541 fprintf(f,"%s ", oav[i]);
543 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
545 fprintf (f, "%s %d %s @ %d %s%s\n",
548 exp->name, exp->ordinal,
549 exp->noname ? "NONAME " : "",
550 exp->constant ? "CONSTANT" : "");
553 /* Generate the .exp file */
560 char outfile[PATHMAX];
564 sprintf (outfile, "%s.exp.s", outfile_prefix);
566 f = fopen (outfile, "w");
569 fprintf (stderr, "Unable to open output file %s\n", outfile);
573 fprintf (f, "\t.section .edata\n\n");
574 fprintf (f, "\t%s 0 %s Allways 0\n", ASM_LONG, ASM_C);
575 fprintf (f, "\t%s %d %s Time and date\n", ASM_LONG, time (0), ASM_C);
576 fprintf (f, "\t%s 0 %s Major and Minor version\n", ASM_LONG, ASM_C);
577 fprintf (f, "\t%s name %s Ptr to name of dll\n", ASM_LONG, ASM_C);
578 fprintf (f, "\t%s %d %s Starting ordinal of exports\n", ASM_LONG, d_ord, ASM_C);
579 fprintf (f, "\t%s The next field is documented as being the number of functions\n", ASM_C);
580 fprintf (f, "\t%s yet it doesn't look like that in real PE dlls\n", ASM_C);
581 fprintf (f, "\t%s But it shouldn't be a problem, causes there's\n", ASM_C);
582 fprintf (f, "\t%s always the number of names field\n", ASM_C);
583 fprintf (f, "\t%s %d %s Number of functions\n", ASM_LONG, d_nfuncs, ASM_C);
584 fprintf (f, "\t%s %d %s Number of names\n", ASM_LONG, d_nfuncs, ASM_C);
585 fprintf (f, "\t%s afuncs %s Address of functions\n", ASM_LONG, ASM_C);
586 fprintf (f, "\t%s anames %s Address of names\n", ASM_LONG, ASM_C);
587 fprintf (f, "\t%s anords %s Address of ordinals\n", ASM_LONG, ASM_C);
589 fprintf (f, "name: %s \"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
591 fprintf (f, "afuncs:\n");
593 for (exp = d_exports; exp; exp = exp->next)
595 if (exp->ordinal != i)
597 fprintf (f, "\t%s\t%d\t@ %d..%d missing\n", ASM_SPACE,
598 (exp->ordinal - i) * 4,
599 i, exp->ordinal - 1);
602 fprintf (f, "\t%s %s\t%s %d\n", ASM_LONG, exp->name, ASM_C, exp->ordinal);
607 fprintf (f, "anames:\n");
608 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
610 fprintf (f, "\t%s 0\t%sNoname\n", ASM_LONG, ASM_C);
612 fprintf (f, "\t%s n%d\n", ASM_LONG, i);
614 fprintf (f, "anords:\n");
615 for (exp = d_exports; exp; exp = exp->next)
616 fprintf (f, "\t%s %d\n", ASM_SHORT, exp->ordinal - d_ord);
618 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
620 fprintf (f, "@n%d: %s \"%s\"\n", i, ASM_TEXT, exp->name);
622 fprintf (f, "n%d: %s \"%s\"\n", i, ASM_TEXT, exp->name);
627 fprintf(f,"\t.section .drectve\n");
628 for (dl = a_list; dl; dl = dl->next)
630 fprintf (f,"\t%s\t\"%s\"\n", ASM_TEXT, dl->text);
635 fprintf(f,"\t.section .rdata\n");
636 for (dl = d_list; dl; dl = dl->next)
640 /* We dont output as ascii 'cause there can
641 be quote characters in the string */
644 for (p = dl->text; *p; p++) {
646 fprintf(f,"\t%s\t", ASM_BYTE);
664 /**********************************************************************/
667 char outfile[PATHMAX];
672 sprintf (outfile, "%s.lib.s", outfile_prefix);
674 f = fopen (outfile, "w");
677 fprintf (stderr, "Unable to open output file %s\n", outfile);
683 fprintf (f, "\t.text\n");
684 fprintf (f, "%s Thunk table\n", ASM_C);
685 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
687 fprintf (f, "\t%s\t%s\n", ASM_GLOBAL, exp->name);
688 fprintf (f, "\t%s\t__imp__%s\n", ASM_GLOBAL, exp->name);
691 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
693 fprintf (f, "%s:\t%s\t__imp__%s\n", exp->name, ASM_JUMP, exp->name);
697 fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
698 fprintf (f, "\t.section .idata$2\n");
699 fprintf (f, "\t%s\thname\t%s Ptr to image import by name list\n", ASM_LONG, ASM_C);
700 fprintf (f, "\t%s\t%d\t%s time\n", ASM_LONG, time (0), ASM_C);
701 fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
702 fprintf (f, "\t%s\tiname\t%s imported dll's name\n", ASM_LONG, ASM_C);
703 fprintf (f, "\t%s\tfthunk\t%s pointer to firstthunk\n", ASM_LONG, ASM_C);
705 fprintf (f, "\n%s Loader modifies this\n", ASM_C);
706 fprintf (f, "\t.section .idata$5\n");
707 fprintf (f, "fthunk:\n");
708 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
710 fprintf (f, "__imp__%s:\n", exp->name);
711 fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
714 fprintf (f, "\n%s Hint name array\n", ASM_C);
715 fprintf (f, "\t.section .idata$4\n");
716 fprintf (f, "hname:\n");
717 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
719 fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
722 fprintf (f, "%s Hint/name array storage and import dll name\n", ASM_C);
723 fprintf (f, "\t.section .idata$6\n");
725 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
727 fprintf (f, "ID%d:\t%s\t%d\n", i, ASM_SHORT, exp->ordinal);
728 fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, exp->name);
731 fprintf (f, "iname:\t%s\t\"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
734 /**********************************************************************/
736 /* Run through the information gathered from the .o files and the
737 .def file and work out the best stuff */
743 export_type *ap = *(export_type **) a;
744 export_type *bp = *(export_type **) b;
745 if (ap->ordinal == bp->ordinal)
748 /* unset ordinals go to the bottom */
749 if (ap->ordinal == -1)
751 if (bp->ordinal == -1)
753 return (ap->ordinal - bp->ordinal);
762 export_type *ap = *(export_type **) a;
763 export_type *bp = *(export_type **) b;
765 return (strcmp (ap->name, bp->name));
770 remove_null_names (ptr)
775 for (dst = src = 0; src < d_nfuncs; src++)
792 for (i = 0; i < d_nfuncs; i++)
796 printf ("%d %s @ %d %s%s\n",
797 i, ptr[i]->name, ptr[i]->ordinal,
798 ptr[i]->noname ? "NONAME " : "",
799 ptr[i]->constant ? "CONSTANT" : "");
808 process_duplicates (d_export_vec)
809 export_type **d_export_vec;
816 /* Remove duplicates */
817 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc);
820 for (i = 0; i < d_nfuncs - 1; i++)
822 if (strcmp (d_export_vec[i]->name,
823 d_export_vec[i + 1]->name) == 0)
826 export_type *a = d_export_vec[i];
827 export_type *b = d_export_vec[i + 1];
831 fprintf (stderr, "warning, ignoring duplicate EXPORT %s\n",
837 fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n",
841 /* Merge attributes */
842 b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal;
843 b->constant |= a->constant;
844 b->noname |= a->noname;
849 remove_null_names (d_export_vec);
856 fill_ordinals (d_export_vec)
857 export_type **d_export_vec;
860 qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
862 /* fill in the unset ordinals with ones from the minimum */
863 for (i = 0; i < d_nfuncs; i++)
865 if (d_export_vec[i]->ordinal == -1)
867 d_export_vec[i]->ordinal = lowest++;
871 if (lowest == d_export_vec[i]->ordinal)
873 fprintf (stderr, "Warning, Duplicate ordinal %s @ %d\n",
874 d_export_vec[i]->name,
875 d_export_vec[i]->ordinal);
877 lowest = d_export_vec[i]->ordinal + 1;
881 /* Work out the lowest ordinal number */
883 d_ord = d_export_vec[0]->ordinal;
888 /* First work out the minimum ordinal chosen */
893 export_type **d_export_vec
894 = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs);
896 for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
898 d_export_vec[i] = exp;
901 process_duplicates (d_export_vec);
902 fill_ordinals (d_export_vec);
904 /* Put back the list in the new order */
906 for (i = d_nfuncs - 1; i >= 0; i--)
908 d_export_vec[i]->next = d_exports;
909 d_exports = d_export_vec[i];
914 /**********************************************************************/
921 fprintf (file, "Usage %s [-m|--machine machine] [-o outprefix] [-d|--def deffile] [--def deffile]\n", program_name);
925 static struct option long_options[] =
927 {"def", required_argument, NULL, 'd'},
928 {"help", no_argument, NULL, 'h'},
929 {"machine", required_argument, NULL, 'm'},
940 program_name = av[0];
943 while ((c = getopt_long (ac, av, "h?m:o:Dd:", long_options, 0)) != EOF)
955 outfile_prefix = optarg;
969 for (i = 0; mtable[i].type; i++)
971 if (strcmp (mtable[i].type, mname) == 0)
977 fprintf(stderr,"Machine not supported\n");
986 process_def_file (def_file);
991 firstarg = av[optind];
992 scan_obj_file (av[optind]);
999 outfile_prefix = d_name;
1001 outfile_prefix = def_file;
1003 outfile_prefix = firstarg;
1006 fprintf (stderr, "No way to create an output filename\n");
1010 outfile_prefix = prefix (outfile_prefix);