winebuild: Add support for generating data-only DLLs.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3eca3516ad
commit
39f6ab55a9
|
@ -283,6 +283,7 @@ extern void output_resources( DLLSPEC *spec );
|
|||
extern void output_bin_resources( DLLSPEC *spec, unsigned int start_rva );
|
||||
extern void output_spec32_file( DLLSPEC *spec );
|
||||
extern void output_fake_module( DLLSPEC *spec );
|
||||
extern void output_data_module( DLLSPEC *spec );
|
||||
extern void output_def_file( DLLSPEC *spec, int import_only );
|
||||
extern void load_res16_file( const char *name, DLLSPEC *spec );
|
||||
extern void output_res16_data( DLLSPEC *spec );
|
||||
|
@ -329,6 +330,7 @@ extern int use_msvcrt;
|
|||
extern int unix_lib;
|
||||
extern int safe_seh;
|
||||
extern int prefer_native;
|
||||
extern int data_only;
|
||||
|
||||
extern char *input_file_name;
|
||||
extern char *spec_file_name;
|
||||
|
|
|
@ -46,6 +46,7 @@ int use_msvcrt = 0;
|
|||
int unix_lib = 0;
|
||||
int safe_seh = 0;
|
||||
int prefer_native = 0;
|
||||
int data_only = 0;
|
||||
|
||||
struct target target = { 0 };
|
||||
|
||||
|
@ -198,6 +199,7 @@ static const char usage_str[] =
|
|||
" -b, --target=TARGET Specify target CPU and platform for cross-compiling\n"
|
||||
" -B PREFIX Look for build tools in the PREFIX directory\n"
|
||||
" --cc-cmd=CC C compiler to use for assembling (default: fall back to --as-cmd)\n"
|
||||
" --data-only Generate a data-only dll (i.e. without any executable code)\n"
|
||||
" -d, --delay-lib=LIB Import the specified library in delayed mode\n"
|
||||
" -D SYM Ignored for C flags compatibility\n"
|
||||
" -e, --entry=FUNC Set the DLL entry point function (default: DllMain)\n"
|
||||
|
@ -251,6 +253,7 @@ enum long_options_values
|
|||
LONG_OPT_BUILTIN,
|
||||
LONG_OPT_ASCMD,
|
||||
LONG_OPT_CCCMD,
|
||||
LONG_OPT_DATA_ONLY,
|
||||
LONG_OPT_EXTERNAL_SYMS,
|
||||
LONG_OPT_FAKE_MODULE,
|
||||
LONG_OPT_FIXUP_CTORS,
|
||||
|
@ -284,6 +287,7 @@ static const struct long_option long_options[] =
|
|||
/* other long options */
|
||||
{ "as-cmd", 1, LONG_OPT_ASCMD },
|
||||
{ "cc-cmd", 1, LONG_OPT_CCCMD },
|
||||
{ "data-only", 0, LONG_OPT_DATA_ONLY },
|
||||
{ "external-symbols", 0, LONG_OPT_EXTERNAL_SYMS },
|
||||
{ "fake-module", 0, LONG_OPT_FAKE_MODULE },
|
||||
{ "large-address-aware", 0, LONG_OPT_LARGE_ADDRESS_AWARE },
|
||||
|
@ -483,6 +487,9 @@ static void option_callback( int optc, char *optarg )
|
|||
case LONG_OPT_CCCMD:
|
||||
cc_command = strarray_fromstring( optarg, " " );
|
||||
break;
|
||||
case LONG_OPT_DATA_ONLY:
|
||||
data_only = 1;
|
||||
break;
|
||||
case LONG_OPT_FAKE_MODULE:
|
||||
fake_module = 1;
|
||||
break;
|
||||
|
@ -637,6 +644,11 @@ int main(int argc, char **argv)
|
|||
output_fake_module( spec );
|
||||
break;
|
||||
}
|
||||
if (data_only)
|
||||
{
|
||||
output_data_module( spec );
|
||||
break;
|
||||
}
|
||||
if (!is_pe())
|
||||
{
|
||||
files = load_import_libs( files );
|
||||
|
|
|
@ -628,6 +628,12 @@ static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (data_only && !(odp->flags & FLAG_FORWARD))
|
||||
{
|
||||
error( "Only forwarded entry points are allowed in data-only mode\n" );
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ordinal != -1)
|
||||
{
|
||||
if (!ordinal)
|
||||
|
|
|
@ -796,6 +796,7 @@ static struct
|
|||
unsigned int file_align;
|
||||
unsigned int sec_count;
|
||||
unsigned int exp_count;
|
||||
unsigned int code_size;
|
||||
struct dir_data dir[16];
|
||||
struct sec_data sec[8];
|
||||
struct exp_data exp[8];
|
||||
|
@ -846,94 +847,97 @@ static unsigned int flush_output_to_section( const char *name, int dir_idx, unsi
|
|||
return sec->size;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* output_fake_module
|
||||
*
|
||||
* Build a fake binary module from a spec file.
|
||||
*/
|
||||
void output_fake_module( DLLSPEC *spec )
|
||||
static void output_pe_exports( DLLSPEC *spec )
|
||||
{
|
||||
static const unsigned char dll_code_section[] = { 0x31, 0xc0, /* xor %eax,%eax */
|
||||
0xc2, 0x0c, 0x00 }; /* ret $12 */
|
||||
unsigned int i, exp_count = get_exports_count( spec );
|
||||
unsigned int exp_rva = current_rva() + 40; /* sizeof(IMAGE_EXPORT_DIRECTORY) */
|
||||
unsigned int pos, str_rva = exp_rva + 4 * exp_count + 6 * spec->nb_names;
|
||||
|
||||
static const unsigned char exe_code_section[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
|
||||
0xc2, 0x04, 0x00 }; /* ret $4 */
|
||||
const unsigned int page_size = get_page_size();
|
||||
const unsigned int lfanew = 0x40 + sizeof(fakedll_signature);
|
||||
unsigned int i;
|
||||
if (!spec->nb_entry_points) return;
|
||||
|
||||
resolve_imports( spec );
|
||||
init_output_buffer();
|
||||
|
||||
pe.section_align = page_size;
|
||||
pe.file_align = 0x200;
|
||||
|
||||
/* .text section */
|
||||
if (spec->characteristics & IMAGE_FILE_DLL) put_data( dll_code_section, sizeof(dll_code_section) );
|
||||
else put_data( exe_code_section, sizeof(exe_code_section) );
|
||||
flush_output_to_section( ".text", -1, 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ );
|
||||
|
||||
if (spec->type == SPEC_WIN16)
|
||||
put_dword( 0 ); /* Characteristics */
|
||||
put_dword( hash_filename(spec->file_name) ); /* TimeDateStamp */
|
||||
put_word( 0 ); /* MajorVersion */
|
||||
put_word( 0 ); /* MinorVersion */
|
||||
put_dword( str_rva ); /* Name */
|
||||
put_dword( spec->base ); /* Base */
|
||||
put_dword( exp_count ); /* NumberOfFunctions */
|
||||
put_dword( spec->nb_names ); /* NumberOfNames */
|
||||
put_dword( exp_rva ); /* AddressOfFunctions */
|
||||
if (spec->nb_names)
|
||||
{
|
||||
add_export( current_rva(), "__wine_spec_dos_header" );
|
||||
|
||||
/* .rodata section */
|
||||
output_fake_module16( spec );
|
||||
if (spec->main_module)
|
||||
{
|
||||
add_export( current_rva() + output_buffer_pos, "__wine_spec_main_module" );
|
||||
put_data( spec->main_module, strlen(spec->main_module) + 1 );
|
||||
}
|
||||
flush_output_to_section( ".rodata", -1, 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );
|
||||
put_dword( exp_rva + 4 * exp_count ); /* AddressOfNames */
|
||||
put_dword( exp_rva + 4 * exp_count + 4 * spec->nb_names ); /* AddressOfNameOrdinals */
|
||||
}
|
||||
else
|
||||
{
|
||||
put_dword( 0 ); /* AddressOfNames */
|
||||
put_dword( 0 ); /* AddressOfNameOrdinals */
|
||||
}
|
||||
|
||||
if (pe.exp_count)
|
||||
/* functions */
|
||||
for (i = 0, pos = str_rva + strlen(spec->file_name) + 1; i < spec->nb_names; i++)
|
||||
pos += strlen( spec->names[i]->name ) + 1;
|
||||
for (i = spec->base; i <= spec->limit; i++)
|
||||
{
|
||||
/* .edata section */
|
||||
unsigned int exp_rva = current_rva() + 40; /* sizeof(IMAGE_EXPORT_DIRECTORY) */
|
||||
unsigned int pos, str_rva = exp_rva + 10 * pe.exp_count;
|
||||
|
||||
put_dword( 0 ); /* Characteristics */
|
||||
put_dword( hash_filename(spec->file_name) ); /* TimeDateStamp */
|
||||
put_word( 0 ); /* MajorVersion */
|
||||
put_word( 0 ); /* MinorVersion */
|
||||
put_dword( str_rva ); /* Name */
|
||||
put_dword( 1 ); /* Base */
|
||||
put_dword( pe.exp_count ); /* NumberOfFunctions */
|
||||
put_dword( pe.exp_count ); /* NumberOfNames */
|
||||
put_dword( exp_rva ); /* AddressOfFunctions */
|
||||
put_dword( exp_rva + 4 * pe.exp_count ); /* AddressOfNames */
|
||||
put_dword( exp_rva + 8 * pe.exp_count ); /* AddressOfNameOrdinals */
|
||||
|
||||
/* functions */
|
||||
for (i = 0; i < pe.exp_count; i++) put_dword( pe.exp[i].rva );
|
||||
/* names */
|
||||
for (i = 0, pos = str_rva + strlen(spec->file_name) + 1; i < pe.exp_count; i++)
|
||||
ORDDEF *odp = spec->ordinals[i];
|
||||
if (odp && (odp->flags & FLAG_FORWARD))
|
||||
{
|
||||
put_dword( pos );
|
||||
pos += strlen( pe.exp[i].name ) + 1;
|
||||
pos += strlen(odp->link_name) + 1;
|
||||
}
|
||||
/* ordinals */
|
||||
for (i = 0; i < pe.exp_count; i++) put_word( i );
|
||||
/* strings */
|
||||
put_data( spec->file_name, strlen(spec->file_name) + 1 );
|
||||
for (i = 0; i < pe.exp_count; i++) put_data( pe.exp[i].name, strlen(pe.exp[i].name) + 1 );
|
||||
flush_output_to_section( ".edata", 0 /* IMAGE_DIRECTORY_ENTRY_EXPORT */,
|
||||
else put_dword( 0 );
|
||||
}
|
||||
|
||||
/* names */
|
||||
for (i = 0, pos = str_rva + strlen(spec->file_name) + 1; i < spec->nb_names; i++)
|
||||
{
|
||||
put_dword( pos );
|
||||
pos += strlen(spec->names[i]->name) + 1;
|
||||
}
|
||||
|
||||
/* ordinals */
|
||||
for (i = 0; i < spec->nb_names; i++) put_word( spec->names[i]->ordinal - spec->base );
|
||||
|
||||
/* strings */
|
||||
put_data( spec->file_name, strlen(spec->file_name) + 1 );
|
||||
for (i = 0; i < spec->nb_names; i++)
|
||||
put_data( spec->names[i]->name, strlen(spec->names[i]->name) + 1 );
|
||||
|
||||
for (i = spec->base; i <= spec->limit; i++)
|
||||
{
|
||||
ORDDEF *odp = spec->ordinals[i];
|
||||
if (odp && (odp->flags & FLAG_FORWARD)) put_data( odp->link_name, strlen(odp->link_name) + 1 );
|
||||
}
|
||||
|
||||
flush_output_to_section( ".edata", 0 /* IMAGE_DIRECTORY_ENTRY_EXPORT */,
|
||||
0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );
|
||||
}
|
||||
|
||||
|
||||
static void output_pe_file( DLLSPEC *spec, const char signature[32] )
|
||||
{
|
||||
const unsigned int lfanew = 0x40 + 32;
|
||||
unsigned int i;
|
||||
|
||||
init_output_buffer();
|
||||
|
||||
/* .rsrc section */
|
||||
if (spec->type == SPEC_WIN32)
|
||||
{
|
||||
output_bin_resources( spec, current_rva() );
|
||||
flush_output_to_section( ".rsrc", 2 /* IMAGE_DIRECTORY_ENTRY_RESOURCE */,
|
||||
0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );
|
||||
}
|
||||
|
||||
/* .reloc section */
|
||||
put_dword( 0 ); /* VirtualAddress */
|
||||
put_dword( 0 ); /* Size */
|
||||
flush_output_to_section( ".reloc", 5 /* IMAGE_DIRECTORY_ENTRY_BASERELOC */,
|
||||
0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ );
|
||||
|
||||
if (spec->type == SPEC_WIN32)
|
||||
if (pe.code_size)
|
||||
{
|
||||
/* .rsrc section */
|
||||
output_bin_resources( spec, current_rva() );
|
||||
flush_output_to_section( ".rsrc", 2 /* IMAGE_DIRECTORY_ENTRY_RESOURCE */,
|
||||
0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );
|
||||
put_dword( 0 ); /* VirtualAddress */
|
||||
put_dword( 0 ); /* Size */
|
||||
flush_output_to_section( ".reloc", 5 /* IMAGE_DIRECTORY_ENTRY_BASERELOC */,
|
||||
0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ );
|
||||
}
|
||||
|
||||
put_word( 0x5a4d ); /* e_magic */
|
||||
|
@ -961,7 +965,7 @@ void output_fake_module( DLLSPEC *spec )
|
|||
put_dword( 0 );
|
||||
put_dword( lfanew );
|
||||
|
||||
put_data( fakedll_signature, sizeof(fakedll_signature) );
|
||||
put_data( signature, 32 );
|
||||
|
||||
put_dword( 0x4550 ); /* Signature */
|
||||
switch (target.cpu)
|
||||
|
@ -984,11 +988,11 @@ void output_fake_module( DLLSPEC *spec )
|
|||
IMAGE_NT_OPTIONAL_HDR32_MAGIC ); /* Magic */
|
||||
put_byte( 7 ); /* MajorLinkerVersion */
|
||||
put_byte( 10 ); /* MinorLinkerVersion */
|
||||
put_dword( pe.sec[0].size ); /* SizeOfCode */
|
||||
put_dword( pe.code_size ); /* SizeOfCode */
|
||||
put_dword( 0 ); /* SizeOfInitializedData */
|
||||
put_dword( 0 ); /* SizeOfUninitializedData */
|
||||
put_dword( pe.sec[0].rva ); /* AddressOfEntryPoint */
|
||||
put_dword( pe.sec[0].rva ); /* BaseOfCode */
|
||||
put_dword( pe.code_size ? pe.sec[0].rva : 0 ); /* AddressOfEntryPoint */
|
||||
put_dword( pe.code_size ? pe.sec[0].rva : 0 ); /* BaseOfCode */
|
||||
if (get_ptr_size() == 4) put_dword( 0 ); /* BaseOfData */
|
||||
put_pword( 0x10000000 ); /* ImageBase */
|
||||
put_dword( pe.section_align ); /* SectionAlignment */
|
||||
|
@ -1006,9 +1010,9 @@ void output_fake_module( DLLSPEC *spec )
|
|||
put_word( spec->subsystem ); /* Subsystem */
|
||||
put_word( spec->dll_characteristics ); /* DllCharacteristics */
|
||||
put_pword( (spec->stack_size ? spec->stack_size : 1024) * 1024 ); /* SizeOfStackReserve */
|
||||
put_pword( page_size ); /* SizeOfStackCommit */
|
||||
put_pword( pe.section_align ); /* SizeOfStackCommit */
|
||||
put_pword( (spec->heap_size ? spec->heap_size : 1024) * 1024 ); /* SizeOfHeapReserve */
|
||||
put_pword( page_size ); /* SizeOfHeapCommit */
|
||||
put_pword( pe.section_align ); /* SizeOfHeapCommit */
|
||||
put_dword( 0 ); /* LoaderFlags */
|
||||
put_dword( 16 ); /* NumberOfRvaAndSizes */
|
||||
|
||||
|
@ -1044,6 +1048,97 @@ void output_fake_module( DLLSPEC *spec )
|
|||
flush_output_buffer( output_file_name ? output_file_name : spec->file_name );
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* output_fake_module
|
||||
*
|
||||
* Build a fake binary module from a spec file.
|
||||
*/
|
||||
void output_fake_module( DLLSPEC *spec )
|
||||
{
|
||||
static const unsigned char dll_code_section[] = { 0x31, 0xc0, /* xor %eax,%eax */
|
||||
0xc2, 0x0c, 0x00 }; /* ret $12 */
|
||||
|
||||
static const unsigned char exe_code_section[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
|
||||
0xc2, 0x04, 0x00 }; /* ret $4 */
|
||||
unsigned int i;
|
||||
|
||||
resolve_imports( spec );
|
||||
pe.section_align = get_page_size();
|
||||
pe.file_align = 0x200;
|
||||
init_output_buffer();
|
||||
|
||||
/* .text section */
|
||||
if (spec->characteristics & IMAGE_FILE_DLL) put_data( dll_code_section, sizeof(dll_code_section) );
|
||||
else put_data( exe_code_section, sizeof(exe_code_section) );
|
||||
pe.code_size = output_buffer_pos;
|
||||
flush_output_to_section( ".text", -1, 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ );
|
||||
|
||||
if (spec->type == SPEC_WIN16)
|
||||
{
|
||||
add_export( current_rva(), "__wine_spec_dos_header" );
|
||||
|
||||
/* .rdata section */
|
||||
output_fake_module16( spec );
|
||||
if (spec->main_module)
|
||||
{
|
||||
add_export( current_rva() + output_buffer_pos, "__wine_spec_main_module" );
|
||||
put_data( spec->main_module, strlen(spec->main_module) + 1 );
|
||||
}
|
||||
flush_output_to_section( ".rdata", -1, 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );
|
||||
}
|
||||
|
||||
/* .edata section */
|
||||
if (pe.exp_count)
|
||||
{
|
||||
unsigned int exp_rva = current_rva() + 40; /* sizeof(IMAGE_EXPORT_DIRECTORY) */
|
||||
unsigned int pos, str_rva = exp_rva + 10 * pe.exp_count;
|
||||
|
||||
put_dword( 0 ); /* Characteristics */
|
||||
put_dword( hash_filename(spec->file_name) ); /* TimeDateStamp */
|
||||
put_word( 0 ); /* MajorVersion */
|
||||
put_word( 0 ); /* MinorVersion */
|
||||
put_dword( str_rva ); /* Name */
|
||||
put_dword( 1 ); /* Base */
|
||||
put_dword( pe.exp_count ); /* NumberOfFunctions */
|
||||
put_dword( pe.exp_count ); /* NumberOfNames */
|
||||
put_dword( exp_rva ); /* AddressOfFunctions */
|
||||
put_dword( exp_rva + 4 * pe.exp_count ); /* AddressOfNames */
|
||||
put_dword( exp_rva + 8 * pe.exp_count ); /* AddressOfNameOrdinals */
|
||||
|
||||
/* functions */
|
||||
for (i = 0; i < pe.exp_count; i++) put_dword( pe.exp[i].rva );
|
||||
/* names */
|
||||
for (i = 0, pos = str_rva + strlen(spec->file_name) + 1; i < pe.exp_count; i++)
|
||||
{
|
||||
put_dword( pos );
|
||||
pos += strlen( pe.exp[i].name ) + 1;
|
||||
}
|
||||
/* ordinals */
|
||||
for (i = 0; i < pe.exp_count; i++) put_word( i );
|
||||
/* strings */
|
||||
put_data( spec->file_name, strlen(spec->file_name) + 1 );
|
||||
for (i = 0; i < pe.exp_count; i++) put_data( pe.exp[i].name, strlen(pe.exp[i].name) + 1 );
|
||||
flush_output_to_section( ".edata", 0 /* IMAGE_DIRECTORY_ENTRY_EXPORT */,
|
||||
0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );
|
||||
}
|
||||
|
||||
output_pe_file( spec, fakedll_signature );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_data_module
|
||||
*
|
||||
* Build a data-only module from a spec file.
|
||||
*/
|
||||
void output_data_module( DLLSPEC *spec )
|
||||
{
|
||||
pe.section_align = pe.file_align = get_page_size();
|
||||
|
||||
output_pe_exports( spec );
|
||||
output_pe_file( spec, builtin_signature );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_def_file
|
||||
|
|
|
@ -644,7 +644,7 @@ DLLSPEC *alloc_dll_spec(void)
|
|||
spec->type = SPEC_WIN32;
|
||||
spec->base = MAX_ORDINALS;
|
||||
spec->characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
|
||||
spec->subsystem = 0;
|
||||
spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
||||
spec->subsystem_major = 4;
|
||||
spec->subsystem_minor = 0;
|
||||
spec->syscall_table = 0;
|
||||
|
|
|
@ -89,6 +89,11 @@ like \fBas\fR, \fBnm\fR and \fBld\fR.
|
|||
Specify the C compiler to use to compile assembly files; the default
|
||||
is to instead use the assembler specified with \fB--as-cmd\fR.
|
||||
.TP
|
||||
.B \--data-only
|
||||
Build a module that contains only data and resources, and no
|
||||
executable code. With this option, \fBwinebuild\fR directly outputs a
|
||||
PE file, instead of an assembly or object file.
|
||||
.TP
|
||||
.BI \-d,\ --delay-lib= name
|
||||
Set the delayed import mode for the specified library, which must be
|
||||
one of the libraries imported with the \fB-l\fR option. Delayed mode
|
||||
|
|
Loading…
Reference in New Issue