winebuild: Add --fixup-ctors option to allow intercepting constructors in .so files.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Alexandre Julliard 2020-04-16 12:21:23 +02:00
parent 3935acd4da
commit 6c4046fef1
4 changed files with 182 additions and 5 deletions

View File

@ -321,6 +321,7 @@ extern void output_fake_module16( DLLSPEC *spec16 );
extern void output_res_o_file( DLLSPEC *spec );
extern void output_asm_relays16(void);
extern void make_builtin_files( char *argv[] );
extern void fixup_constructors( char *argv[] );
extern void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 );
extern int parse_spec_file( FILE *file, DLLSPEC *spec );

View File

@ -115,6 +115,7 @@ enum exec_mode_values
MODE_IMPLIB,
MODE_STATICLIB,
MODE_BUILTIN,
MODE_FIXUP_CTORS,
MODE_RESOURCES
};
@ -301,8 +302,9 @@ static const char usage_str[] =
" --exe Build an executable from object files\n"
" --implib Build an import library\n"
" --staticlib Build a static library\n"
" --builtin Mark a library as a Wine builtin\n"
" --resources Build a .o or .res file for the resource files\n\n"
" --builtin Mark a library as a Wine builtin\n"
" --fixup-ctors Fixup the constructors data after the module has been built\n"
"The mode options are mutually exclusive; you must specify one and only one.\n\n";
enum long_options_values
@ -316,6 +318,7 @@ enum long_options_values
LONG_OPT_CCCMD,
LONG_OPT_EXTERNAL_SYMS,
LONG_OPT_FAKE_MODULE,
LONG_OPT_FIXUP_CTORS,
LONG_OPT_LARGE_ADDRESS_AWARE,
LONG_OPT_LDCMD,
LONG_OPT_NMCMD,
@ -341,6 +344,7 @@ static const struct option long_options[] =
{ "cc-cmd", 1, 0, LONG_OPT_CCCMD },
{ "external-symbols", 0, 0, LONG_OPT_EXTERNAL_SYMS },
{ "fake-module", 0, 0, LONG_OPT_FAKE_MODULE },
{ "fixup-ctors", 0, 0, LONG_OPT_FIXUP_CTORS },
{ "large-address-aware", 0, 0, LONG_OPT_LARGE_ADDRESS_AWARE },
{ "ld-cmd", 1, 0, LONG_OPT_LDCMD },
{ "nm-cmd", 1, 0, LONG_OPT_NMCMD },
@ -511,6 +515,9 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
case LONG_OPT_BUILTIN:
set_exec_mode( MODE_BUILTIN );
break;
case LONG_OPT_FIXUP_CTORS:
set_exec_mode( MODE_FIXUP_CTORS );
break;
case LONG_OPT_ASCMD:
as_command = strarray_fromstring( optarg, " " );
break;
@ -701,6 +708,10 @@ int main(int argc, char **argv)
if (!argv[0]) fatal_error( "missing file argument for --builtin option\n" );
make_builtin_files( argv );
break;
case MODE_FIXUP_CTORS:
if (!argv[0]) fatal_error( "missing file argument for --fixup-ctors option\n" );
fixup_constructors( argv );
break;
case MODE_RESOURCES:
load_resources( argv, spec );
output_res_o_file( spec );

View File

@ -1095,3 +1095,162 @@ void make_builtin_files( char *argv[] )
close( fd );
}
}
static void fixup_elf32( const char *name, int fd, void *header, size_t header_size )
{
struct
{
unsigned char e_ident[16];
unsigned short e_type;
unsigned short e_machine;
unsigned int e_version;
unsigned int e_entry;
unsigned int e_phoff;
unsigned int e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shstrndx;
} *elf = header;
struct
{
unsigned int p_type;
unsigned int p_offset;
unsigned int p_vaddr;
unsigned int p_paddr;
unsigned int p_filesz;
unsigned int p_memsz;
unsigned int p_flags;
unsigned int p_align;
} *phdr;
struct
{
unsigned int d_tag;
unsigned int d_val;
} *dyn;
unsigned int i, size;
if (header_size < sizeof(*elf)) return;
if (elf->e_ident[6] != 1 /* EV_CURRENT */) return;
size = elf->e_phnum * elf->e_phentsize;
phdr = xmalloc( size );
lseek( fd, elf->e_phoff, SEEK_SET );
if (read( fd, phdr, size ) != size) return;
for (i = 0; i < elf->e_phnum; i++)
{
if (phdr->p_type == 2 /* PT_DYNAMIC */ ) break;
phdr = (void *)((char *)phdr + elf->e_phentsize);
}
if (i == elf->e_phnum) return;
dyn = xmalloc( phdr->p_filesz );
lseek( fd, phdr->p_offset, SEEK_SET );
if (read( fd, dyn, phdr->p_filesz ) != phdr->p_filesz) return;
for (i = 0; i < phdr->p_filesz / sizeof(*dyn) && dyn[i].d_tag; i++)
{
switch (dyn[i].d_tag)
{
case 25: dyn[i].d_tag = 0x60009990; break; /* DT_INIT_ARRAY */
case 27: dyn[i].d_tag = 0x60009991; break; /* DT_INIT_ARRAYSZ */
case 12: dyn[i].d_tag = 0x60009992; break; /* DT_INIT */
}
}
lseek( fd, phdr->p_offset, SEEK_SET );
write( fd, dyn, phdr->p_filesz );
}
static void fixup_elf64( const char *name, int fd, void *header, size_t header_size )
{
struct
{
unsigned char e_ident[16];
unsigned short e_type;
unsigned short e_machine;
unsigned int e_version;
unsigned __int64 e_entry;
unsigned __int64 e_phoff;
unsigned __int64 e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shstrndx;
} *elf = header;
struct
{
unsigned int p_type;
unsigned int p_flags;
unsigned __int64 p_offset;
unsigned __int64 p_vaddr;
unsigned __int64 p_paddr;
unsigned __int64 p_filesz;
unsigned __int64 p_memsz;
unsigned __int64 p_align;
} *phdr;
struct
{
unsigned __int64 d_tag;
unsigned __int64 d_val;
} *dyn;
unsigned int i, size;
if (header_size < sizeof(*elf)) return;
if (elf->e_ident[6] != 1 /* EV_CURRENT */) return;
size = elf->e_phnum * elf->e_phentsize;
phdr = xmalloc( size );
lseek( fd, elf->e_phoff, SEEK_SET );
if (read( fd, phdr, size ) != size) return;
for (i = 0; i < elf->e_phnum; i++)
{
if (phdr->p_type == 2 /* PT_DYNAMIC */ ) break;
phdr = (void *)((char *)phdr + elf->e_phentsize);
}
if (i == elf->e_phnum) return;
dyn = xmalloc( phdr->p_filesz );
lseek( fd, phdr->p_offset, SEEK_SET );
if (read( fd, dyn, phdr->p_filesz ) != phdr->p_filesz) return;
for (i = 0; i < phdr->p_filesz / sizeof(*dyn) && dyn[i].d_tag; i++)
{
switch (dyn[i].d_tag)
{
case 25: dyn[i].d_tag = 0x60009990; break; /* DT_INIT_ARRAY */
case 27: dyn[i].d_tag = 0x60009991; break; /* DT_INIT_ARRAYSZ */
case 12: dyn[i].d_tag = 0x60009992; break; /* DT_INIT */
}
}
lseek( fd, phdr->p_offset, SEEK_SET );
write( fd, dyn, phdr->p_filesz );
}
/*******************************************************************
* fixup_constructors
*/
void fixup_constructors( char *argv[] )
{
int i, fd, size;
unsigned int header[64];
for (i = 0; argv[i]; i++)
{
if ((fd = open( argv[i], O_RDWR | O_BINARY )) == -1) fatal_perror( "Cannot open %s", argv[i] );
size = read( fd, &header, sizeof(header) );
if (size > 5)
{
if (!memcmp( header, "\177ELF\001", 5 )) fixup_elf32( argv[i], fd, header, size );
else if (!memcmp( header, "\177ELF\002", 5 )) fixup_elf64( argv[i], fd, header, size );
}
close( fd );
}
}

View File

@ -54,16 +54,22 @@ in .delay.a, a delayed import library is built.
.BI \--staticlib
Build a .a static library from object files.
.TP
.BI \--builtin
Mark a PE module as a Wine builtin module, by adding the "Wine builtin
DLL" signature string after the DOS header.
.TP
.B \--resources
Generate a .o file containing all the input resources. This is useful
when building with a PE compiler, since the PE binutils cannot handle
multiple resource files as input. For a standard Unix build, the
resource files are automatically included when building the spec file,
so there's no need for an intermediate .o file.
.TP
.BI \--builtin
Mark a PE module as a Wine builtin module, by adding the "Wine builtin
DLL" signature string after the DOS header.
.TP
.BI \--fixup-ctors
Fixup constructors after a module has been built. This should be done
on the final .so module if its code contains constructors, to ensure
that Wine has a chance to initialize the module before the
constructors are executed.
.SH OPTIONS
.TP
.BI \--as-cmd= as-command