static void output_bin_data( lan_blk_t *lbp ) { unsigned int offs = 4 * (lbp->nblk * 3 + 1); int i, j, k; put_dword( lbp->nblk ); /* NBlocks */ for (i = 0; i < lbp->nblk; i++) { put_dword( lbp->blks[i].idlo ); /* Lo */ put_dword( lbp->blks[i].idhi ); /* Hi */ put_dword( offs ); /* Offs */ offs += lbp->blks[i].size; } for (i = 0; i < lbp->nblk; i++) { block_t *blk = &lbp->blks[i]; for (j = 0; j < blk->nmsg; j++) { int len = (2 * blk->msgs[j]->len + 3) & ~3; put_word( len + 4 ); put_word( 1 ); for (k = 0; k < blk->msgs[j]->len; k++) put_word( blk->msgs[j]->msg[k] ); align_output( 4 ); } } }
void write_res_file( const char *name ) { lan_blk_t *lbp; int i, j; init_output_buffer(); put_dword( 0 ); /* ResSize */ put_dword( 32 ); /* HeaderSize */ put_word( 0xffff ); /* ResType */ put_word( 0x0000 ); put_word( 0xffff ); /* ResName */ put_word( 0x0000 ); put_dword( 0 ); /* DataVersion */ put_word( 0 ); /* Memory options */ put_word( 0 ); /* Language */ put_dword( 0 ); /* Version */ put_dword( 0 ); /* Characteristics */ for (lbp = lanblockhead; lbp; lbp = lbp->next) { unsigned int data_size = 4 * (lbp->nblk * 3 + 1); unsigned int header_size = 5 * sizeof(unsigned int) + 6 * sizeof(unsigned short); for (i = 0; i < lbp->nblk; i++) { block_t *blk = &lbp->blks[i]; for (j = 0; j < blk->nmsg; j++) data_size += 4 + ((blk->msgs[j]->len * 2 + 3) & ~3); } put_dword( data_size ); /* ResSize */ put_dword( header_size ); /* HeaderSize */ put_word( 0xffff ); /* ResType */ put_word( 0x000b /*RT_MESSAGETABLE*/ ); put_word( 0xffff ); /* ResName */ put_word( 0x0001 ); align_output( 4 ); put_dword( 0 ); /* DataVersion */ put_word( 0x30 ); /* Memory options */ put_word( lbp->lan ); /* Language */ put_dword( lbp->version ); /* Version */ put_dword( 0 ); /* Characteristics */ output_bin_data( lbp ); } flush_output_buffer( name ); }
/* output the resources into a .o file */ void output_res_o_file( DLLSPEC *spec ) { unsigned int i; char *res_file = NULL; int fd, err; if (!spec->nb_resources) fatal_error( "--resources mode needs at least one resource file as input\n" ); if (!output_file_name) fatal_error( "No output file name specified\n" ); byte_swapped = 0; init_output_buffer(); put_dword( 0 ); /* ResSize */ put_dword( 32 ); /* HeaderSize */ put_word( 0xffff ); /* ResType */ put_word( 0x0000 ); put_word( 0xffff ); /* ResName */ put_word( 0x0000 ); put_dword( 0 ); /* DataVersion */ put_word( 0 ); /* Memory options */ put_word( 0 ); /* Language */ put_dword( 0 ); /* Version */ put_dword( 0 ); /* Characteristics */ for (i = 0; i < spec->nb_resources; i++) { unsigned int header_size = get_resource_header_size( &spec->resources[i] ); put_dword( spec->resources[i].data_size ); put_dword( (header_size + 3) & ~3 ); put_string( &spec->resources[i].type ); put_string( &spec->resources[i].name ); align_output( 4 ); put_dword( 0 ); put_word( spec->resources[i].mem_options ); put_word( spec->resources[i].lang ); put_dword( 0 ); put_dword( 0 ); put_data( spec->resources[i].data, spec->resources[i].data_size ); align_output( 4 ); } /* if the output file name is a .res too, don't run the results through windres */ if (strendswith( output_file_name, ".res")) { flush_output_buffer(); return; } res_file = get_temp_file_name( output_file_name, ".res" ); if ((fd = open( res_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600 )) == -1) fatal_error( "Cannot create %s\n", res_file ); if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos) fatal_error( "Error writing to %s\n", res_file ); close( fd ); free( output_buffer ); if (res_file) { char *prog = find_tool( "windres", NULL ); char *cmd = xmalloc( strlen(prog) + strlen(res_file) + strlen(output_file_name) + 9 ); sprintf( cmd, "%s -i %s -o %s", prog, res_file, output_file_name ); if (verbose) fprintf( stderr, "%s\n", cmd ); err = system( cmd ); if (err) fatal_error( "%s failed with status %d\n", prog, err ); free( cmd ); free( prog ); } output_file_name = NULL; /* so we don't try to assemble it */ }
/* output the resource definitions in binary format */ void output_bin_resources( DLLSPEC *spec, unsigned int start_rva ) { int k, nb_id_types; unsigned int i, n, data_offset; struct res_tree *tree; struct res_type *type; struct res_name *name; const struct resource *res; if (!spec->nb_resources) return; tree = build_resource_tree( spec, &data_offset ); init_output_buffer(); /* output the resource directories */ for (i = nb_id_types = 0, type = tree->types; i < tree->nb_types; i++, type++) if (!type->type->str) nb_id_types++; output_bin_res_dir( tree->nb_types - nb_id_types, nb_id_types ); /* dump the type directory */ for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) { put_dword( type->name_offset ); put_dword( type->dir_offset | 0x80000000 ); } /* dump the names and languages directories */ for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) { output_bin_res_dir( type->nb_names - type->nb_id_names, type->nb_id_names ); for (n = 0, name = type->names; n < type->nb_names; n++, name++) { put_dword( name->name_offset ); put_dword( name->dir_offset | 0x80000000 ); } for (n = 0, name = type->names; n < type->nb_names; n++, name++) { output_bin_res_dir( 0, name->nb_languages ); for (k = 0, res = name->res; k < name->nb_languages; k++, res++) { put_dword( res->lang ); put_dword( res->data_offset ); } } } /* dump the resource data entries */ for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) { put_dword( data_offset + start_rva ); put_dword( (res->data_size + 3) & ~3 ); put_dword( 0 ); put_dword( 0 ); data_offset += (res->data_size + 3) & ~3; } /* dump the name strings */ for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) { if (type->type->str) output_bin_string( type->type->str ); for (n = 0, name = type->names; n < type->nb_names; n++, name++) if (name->name->str) output_bin_string( name->name->str ); } /* resource data */ align_output( 4 ); for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) { put_data( res->data, res->data_size ); align_output( 4 ); } free_resource_tree( tree ); }
/******************************************************************* * output_fake_module * * Build a fake binary module from a spec file. */ void output_fake_module( DLLSPEC *spec ) { static const unsigned char dll_code_section[] = { 0x31, 0xc0, /* xor %eax,%eax */ 0xc2, 0x0c, 0x00 }; /* ret $12 */ static const unsigned char exe_code_section[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */ 0xc2, 0x04, 0x00 }; /* ret $4 */ static const char fakedll_signature[] = "Wine placeholder DLL"; 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 */ put_word( 0x01 ); /* e_cp */ put_word( 0 ); /* e_crlc */ put_word( lfanew / 16 ); /* e_cparhdr */ put_word( 0x0000 ); /* e_minalloc */ put_word( 0xffff ); /* e_maxalloc */ put_word( 0x0000 ); /* e_ss */ put_word( 0x00b8 ); /* e_sp */ put_word( 0 ); /* e_csum */ put_word( 0 ); /* e_ip */ put_word( 0 ); /* e_cs */ put_word( lfanew ); /* e_lfarlc */ put_word( 0 ); /* e_ovno */ put_dword( 0 ); /* e_res */ put_dword( 0 ); put_word( 0 ); /* e_oemid */ put_word( 0 ); /* e_oeminfo */ put_dword( 0 ); /* e_res2 */ put_dword( 0 ); put_dword( 0 ); put_dword( 0 ); put_dword( 0 ); put_dword( lfanew ); put_data( fakedll_signature, sizeof(fakedll_signature) ); align_output( 16 ); put_dword( 0x4550 ); /* Signature */ switch(target_cpu) { case CPU_x86: put_word( IMAGE_FILE_MACHINE_I386 ); break; case CPU_x86_64: put_word( IMAGE_FILE_MACHINE_AMD64 ); break; case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break; case CPU_SPARC: put_word( IMAGE_FILE_MACHINE_SPARC ); break; case CPU_ARM: put_word( IMAGE_FILE_MACHINE_ARMV7 ); break; } put_word( nb_sections ); /* NumberOfSections */ put_dword( 0 ); /* TimeDateStamp */ put_dword( 0 ); /* PointerToSymbolTable */ put_dword( 0 ); /* NumberOfSymbols */ put_word( get_ptr_size() == 8 ? IMAGE_SIZEOF_NT_OPTIONAL64_HEADER : IMAGE_SIZEOF_NT_OPTIONAL32_HEADER ); /* SizeOfOptionalHeader */ put_word( spec->characteristics ); /* Characteristics */ put_word( get_ptr_size() == 8 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC : IMAGE_NT_OPTIONAL_HDR32_MAGIC ); /* Magic */ put_byte( 0 ); /* MajorLinkerVersion */ put_byte( 0 ); /* MinorLinkerVersion */ put_dword( text_size ); /* SizeOfCode */ put_dword( 0 ); /* SizeOfInitializedData */ put_dword( 0 ); /* SizeOfUninitializedData */ put_dword( section_align ); /* AddressOfEntryPoint */ put_dword( section_align ); /* BaseOfCode */ if (get_ptr_size() == 4) put_dword( 0 ); /* BaseOfData */ put_pword( 0x10000000 ); /* ImageBase */ put_dword( section_align ); /* SectionAlignment */ put_dword( file_align ); /* FileAlignment */ put_word( 1 ); /* MajorOperatingSystemVersion */ put_word( 0 ); /* MinorOperatingSystemVersion */ put_word( 0 ); /* MajorImageVersion */ put_word( 0 ); /* MinorImageVersion */ 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( 0 ); /* CheckSum */ put_word( spec->subsystem ); /* Subsystem */ put_word( spec->dll_characteristics ); /* DllCharacteristics */ put_pword( (spec->stack_size ? spec->stack_size : 1024) * 1024 ); /* SizeOfStackReserve */ put_pword( page_size ); /* SizeOfStackCommit */ put_pword( (spec->heap_size ? spec->heap_size : 1024) * 1024 ); /* SizeOfHeapReserve */ put_pword( page_size ); /* SizeOfHeapCommit */ put_dword( 0 ); /* LoaderFlags */ put_dword( 16 ); /* NumberOfRvaAndSizes */ 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] */ { put_dword( 3 * section_align ); put_dword( resources_size ); } else { put_dword( 0 ); put_dword( 0 ); } 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( 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] */ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] */ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG] */ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] */ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] */ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT] */ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] */ 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 */ /* .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_dword( 0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ ); /* Characteristics */ /* .rsrc section */ if (resources_size) { 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 */ } /* .text contents */ align_output( file_align ); 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) ); /* .reloc contents */ align_output( file_align ); put_dword( 0 ); /* VirtualAddress */ put_dword( 0 ); /* SizeOfBlock */ /* .rsrc contents */ if (resources_size) { align_output( file_align ); put_data( resources, resources_size ); } flush_output_buffer(); }
/******************************************************************* * output_fake_module16 * * Create a fake 16-bit binary module. */ void output_fake_module16( DLLSPEC *spec ) { static const unsigned char code_segment[] = { 0x90, 0xc3 }; static const unsigned char data_segment[16] = { 0 }; static const char fakedll_signature[] = "Wine placeholder DLL"; const unsigned int cseg = 2; const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15; const unsigned int segtab = lfanew + 0x40; unsigned int i, rsrctab, restab, namelen, modtab, imptab, enttab, cbenttab, codeseg, dataseg, rsrcdata; init_output_buffer(); rsrctab = lfanew; restab = segtab + 8 * cseg; if (spec->nb_resources) { output_bin_res16_directory( spec, 0 ); align_output( 2 ); rsrctab = restab; restab += output_buffer_pos; free( output_buffer ); init_output_buffer(); } namelen = strlen( spec->dll_name ); modtab = restab + ((namelen + 3) & ~1); imptab = modtab; enttab = modtab + 2; cbenttab = 1; codeseg = (enttab + cbenttab + 1) & ~1; dataseg = codeseg + sizeof(code_segment); rsrcdata = dataseg + sizeof(data_segment); init_output_buffer(); put_word( 0x5a4d ); /* e_magic */ put_word( 0x40 ); /* e_cblp */ put_word( 0x01 ); /* e_cp */ put_word( 0 ); /* e_crlc */ put_word( lfanew / 16 ); /* e_cparhdr */ put_word( 0x0000 ); /* e_minalloc */ put_word( 0xffff ); /* e_maxalloc */ put_word( 0x0000 ); /* e_ss */ put_word( 0x00b8 ); /* e_sp */ put_word( 0 ); /* e_csum */ put_word( 0 ); /* e_ip */ put_word( 0 ); /* e_cs */ put_word( lfanew ); /* e_lfarlc */ put_word( 0 ); /* e_ovno */ put_dword( 0 ); /* e_res */ put_dword( 0 ); put_word( 0 ); /* e_oemid */ put_word( 0 ); /* e_oeminfo */ put_dword( 0 ); /* e_res2 */ put_dword( 0 ); put_dword( 0 ); put_dword( 0 ); put_dword( 0 ); put_dword( lfanew ); put_data( fakedll_signature, sizeof(fakedll_signature) ); align_output( 16 ); put_word( 0x454e ); /* ne_magic */ put_byte( 0 ); /* ne_ver */ put_byte( 0 ); /* ne_rev */ put_word( enttab - lfanew ); /* ne_enttab */ put_word( cbenttab ); /* ne_cbenttab */ put_dword( 0 ); /* ne_crc */ put_word( NE_FFLAGS_SINGLEDATA | /* ne_flags */ ((spec->characteristics & IMAGE_FILE_DLL) ? NE_FFLAGS_LIBMODULE : 0) ); put_word( 2 ); /* ne_autodata */ put_word( spec->heap_size ); /* ne_heap */ put_word( 0 ); /* ne_stack */ put_word( 0 ); put_word( 0 ); /* ne_csip */ put_word( 0 ); put_word( 2 ); /* ne_sssp */ put_word( cseg ); /* ne_cseg */ put_word( 0 ); /* ne_cmod */ put_word( 0 ); /* ne_cbnrestab */ put_word( segtab - lfanew ); /* ne_segtab */ put_word( rsrctab - lfanew ); /* ne_rsrctab */ put_word( restab - lfanew ); /* ne_restab */ put_word( modtab - lfanew ); /* ne_modtab */ put_word( imptab - lfanew ); /* ne_imptab */ put_dword( 0 ); /* ne_nrestab */ put_word( 0 ); /* ne_cmovent */ put_word( 0 ); /* ne_align */ put_word( 0 ); /* ne_cres */ put_byte( 2 /*NE_OSFLAGS_WINDOWS*/ ); /* ne_exetyp */ put_byte( 8 /*NE_AFLAGS_FASTLOAD*/ ); /* ne_flagsothers */ put_word( 0 ); /* ne_pretthunks */ put_word( 0 ); /* ne_psegrefbytes */ put_word( 0 ); /* ne_swaparea */ put_word( 0 ); /* ne_expver */ /* segment table */ put_word( codeseg ); put_word( sizeof(code_segment) ); put_word( 0x2000 /* NE_SEGFLAGS_32BIT */ ); put_word( sizeof(code_segment) ); put_word( dataseg ); put_word( sizeof(data_segment) ); put_word( 0x0001 /* NE_SEGFLAGS_DATA */ ); put_word( sizeof(data_segment) ); /* resource directory */ if (spec->nb_resources) { output_bin_res16_directory( spec, rsrcdata ); align_output( 2 ); } /* resident names table */ put_byte( namelen ); for (i = 0; i < namelen; i++) put_byte( toupper(spec->dll_name[i]) ); put_byte( 0 ); align_output( 2 ); /* imported names table */ put_word( 0 ); /* entry table */ put_byte( 0 ); align_output( 2 ); /* code segment */ put_data( code_segment, sizeof(code_segment) ); /* data segment */ put_data( data_segment, sizeof(data_segment) ); /* resource data */ output_bin_res16_data( spec ); flush_output_buffer(); }
/* output the resources into a .o file */ void output_res_o_file( DLLSPEC *spec ) { unsigned int i; char *res_file = NULL; int fd; struct strarray *args; if (!spec->nb_resources) fatal_error( "--resources mode needs at least one resource file as input\n" ); if (!output_file_name) fatal_error( "No output file name specified\n" ); qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res ); remove_duplicate_resources( spec ); byte_swapped = 0; init_output_buffer(); put_dword( 0 ); /* ResSize */ put_dword( 32 ); /* HeaderSize */ put_word( 0xffff ); /* ResType */ put_word( 0x0000 ); put_word( 0xffff ); /* ResName */ put_word( 0x0000 ); put_dword( 0 ); /* DataVersion */ put_word( 0 ); /* Memory options */ put_word( 0 ); /* Language */ put_dword( 0 ); /* Version */ put_dword( 0 ); /* Characteristics */ for (i = 0; i < spec->nb_resources; i++) { unsigned int header_size = get_resource_header_size( &spec->resources[i] ); put_dword( spec->resources[i].data_size ); put_dword( (header_size + 3) & ~3 ); put_string( &spec->resources[i].type ); put_string( &spec->resources[i].name ); align_output( 4 ); put_dword( 0 ); put_word( spec->resources[i].mem_options ); put_word( spec->resources[i].lang ); put_dword( spec->resources[i].version ); put_dword( 0 ); put_data( spec->resources[i].data, spec->resources[i].data_size ); align_output( 4 ); } /* if the output file name is a .res too, don't run the results through windres */ if (strendswith( output_file_name, ".res")) { flush_output_buffer(); return; } res_file = get_temp_file_name( output_file_name, ".res" ); if ((fd = open( res_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600 )) == -1) fatal_error( "Cannot create %s\n", res_file ); if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos) fatal_error( "Error writing to %s\n", res_file ); close( fd ); free( output_buffer ); args = find_tool( "windres", NULL ); strarray_add( args, "-i", res_file, "-o", output_file_name, NULL ); spawn( args ); strarray_free( args ); output_file_name = NULL; /* so we don't try to assemble it */ }