binutils-gdb/binutils/dlltool.c
Steve Chamberlain 6f2d32120e * ar.c: (print_contents.c, extract_file, do_quick_append):
Malloc buffers rather than allocate on stack (so it works
	on NT).
	* deflex.l: Names can have an @ in them.
	* dlltool.c: Loads of stuff. Can now generate .imp files which
	work with NT .dlls.
1995-06-29 00:59:07 +00:00

1248 lines
26 KiB
C

/* dlltool.c -- tool to generate stuff for PE style DLLs
Copyright (C) 1995 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., 675 Mass Ave, Cambridge, MA 02139, 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)
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 ".drective" 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 .drective 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
.drective section. The linker will see this and act
upon it.
A -export:<name> in a .drective 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 output files are <prefix>-exp.s and <prefix>-lib.s
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 -o thedll -d thedll.def thedll.in
# build the export table for the dll
as -o thedll.exp thedll-exp.s
# build the dll with the library with file1.o, file2.o and the export table
ld -o thedll.dll thedll.exp thedll.in
# build the import table for the executable
as -o thedll.lib thedll-lib.s
# 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.lib
*/
#define PAGE_SIZE 4096
#define PAGE_MASK (-PAGE_SIZE)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getopt.h"
#include "bfd.h"
int yydebug;
char *def_file;
char *program_name;
char *strrchr ();
char *outfile_prefix;
char *xmalloc ();
char *strdup ();
static int machine;
int suckunderscore;
static int verbose;
FILE *base_file;
#ifdef DLLTOOL_ARM
static char *mname = "arm";
#endif
#ifdef DLLTOOL_I386
static char *mname = "i386";
#endif
#define PATHMAX 250 /* What's the right name for this ? */
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;
}
mtable[]
=
{
{
"arm", ".byte", ".short", ".long", ".asciz", "@", "ldr\tip,[pc]\n\tldr\tpc,[ip]\n\t.long", ".global", ".space"
}
,
{
"i386", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space"
}
,
0
};
#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
static char **oav;
int i;
FILE *yyin; /* communications with flex */
extern int linenumber;
void
process_def_file (name)
char *name;
{
FILE *f = fopen (name, "r");
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;
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_ord; /* Base ordinal index */
static export_type *d_exports; /*list of exported functions */
static char *d_suffix = "dll";
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;
yyerror ()
{
fprintf (stderr, "%s: Syntax error in def file %s:%d\n",
program_name, def_file, linenumber);
}
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;
if (strchr (d_name, '.'))
d_suffix = strdup (strchr (d_name, '.') + 1);
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;
if (strchr (d_name, '.'))
d_suffix = strdup (strchr (d_name, '.') + 1);
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)
{
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);
}
/**********************************************************************/
/* read in and block out the base relocations */
static void
basenames (abfd)
bfd *abfd;
{
}
void
scan_open_obj_file (abfd)
bfd *abfd;
{
/* Look for .drectives */
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 != ' ' && *p != '-' && p < e)
p++;
c = xmalloc (p - name + 1);
memcpy (c, name, p - name);
c[p - name] = 0;
def_exports (c, 0, -1, 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);
}
}
if (bfd_check_format (f, bfd_object))
{
scan_open_obj_file (f);
}
bfd_close (f);
}
/**********************************************************************/
/* return the bit of the name before the last . */
static
char *
prefix (name)
char *name;
{
char *res = strdup (name);
char *p = strrchr (res, '.');
if (p)
*p = 0;
return res;
}
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;
long *need;
long page_addr;
int on_page;
{
int i;
/* Flush this page */
fprintf (f, "\t%s\t0x%x\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_exp_file ()
{
FILE *f;
int i;
export_type *exp;
dlist_type *dl;
int had_noname = 0;
sprintf (outfile, "%s-exp.s", outfile_prefix);
if (verbose)
fprintf (stderr, "%s: Generate exp file %s\n",
program_name, outfile_prefix);
f = fopen (outfile, "w");
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);
fprintf (f, "\t.section .edata\n\n");
fprintf (f, "\t%s 0 %s Allways 0\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s %d %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%s name %s Ptr to name of dll\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s %d %s Starting ordinal of exports\n", ASM_LONG, d_ord, ASM_C);
fprintf (f, "\t%s The next field is documented as being the number of functions\n", ASM_C);
fprintf (f, "\t%s yet it doesn't look like that in real PE dlls\n", ASM_C);
fprintf (f, "\t%s But it shouldn't be a problem, causes there's\n", ASM_C);
fprintf (f, "\t%s always the number of names field\n", ASM_C);
fprintf (f, "\t%s %d %s Number of functions\n", ASM_LONG, d_nfuncs, ASM_C);
fprintf (f, "\t%s %d %s Number of names\n", ASM_LONG, d_nfuncs, ASM_C);
fprintf (f, "\t%s afuncs %s Address of functions\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s anames %s Address of names\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s anords %s Address of ordinals\n", ASM_LONG, ASM_C);
fprintf (f, "name: %s \"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
fprintf (f, "afuncs:\n");
i = d_ord;
for (exp = d_exports; exp; exp = exp->next)
{
#if 0
/* This seems necessary in the doc, but in real
life it's not used.. */
if (exp->ordinal != i)
{
fprintf (f, "%s\t%s\t%d\t@ %d..%d missing\n", ASM_C, ASM_SPACE,
(exp->ordinal - i) * 4,
i, exp->ordinal - 1);
i = exp->ordinal;
}
#endif
fprintf (f, "\t%s %s\t%s %d\n", ASM_LONG, exp->internal_name, ASM_C, exp->ordinal);
i++;
}
fprintf (f, "anames:\n");
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
if (exp->noname)
{
had_noname = 1;
fprintf (f, "\t%s nNoname\n", ASM_LONG, ASM_C);
}
else
{
fprintf (f, "\t%s n%d\n", ASM_LONG, i);
}
}
fprintf (f, "anords:\n");
for (exp = d_exports; exp; exp = exp->next)
fprintf (f, "\t%s %d\n", ASM_SHORT, exp->ordinal - d_ord);
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
if (exp->noname)
fprintf (f, "@n%d: %s \"%s\"\n", i, ASM_TEXT, exp->name);
else
fprintf (f, "n%d: %s \"%s\"\n", i, ASM_TEXT, exp->name);
if (had_noname)
fprintf (f, "nNoname: %s \"__noname__\"\n", ASM_TEXT);
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;
}
}
}
}
/* 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.reloc\n");
fseek (base_file, 0, SEEK_END);
numbytes = ftell (base_file);
fseek (base_file, 0, SEEK_SET);
copy = malloc (numbytes);
fread (copy, 1, numbytes, base_file);
num_entries = numbytes / sizeof (long);
qsort (copy, num_entries, sizeof (long), sfunc);
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);
}
fclose (f);
}
static char *
xlate (char *name)
{
char *p;
if (!suckunderscore)
return name;
if (name[0] == '_')
name++;
p = strchr (name, '@');
if (p)
*p = 0;
return name;
}
/**********************************************************************/
gen_lib_file ()
{
int i;
FILE *f;
export_type *exp;
sprintf (outfile, "%s-lib.s", outfile_prefix);
f = fopen (outfile, "w");
if (!f)
{
fprintf (stderr, "Unable to open output file %s\n", outfile);
exit (1);
}
dump_def_info (f);
fprintf (f, "\t.text\n");
fprintf (f, "%s Thunk table\n", ASM_C);
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
fprintf (f, "\t%s\t%s\n", ASM_GLOBAL, exp->name);
fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
}
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
fprintf (f, "%s:\t%s\t__imp_%s\n", exp->name, ASM_JUMP, exp->name);
}
fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
fprintf (f, "\t.section .idata$2\n");
fprintf (f, "\t%s\thname\t%s Ptr to image import by name list\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s\t%d\t%s time\n", ASM_LONG, time (0), ASM_C);
fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s\tiname\t%s imported dll's name\n", ASM_LONG, ASM_C);
fprintf (f, "\t%s\tfthunk\t%s pointer to firstthunk\n", ASM_LONG, ASM_C);
fprintf (f, "%sStuff for compatibility\n", ASM_C);
fprintf (f, "\t.section\t.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);
fprintf (f, "\t.section\t.idata$5\n");
fprintf (f, "\t%s\t0\n", ASM_LONG);
fprintf (f, "\t.section\t.idata$4\n");
fprintf (f, "\t%s\t0\n", ASM_LONG);
fprintf (f, "\n%s Loader modifies this\n", ASM_C);
fprintf (f, "\t.section .idata$5\n");
fprintf (f, "fthunk:\n");
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
fprintf (f, "__imp_%s:\n", exp->name);
fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
}
fprintf (f, "\t%s\t0\n", ASM_LONG);
fprintf (f, "\n%s Hint name array\n", ASM_C);
fprintf (f, "\t.section .idata$4\n");
fprintf (f, "hname:\n");
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
fprintf (f, "\t%s\tID%d\n", ASM_LONG, i);
}
fprintf (f, "\t%s\t0\n", ASM_LONG);
fprintf (f, "%s Hint/name array storage and import dll name\n", ASM_C);
fprintf (f, "\t.section .idata$6\n");
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
fprintf (f, "ID%d:\t%s\t%d\n", i, ASM_SHORT, exp->ordinal);
fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name));
}
fprintf (f, "\t%s\t0\n", ASM_LONG);
fprintf (f, "iname:\t%s\t\"%s.%s\"\n", ASM_TEXT, outfile_prefix, d_suffix);
fclose (f);
}
/**********************************************************************/
/* 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;
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);
}
}
}
static void
fill_ordinals (d_export_vec)
export_type **d_export_vec;
{
int lowest = 0;
int unset = 0;
char *ptr;
qsort (d_export_vec, d_nfuncs, sizeof (export_type *), pfunc);
/* fill in the unset ordinals with ones from our range */
ptr = (char *) malloc (65536);
memset (ptr, 65536, 0);
/* 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 == 0)
lowest = d_export_vec[i]->ordinal;
}
}
for (i = 0; i < d_nfuncs; i++)
{
if (d_export_vec[i]->ordinal == -1)
{
int j;
for (j = lowest; j < 65536; j++)
if (ptr[j] == 0)
{
ptr[j] = 1;
d_export_vec[i]->ordinal = j;
goto done;
}
for (j = 1; j < lowest; 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 ordinal number */
if (d_export_vec[0])
d_ord = d_export_vec[0]->ordinal;
}
void
mangle_defs ()
{
/* First work out the minimum ordinal chosen */
export_type *exp;
int lowest = 0;
int i;
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];
}
}
/**********************************************************************/
void
usage (file, status)
FILE *file;
int status;
{
fprintf (file, "Usage %s <options> <object-files>\n", program_name);
fprintf (file, "\t -m <machine> Generate code for <machine>\n");
fprintf (file, "\t --machine <machine>\n");
fprintf (file, "\t -o <outprefix> Set output prefix\n");
fprintf (file, "\t -d <deffile> Name input .def file\n");
fprintf (file, "\t --def <deffile> \n");
fprintf (file, "\t --base-file <basefile> Read linker generated base file\n");
fprintf (file, "\t -b <basefile> \n");
fprintf (file, "\t -v Verbose\n");
exit (status);
}
static struct option long_options[] =
{
{"def", required_argument, NULL, 'd'},
{"underscore", no_argument, NULL, 'u'},
{"help", no_argument, NULL, 'h'},
{"machine", required_argument, NULL, 'm'},
{"base-file", required_argument, NULL, 'b'},
0
};
int
main (ac, av)
int ac;
char **av;
{
int c;
char *firstarg = 0;
program_name = av[0];
oav = av;
while ((c = getopt_long (ac, av, "vbuh?m:o:Dd:", long_options, 0)) != EOF)
{
switch (c)
{
case 'h':
case '?':
usage (stderr, 0);
break;
case 'm':
mname = optarg;
break;
case 'o':
outfile_prefix = optarg;
break;
case 'v':
verbose = 1;
break;
case 'D':
yydebug = 1;
break;
case 'u':
suckunderscore = 1;
break;
case 'd':
def_file = optarg;
break;
case 'b':
base_file = fopen (optarg, "r");
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 (def_file)
{
process_def_file (def_file);
}
while (optind < ac)
{
if (!firstarg)
firstarg = av[optind];
scan_obj_file (av[optind]);
optind++;
}
if (!outfile_prefix)
{
if (d_name)
outfile_prefix = d_name;
else if (def_file)
outfile_prefix = def_file;
else if (firstarg)
outfile_prefix = firstarg;
else
{
fprintf (stderr, "No way to create an output filename\n");
exit (1);
}
}
outfile_prefix = prefix (outfile_prefix);
if (verbose)
fprintf (stderr, "%s: Outfile prefix is %s\n",
program_name, outfile_prefix);
mangle_defs ();
gen_exp_file ();
gen_lib_file ();
return 0;
}