Output the exports table in assembly code to make it possible to

export C++ mangled names.
This commit is contained in:
Alexandre Julliard 2000-12-11 03:42:20 +00:00
parent 361943aaec
commit 2a37decc39
1 changed files with 137 additions and 162 deletions

View File

@ -34,8 +34,8 @@ static int string_compare( const void *ptr1, const void *ptr2 )
static const char *make_internal_name( const ORDDEF *odp, const char *prefix ) static const char *make_internal_name( const ORDDEF *odp, const char *prefix )
{ {
static char buffer[256]; static char buffer[256];
if (odp->name[0]) sprintf( buffer, "__wine_%s_%s", prefix, odp->name ); if (odp->name[0]) sprintf( buffer, "__wine_%s_%s_%s", prefix, DLLName, odp->name );
else sprintf( buffer, "__wine_%s_%d", prefix, odp->ordinal ); else sprintf( buffer, "__wine_%s_%s_%d", prefix, DLLName, odp->ordinal );
return buffer; return buffer;
} }
@ -102,156 +102,132 @@ static int output_debug( FILE *outfile )
* *
* Output the export table for a Win32 module. * Output the export table for a Win32 module.
*/ */
static void output_exports( FILE *outfile, int nr_exports, int fwd_size ) static int output_exports( FILE *outfile, int nr_exports )
{ {
int i, fwd_pos = 0; int i, fwd_size = 0, total_size = 0;
char *p;
ORDDEF *odp;
if (!nr_exports) return; if (!nr_exports) return 0;
fprintf( outfile, "\n\n/* exports */\n\n" ); fprintf( outfile, "asm(\".data\\n\"\n" );
fprintf( outfile, "typedef void (*func_ptr)();\n" ); fprintf( outfile, " \"\\t.align 4\\n\"\n" );
fprintf( outfile, "static struct {\n" ); fprintf( outfile, " \"" PREFIX "__wine_spec_exports:\\n\"\n" );
fprintf( outfile, " struct {\n" );
fprintf( outfile, " unsigned int Characteristics;\n" ); /* export directory header */
fprintf( outfile, " unsigned int TimeDateStamp;\n" );
fprintf( outfile, " unsigned short MajorVersion;\n" ); fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* Characteristics */
fprintf( outfile, " unsigned short MinorVersion;\n" ); fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* TimeDateStamp */
fprintf( outfile, " const char *Name;\n" ); fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* MajorVersion/MinorVersion */
fprintf( outfile, " unsigned int Base;\n" ); fprintf( outfile, " \"\\t.long " PREFIX "dllname\\n\"\n" ); /* Name */
fprintf( outfile, " unsigned int NumberOfFunctions;\n" ); fprintf( outfile, " \"\\t.long %d\\n\"\n", Base ); /* Base */
fprintf( outfile, " unsigned int NumberOfNames;\n" ); fprintf( outfile, " \"\\t.long %d\\n\"\n", nr_exports ); /* NumberOfFunctions */
fprintf( outfile, " func_ptr *AddressOfFunctions;\n" ); fprintf( outfile, " \"\\t.long %d\\n\"\n", nb_names ); /* NumberOfNames */
fprintf( outfile, " const char **AddressOfNames;\n" ); fprintf( outfile, " \"\\t.long __wine_spec_exports_funcs\\n\"\n" ); /* AddressOfFunctions */
fprintf( outfile, " unsigned short *AddressOfNameOrdinals;\n" );
fprintf( outfile, " func_ptr functions[%d];\n", nr_exports );
if (nb_names) if (nb_names)
{ {
fprintf( outfile, " const char *names[%d];\n", nb_names ); fprintf( outfile, " \"\\t.long __wine_spec_exp_name_ptrs\\n\"\n" ); /* AddressOfNames */
fprintf( outfile, " unsigned short ordinals[%d];\n", nb_names ); fprintf( outfile, " \"\\t.long __wine_spec_exp_ordinals\\n\"\n" ); /* AddressOfNameOrdinals */
if (nb_names % 2) fprintf( outfile, " unsigned short pad1;\n" );
}
if (fwd_size)
{
fprintf( outfile, " char forwards[%d];\n", (fwd_size + 3) & ~3 );
}
fprintf( outfile, " } exp;\n" );
if (debugging)
{
fprintf( outfile, " struct {\n" );
fprintf( outfile, " unsigned char jmp;\n" );
fprintf( outfile, " unsigned char addr[4];\n" );
fprintf( outfile, " unsigned char ret;\n" );
fprintf( outfile, " unsigned short args;\n" );
fprintf( outfile, " func_ptr orig;\n" );
fprintf( outfile, " unsigned int argtypes;\n" );
fprintf( outfile, " } relay[%d];\n", nr_exports );
}
fprintf( outfile, "} exports = {\n {\n" );
fprintf( outfile, " 0,\n" ); /* Characteristics */
fprintf( outfile, " 0,\n" ); /* TimeDateStamp */
fprintf( outfile, " 0,\n" ); /* MajorVersion */
fprintf( outfile, " 0,\n" ); /* MinorVersion */
fprintf( outfile, " dllname,\n" ); /* Name */
fprintf( outfile, " %d,\n", Base ); /* Base */
fprintf( outfile, " %d,\n", nr_exports ); /* NumberOfFunctions */
fprintf( outfile, " %d,\n", nb_names ); /* NumberOfNames */
fprintf( outfile, " exports.exp.functions,\n" ); /* AddressOfFunctions */
if (nb_names)
{
fprintf( outfile, " exports.exp.names,\n" ); /* AddressOfNames */
fprintf( outfile, " exports.exp.ordinals,\n" ); /* AddressOfNameOrdinals */
} }
else else
{ {
fprintf( outfile, " 0,\n" ); /* AddressOfNames */ fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* AddressOfNames */
fprintf( outfile, " 0,\n" ); /* AddressOfNameOrdinals */ fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* AddressOfNameOrdinals */
} }
total_size += 10 * sizeof(int);
/* output the function addresses */ /* output the function pointers */
fprintf( outfile, " {\n " ); fprintf( outfile, " \"__wine_spec_exports_funcs:\\n\"\n" );
for (i = Base; i <= Limit; i++) for (i = Base; i <= Limit; i++)
{ {
ORDDEF *odp = Ordinals[i]; ORDDEF *odp = Ordinals[i];
if (!odp) fprintf( outfile, "0" ); if (!odp) fprintf( outfile, " \"\\t.long 0\\n\"\n" );
else switch(odp->type) else switch(odp->type)
{ {
case TYPE_EXTERN: case TYPE_EXTERN:
fprintf( outfile, "%s", odp->u.ext.link_name ); fprintf( outfile, " \"\\t.long " PREFIX "%s\\n\"\n", odp->u.ext.link_name );
break; break;
case TYPE_STDCALL: case TYPE_STDCALL:
case TYPE_VARARGS: case TYPE_VARARGS:
case TYPE_CDECL: case TYPE_CDECL:
fprintf( outfile, "%s", odp->u.func.link_name); fprintf( outfile, " \"\\t.long " PREFIX "%s\\n\"\n", odp->u.func.link_name);
break; break;
case TYPE_STUB: case TYPE_STUB:
fprintf( outfile, "%s", make_internal_name( odp, "stub" ) ); fprintf( outfile, " \"\\t.long " PREFIX "%s\\n\"\n", make_internal_name( odp, "stub" ) );
break; break;
case TYPE_REGISTER: case TYPE_REGISTER:
fprintf( outfile, "%s", make_internal_name( odp, "regs" ) ); fprintf( outfile, " \"\\t.long " PREFIX "%s\\n\"\n", make_internal_name( odp, "regs" ) );
break; break;
case TYPE_VARIABLE: case TYPE_VARIABLE:
fprintf( outfile, "(func_ptr)%s", make_internal_name( odp, "var" ) ); fprintf( outfile, " \"\\t.long " PREFIX "%s\\n\"\n", make_internal_name( odp, "var" ) );
break; break;
case TYPE_FORWARD: case TYPE_FORWARD:
fprintf( outfile, "(func_ptr)&exports.exp.forwards[%d] /* %s */", fprintf( outfile, " \"\\t.long __wine_spec_forwards+%d\\n\"\n", fwd_size );
fwd_pos, odp->u.fwd.link_name ); fwd_size += strlen(odp->u.fwd.link_name) + 1;
fwd_pos += strlen(odp->u.fwd.link_name) + 1;
break; break;
default: default:
assert(0); assert(0);
} }
if (i < Limit) fprintf( outfile, ",\n " );
else fprintf( outfile, "\n },\n" );
} }
total_size += (Limit - Base + 1) * sizeof(int);
if (nb_names) if (nb_names)
{ {
/* output the function names */ /* output the function name pointers */
fprintf( outfile, " {\n" ); int namepos = 0;
fprintf( outfile, " \"__wine_spec_exp_name_ptrs:\\n\"\n" );
for (i = 0; i < nb_names; i++) for (i = 0; i < nb_names; i++)
{ {
if (i) fprintf( outfile, ",\n" ); fprintf( outfile, " \"\\t.long __wine_spec_exp_names+%d\\n\"\n", namepos );
fprintf( outfile, " \"%s\"", Names[i]->name ); namepos += strlen(Names[i]->name) + 1;
} }
fprintf( outfile, "\n },\n" ); total_size += nb_names * sizeof(int);
/* output the function names */
fprintf( outfile, " \"\\t.text\\n\"\n" );
fprintf( outfile, " \"__wine_spec_exp_names:\\n\"\n" );
for (i = 0; i < nb_names; i++)
fprintf( outfile, " \"\\t" STRING " \\\"%s\\\"\\n\"\n", Names[i]->name );
fprintf( outfile, " \"\\t.data\\n\"\n" );
/* output the function ordinals */ /* output the function ordinals */
fprintf( outfile, " {\n " ); fprintf( outfile, " \"__wine_spec_exp_ordinals:\\n\"\n" );
for (i = 0; i < nb_names; i++) for (i = 0; i < nb_names; i++)
{ {
fprintf( outfile, "%4d", Names[i]->ordinal - Base ); fprintf( outfile, " \"\\t.short %d\\n\"\n", Names[i]->ordinal - Base );
if (i < nb_names-1) }
{ total_size += nb_names * sizeof(short);
fputc( ',', outfile ); if (nb_names % 2)
if ((i % 8) == 7) fprintf( outfile, "\n " ); {
} fprintf( outfile, " \"\\t.short 0\\n\"\n" );
total_size += sizeof(short);
} }
fprintf( outfile, "\n },\n" );
if (nb_names % 2) fprintf( outfile, " 0,\n" );
} }
/* output forwards */ /* output forward strings */
if (fwd_size) if (fwd_size)
{ {
fprintf( outfile, " \"__wine_spec_forwards:\\n\"\n" );
for (i = Base; i <= Limit; i++) for (i = Base; i <= Limit; i++)
{ {
ORDDEF *odp = Ordinals[i]; ORDDEF *odp = Ordinals[i];
if (odp && odp->type == TYPE_FORWARD) if (odp && odp->type == TYPE_FORWARD)
fprintf( outfile, " \"%s\\0\"\n", odp->u.fwd.link_name ); fprintf( outfile, " \"\\t" STRING " \\\"%s\\\"\\n\"\n", odp->u.fwd.link_name );
} }
fprintf( outfile, " \"\\t.align 4\\n\"\n" );
total_size += (fwd_size + 3) & ~3;
} }
/* output relays */ /* output relays */
if (debugging) if (debugging)
{ {
fprintf( outfile, " },\n {\n" );
for (i = Base; i <= Limit; i++) for (i = Base; i <= Limit; i++)
{ {
ORDDEF *odp = Ordinals[i]; ORDDEF *odp = Ordinals[i];
@ -276,45 +252,77 @@ static void output_exports( FILE *outfile, int nr_exports, int fwd_size )
switch(odp->type) switch(odp->type)
{ {
case TYPE_STDCALL: case TYPE_STDCALL:
fprintf( outfile, " { 0xe9, { 0,0,0,0 }, 0xc2, 0x%04x, %s, 0x%08x }", fprintf( outfile, " \"\\tjmp " PREFIX "%s\\n\"\n", odp->u.func.link_name );
strlen(odp->u.func.arg_types) * sizeof(int), fprintf( outfile, " \"\\tret $%d\\n\"\n",
strlen(odp->u.func.arg_types) * sizeof(int) );
fprintf( outfile, " \"\\t.long " PREFIX "%s,0x%08x\\n\"\n",
odp->u.func.link_name, mask ); odp->u.func.link_name, mask );
break; break;
case TYPE_CDECL: case TYPE_CDECL:
fprintf( outfile, " { 0xe9, { 0,0,0,0 }, 0xc3, 0x%04x, %s, 0x%08x }", fprintf( outfile, " \"\\tjmp " PREFIX "%s\\n\"\n", odp->u.func.link_name );
strlen(odp->u.func.arg_types) * sizeof(int), fprintf( outfile, " \"\\tret\\n\"\n" );
fprintf( outfile, " \"\\t.short %d\\n\"\n",
strlen(odp->u.func.arg_types) * sizeof(int) );
fprintf( outfile, " \"\\t.long " PREFIX "%s,0x%08x\\n\"\n",
odp->u.func.link_name, mask ); odp->u.func.link_name, mask );
break; break;
case TYPE_REGISTER: case TYPE_REGISTER:
fprintf( outfile, " { 0xe9, { 0,0,0,0 }, 0xc3, 0x%04x, %s, 0x%08x }", fprintf( outfile, " \"\\tjmp " PREFIX "%s\\n\"\n",
0x8000 | (strlen(odp->u.func.arg_types) * sizeof(int)), make_internal_name( odp, "regs" ) );
fprintf( outfile, " \"\\tret\\n\"\n" );
fprintf( outfile, " \"\\t.short 0x%04x\\n\"\n",
0x8000 | strlen(odp->u.func.arg_types) * sizeof(int) );
fprintf( outfile, " \"\\t.long " PREFIX "%s,0x%08x\\n\"\n",
make_internal_name( odp, "regs" ), mask ); make_internal_name( odp, "regs" ), mask );
break; break;
default: default:
assert(0); assert(0);
} }
goto done; continue;
ignore: ignore:
fprintf( outfile, " { 0, { 0,0,0,0 }, 0, 0, 0, 0 }" ); fprintf( outfile, " \"\\t.long 0,0,0,0\\n\"\n" );
done:
if (i < Limit) fprintf( outfile, ",\n" );
} }
} }
fprintf( outfile, " }\n};\n\n" );
/* output __wine_dllexport symbols */ /* output __wine_dllexport symbols */
for (i = 0; i < nb_names; i++) for (i = 0; i < nb_names; i++)
{ {
char *p;
if (Names[i]->flags & FLAG_NOIMPORT) continue; if (Names[i]->flags & FLAG_NOIMPORT) continue;
/* check for invalid characters in the name */ /* check for invalid characters in the name */
for (p = Names[i]->name; *p; p++) if (!isalnum(*p) && *p != '_') break; for (p = Names[i]->name; *p; p++)
if (!*p) fprintf( outfile, "const char __wine_dllexport_%s_%s = 0;\n", if (!isalnum(*p) && *p != '_' && *p != '.') goto next;
DLLName, Names[i]->name ); fprintf( outfile, " \"\\t.globl " PREFIX "__wine_dllexport_%s_%s\\n\"\n",
DLLName, Names[i]->name );
fprintf( outfile, " \"" PREFIX "__wine_dllexport_%s_%s:\\n\"\n",
DLLName, Names[i]->name );
next:
} }
fprintf( outfile, " \"\\t.long 0xffffffff\\n\"\n" );
/* output variables */
for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
{
if (odp->type == TYPE_VARIABLE)
{
int j;
fprintf( outfile, " \"%s:\\n\"\n", make_internal_name( odp, "var" ) );
fprintf( outfile, " \"\\t.long " );
for (j = 0; j < odp->u.var.n_values; j++)
{
fprintf( outfile, "0x%08x", odp->u.var.values[j] );
if (j < odp->u.var.n_values-1) fputc( ',', outfile );
}
fprintf( outfile, "\\n\"\n" );
}
}
fprintf( outfile, ");\n\n" );
return total_size;
} }
@ -360,7 +368,7 @@ static void output_stub_funcs( FILE *outfile )
for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++) for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
{ {
if (odp->type != TYPE_STUB) continue; if (odp->type != TYPE_STUB) continue;
fprintf( outfile, "static void %s(void) ", make_internal_name( odp, "stub" ) ); fprintf( outfile, "void %s(void) ", make_internal_name( odp, "stub" ) );
if (odp->name[0]) if (odp->name[0])
fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->name ); fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->name );
else else
@ -380,9 +388,6 @@ static void output_register_funcs( FILE *outfile )
const char *name; const char *name;
int i; int i;
fprintf( outfile, "#ifndef __GNUC__\n" );
fprintf( outfile, "static void __asm__dummy(void) {\n" );
fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++) for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
{ {
if (odp->type != TYPE_REGISTER) continue; if (odp->type != TYPE_REGISTER) continue;
@ -397,9 +402,6 @@ static void output_register_funcs( FILE *outfile )
name, name, odp->u.func.link_name, name, name, odp->u.func.link_name,
4 * strlen(odp->u.func.arg_types), 4 * strlen(odp->u.func.arg_types) ); 4 * strlen(odp->u.func.arg_types), 4 * strlen(odp->u.func.arg_types) );
} }
fprintf( outfile, "#ifndef __GNUC__\n" );
fprintf( outfile, "}\n" );
fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
} }
@ -410,8 +412,7 @@ static void output_register_funcs( FILE *outfile )
*/ */
void BuildSpec32File( FILE *outfile ) void BuildSpec32File( FILE *outfile )
{ {
ORDDEF *odp; int exports_size = 0;
int i, j, fwd_size = 0, have_regs = FALSE;
int nr_exports, nr_imports, nr_resources, nr_debug; int nr_exports, nr_imports, nr_resources, nr_debug;
int characteristics, subsystem, has_imports; int characteristics, subsystem, has_imports;
const char *init_func; const char *init_func;
@ -443,6 +444,7 @@ void BuildSpec32File( FILE *outfile )
fprintf( outfile, " \"pe_header:\\t.fill %ld,1,0\\n\\t\");\n", page_size ); fprintf( outfile, " \"pe_header:\\t.fill %ld,1,0\\n\\t\");\n", page_size );
fprintf( outfile, "static const char dllname[] = \"%s\";\n\n", DLLName ); fprintf( outfile, "static const char dllname[] = \"%s\";\n\n", DLLName );
fprintf( outfile, "extern int __wine_spec_exports[];\n\n" );
#ifdef __i386__ #ifdef __i386__
fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" ); fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
@ -450,56 +452,29 @@ void BuildSpec32File( FILE *outfile )
fprintf( outfile, "#define __stdcall\n\n" ); fprintf( outfile, "#define __stdcall\n\n" );
#endif #endif
/* Output the stub functions */ if (nr_exports)
output_stub_funcs( outfile );
/* Output the DLL functions prototypes */
for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
{ {
switch(odp->type) /* Output the stub functions */
{
case TYPE_EXTERN: output_stub_funcs( outfile );
fprintf( outfile, "extern void %s();\n", odp->u.ext.link_name );
break; fprintf( outfile, "#ifndef __GNUC__\n" );
case TYPE_STDCALL: fprintf( outfile, "static void __asm__dummy(void) {\n" );
case TYPE_VARARGS: fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
case TYPE_CDECL:
fprintf( outfile, "extern void %s();\n", odp->u.func.link_name ); /* Output code for all register functions */
break;
case TYPE_FORWARD: output_register_funcs( outfile );
fwd_size += strlen(odp->u.fwd.link_name) + 1;
break; /* Output the exports and relay entry points */
case TYPE_REGISTER:
fprintf( outfile, "extern void %s();\n", make_internal_name( odp, "regs" ) ); exports_size = output_exports( outfile, nr_exports );
have_regs = TRUE;
break; fprintf( outfile, "#ifndef __GNUC__\n" );
case TYPE_STUB: fprintf( outfile, "}\n" );
break; fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
case TYPE_VARIABLE:
fprintf( outfile, "unsigned int %s[%d] = {",
make_internal_name( odp, "var" ), odp->u.var.n_values );
for (j = 0; j < odp->u.var.n_values; j++)
{
fprintf( outfile, " 0x%08x", odp->u.var.values[j] );
if (j < odp->u.var.n_values-1) fputc( ',', outfile );
}
fprintf( outfile, " };\n" );
break;
default:
fatal_error("function type %d not available for Win32\n", odp->type);
}
} }
/* Output code for all register functions */
if (have_regs) output_register_funcs( outfile );
/* Output the exports and relay entry points */
output_exports( outfile, nr_exports, fwd_size );
/* Output the DLL imports */ /* Output the DLL imports */
nr_imports = output_imports( outfile ); nr_imports = output_imports( outfile );
@ -660,8 +635,8 @@ void BuildSpec32File( FILE *outfile )
fprintf( outfile, " 0, 0, 0, 0, 0, 0,\n" ); fprintf( outfile, " 0, 0, 0, 0, 0, 0,\n" );
fprintf( outfile, " %d,\n", IMAGE_NUMBEROF_DIRECTORY_ENTRIES ); /* NumberOfRvaAndSizes */ fprintf( outfile, " %d,\n", IMAGE_NUMBEROF_DIRECTORY_ENTRIES ); /* NumberOfRvaAndSizes */
fprintf( outfile, " {\n" ); fprintf( outfile, " {\n" );
fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_EXPORT */ fprintf( outfile, " { %s, %d },\n", /* IMAGE_DIRECTORY_ENTRY_EXPORT */
nr_exports ? "&exports" : "0", nr_exports ? "sizeof(exports.exp)" : "0" ); exports_size ? "__wine_spec_exports" : "0", exports_size );
fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_IMPORT */ fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_IMPORT */
nr_imports ? "&imports" : "0", nr_imports ? "sizeof(imports)" : "0" ); nr_imports ? "&imports" : "0", nr_imports ? "sizeof(imports)" : "0" );
fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_RESOURCE */ fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_RESOURCE */