Alexandre Julliard : winebuild: Add --fixup-ctors option to allow intercepting constructors in .so files.
Alexandre Julliard
julliard at winehq.org
Thu Apr 16 16:45:12 CDT 2020
Module: wine
Branch: master
Commit: 6c4046fef1fb4a78cfb649de34af7770ffe05024
URL: https://source.winehq.org/git/wine.git/?a=commit;h=6c4046fef1fb4a78cfb649de34af7770ffe05024
Author: Alexandre Julliard <julliard at 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 at 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
More information about the wine-cvs
mailing list