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