Module: wine Branch: master Commit: 6c4046fef1fb4a78cfb649de34af7770ffe05024 URL: https://source.winehq.org/git/wine.git/?a=commit;h=6c4046fef1fb4a78cfb649de3...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Apr 16 12:21:23 2020 +0200
winebuild: Add --fixup-ctors option to allow intercepting constructors in .so files.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
tools/winebuild/build.h | 1 + tools/winebuild/main.c | 13 +++- tools/winebuild/spec32.c | 159 +++++++++++++++++++++++++++++++++++++++ tools/winebuild/winebuild.man.in | 14 +++- 4 files changed, 182 insertions(+), 5 deletions(-)
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 65493ec37f..b30785b74a 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -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 ); diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index db8587c3bd..d973a4e973 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -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 ); diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 631a467a5e..6e6f502e99 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -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 ); + } +} diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in index 29a17484ad..9c91c1a504 100644 --- a/tools/winebuild/winebuild.man.in +++ b/tools/winebuild/winebuild.man.in @@ -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