diff options
Diffstat (limited to 'contrib/binutils/binutils/dlltool.c')
-rw-r--r-- | contrib/binutils/binutils/dlltool.c | 2358 |
1 files changed, 2358 insertions, 0 deletions
diff --git a/contrib/binutils/binutils/dlltool.c b/contrib/binutils/binutils/dlltool.c new file mode 100644 index 0000000..c5530bd --- /dev/null +++ b/contrib/binutils/binutils/dlltool.c @@ -0,0 +1,2358 @@ +/* dlltool.c -- tool to generate stuff for PE style DLLs + Copyright (C) 1995, 96, 1997 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* + This program allows you to build the files necessary to create + DLLs to run on a system which understands PE format image files. + (eg, Windows NT) + + See "Peering Inside the PE: A Tour of the Win32 Portable Executable + File Format", MSJ 1994, Volume 9 for more information. + Also see "Microsoft Portable Executable and Common Object File Format, + Specification 4.1" for more information. + + A DLL contains an export table which contains the information + which the runtime loader needs to tie up references from a + referencing program. + + The export table is generated by this program by reading + in a .DEF file or scanning the .a and .o files which will be in the + DLL. A .o file can contain information in special ".drectve" sections + with export information. + + A DEF file contains any number of the following commands: + + + NAME <name> [ , <base> ] + The result is going to be <name>.EXE + + LIBRARY <name> [ , <base> ] + The result is going to be <name>.DLL + + EXPORTS ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) * + Declares name1 as an exported symbol from the + DLL, with optional ordinal number <integer> + + IMPORTS ( [ <name> = ] <name> . <name> ) * + Ignored for compatibility + + DESCRIPTION <string> + Puts <string> into output .exp file in the .rdata section + + [STACKSIZE|HEAPSIZE] <number-reserve> [ , <number-commit> ] + Generates --stack|--heap <number-reserve>,<number-commit> + in the output .drectve section. The linker will + see this and act upon it. + + [CODE|DATA] <attr>+ + SECTIONS ( <sectionname> <attr>+ )* + <attr> = READ | WRITE | EXECUTE | SHARED + Generates --attr <sectionname> <attr> in the output + .drectve section. The linker will see this and act + upon it. + + + A -export:<name> in a .drectve section in an input .o or .a + file to this program is equivalent to a EXPORTS <name> + in a .DEF file. + + + + The program generates output files with the prefix supplied + on the command line, or in the def file, or taken from the first + supplied argument. + + The .exp.s file contains the information necessary to export + the routines in the DLL. The .lib.s file contains the information + necessary to use the DLL's routines from a referencing program. + + + + Example: + + file1.c: + asm (".section .drectve"); + asm (".ascii \"-export:adef\""); + + adef(char *s) + { + printf("hello from the dll %s\n",s); + } + + bdef(char *s) + { + printf("hello from the dll and the other entry point %s\n",s); + } + + file2.c: + asm (".section .drectve"); + asm (".ascii \"-export:cdef\""); + asm (".ascii \"-export:ddef\""); + cdef(char *s) + { + printf("hello from the dll %s\n",s); + } + + ddef(char *s) + { + printf("hello from the dll and the other entry point %s\n",s); + } + + printf() + { + return 9; + } + + main.c + + main() + { + cdef(); + } + + thedll.def + + LIBRARY thedll + HEAPSIZE 0x40000, 0x2000 + EXPORTS bdef @ 20 + cdef @ 30 NONAME + + SECTIONS donkey READ WRITE + aardvark EXECUTE + + + # compile up the parts of the dll + + gcc -c file1.c + gcc -c file2.c + + # put them in a library (you don't have to, you + # could name all the .os on the dlltool line) + + ar qcv thedll.in file1.o file2.o + ranlib thedll.in + + # run this tool over the library and the def file + ./dlltool --def thedll.def --output-exp thedll.o --output-lib thedll.a + + # build the dll with the library with file1.o, file2.o and the export table + ld -o thedll.dll thedll.o thedll.in + + # build the mainline + gcc -c themain.c + + # link the executable with the import library + ld -e main -Tthemain.ld -o themain.exe themain.o thedll.a + + */ + +/* .idata section description + + The .idata section is the import table. It is a collection of several + subsections used to keep the pieces for each dll together: .idata$[234567]. + IE: Each dll's .idata$2's are catenated together, each .idata$3's, etc. + + .idata$2 = Import Directory Table + = array of IMAGE_IMPORT_DESCRIPTOR's. + + DWORD Characteristics; - pointer to .idata$4 + DWORD TimeDateStamp; - currently always 0 + DWORD ForwarderChain; - currently always 0 + DWORD Name; - pointer to dll's name + PIMAGE_THUNK_DATA FirstThunk; - pointer to .idata$5 + + .idata$3 = null terminating entry for .idata$2. + + .idata$4 = Import Lookup Table + = array of array of pointers to hint name table. + There is one for each dll being imported from, and each dll's set is + terminated by a trailing NULL. + + .idata$5 = Import Address Table + = array of array of pointers to hint name table. + There is one for each dll being imported from, and each dll's set is + terminated by a trailing NULL. + Initially, this table is identical to the Import Lookup Table. However, + at load time, the loader overwrites the entries with the address of the + function. + + .idata$6 = Hint Name Table + = Array of { short, asciz } entries, one for each imported function. + The `short' is the function's ordinal number. + + .idata$7 = dll name (eg: "kernel32.dll"). (.idata$6 for ppc) +*/ + +/* AIX requires this to be the first thing in the file. */ +/* AIX requires this to be the first thing in the file. */ +#ifndef __GNUC__ +# ifdef _AIX + #pragma alloca +#endif +#endif + +#define show_allnames 0 + +#define PAGE_SIZE 4096 +#define PAGE_MASK (-PAGE_SIZE) +#include "bfd.h" +#include "libiberty.h" +#include "bucomm.h" +#include "getopt.h" +#include "demangle.h" +#include <ctype.h> +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#else +#ifndef WIFEXITED +#define WIFEXITED(w) (((w)&0377) == 0) +#endif +#ifndef WIFSIGNALED +#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) +#endif +#ifndef WTERMSIG +#define WTERMSIG(w) ((w) & 0177) +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(w) (((w) >> 8) & 0377) +#endif +#endif + +#ifdef HAVE_VFORK_H +#include <vfork.h> +#endif + +char *as_name = "as"; + +static int no_idata4; +static int no_idata5; +static char *exp_name; +static char *imp_name; +static char *head_label; +static char *imp_name_lab; +static char *dll_name; + +static int add_indirect = 0; +static int add_underscore = 0; +static int dontdeltemps = 0; + +int yyparse(); +int yydebug; +static char *def_file; + +static char *program_name; +char *strrchr (); +char *strdup (); + +static int machine; +int killat; +static int verbose; +FILE *output_def; +FILE *base_file; + +#ifdef DLLTOOL_ARM +static char *mname = "arm"; +#endif + +#ifdef DLLTOOL_I386 +static char *mname = "i386"; +#endif + +#ifdef DLLTOOL_PPC +static char *mname = "ppc"; +#endif + +#define PATHMAX 250 /* What's the right name for this ? */ + +/* This bit of assemly does jmp * .... +s set how_jtab_roff to mark where the 32bit abs branch should go */ +unsigned char i386_jtab[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90}; + + +unsigned char arm_jtab[] = { 0x00, 0xc0, 0x9f, 0xe5, + 0x00, 0xf0, 0x9c, 0xe5, + 0, 0, 0, 0}; + +/* This is the glue sequence for PowerPC PE. There is a */ +/* tocrel16-tocdefn reloc against the first instruction. */ +/* We also need a IMGLUE reloc against the glue function */ +/* to restore the toc saved by the third instruction in */ +/* the glue. */ +unsigned char ppc_jtab[] = +{ + 0x00, 0x00, 0x62, 0x81, /* lwz r11,0(r2) */ + /* Reloc TOCREL16 __imp_xxx */ + 0x00, 0x00, 0x8B, 0x81, /* lwz r12,0(r11) */ + 0x04, 0x00, 0x41, 0x90, /* stw r2,4(r1) */ + 0xA6, 0x03, 0x89, 0x7D, /* mtctr r12 */ + 0x04, 0x00, 0x4B, 0x80, /* lwz r2,4(r11) */ + 0x20, 0x04, 0x80, 0x4E /* bctr */ +}; + +/* the glue instruction, picks up the toc from the stw in */ +/* the above code: "lwz r2,4(r1)" */ +bfd_vma ppc_glue_insn = 0x80410004; + + +char outfile[PATHMAX]; +struct mac + { + char *type; + char *how_byte; + char *how_short; + char *how_long; + char *how_asciz; + char *how_comment; + char *how_jump; + char *how_global; + char *how_space; + char *how_align_short; + char *how_align_long; + char *how_bfd_target; + enum bfd_architecture how_bfd_arch; + unsigned char *how_jtab; + int how_jtab_size; /* size of the jtab entry */ + int how_jtab_roff; /* offset into it for the ind 32 reloc into idata 5 */ + } +mtable[] += +{ + { +#define MARM 0 + "arm", ".byte", ".short", ".long", ".asciz", "@", + "ldr\tip,[pc]\n\tldr\tpc,[ip]\n\t.long", + ".global", ".space", ".align\t2",".align\t4","pe-arm-little", bfd_arch_arm, + arm_jtab, sizeof(arm_jtab),8 + } + , + { +#define M386 1 + "i386", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space", ".align\t2",".align\t4","pe-i386",bfd_arch_i386, + i386_jtab,sizeof(i386_jtab),2, + } + , + { +#define MPPC 2 + "ppc", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space", ".align\t2",".align\t4","pe-powerpcle",bfd_arch_powerpc, + ppc_jtab,sizeof(ppc_jtab),0, + } + , +{ 0} +}; + + +char * +rvaafter (machine) + int machine; +{ + switch (machine) + { + case MARM: + return ""; + case M386: + return ""; + case MPPC: + return ""; + } +return ""; +} + +char * +rvabefore (machine) + int machine; +{ + switch (machine) + { + case MARM: + return ".rva\t"; + case M386: + return ".rva\t"; + case MPPC: + return ".rva\t"; + } +return ""; +} + +char * +asm_prefix (machine) +int machine; +{ + switch (machine) + { + case MARM: + return ""; + case M386: + return "_"; + case MPPC: + return ""; + } +return ""; +} +#define ASM_BYTE mtable[machine].how_byte +#define ASM_SHORT mtable[machine].how_short +#define ASM_LONG mtable[machine].how_long +#define ASM_TEXT mtable[machine].how_asciz +#define ASM_C mtable[machine].how_comment +#define ASM_JUMP mtable[machine].how_jump +#define ASM_GLOBAL mtable[machine].how_global +#define ASM_SPACE mtable[machine].how_space +#define ASM_ALIGN_SHORT mtable[machine].how_align_short +#define ASM_RVA_BEFORE rvabefore(machine) +#define ASM_RVA_AFTER rvaafter(machine) +#define ASM_PREFIX asm_prefix(machine) +#define ASM_ALIGN_LONG mtable[machine].how_align_long +#define HOW_BFD_TARGET 0 /* always default*/ +#define HOW_BFD_ARCH mtable[machine].how_bfd_arch +#define HOW_JTAB mtable[machine].how_jtab +#define HOW_JTAB_SIZE mtable[machine].how_jtab_size +#define HOW_JTAB_ROFF mtable[machine].how_jtab_roff +static char **oav; + + +FILE *yyin; /* communications with flex */ +extern int linenumber; +void +process_def_file (name) + char *name; +{ + FILE *f = fopen (name, FOPEN_RT); + if (!f) + { + fprintf (stderr, "%s: Can't open def file %s\n", program_name, name); + exit (1); + } + + yyin = f; + + yyparse (); +} + +/**********************************************************************/ + +/* Communications with the parser */ + + +typedef struct dlist +{ + char *text; + struct dlist *next; +} +dlist_type; + +typedef struct export + { + char *name; + char *internal_name; + int ordinal; + int constant; + int noname; + int hint; + struct export *next; + } +export_type; + +static char *d_name; /* Arg to NAME or LIBRARY */ +static int d_nfuncs; /* Number of functions exported */ +static int d_named_nfuncs; /* Number of named functions exported */ +static int d_low_ord; /* Lowest ordinal index */ +static int d_high_ord; /* Highest ordinal index */ +static export_type *d_exports; /*list of exported functions */ +static export_type **d_exports_lexically; /* vector of exported functions in alpha order */ +static dlist_type *d_list; /* Descriptions */ +static dlist_type *a_list; /* Stuff to go in directives */ + +static int d_is_dll; +static int d_is_exe; + +int +yyerror () +{ + fprintf (stderr, "%s: Syntax error in def file %s:%d\n", + program_name, def_file, linenumber); + return 0; +} + +void +def_exports (name, internal_name, ordinal, noname, constant) + char *name; + char *internal_name; + int ordinal; + int noname; + int constant; +{ + struct export *p = (struct export *) xmalloc (sizeof (*p)); + + p->name = name; + p->internal_name = internal_name ? internal_name : name; + p->ordinal = ordinal; + p->constant = constant; + p->noname = noname; + p->next = d_exports; + d_exports = p; + d_nfuncs++; +} + + +void +def_name (name, base) + char *name; + int base; +{ + if (verbose) + fprintf (stderr, "%s NAME %s base %x\n", program_name, name, base); + if (d_is_dll) + { + fprintf (stderr, "Can't have LIBRARY and NAME\n"); + } + d_name = name; + d_is_exe = 1; +} + +void +def_library (name, base) + char *name; + int base; +{ + if (verbose) + printf ("%s: LIBRARY %s base %x\n", program_name, name, base); + if (d_is_exe) + { + fprintf (stderr, "%s: Can't have LIBRARY and NAME\n", program_name); + } + d_name = name; + d_is_dll = 1; +} + +void +def_description (desc) + char *desc; +{ + dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type)); + d->text = strdup (desc); + d->next = d_list; + d_list = d; +} + +void +new_directive (dir) + char *dir; +{ + dlist_type *d = (dlist_type *) xmalloc (sizeof (dlist_type)); + d->text = strdup (dir); + d->next = a_list; + a_list = d; +} + +void +def_stacksize (reserve, commit) + int reserve; + int commit; +{ + char b[200]; + if (commit > 0) + sprintf (b, "-stack 0x%x,0x%x ", reserve, commit); + else + sprintf (b, "-stack 0x%x ", reserve); + new_directive (strdup (b)); +} + +void +def_heapsize (reserve, commit) + int reserve; + int commit; +{ + char b[200]; + if (commit > 0) + sprintf (b, "-heap 0x%x,0x%x ", reserve, commit); + else + sprintf (b, "-heap 0x%x ", reserve); + new_directive (strdup (b)); +} + + +void +def_import (internal, module, entry) + char *internal; + char *module; + char *entry; +{ + if (verbose) + fprintf (stderr, "%s: IMPORTS are ignored", program_name); +} + +void +def_version (major, minor) +int major; +int minor; +{ + printf ("VERSION %d.%d\n", major, minor); +} + + +void +def_section (name, attr) + char *name; + int attr; +{ + char buf[200]; + char atts[5]; + char *d = atts; + if (attr & 1) + *d++ = 'R'; + + if (attr & 2) + *d++ = 'W'; + if (attr & 4) + *d++ = 'X'; + if (attr & 8) + *d++ = 'S'; + *d++ = 0; + sprintf (buf, "-attr %s %s", name, atts); + new_directive (strdup (buf)); +} +void +def_code (attr) + int attr; +{ + + def_section ("CODE", attr); +} + +void +def_data (attr) + int attr; +{ + def_section ("DATA", attr); +} + + +/**********************************************************************/ + +void +run (what, args) + char *what; + char *args; +{ + char *s; + int pid; + int i; + char **argv; + extern char **environ; + if (verbose) + fprintf (stderr, "%s %s\n", what, args); + + /* Count the args */ + i = 0; + for (s = args; *s; s++) + if (*s == ' ') + i++; + i++; + argv = alloca (sizeof (char *) * (i + 3)); + i = 0; + argv[i++] = what; + s = args; + while (1) + { + argv[i++] = s; + while (*s != ' ' && *s != 0) + s++; + if (*s == 0) + break; + *s++ = 0; + } + argv[i++] = 0; + + + pid = vfork (); + + if (pid == 0) + { + execvp (what, argv); + fprintf (stderr, "%s: can't exec %s\n", program_name, what); + exit (1); + } + else if (pid == -1) + { + extern int errno; + fprintf (stderr, "%s: vfork failed, %d\n", program_name, errno); + exit (1); + } + else + { + int status; + waitpid (pid, &status, 0); + if (status) + { + if (WIFSIGNALED (status)) + { + fprintf (stderr, "%s: %s %s terminated with signal %d\n", + program_name, what, args, WTERMSIG (status)); + exit (1); + } + + if (WIFEXITED (status)) + { + fprintf (stderr, "%s: %s %s terminated with exit status %d\n", + program_name, what, args, WEXITSTATUS (status)); + exit (1); + } + } + } +} + +/* read in and block out the base relocations */ +static void +basenames (abfd) + bfd *abfd; +{ + + + + +} + +void +scan_open_obj_file (abfd) + bfd *abfd; +{ + /* Look for .drectve's */ + asection *s = bfd_get_section_by_name (abfd, ".drectve"); + if (s) + { + int size = bfd_get_section_size_before_reloc (s); + char *buf = xmalloc (size); + char *p; + char *e; + bfd_get_section_contents (abfd, s, buf, 0, size); + if (verbose) + fprintf (stderr, "%s: Sucking in info from %s\n", + program_name, + bfd_get_filename (abfd)); + + /* Search for -export: strings */ + p = buf; + e = buf + size; + while (p < e) + { + if (p[0] == '-' + && strncmp (p, "-export:", 8) == 0) + { + char *name; + char *c; + p += 8; + name = p; + while (p < e && *p != ' ' && *p != '-') + p++; + c = xmalloc (p - name + 1); + memcpy (c, name, p - name); + c[p - name] = 0; + /* FIXME: The 5th arg is for the `constant' field. + What should it be? Not that it matters since it's not + currently useful. */ + def_exports (c, 0, -1, 0, 0); + } + else + p++; + } + free (buf); + } + + basenames (abfd); + + if (verbose) + fprintf (stderr, "%s: Done readin\n", + program_name); +} + + +void +scan_obj_file (filename) + char *filename; +{ + bfd *f = bfd_openr (filename, 0); + + if (!f) + { + fprintf (stderr, "%s: Unable to open object file %s\n", + program_name, + filename); + exit (1); + } + if (bfd_check_format (f, bfd_archive)) + { + bfd *arfile = bfd_openr_next_archived_file (f, 0); + while (arfile) + { + if (bfd_check_format (arfile, bfd_object)) + scan_open_obj_file (arfile); + bfd_close (arfile); + arfile = bfd_openr_next_archived_file (f, arfile); + } + } + else if (bfd_check_format (f, bfd_object)) + { + scan_open_obj_file (f); + } + + bfd_close (f); +} + +/**********************************************************************/ + + + +void +dump_def_info (f) + FILE *f; +{ + int i; + export_type *exp; + fprintf (f, "%s ", ASM_C); + for (i = 0; oav[i]; i++) + fprintf (f, "%s ", oav[i]); + fprintf (f, "\n"); + for (i = 0, exp = d_exports; exp; i++, exp = exp->next) + { + fprintf (f, "%s %d = %s %s @ %d %s%s\n", + ASM_C, + i, + exp->name, + exp->internal_name, + exp->ordinal, + exp->noname ? "NONAME " : "", + exp->constant ? "CONSTANT" : ""); + } +} +/* Generate the .exp file */ + +int +sfunc (a, b) + long *a; + long *b; +{ + return *a - *b; +} + + + +static void +flush_page (f, need, page_addr, on_page) + FILE *f; + int *need; + int page_addr; + int on_page; +{ + int i; + + /* Flush this page */ + fprintf (f, "\t%s\t0x%08x\t%s Starting RVA for chunk\n", + ASM_LONG, + page_addr, + ASM_C); + fprintf (f, "\t%s\t0x%x\t%s Size of block\n", + ASM_LONG, + (on_page * 2) + (on_page & 1) * 2 + 8, + ASM_C); + for (i = 0; i < on_page; i++) + { + fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, (need[i] - page_addr) | 0x3000); + } + /* And padding */ + if (on_page & 1) + fprintf (f, "\t%s\t0x%x\n", ASM_SHORT, 0 | 0x0000); + +} + + +void +gen_def_file () +{ + int i; + export_type *exp; + + fprintf (output_def, ";"); + for (i = 0; oav[i]; i++) + fprintf (output_def, " %s", oav[i]); + + fprintf (output_def, "\nEXPORTS\n"); + + for (i = 0, exp = d_exports; exp; i++, exp = exp->next) + { + char *quote = strchr (exp->name, '.') ? "\"" : ""; + fprintf (output_def, "\t%s%s%s @ %d%s ; %s\n", + quote, + exp->name, + quote, + exp->ordinal, + exp->noname ? " NONAME" : "", + cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_PARAMS)); + } +} +void +gen_exp_file () +{ + FILE *f; + int i; + export_type *exp; + dlist_type *dl; + + + sprintf (outfile, "t%s", exp_name); + + if (verbose) + fprintf (stderr, "%s: Generate exp file %s\n", + program_name, exp_name); + + f = fopen (outfile, FOPEN_WT); + if (!f) + { + fprintf (stderr, "%s: Unable to open output file %s\n", program_name, outfile); + exit (1); + } + if (verbose) + { + fprintf (stderr, "%s: Opened file %s\n", + program_name, outfile); + } + + dump_def_info (f); + if (d_exports) + { + fprintf (f, "\t.section .edata\n\n"); + fprintf (f, "\t%s 0 %s Allways 0\n", ASM_LONG, ASM_C); + fprintf (f, "\t%s 0x%x %s Time and date\n", ASM_LONG, time(0),ASM_C); + fprintf (f, "\t%s 0 %s Major and Minor version\n", ASM_LONG, ASM_C); + fprintf (f, "\t%sname%s %s Ptr to name of dll\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C); + fprintf (f, "\t%s %d %s Starting ordinal of exports\n", ASM_LONG, d_low_ord, ASM_C); + + + fprintf (f, "\t%s %d %s Number of functions\n", ASM_LONG, d_high_ord - d_low_ord + 1, ASM_C); + fprintf(f,"\t%s named funcs %d, low ord %d, high ord %d\n", + ASM_C, + d_named_nfuncs, d_low_ord, d_high_ord); + fprintf (f, "\t%s %d %s Number of names\n", ASM_LONG, + show_allnames ? d_high_ord - d_low_ord + 1 : d_named_nfuncs, ASM_C); + fprintf (f, "\t%safuncs%s %s Address of functions\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C); + + fprintf (f, "\t%sanames%s %s Address of Name Pointer Table\n", + ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C); + + fprintf (f, "\t%sanords%s %s Address of ordinals\n", ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C); + + fprintf (f, "name: %s \"%s\"\n", ASM_TEXT, dll_name); + + + fprintf(f,"%s Export address Table\n", ASM_C); + fprintf(f,"\t%s\n", ASM_ALIGN_LONG); + fprintf (f, "afuncs:\n"); + i = d_low_ord; + + for (exp = d_exports; exp; exp = exp->next) + { + if (exp->ordinal != i) + { +#if 0 + fprintf (f, "\t%s\t%d\t%s %d..%d missing\n", + ASM_SPACE, + (exp->ordinal - i) * 4, + ASM_C, + i, exp->ordinal - 1); + i = exp->ordinal; +#endif + while (i < exp->ordinal) + { + fprintf(f,"\t%s\t0\n", ASM_LONG); + i++; + } + } + fprintf (f, "\t%s%s%s%s\t%s %d\n", ASM_RVA_BEFORE, + ASM_PREFIX, + exp->internal_name, ASM_RVA_AFTER, ASM_C, exp->ordinal); + i++; + } + + fprintf (f,"%s Export Name Pointer Table\n", ASM_C); + fprintf (f, "anames:\n"); + + for (i = 0; (exp = d_exports_lexically[i]); i++) + { + if (!exp->noname || show_allnames) + fprintf (f, "\t%sn%d%s\n", ASM_RVA_BEFORE, exp->ordinal, ASM_RVA_AFTER); + } + + fprintf (f,"%s Export Oridinal Table\n", ASM_C); + fprintf (f, "anords:\n"); + for (i = 0; (exp = d_exports_lexically[i]); i++) + { + if (!exp->noname || show_allnames) + fprintf (f, "\t%s %d\n", ASM_SHORT, exp->ordinal - d_low_ord); + } + + fprintf(f,"%s Export Name Table\n", ASM_C); + for (i = 0; (exp = d_exports_lexically[i]); i++) + if (!exp->noname || show_allnames) + fprintf (f, "n%d: %s \"%s\"\n", exp->ordinal, ASM_TEXT, exp->name); + + if (a_list) + { + fprintf (f, "\t.section .drectve\n"); + for (dl = a_list; dl; dl = dl->next) + { + fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, dl->text); + } + } + if (d_list) + { + fprintf (f, "\t.section .rdata\n"); + for (dl = d_list; dl; dl = dl->next) + { + char *p; + int l; + /* We dont output as ascii 'cause there can + be quote characters in the string */ + + l = 0; + for (p = dl->text; *p; p++) + { + if (l == 0) + fprintf (f, "\t%s\t", ASM_BYTE); + else + fprintf (f, ","); + fprintf (f, "%d", *p); + if (p[1] == 0) + { + fprintf (f, ",0\n"); + break; + } + if (++l == 10) + { + fprintf (f, "\n"); + l = 0; + } + } + } + } + } + + + /* Add to the output file a way of getting to the exported names + without using the import library. */ + if (add_indirect) + { + fprintf (f, "\t.section\t.rdata\n"); + for (i = 0, exp = d_exports; exp; i++, exp = exp->next) + if (!exp->noname || show_allnames) + { + fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name); + fprintf (f, "__imp_%s:\n", exp->name); + fprintf (f, "\t%s\t%s\n", ASM_LONG, exp->name); + } + } + + /* Dump the reloc section if a base file is provided */ + if (base_file) + { + int addr; + long need[PAGE_SIZE]; + long page_addr; + int numbytes; + int num_entries; + long *copy; + int j; + int on_page; + fprintf (f, "\t.section\t.init\n"); + fprintf (f, "lab:\n"); + + fseek (base_file, 0, SEEK_END); + numbytes = ftell (base_file); + fseek (base_file, 0, SEEK_SET); + copy = xmalloc (numbytes); + fread (copy, 1, numbytes, base_file); + num_entries = numbytes / sizeof (long); + + + fprintf (f, "\t.section\t.reloc\n"); + if (num_entries) + { + + int src; + int dst = 0; + int last = -1; + qsort (copy, num_entries, sizeof (long), sfunc); + /* Delete duplcates */ + for (src = 0; src < num_entries; src++) + { + if (last != copy[src]) + last = copy[dst++] = copy[src]; + } + num_entries = dst; + addr = copy[0]; + page_addr = addr & PAGE_MASK; /* work out the page addr */ + on_page = 0; + for (j = 0; j < num_entries; j++) + { + addr = copy[j]; + if ((addr & PAGE_MASK) != page_addr) + { + flush_page (f, need, page_addr, on_page); + on_page = 0; + page_addr = addr & PAGE_MASK; + } + need[on_page++] = addr; + } + flush_page (f, need, page_addr, on_page); + +/* fprintf (f, "\t%s\t0,0\t%s End\n", ASM_LONG, ASM_C);*/ + } + } + + fclose (f); + + /* assemble the file */ + sprintf (outfile, "-o %s t%s", exp_name, exp_name); + run (as_name, outfile); + if (dontdeltemps == 0) + { + sprintf (outfile, "t%s", exp_name); + unlink (outfile); + } +} + +static char * +xlate (char *name) +{ + if (add_underscore) + { + char *copy = xmalloc (strlen (name) + 2); + copy[0] = '_'; + strcpy (copy + 1, name); + name = copy; + } + + if (killat) + { + char *p; + p = strchr (name, '@'); + if (p) + *p = 0; + } + return name; +} + +/**********************************************************************/ + +static void dump_iat (f, exp) +FILE *f; +export_type *exp; +{ + if (exp->noname && !show_allnames ) + { + fprintf (f, "\t%s\t0x%08x\n", + ASM_LONG, + exp->ordinal | 0x80000000); /* hint or orindal ?? */ + } + else + { + fprintf (f, "\t%sID%d%s\n", ASM_RVA_BEFORE, + exp->ordinal, + ASM_RVA_AFTER); + } +} + + + +typedef struct +{ + int id; + const char *name; + int flags; + int align; + asection *sec; + asymbol *sym; + asymbol **sympp; + int size; + unsigned char *data; +} sinfo; + + +#ifndef DLLTOOL_PPC + +#define TEXT 0 +#define DATA 1 +#define BSS 2 +#define IDATA7 3 +#define IDATA5 4 +#define IDATA4 5 +#define IDATA6 6 +#define PDATA 7 +#define RDATA 8 + +#define NSECS 7 + + +static sinfo secdata[NSECS] = +{ + { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS, 2}, + { DATA, ".data", SEC_DATA, 2}, + { BSS, ".bss", 0, 2}, + { IDATA7, ".idata$7", SEC_HAS_CONTENTS, 2}, + { IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2}, + { IDATA4, ".idata$4", SEC_HAS_CONTENTS, 2}, + { IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1} +}; + +#else + +/* Sections numbered to make the order the same as other PowerPC NT */ +/* compilers. This also keeps funny alignment thingies from happening. */ +#define TEXT 0 +#define PDATA 1 +#define RDATA 2 +#define IDATA5 3 +#define IDATA4 4 +#define IDATA6 5 +#define IDATA7 6 +#define DATA 7 +#define BSS 8 + +#define NSECS 9 + +static sinfo secdata[NSECS] = +{ + { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS, 3}, + { PDATA, ".pdata", SEC_HAS_CONTENTS, 2}, + { RDATA, ".reldata", SEC_HAS_CONTENTS, 2}, + { IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2}, + { IDATA4, ".idata$4", SEC_HAS_CONTENTS, 2}, + { IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1}, + { IDATA7, ".idata$7", SEC_HAS_CONTENTS, 2}, + { DATA, ".data", SEC_DATA, 2}, + { BSS, ".bss", 0, 2} +}; + +#endif + +/* +This is what we're trying to make + + .text + .global _GetFileVersionInfoSizeW@8 + .global __imp_GetFileVersionInfoSizeW@8 +_GetFileVersionInfoSizeW@8: + jmp * __imp_GetFileVersionInfoSizeW@8 + .section .idata$7 # To force loading of head + .long __version_a_head +# Import Address Table + .section .idata$5 +__imp_GetFileVersionInfoSizeW@8: + .rva ID2 + +# Import Lookup Table + .section .idata$4 + .rva ID2 +# Hint/Name table + .section .idata$6 +ID2: .short 2 + .asciz "GetFileVersionInfoSizeW" + + +For the PowerPC, here's the variation on the above scheme: + +# Rather than a simple "jmp *", the code to get to the dll function +# looks like: + .text + lwz r11,[tocv]__imp_function_name(r2) +# RELOC: 00000000 TOCREL16,TOCDEFN __imp_function_name + lwz r12,0(r11) + stw r2,4(r1) + mtctr r12 + lwz r2,4(r11) + bctr +*/ + +static char * +make_label (prefix, name) + const char *prefix; + const char *name; +{ + int len = strlen (ASM_PREFIX) + strlen (prefix) + strlen (name); + char *copy = xmalloc (len +1 ); + strcpy (copy, ASM_PREFIX); + strcat (copy, prefix); + strcat (copy, name); + return copy; +} + +static bfd * +make_one_lib_file (exp, i) + export_type *exp; + int i; +{ + if (0) + { + FILE *f; + char *prefix="d"; + sprintf (outfile, "%ss%d.s", prefix, i); + f = fopen (outfile, FOPEN_WT); + fprintf (f, "\t.text\n"); + fprintf (f, "\t%s\t%s%s\n", ASM_GLOBAL, ASM_PREFIX, exp->name); + fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name); + fprintf (f, "%s%s:\n\t%s\t__imp_%s\n", ASM_PREFIX, + exp->name, ASM_JUMP, exp->name); + + fprintf (f, "\t.section\t.idata$7\t%s To force loading of head\n", ASM_C); + fprintf (f, "\t%s\t%s\n", ASM_LONG, head_label); + + + fprintf (f,"%s Import Address Table\n", ASM_C); + + fprintf (f, "\t.section .idata$5\n"); + fprintf (f, "__imp_%s:\n", exp->name); + + dump_iat (f, exp); + + fprintf (f, "\n%s Import Lookup Table\n", ASM_C); + fprintf (f, "\t.section .idata$4\n"); + + dump_iat (f, exp); + + if(!exp->noname || show_allnames) + { + fprintf (f, "%s Hint/Name table\n", ASM_C); + fprintf (f, "\t.section .idata$6\n"); + fprintf (f, "ID%d:\t%s\t%d\n", exp->ordinal, ASM_SHORT, exp->hint); + fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name)); + } + + fclose (f); + + + sprintf (outfile, "-o %ss%d.o %ss%d.s", prefix, i, prefix, i); + + run (as_name, outfile); + + } + else + { + + bfd *abfd; + + asymbol *exp_label; + asymbol *iname; + asymbol *iname_lab; + asymbol **iname_lab_pp; + asymbol **iname_pp; + + /* Extra Symbols for PPC */ +#ifdef DLLTOOL_PPC +#define EXTRA 2 +#else +#define EXTRA 0 +#endif + + asymbol *function_name; /* ".." functionName */ + asymbol **fn_pp; + asymbol *toc_symbol; /* The .toc symbol */ + asymbol **toc_pp; + + /* one symbol for each section, 2 extra + a null */ + asymbol *ptrs[NSECS+3+EXTRA+1]; + + char *outname = xmalloc (10); + int oidx = 0; + sprintf (outname, "ds%d.o", i); + abfd = bfd_openw (outname, HOW_BFD_TARGET); + if (!abfd) + { + fprintf (stderr, "%s: bfd_open failed open output file %s\n", + program_name, outname); + exit (1); + } + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0); + + + /* First make symbols for the sections */ + for (i = 0; i < NSECS; i++) + { + sinfo *si = secdata + i; + if (si->id != i) + abort(); + si->sec = bfd_make_section_old_way (abfd, si->name); + bfd_set_section_flags (abfd, + si->sec, + si->flags); + + bfd_set_section_alignment(abfd, si->sec, si->align); + si->sec->output_section = si->sec; + si->sym = bfd_make_empty_symbol(abfd); + si->sym->name = si->sec->name; + si->sym->section = si->sec; + si->sym->flags = BSF_LOCAL; + si->sym->value = 0; + ptrs[oidx] = si->sym; + si->sympp = ptrs + oidx; + + oidx++; + } + + exp_label = bfd_make_empty_symbol(abfd); + exp_label->name = make_label ("",exp->name); + + /* On PowerPC, the function name points to a descriptor in the + rdata section, the first element of which is a pointer to the + code (..function_name), and the second points to the .toc + */ + if (machine == MPPC) + exp_label->section = secdata[RDATA].sec; + else + exp_label->section = secdata[TEXT].sec; + + exp_label->flags = BSF_GLOBAL; + exp_label->value = 0; + + ptrs[oidx++] = exp_label; + + iname = bfd_make_empty_symbol(abfd); + iname->name = make_label ("__imp_", exp->name); + iname->section = secdata[IDATA5].sec; + iname->flags = BSF_GLOBAL; + iname->value = 0; + + + iname_lab = bfd_make_empty_symbol(abfd); + + iname_lab->name = head_label; + iname_lab->section = (asection *)&bfd_und_section; + iname_lab->flags = 0; + iname_lab->value = 0; + + + iname_pp = ptrs + oidx; + ptrs[oidx++] = iname; + + iname_lab_pp = ptrs + oidx; + ptrs[oidx++] = iname_lab; + +#ifdef DLLTOOL_PPC + /* The symbol refering to the code (.text) */ + function_name = bfd_make_empty_symbol(abfd); + function_name->name = make_label ("..", exp->name); + function_name->section = secdata[TEXT].sec; + function_name->flags = BSF_GLOBAL; + function_name->value = 0; + + fn_pp = ptrs + oidx; + ptrs[oidx++] = function_name; + + /* The .toc symbol */ + toc_symbol = bfd_make_empty_symbol(abfd); + toc_symbol->name = make_label (".", "toc"); + toc_symbol->section = (asection *)&bfd_und_section; + toc_symbol->flags = BSF_GLOBAL; + toc_symbol->value = 0; + + toc_pp = ptrs + oidx; + ptrs[oidx++] = toc_symbol; +#endif + + ptrs[oidx] = 0; + + for (i = 0; i < NSECS; i++) + { + sinfo *si = secdata + i; + asection *sec = si->sec; + arelent *rel; + arelent **rpp; + + switch (i) + { + case TEXT: + si->size = HOW_JTAB_SIZE; + si->data = xmalloc (HOW_JTAB_SIZE); + memcpy (si->data, HOW_JTAB, HOW_JTAB_SIZE); + + /* add the reloc into idata$5 */ + rel = xmalloc (sizeof (arelent)); + rpp = xmalloc (sizeof (arelent *) * 2); + rpp[0] = rel; + rpp[1] = 0; + rel->address = HOW_JTAB_ROFF; + rel->addend = 0; + + if (machine == MPPC) + { + rel->howto = bfd_reloc_type_lookup (abfd, + BFD_RELOC_16_GOTOFF); + rel->sym_ptr_ptr = iname_pp; + } + else + { + rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32); + rel->sym_ptr_ptr = secdata[IDATA5].sympp; + } + sec->orelocation = rpp; + sec->reloc_count = 1; + break; + case IDATA4: + case IDATA5: + /* An idata$4 or idata$5 is one word long, and has an + rva to idata$6 */ + + si->data = xmalloc (4); + si->size = 4; + + if (exp->noname) + { + si->data[0] = exp->ordinal ; + si->data[1] = exp->ordinal >> 8; + si->data[2] = exp->ordinal >> 16; + si->data[3] = 0x80; + } + else + { + sec->reloc_count = 1; + memset (si->data, 0, si->size); + rel = xmalloc (sizeof (arelent)); + rpp = xmalloc (sizeof (arelent *) * 2); + rpp[0] = rel; + rpp[1] = 0; + rel->address = 0; + rel->addend = 0; + rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA); + rel->sym_ptr_ptr = secdata[IDATA6].sympp; + sec->orelocation = rpp; + } + + break; + + case IDATA6: + if (!exp->noname) + { + int idx = exp->hint + 1; + si->size = strlen (xlate (exp->name)) + 3; + si->data = xmalloc (si->size); + si->data[0] = idx & 0xff; + si->data[1] = idx >> 8; + strcpy (si->data + 2, xlate (exp->name)); + } + break; + case IDATA7: + si->size = 4; + si->data =xmalloc(4); + memset (si->data, 0, si->size); + rel = xmalloc (sizeof (arelent)); + rpp = xmalloc (sizeof (arelent *) * 2); + rpp[0] = rel; + rel->address = 0; + rel->addend = 0; + rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA); + rel->sym_ptr_ptr = iname_lab_pp; + sec->orelocation = rpp; + sec->reloc_count = 1; + break; + + case PDATA: + { + /* The .pdata section is 5 words long. */ + /* Think of it as: */ + /* struct */ + /* { */ + /* bfd_vma BeginAddress, [0x00] */ + /* EndAddress, [0x04] */ + /* ExceptionHandler, [0x08] */ + /* HandlerData, [0x0c] */ + /* PrologEndAddress; [0x10] */ + /* }; */ + + /* So this pdata section setups up this as a glue linkage to + a dll routine. There are a number of house keeping things + we need to do: + + 1. In the name of glue trickery, the ADDR32 relocs for 0, + 4, and 0x10 are set to point to the same place: + "..function_name". + 2. There is one more reloc needed in the pdata section. + The actual glue instruction to restore the toc on + return is saved as the offset in an IMGLUE reloc. + So we need a total of four relocs for this section. + + 3. Lastly, the HandlerData field is set to 0x03, to indicate + that this is a glue routine. + */ + arelent *imglue, *ba_rel, *ea_rel, *pea_rel; + + /* alignment must be set to 2**2 or you get extra stuff */ + bfd_set_section_alignment(abfd, sec, 2); + + si->size = 4 * 5; + si->data =xmalloc(4 * 5); + memset (si->data, 0, si->size); + rpp = xmalloc (sizeof (arelent *) * 5); + rpp[0] = imglue = xmalloc (sizeof (arelent)); + rpp[1] = ba_rel = xmalloc (sizeof (arelent)); + rpp[2] = ea_rel = xmalloc (sizeof (arelent)); + rpp[3] = pea_rel = xmalloc (sizeof (arelent)); + rpp[4] = 0; + + /* stick the toc reload instruction in the glue reloc */ + bfd_put_32(abfd, ppc_glue_insn, (char *) &imglue->address); + + imglue->addend = 0; + imglue->howto = bfd_reloc_type_lookup (abfd, + BFD_RELOC_32_GOTOFF); + imglue->sym_ptr_ptr = fn_pp; + + ba_rel->address = 0; + ba_rel->addend = 0; + ba_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32); + ba_rel->sym_ptr_ptr = fn_pp; + + bfd_put_32(abfd, 0x18, si->data + 0x04); + ea_rel->address = 4; + ea_rel->addend = 0; + ea_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32); + ea_rel->sym_ptr_ptr = fn_pp; + + /* mark it as glue */ + bfd_put_32(abfd, 0x03, si->data + 0x0c); + + /* mark the prolog end address */ + bfd_put_32(abfd, 0x0D, si->data + 0x10); + pea_rel->address = 0x10; + pea_rel->addend = 0; + pea_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32); + pea_rel->sym_ptr_ptr = fn_pp; + + sec->orelocation = rpp; + sec->reloc_count = 4; + break; + } + case RDATA: + /* Each external function in a PowerPC PE file has a two word + descriptor consisting of: + 1. The address of the code. + 2. The address of the appropriate .toc + We use relocs to build this. + */ + + si->size = 8; + si->data =xmalloc(8); + memset (si->data, 0, si->size); + + rpp = xmalloc (sizeof (arelent *) * 3); + rpp[0] = rel = xmalloc (sizeof (arelent)); + rpp[1] = xmalloc (sizeof (arelent)); + rpp[2] = 0; + + rel->address = 0; + rel->addend = 0; + rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32); + rel->sym_ptr_ptr = fn_pp; + + rel = rpp[1]; + + rel->address = 4; + rel->addend = 0; + rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32); + rel->sym_ptr_ptr = toc_pp; + + sec->orelocation = rpp; + sec->reloc_count = 2; + break; + } + } + + { + bfd_vma vma = 0; + /* Size up all the sections */ + for (i = 0; i < NSECS; i++) + { + sinfo *si = secdata + i; + + bfd_set_section_size (abfd, si->sec, si->size); + bfd_set_section_vma (abfd, si->sec, vma); + +/* vma += si->size;*/ + } + } + /* Write them out */ + for (i = 0; i < NSECS; i++) + { + sinfo *si = secdata + i; + + if (i == IDATA5 && no_idata5) + continue; + + if (i == IDATA4 && no_idata4) + continue; + + bfd_set_section_contents (abfd, si->sec, + si->data, 0, + si->size); + } + + bfd_set_symtab (abfd, ptrs, oidx); + bfd_close (abfd); + abfd = bfd_openr (outname, HOW_BFD_TARGET); + return abfd; + } + +} + + +static bfd * +make_head() +{ + FILE * f = fopen ("dh.s", FOPEN_WT); + + fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C); + fprintf (f, "\t.section .idata$2\n"); + + fprintf(f,"\t%s\t%s\n", ASM_GLOBAL,head_label); + + fprintf (f, "%s:\n", head_label); + + fprintf (f, "\t%shname%s\t%sPtr to image import by name list\n", + ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C); + + fprintf (f, "\t%sthis should be the timestamp, but NT sometimes\n", ASM_C); + fprintf (f, "\t%sdoesn't load DLLs when this is set.\n", ASM_C); + fprintf (f, "\t%s\t0\t%s loaded time\n", ASM_LONG, ASM_C); + fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C); + fprintf (f, "\t%s__%s_iname%s\t%s imported dll's name\n", + ASM_RVA_BEFORE, + imp_name_lab, + ASM_RVA_AFTER, + ASM_C); + fprintf (f, "\t%sfthunk%s\t%s pointer to firstthunk\n", + ASM_RVA_BEFORE, + ASM_RVA_AFTER, ASM_C); + + fprintf (f, "%sStuff for compatibility\n", ASM_C); + + if (!no_idata5) + { + fprintf (f, "\t.section\t.idata$5\n"); + fprintf (f, "\t%s\t0\n", ASM_LONG); + fprintf (f, "fthunk:\n"); + } + if (!no_idata4) + { + fprintf (f, "\t.section\t.idata$4\n"); + + fprintf (f, "\t%s\t0\n", ASM_LONG); + fprintf (f, "\t.section .idata$4\n"); + fprintf (f, "hname:\n"); + } + fclose (f); + + sprintf (outfile, "-o dh.o dh.s"); + run (as_name, outfile); + + return bfd_openr ("dh.o", HOW_BFD_TARGET); +} + +static bfd * +make_tail() +{ + FILE * f = fopen ("dt.s", FOPEN_WT); + + if (!no_idata4) + { + fprintf (f, "\t.section .idata$4\n"); + fprintf (f, "\t%s\t0\n", ASM_LONG); + } + if (!no_idata5) + { + fprintf (f, "\t.section .idata$5\n"); + fprintf (f, "\t%s\t0\n", ASM_LONG); + } + +#ifdef DLLTOOL_PPC + /* Normally, we need to see a null descriptor built in idata$3 to + act as the terminator for the list. The ideal way, I suppose, + would be to mark this section as a comdat type 2 section, so + only one would appear in the final .exe (if our linker supported + comdat, that is) or cause it to be inserted by something else (say + crt0) + */ + + fprintf (f, "\t.section .idata$3\n"); + fprintf (f, "\t%s\t0\n", ASM_LONG); + fprintf (f, "\t%s\t0\n", ASM_LONG); + fprintf (f, "\t%s\t0\n", ASM_LONG); + fprintf (f, "\t%s\t0\n", ASM_LONG); + fprintf (f, "\t%s\t0\n", ASM_LONG); +#endif + +#ifdef DLLTOOL_PPC + /* Other PowerPC NT compilers use idata$6 for the dllname, so I + do too. Original, huh? */ + fprintf (f, "\t.section .idata$6\n"); +#else + fprintf (f, "\t.section .idata$7\n"); +#endif + + fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab); + fprintf (f, "__%s_iname:\t%s\t\"%s\"\n", + imp_name_lab, ASM_TEXT, dll_name); + + fclose (f); + + sprintf (outfile, "-o dt.o dt.s"); + run (as_name, outfile); + return bfd_openr ("dt.o", HOW_BFD_TARGET); +} + +static void +gen_lib_file () +{ + int i; + export_type *exp; + bfd *ar_head; + bfd *ar_tail; + bfd *outarch; + bfd * head = 0; + + unlink (imp_name); + + outarch = bfd_openw (imp_name, HOW_BFD_TARGET); + + if (!outarch) + { + fprintf (stderr, "%s: Can't open .lib file %s\n", program_name, imp_name); + exit (1); + } + bfd_set_format (outarch, bfd_archive); + outarch->has_armap = 1; + + /* Work out a reasonable size of things to put onto one line. */ + + + + ar_head = make_head (); + ar_tail = make_tail(); + + for (i = 0; (exp = d_exports_lexically[i]); i++) + { + bfd *n = make_one_lib_file (exp, i); + n->next = head; + head = n; + } + + + /* Now stick them all into the archive */ + + ar_head->next = head; + ar_tail->next = ar_head; + head = ar_tail; + + bfd_set_archive_head (outarch, head); + bfd_close (outarch); + + /* Delete all the temp files */ + + if (dontdeltemps == 0) + { + sprintf (outfile, "dh.o"); + unlink (outfile); + sprintf (outfile, "dh.s"); + unlink (outfile); + sprintf (outfile, "dt.o"); + unlink (outfile); + sprintf (outfile, "dt.s"); + unlink (outfile); + } + + if (dontdeltemps < 2) + for (i = 0, exp = d_exports; exp; i++, exp = exp->next) + { + sprintf (outfile, "ds%d.o",i); + unlink (outfile); + } + +} +/**********************************************************************/ + +/* Run through the information gathered from the .o files and the + .def file and work out the best stuff */ +int +pfunc (a, b) + void *a; + void *b; +{ + export_type *ap = *(export_type **) a; + export_type *bp = *(export_type **) b; + if (ap->ordinal == bp->ordinal) + return 0; + + /* unset ordinals go to the bottom */ + if (ap->ordinal == -1) + return 1; + if (bp->ordinal == -1) + return -1; + return (ap->ordinal - bp->ordinal); +} + + +int +nfunc (a, b) + void *a; + void *b; +{ + export_type *ap = *(export_type **) a; + export_type *bp = *(export_type **) b; + + return (strcmp (ap->name, bp->name)); +} + +static +void +remove_null_names (ptr) + export_type **ptr; +{ + int src; + int dst; + for (dst = src = 0; src < d_nfuncs; src++) + { + if (ptr[src]) + { + ptr[dst] = ptr[src]; + dst++; + } + } + d_nfuncs = dst; +} + +static void +dtab (ptr) + export_type **ptr; +{ +#ifdef SACDEBUG + int i; + for (i = 0; i < d_nfuncs; i++) + { + if (ptr[i]) + { + printf ("%d %s @ %d %s%s\n", + i, ptr[i]->name, ptr[i]->ordinal, + ptr[i]->noname ? "NONAME " : "", + ptr[i]->constant ? "CONSTANT" : ""); + } + else + printf ("empty\n"); + } +#endif +} + +static void +process_duplicates (d_export_vec) + export_type **d_export_vec; +{ + int more = 1; + int i; + while (more) + { + + more = 0; + /* Remove duplicates */ + qsort (d_export_vec, d_nfuncs, sizeof (export_type *), nfunc); + + dtab (d_export_vec); + for (i = 0; i < d_nfuncs - 1; i++) + { + if (strcmp (d_export_vec[i]->name, + d_export_vec[i + 1]->name) == 0) + { + + export_type *a = d_export_vec[i]; + export_type *b = d_export_vec[i + 1]; + + more = 1; + if (verbose) + fprintf (stderr, "Warning, ignoring duplicate EXPORT %s %d,%d\n", + a->name, + a->ordinal, + b->ordinal); + if (a->ordinal != -1 + && b->ordinal != -1) + { + + fprintf (stderr, "Error, duplicate EXPORT with oridinals %s\n", + a->name); + exit (1); + } + /* Merge attributes */ + b->ordinal = a->ordinal > 0 ? a->ordinal : b->ordinal; + b->constant |= a->constant; + b->noname |= a->noname; + d_export_vec[i] = 0; + } + + dtab (d_export_vec); + remove_null_names (d_export_vec); + dtab (d_export_vec); + } + } + + + /* Count the names */ + for (i = 0; i < d_nfuncs; i++) + { + if (!d_export_vec[i]->noname) + d_named_nfuncs++; + } +} + +static void +fill_ordinals (d_export_vec) + export_type **d_export_vec; +{ + int lowest = -1; + int i; + char *ptr; + int size = 65536; + + qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc); + + /* fill in the unset ordinals with ones from our range */ + + ptr = (char *) xmalloc (size); + + memset (ptr, 0, size); + + /* Mark in our large vector all the numbers that are taken */ + for (i = 0; i < d_nfuncs; i++) + { + if (d_export_vec[i]->ordinal != -1) + { + ptr[d_export_vec[i]->ordinal] = 1; + if (lowest == -1 || d_export_vec[i]->ordinal < lowest) + { + lowest = d_export_vec[i]->ordinal; + } + } + } + + /* Start at 1 for compatibility with MS toolchain. */ + if (lowest == -1) + lowest = 1; + + /* Now fill in ordinals where the user wants us to choose. */ + for (i = 0; i < d_nfuncs; i++) + { + if (d_export_vec[i]->ordinal == -1) + { + register int j; + + /* First try within or after any user supplied range. */ + for (j = lowest; j < size; j++) + if (ptr[j] == 0) + { + ptr[j] = 1; + d_export_vec[i]->ordinal = j; + goto done; + } + + /* Then try before the range. */ + for (j = lowest; j >0; j--) + if (ptr[j] == 0) + { + ptr[j] = 1; + d_export_vec[i]->ordinal = j; + goto done; + } + done:; + } + } + + free (ptr); + + /* And resort */ + + qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc); + + /* Work out the lowest and highest ordinal numbers. */ + if (d_nfuncs) + { + if (d_export_vec[0]) + d_low_ord = d_export_vec[0]->ordinal; + if (d_export_vec[d_nfuncs-1]) + d_high_ord = d_export_vec[d_nfuncs-1]->ordinal; + } +} + +int alphafunc(av,bv) +void *av; +void *bv; +{ + export_type **a = av; + export_type **b = bv; + + return strcmp ((*a)->name, (*b)->name); +} + +void +mangle_defs () +{ + /* First work out the minimum ordinal chosen */ + + export_type *exp; + + int i; + int hint = 0; + export_type **d_export_vec + = (export_type **) xmalloc (sizeof (export_type *) * d_nfuncs); + + for (i = 0, exp = d_exports; exp; i++, exp = exp->next) + { + d_export_vec[i] = exp; + } + + process_duplicates (d_export_vec); + fill_ordinals (d_export_vec); + + /* Put back the list in the new order */ + d_exports = 0; + for (i = d_nfuncs - 1; i >= 0; i--) + { + d_export_vec[i]->next = d_exports; + d_exports = d_export_vec[i]; + } + + /* Build list in alpha order */ + d_exports_lexically = (export_type **)xmalloc (sizeof(export_type *)*(d_nfuncs+1)); + + for (i = 0, exp = d_exports; exp; i++, exp = exp->next) + { + d_exports_lexically[i] = exp; + } + d_exports_lexically[i] = 0; + + qsort (d_exports_lexically, i, sizeof (export_type *), alphafunc); + + /* Fill exp entries with their hint values */ + + for (i = 0; i < d_nfuncs; i++) + { + if (!d_exports_lexically[i]->noname || show_allnames) + d_exports_lexically[i]->hint = hint++; + } + +} + + + + + + +/**********************************************************************/ + +void +usage (file, status) + FILE *file; + int status; +{ + fprintf (file, "Usage %s <options> <object-files>\n", program_name); + fprintf (file, " --machine <machine>\n"); + fprintf (file, " --output-exp <outname> Generate export file.\n"); + fprintf (file, " --output-lib <outname> Generate input library.\n"); + fprintf (file, " --add-indirect Add dll indirects to export file.\n"); + fprintf (file, " --dllname <name> Name of input dll to put into output lib.\n"); + fprintf (file, " --def <deffile> Name input .def file\n"); + fprintf (file, " --output-def <deffile> Name output .def file\n"); + fprintf (file, " --base-file <basefile> Read linker generated base file\n"); + fprintf (file, " --no-idata4 Don't generate idata$4 section\n"); + fprintf (file, " --no-idata5 Don't generate idata$5 section\n"); + fprintf (file, " -v Verbose\n"); + fprintf (file, " -U Add underscores to .lib\n"); + fprintf (file, " -k Kill @<n> from exported names\n"); + fprintf (file, " --as <name> Use <name> for assembler\n"); + fprintf (file, " --nodelete Keep temp files.\n"); + exit (status); +} + +#define OPTION_NO_IDATA4 'x' +#define OPTION_NO_IDATA5 'c' +static struct option long_options[] = +{ + {"nodelete", no_argument, NULL, 'n'}, + {"dllname", required_argument, NULL, 'D'}, + {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4}, + {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5}, + {"output-exp", required_argument, NULL, 'e'}, + {"output-def", required_argument, NULL, 'z'}, + {"output-lib", required_argument, NULL, 'l'}, + {"def", required_argument, NULL, 'd'}, + {"add-underscore", no_argument, NULL, 'U'}, + {"killat", no_argument, NULL, 'k'}, + {"help", no_argument, NULL, 'h'}, + {"machine", required_argument, NULL, 'm'}, + {"add-indirect", no_argument, NULL, 'a'}, + {"base-file", required_argument, NULL, 'b'}, + {"as", required_argument, NULL, 'S'}, + {0} +}; + + + +int +main (ac, av) + int ac; + char **av; +{ + int c; + int i; + char *firstarg = 0; + program_name = av[0]; + oav = av; + + while ((c = getopt_long (ac, av, "xcz:S:R:A:puaD:l:e:nkvbUh?m:yd:", long_options, 0)) + != EOF) + { + switch (c) + { + case OPTION_NO_IDATA4: + no_idata4 = 1; + break; + case OPTION_NO_IDATA5: + no_idata5 = 1; + break; + case 'S': + as_name = optarg; + break; + + /* ignored for compatibility */ + case 'u': + break; + case 'a': + add_indirect = 1; + break; + case 'z': + output_def = fopen (optarg, FOPEN_WT); + break; + case 'D': + dll_name = optarg; + break; + case 'l': + imp_name = optarg; + break; + case 'e': + exp_name = optarg; + break; + case 'h': + case '?': + usage (stderr, 0); + break; + case 'm': + mname = optarg; + break; + case 'v': + verbose = 1; + break; + case 'y': + yydebug = 1; + break; + case 'U': + add_underscore = 1; + break; + case 'k': + killat = 1; + break; + case 'd': + def_file = optarg; + break; + case 'n': + dontdeltemps++; + break; + case 'b': + base_file = fopen (optarg, FOPEN_RB); + if (!base_file) + { + fprintf (stderr, "%s: Unable to open base-file %s\n", + av[0], + optarg); + exit (1); + } + break; + default: + usage (stderr, 1); + } + } + + + for (i = 0; mtable[i].type; i++) + { + if (strcmp (mtable[i].type, mname) == 0) + break; + } + + if (!mtable[i].type) + { + fprintf (stderr, "Machine not supported\n"); + exit (1); + } + machine = i; + + + if (!dll_name && exp_name) + { + char len = strlen (exp_name) + 5; + dll_name = xmalloc (len); + strcpy (dll_name, exp_name); + strcat (dll_name, ".dll"); + } + + if (def_file) + { + process_def_file (def_file); + } + while (optind < ac) + { + if (!firstarg) + firstarg = av[optind]; + scan_obj_file (av[optind]); + optind++; + } + + mangle_defs (); + + if (exp_name) + gen_exp_file (); + if (imp_name) + { + /* Make imp_name safe for use as a label. */ + char *p; + imp_name_lab = strdup (imp_name); + for (p = imp_name_lab; *p; *p++) + { + if (!isalpha (*p) && !isdigit (*p)) + *p = '_'; + } + head_label = make_label("_head_", imp_name_lab); + gen_lib_file (); + } + if (output_def) + gen_def_file (); + + return 0; +} |