From 06aedadd2d7a6f0333e050806ce1d368e8a5fece Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Mon, 15 May 2017 02:05:49 +0200
Subject: [PATCH] winebuild: Use multipass label system to generate fake dlls.

---
 tools/winebuild/build.h  |   6 ++
 tools/winebuild/res32.c  |   1 -
 tools/winebuild/spec32.c | 145 +++++++++++++++++++++++++++--------------------
 tools/winebuild/utils.c  |  92 ++++++++++++++++++++++++++++++
 4 files changed, 180 insertions(+), 64 deletions(-)

diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index 0b7cb37..c1703de 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -338,6 +338,7 @@ extern size_t input_buffer_pos;
 extern size_t input_buffer_size;
 extern unsigned char *output_buffer;
 extern size_t output_buffer_pos;
+extern size_t output_buffer_rva;
 extern size_t output_buffer_size;
 
 extern void init_input_buffer( const char *file );
@@ -353,6 +354,11 @@ extern void put_dword( unsigned int val );
 extern void put_qword( unsigned int val );
 extern void put_pword( unsigned int val );
 extern void align_output( unsigned int align );
+extern void align_output_rva( unsigned int file_align, unsigned int rva_align );
+extern size_t label_pos( const char *name );
+extern size_t label_rva( const char *name );
+extern size_t label_rva_align( const char *name );
+extern void put_label( const char *name );
 
 /* global variables */
 
diff --git a/tools/winebuild/res32.c b/tools/winebuild/res32.c
index bd55bb2..d932901 100644
--- a/tools/winebuild/res32.c
+++ b/tools/winebuild/res32.c
@@ -539,7 +539,6 @@ void output_bin_resources( DLLSPEC *spec, unsigned int start_rva )
     if (!spec->nb_resources) return;
 
     tree = build_resource_tree( spec, &data_offset );
-    init_output_buffer();
 
     /* output the resource directories */
 
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index f9b6a72..f176519 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -823,11 +823,11 @@ void output_pe_module( DLLSPEC *spec )
 
 
 /*******************************************************************
- *         output_fake_module
+ *         output_fake_module_pass
  *
- * Build a fake binary module from a spec file.
+ * Helper to create a fake binary module from a spec file.
  */
-void output_fake_module( DLLSPEC *spec )
+static void output_fake_module_pass( DLLSPEC *spec )
 {
     static const unsigned char dll_code_section[] = { 0x31, 0xc0,          /* xor %eax,%eax */
                                                       0xc2, 0x0c, 0x00 };  /* ret $12 */
@@ -839,22 +839,8 @@ void output_fake_module( DLLSPEC *spec )
     const unsigned int page_size = get_page_size();
     const unsigned int section_align = page_size;
     const unsigned int file_align = 0x200;
-    const unsigned int reloc_size = 8;
     const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
     const unsigned int nb_sections = 2 + (spec->nb_resources != 0);
-    const unsigned int text_size = (spec->characteristics & IMAGE_FILE_DLL) ?
-                                    sizeof(dll_code_section) : sizeof(exe_code_section);
-    unsigned char *resources;
-    unsigned int resources_size;
-    unsigned int image_size = 3 * section_align;
-
-    resolve_imports( spec );
-    output_bin_resources( spec, 3 * section_align );
-    resources = output_buffer;
-    resources_size = output_buffer_pos;
-    if (resources_size) image_size += (resources_size + section_align - 1) & ~(section_align - 1);
-
-    init_output_buffer();
 
     put_word( 0x5a4d );       /* e_magic */
     put_word( 0x40 );         /* e_cblp */
@@ -882,7 +868,7 @@ void output_fake_module( DLLSPEC *spec )
     put_dword( lfanew );
 
     put_data( fakedll_signature, sizeof(fakedll_signature) );
-    align_output( 16 );
+    align_output_rva( 16, 16 );
 
     put_dword( 0x4550 );                             /* Signature */
     switch(target_cpu)
@@ -906,11 +892,11 @@ void output_fake_module( DLLSPEC *spec )
               IMAGE_NT_OPTIONAL_HDR32_MAGIC );       /* Magic */
     put_byte(  7 );                                  /* MajorLinkerVersion */
     put_byte(  10 );                                 /* MinorLinkerVersion */
-    put_dword( text_size );                          /* SizeOfCode */
+    put_dword( label_pos("text_end") - label_pos("text_start") ); /* SizeOfCode */
     put_dword( 0 );                                  /* SizeOfInitializedData */
     put_dword( 0 );                                  /* SizeOfUninitializedData */
-    put_dword( section_align );                      /* AddressOfEntryPoint */
-    put_dword( section_align );                      /* BaseOfCode */
+    put_dword( label_rva("entrypoint") );            /* AddressOfEntryPoint */
+    put_dword( label_rva("text_start") );            /* BaseOfCode */
     if (get_ptr_size() == 4) put_dword( 0 );         /* BaseOfData */
     put_pword( 0x10000000 );                         /* ImageBase */
     put_dword( section_align );                      /* SectionAlignment */
@@ -922,8 +908,8 @@ void output_fake_module( DLLSPEC *spec )
     put_word( spec->subsystem_major );               /* MajorSubsystemVersion */
     put_word( spec->subsystem_minor );               /* MinorSubsystemVersion */
     put_dword( 0 );                                  /* Win32VersionValue */
-    put_dword( image_size );                         /* SizeOfImage */
-    put_dword( file_align );                         /* SizeOfHeaders */
+    put_dword( label_rva_align("file_end") );        /* SizeOfImage */
+    put_dword( label_pos("header_end") );            /* SizeOfHeaders */
     put_dword( 0 );                                  /* CheckSum */
     put_word( spec->subsystem );                     /* Subsystem */
     put_word( spec->dll_characteristics );           /* DllCharacteristics */
@@ -936,10 +922,10 @@ void output_fake_module( DLLSPEC *spec )
 
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
-    if (resources_size)   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
+    if (spec->nb_resources)           /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
     {
-        put_dword( 3 * section_align );
-        put_dword( resources_size );
+        put_dword( label_rva("res_start") );
+        put_dword( label_pos("res_end") - label_pos("res_start") );
     }
     else
     {
@@ -949,8 +935,8 @@ void output_fake_module( DLLSPEC *spec )
 
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] */
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] */
-    put_dword( 2 * section_align );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
-    put_dword( reloc_size );
+    put_dword( label_rva("reloc_start") ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
+    put_dword( label_pos("reloc_end") - label_pos("reloc_start") );
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] */
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT] */
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR] */
@@ -963,62 +949,95 @@ void output_fake_module( DLLSPEC *spec )
     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[15] */
 
     /* .text section */
-    put_data( ".text\0\0", 8 );    /* Name */
-    put_dword( section_align );    /* VirtualSize */
-    put_dword( section_align );    /* VirtualAddress */
-    put_dword( text_size );        /* SizeOfRawData */
-    put_dword( file_align );       /* PointerToRawData */
-    put_dword( 0 );                /* PointerToRelocations */
-    put_dword( 0 );                /* PointerToLinenumbers */
-    put_word( 0 );                 /* NumberOfRelocations */
-    put_word( 0 );                 /* NumberOfLinenumbers */
-    put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics  */
+    put_data( ".text\0\0", 8 );                                           /* Name */
+    put_dword( label_rva_align("text_end") - label_rva("text_start") );   /* VirtualSize */
+    put_dword( label_rva("text_start") );                                 /* VirtualAddress */
+    put_dword( label_pos("text_end") - label_pos("text_start") );         /* SizeOfRawData */
+    put_dword( label_pos("text_start") );                                 /* PointerToRawData */
+    put_dword( 0 );                                                       /* PointerToRelocations */
+    put_dword( 0 );                                                       /* PointerToLinenumbers */
+    put_word( 0 );                                                        /* NumberOfRelocations */
+    put_word( 0 );                                                        /* NumberOfLinenumbers */
+    put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ );          /* Characteristics  */
 
     /* .reloc section */
-    put_data( ".reloc\0", 8 );     /* Name */
-    put_dword( section_align );    /* VirtualSize */
-    put_dword( 2 * section_align );/* VirtualAddress */
-    put_dword( reloc_size );       /* SizeOfRawData */
-    put_dword( 2 * file_align );   /* PointerToRawData */
-    put_dword( 0 );                /* PointerToRelocations */
-    put_dword( 0 );                /* PointerToLinenumbers */
-    put_word( 0 );                 /* NumberOfRelocations */
-    put_word( 0 );                 /* NumberOfLinenumbers */
+    put_data( ".reloc\0", 8 );                                            /* Name */
+    put_dword( label_rva_align("reloc_end") - label_rva("reloc_start") ); /* VirtualSize */
+    put_dword( label_rva("reloc_start") );                                /* VirtualAddress */
+    put_dword( label_pos("reloc_end") - label_pos("reloc_start") );       /* SizeOfRawData */
+    put_dword( label_pos("reloc_start") );                                /* PointerToRawData */
+    put_dword( 0 );                                                       /* PointerToRelocations */
+    put_dword( 0 );                                                       /* PointerToLinenumbers */
+    put_word( 0 );                                                        /* NumberOfRelocations */
+    put_word( 0 );                                                        /* NumberOfLinenumbers */
     put_dword( 0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ ); /* Characteristics */
 
     /* .rsrc section */
-    if (resources_size)
+    if (spec->nb_resources)
     {
-        put_data( ".rsrc\0\0", 8 );    /* Name */
-        put_dword( (resources_size + section_align - 1) & ~(section_align - 1) ); /* VirtualSize */
-        put_dword( 3 * section_align );/* VirtualAddress */
-        put_dword( resources_size );   /* SizeOfRawData */
-        put_dword( 3 * file_align );   /* PointerToRawData */
-        put_dword( 0 );                /* PointerToRelocations */
-        put_dword( 0 );                /* PointerToLinenumbers */
-        put_word( 0 );                 /* NumberOfRelocations */
-        put_word( 0 );                 /* NumberOfLinenumbers */
-        put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ ); /* Characteristics */
+        put_data( ".rsrc\0\0", 8 );                                       /* Name */
+        put_dword( label_rva_align("res_end") - label_rva("res_start") ); /* VirtualSize */
+        put_dword( label_rva("res_start") );                              /* VirtualAddress */
+        put_dword( label_pos("res_end") - label_pos("res_start") );       /* SizeOfRawData */
+        put_dword( label_pos("res_start") );                              /* PointerToRawData */
+        put_dword( 0 );                                                   /* PointerToRelocations */
+        put_dword( 0 );                                                   /* PointerToLinenumbers */
+        put_word( 0 );                                                    /* NumberOfRelocations */
+        put_word( 0 );                                                    /* NumberOfLinenumbers */
+        put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ );      /* Characteristics */
     }
 
+    align_output_rva( file_align, file_align );
+    put_label( "header_end" );
+
     /* .text contents */
-    align_output( file_align );
+    align_output_rva( file_align, section_align );
+    put_label( "text_start" );
+    put_label( "entrypoint" );
     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) );
+    put_label( "text_end" );
 
     /* .reloc contents */
-    align_output( file_align );
+    align_output_rva( file_align, section_align );
+    put_label( "reloc_start" );
     put_dword( 0 );   /* VirtualAddress */
     put_dword( 0 );   /* SizeOfBlock */
+    put_label( "reloc_end" );
 
     /* .rsrc contents */
-    if (resources_size)
+    if (spec->nb_resources)
     {
-        align_output( file_align );
-        put_data( resources, resources_size );
+        align_output_rva( file_align, section_align );
+        put_label( "res_start" );
+        output_bin_resources( spec, label_rva("res_start") );
+        put_label( "res_end" );
     }
+
+    put_label( "file_end" );
+}
+
+
+/*******************************************************************
+ *         output_fake_module
+ *
+ * Build a fake binary module from a spec file.
+ */
+void output_fake_module( DLLSPEC *spec )
+{
+    resolve_imports( spec );
+
+    /* First pass */
+    init_output_buffer();
+    output_fake_module_pass( spec );
+
+    /* Second pass */
+    output_buffer_pos = 0;
+    output_buffer_rva = 0;
+    output_fake_module_pass( spec );
+
     flush_output_buffer();
 }
 
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c
index 355c5ab..26ef44e 100644
--- a/tools/winebuild/utils.c
+++ b/tools/winebuild/utils.c
@@ -34,6 +34,7 @@
 # include <sys/stat.h>
 #endif
 
+#include "wine/list.h"
 #include "build.h"
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -522,8 +523,86 @@ size_t input_buffer_pos;
 size_t input_buffer_size;
 unsigned char *output_buffer;
 size_t output_buffer_pos;
+size_t output_buffer_rva;
 size_t output_buffer_size;
 
+struct label
+{
+    struct list entry;
+    const char *name;
+    size_t pos;
+    size_t rva;
+};
+
+static struct list labels = LIST_INIT( labels );
+
+struct label *get_label( const char *name )
+{
+    struct label *label;
+
+    LIST_FOR_EACH_ENTRY( label, &labels, struct label, entry )
+    {
+        if (!strcmp(name, label->name))
+            return label;
+    }
+
+    label = xmalloc( sizeof(*label) );
+    label->name = name;
+    label->pos = 0;
+    label->rva = 0;
+
+    list_add_tail( &labels, &label->entry );
+
+    return label;
+}
+
+size_t label_pos( const char *name )
+{
+    struct label *label = get_label( name );
+    return label->pos;
+}
+
+size_t label_rva( const char *name )
+{
+    struct label *label = get_label( name );
+    return label->rva;
+}
+
+size_t label_rva_align( const char *name )
+{
+    const unsigned int page_size = get_page_size();
+    size_t rva = label_rva( name );
+    size_t size = page_size - (rva % page_size);
+
+    if (size != page_size) rva += size;
+    return rva;
+}
+
+void put_label( const char *name )
+{
+    struct label *label = get_label( name );
+
+    if (label->pos || label->rva)
+    {
+        assert( label->pos == output_buffer_pos );
+        assert( label->rva == output_buffer_rva );
+    }
+
+    label->pos = output_buffer_pos;
+    label->rva = output_buffer_rva;
+}
+
+void free_labels( void )
+{
+    struct label *label, *label2;
+
+    LIST_FOR_EACH_ENTRY_SAFE( label, label2, &labels, struct label, entry )
+    {
+        list_remove( &label->entry );
+        free( label );
+    }
+}
+
 static void check_output_buffer_space( size_t size )
 {
     if (output_buffer_pos + size >= output_buffer_size)
@@ -555,7 +634,9 @@ void init_output_buffer(void)
 {
     output_buffer_size = 1024;
     output_buffer_pos = 0;
+    output_buffer_rva = 0;
     output_buffer = xmalloc( output_buffer_size );
+    free_labels();
 }
 
 void flush_output_buffer(void)
@@ -565,6 +646,7 @@ void flush_output_buffer(void)
         fatal_error( "Error writing to %s\n", output_file_name );
     close_output_file();
     free( output_buffer );
+    free_labels();
 }
 
 unsigned char get_byte(void)
@@ -604,12 +686,14 @@ void put_data( const void *data, size_t size )
     check_output_buffer_space( size );
     memcpy( output_buffer + output_buffer_pos, data, size );
     output_buffer_pos += size;
+    output_buffer_rva += size;
 }
 
 void put_byte( unsigned char val )
 {
     check_output_buffer_space( 1 );
     output_buffer[output_buffer_pos++] = val;
+    output_buffer_rva++;
 }
 
 void put_word( unsigned short val )
@@ -656,6 +740,14 @@ void align_output( unsigned int align )
     output_buffer_pos += size;
 }
 
+void align_output_rva( unsigned int file_align, unsigned int rva_align )
+{
+    size_t size = rva_align - (output_buffer_rva % rva_align);
+
+    if (size != rva_align) output_buffer_rva += size;
+    align_output( file_align );
+}
+
 /* output a standard header for generated files */
 void output_standard_file_header(void)
 {
-- 
1.9.1

