diff --git a/reactos/include/wine/exception.h b/reactos/include/wine/exception.h index 594fd338c09..7bfc1c93d55 100644 --- a/reactos/include/wine/exception.h +++ b/reactos/include/wine/exception.h @@ -24,6 +24,7 @@ #include #include #include +#include /* The following definitions allow using exceptions in Wine and Winelib code * @@ -75,6 +76,10 @@ #else /* USE_COMPILER_EXCEPTIONS */ +#ifndef __GNUC__ +#define __attribute__(x) /* nothing */ +#endif + #define __TRY \ do { __WINE_FRAME __f; \ int __first = 1; \ @@ -91,7 +96,7 @@ __f.u.filter = (func); \ __wine_push_frame( &__f.frame ); \ if (sigsetjmp( __f.jmp, 1 )) { \ - const __WINE_FRAME * const __eptr WINE_UNUSED = &__f; \ + const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \ do { #define __ENDTRY \ @@ -125,10 +130,7 @@ typedef void (CALLBACK *__WINE_FINALLY)(BOOL); #define GetExceptionInformation() (__eptr) #define GetExceptionCode() (__eptr->ExceptionRecord->ExceptionCode) -#if defined(AbnormalTermination) && defined(__REACTOS__) #undef AbnormalTermination -#endif - #define AbnormalTermination() (!__normal) typedef struct __tagWINE_FRAME @@ -175,8 +177,6 @@ static inline EXCEPTION_REGISTRATION_RECORD *__wine_pop_frame( EXCEPTION_REGISTR { #if defined(__GNUC__) && defined(__i386__) __asm__ __volatile__(".byte 0x64\n\tmovl %0,(0)" - //: : "r" (frame->Prev) : "memory" ); - //return frame->Prev; : : "r" (frame->prev) : "memory" ); return frame->prev; diff --git a/reactos/tools/winebuild/Makefile b/reactos/tools/winebuild/Makefile index 6d7cec5f718..2b9596a22f7 100644 --- a/reactos/tools/winebuild/Makefile +++ b/reactos/tools/winebuild/Makefile @@ -22,7 +22,7 @@ OBJECTS = \ CLEAN_FILES = *.o $(TARGET) -HOST_CFLAGS = $(HOSTARCH) -D__USE_W32API -I$(PATH_TO_TOP)/include/wine +HOST_CFLAGS = $(HOSTARCH) -D__USE_W32API -I$(PATH_TO_TOP)/include/wine -I$(PATH_TO_TOP)/include %.o: %.c $(HOST_CC) $(HOST_CFLAGS) -c $< -o $@ diff --git a/reactos/tools/winebuild/build.h b/reactos/tools/winebuild/build.h index d6af3a0fbd2..10573db60cf 100644 --- a/reactos/tools/winebuild/build.h +++ b/reactos/tools/winebuild/build.h @@ -133,7 +133,7 @@ typedef struct #define STACK32OFFSET(reg) STRUCTOFFSET(STACK32FRAME,reg) /* Offset of the stack pointer relative to %fs:(0) */ -#define STACKOFFSET (STRUCTOFFSET(TEB,cur_stack)) +#define STACKOFFSET (STRUCTOFFSET(TEB,WOW32Reserved)) #define MAX_ORDINALS 65535 @@ -148,6 +148,7 @@ extern void *xmalloc (size_t size); extern void *xrealloc (void *ptr, size_t size); extern char *xstrdup( const char *str ); extern char *strupper(char *s); +extern int strendswith(const char* str, const char* end); extern void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); extern void fatal_perror( const char *msg, ... ) @@ -167,16 +168,22 @@ extern void free_dll_spec( DLLSPEC *spec ); extern const char *make_c_identifier( const char *str ); extern int get_alignment(int alignBoundary); -extern void add_import_dll( const char *name, int delay ); +extern void add_import_dll( const char *name, const char *filename ); +extern void add_delayed_import( const char *name ); extern void add_ignore_symbol( const char *name ); extern void read_undef_symbols( char **argv ); extern int resolve_imports( DLLSPEC *spec ); -extern int output_imports( FILE *outfile, DLLSPEC *spec ); +extern int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed ); extern int load_res32_file( const char *name, DLLSPEC *spec ); extern void output_resources( FILE *outfile, DLLSPEC *spec ); extern void load_res16_file( const char *name, DLLSPEC *spec ); -extern int output_res16_data( FILE *outfile, DLLSPEC *spec ); -extern int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ); +extern unsigned int get_res16_data_size( DLLSPEC *spec, unsigned int res_offset, + unsigned int alignment ); +extern unsigned int output_res16_data( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ); +extern unsigned int get_res16_directory_size( DLLSPEC *spec ); +extern unsigned int output_res16_directory( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ); extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor ); extern void BuildRelays16( FILE *outfile ); diff --git a/reactos/tools/winebuild/import.c b/reactos/tools/winebuild/import.c index 0a6aff1b3d1..e6f97e144db 100644 --- a/reactos/tools/winebuild/import.c +++ b/reactos/tools/winebuild/import.c @@ -26,16 +26,23 @@ #include #include #include +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif #include "winglue.h" +#include "wine/exception.h" #include "build.h" struct import { - DLLSPEC *spec; /* description of the imported dll */ + DLLSPEC *spec; /* description of the imported dll */ + char *full_name; /* full name of the input file */ + dev_t dev; /* device/inode of the input file */ + ino_t ino; int delay; /* delay or not dll loading ? */ ORDDEF **exports; /* functions exported from this dll */ int nb_exports; /* number of exported functions */ @@ -58,6 +65,8 @@ static int nb_imports = 0; /* number of imported dlls (delayed or not) */ static int nb_delayed = 0; /* number of delayed dlls */ static int total_imports = 0; /* total number of imported functions */ static int total_delayed = 0; /* total number of imported functions in delayed DLLs */ +static char **delayed_imports; /* names of delayed import dlls */ +static int nb_delayed_imports; /* size of the delayed_imports array */ /* list of symbols that are ignored by default */ static const char * const default_ignored_symbols[] = @@ -187,6 +196,7 @@ static void free_imports( struct import *imp ) free( imp->exports ); free( imp->imports ); free_dll_spec( imp->spec ); + free( imp->full_name ); free( imp ); } @@ -196,16 +206,28 @@ static void remove_ld_tmp_file(void) if (ld_tmp_file) unlink( ld_tmp_file ); } +/* check whether a given dll is imported in delayed mode */ +static int is_delayed_import( const char *name ) +{ + int i; + + for (i = 0; i < nb_delayed_imports; i++) + { + if (!strcmp( delayed_imports[i], name )) return 1; + } + return 0; +} + /* check whether a given dll has already been imported */ -static int is_already_imported( const char *name ) +static struct import *is_already_imported( const char *name ) { int i; for (i = 0; i < nb_imports; i++) { - if (!strcmp( dll_imports[i]->spec->file_name, name )) return 1; + if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i]; } - return 0; + return NULL; } /* open the .so library for a given dll in a specified path */ @@ -227,8 +249,8 @@ static char *try_library_path( const char *path, const char *name ) return NULL; } -/* open the .so library for a given dll */ -static char *open_library( const char *name ) +/* find the .def import library for a given dll */ +static char *find_library( const char *name ) { char *fullname; int i; @@ -242,24 +264,36 @@ static char *open_library( const char *name ) } /* read in the list of exported symbols of an import library */ -static int read_import_lib( const char *name, struct import *imp ) +static int read_import_lib( struct import *imp ) { FILE *f; - char *fullname; int i, ret; + struct stat stat; + struct import *prev_imp; DLLSPEC *spec = imp->spec; - imp->exports = NULL; - imp->nb_exports = 0; - - fullname = open_library( name ); - f = open_input_file( NULL, fullname ); - free( fullname ); - + f = open_input_file( NULL, imp->full_name ); + fstat( fileno(f), &stat ); + imp->dev = stat.st_dev; + imp->ino = stat.st_ino; ret = parse_def_file( f, spec ); close_input_file( f ); if (!ret) return 0; - if (is_already_imported( spec->file_name )) return 0; + + /* check if we already imported that library from a different file */ + if ((prev_imp = is_already_imported( spec->file_name ))) + { + if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino) + fatal_error( "%s and %s have the same export name '%s'\n", + prev_imp->full_name, imp->full_name, spec->file_name ); + return 0; /* the same file was already loaded, ignore this one */ + } + + if (is_delayed_import( spec->file_name )) + { + imp->delay = 1; + nb_delayed++; + } imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) ); @@ -277,32 +311,47 @@ static int read_import_lib( const char *name, struct import *imp ) return 1; } -/* add a dll to the list of imports */ -void add_import_dll( const char *name, int delay ) +/* build the dll exported name from the import lib name or path */ +static char *get_dll_name( const char *name, const char *filename ) { - struct import *imp; - char *fullname; + char *ret; - fullname = xmalloc( strlen(name) + 5 ); - strcpy( fullname, name ); - if (!strchr( fullname, '.' )) strcat( fullname, ".dll" ); - - /* check if we already imported it */ - if (is_already_imported( fullname )) + if (filename) { - free( fullname ); - return; + const char *basename = strrchr( filename, '/' ); + if (!basename) basename = filename; + else basename++; + if (!strncmp( basename, "lib", 3 )) basename += 3; + ret = xmalloc( strlen(basename) + 5 ); + strcpy( ret, basename ); + if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0; } + else + { + ret = xmalloc( strlen(name) + 5 ); + strcpy( ret, name ); + } + if (!strchr( ret, '.' )) strcat( ret, ".dll" ); + return ret; +} + +/* add a dll to the list of imports */ +void add_import_dll( const char *name, const char *filename ) +{ + struct import *imp = xmalloc( sizeof(*imp) ); - imp = xmalloc( sizeof(*imp) ); imp->spec = alloc_dll_spec(); - imp->spec->file_name = fullname; - imp->delay = delay; + imp->spec->file_name = get_dll_name( name, filename ); + imp->delay = 0; imp->imports = NULL; imp->nb_imports = 0; - if (delay) nb_delayed++; + imp->exports = NULL; + imp->nb_exports = 0; - if (read_import_lib( name, imp )) + if (filename) imp->full_name = xstrdup( filename ); + else imp->full_name = find_library( name ); + + if (read_import_lib( imp )) { dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) ); dll_imports[nb_imports++] = imp; @@ -314,6 +363,21 @@ void add_import_dll( const char *name, int delay ) } } +/* add a library to the list of delayed imports */ +void add_delayed_import( const char *name ) +{ + struct import *imp; + char *fullname = get_dll_name( name, NULL ); + + delayed_imports = xrealloc( delayed_imports, (nb_delayed_imports+1) * sizeof(*delayed_imports) ); + delayed_imports[nb_delayed_imports++] = fullname; + if ((imp = is_already_imported( fullname )) && !imp->delay) + { + imp->delay = 1; + nb_delayed++; + } +} + /* remove an imported dll, based on its index in the dll_imports array */ static void remove_import_dll( int index ) { @@ -438,7 +502,7 @@ static int add_extra_symbol( const char **extras, int *count, const char *name, static void add_extra_undef_symbols( const DLLSPEC *spec ) { const char *extras[10]; - int i, count = 0, nb_stubs = 0, nb_regs = 0; + int i, count = 0, nb_stubs = 0; int kernel_imports = 0, ntdll_imports = 0; sort_symbols( undef_symbols, nb_undef_symbols ); @@ -447,7 +511,6 @@ static void add_extra_undef_symbols( const DLLSPEC *spec ) { ORDDEF *odp = &spec->entry_points[i]; if (odp->type == TYPE_STUB) nb_stubs++; - if (odp->flags & FLAG_REGISTER) nb_regs++; } /* add symbols that will be contained in the spec file itself */ @@ -467,16 +530,16 @@ static void add_extra_undef_symbols( const DLLSPEC *spec ) if (nb_delayed) { kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA", spec ); + kernel_imports += add_extra_symbol( extras, &count, "FreeLibrary", spec ); kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress", spec ); + kernel_imports += add_extra_symbol( extras, &count, "RaiseException", spec ); } - if (nb_regs) - ntdll_imports += add_extra_symbol( extras, &count, "__wine_call_from_32_regs", spec ); - if (nb_delayed || nb_stubs) + if (nb_stubs) ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException", spec ); /* make sure we import the dlls that contain these functions */ - if (kernel_imports) add_import_dll( "kernel32", 0 ); - if (ntdll_imports) add_import_dll( "ntdll", 0 ); + if (kernel_imports) add_import_dll( "kernel32", NULL ); + if (ntdll_imports) add_import_dll( "ntdll", NULL ); if (count) { @@ -777,10 +840,10 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) if (!nb_delayed) goto done; + fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed ); for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; - fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i); for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; @@ -807,7 +870,7 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) for (i = j = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; - fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n", + fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_hmod[%d], &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n", dll_imports[i]->spec->file_name, i, j, j ); j += dll_imports[i]->nb_imports; } @@ -839,21 +902,7 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) } fprintf( outfile, " }\n};\n\n" ); - /* check if there's some stub defined. if so, exception struct - * is already defined, so don't emit it twice - */ - for (i = 0; i < spec->nb_entry_points; i++) if (spec->entry_points[i].type == TYPE_STUB) break; - - if (i == spec->nb_entry_points) { - fprintf( outfile, "struct exc_record {\n" ); - fprintf( outfile, " unsigned int code, flags;\n" ); - fprintf( outfile, " void *rec, *addr;\n" ); - fprintf( outfile, " unsigned int params;\n" ); - fprintf( outfile, " const void *info[15];\n" ); - fprintf( outfile, "};\n\n" ); - fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n" ); - } - + fprintf( outfile, "extern void __stdcall RaiseException(unsigned int, unsigned int, unsigned int, const void *args[]);\n" ); fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n"); fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n"); fprintf( outfile, "\n" ); @@ -871,20 +920,12 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) fprintf( outfile, " /* patch IAT with final value */\n" ); fprintf( outfile, " return *pIAT = fn;\n" ); fprintf( outfile, " else {\n"); - fprintf( outfile, " struct exc_record rec;\n" ); - fprintf( outfile, " rec.code = 0x80000100;\n" ); - fprintf( outfile, " rec.flags = 1;\n" ); - fprintf( outfile, " rec.rec = 0;\n" ); - fprintf( outfile, " rec.params = 2;\n" ); - fprintf( outfile, " rec.info[0] = imd->szName;\n" ); - fprintf( outfile, " rec.info[1] = *pINT;\n" ); - fprintf( outfile, "#ifdef __GNUC__\n" ); - fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" ); - fprintf( outfile, "#else\n" ); - fprintf( outfile, " rec.addr = 0;\n" ); - fprintf( outfile, "#endif\n" ); - fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n" ); - fprintf( outfile, " return 0; /* shouldn't go here */\n" ); + fprintf( outfile, " const void *args[2];\n" ); + fprintf( outfile, " args[0] = imd->szName;\n" ); + fprintf( outfile, " args[1] = *pINT;\n" ); + fprintf( outfile, " RaiseException( 0x%08x, %d, 2, args );\n", + EXCEPTION_WINE_STUB, EXCEPTION_NONCONTINUABLE ); + fprintf( outfile, " return 0;\n" ); fprintf( outfile, " }\n}\n\n" ); fprintf( outfile, "#ifndef __GNUC__\n" ); @@ -1100,8 +1141,8 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) /* output the import and delayed import tables of a Win32 module * returns number of DLLs exported in 'immediate' mode */ -int output_imports( FILE *outfile, DLLSPEC *spec ) +int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed ) { - output_delayed_imports( outfile, spec ); - return output_immediate_imports( outfile ); + *nb_delayed = output_delayed_imports( outfile, spec ); + return output_immediate_imports( outfile ); } diff --git a/reactos/tools/winebuild/main.c b/reactos/tools/winebuild/main.c index 8148ba71677..3f98a88a46c 100644 --- a/reactos/tools/winebuild/main.c +++ b/reactos/tools/winebuild/main.c @@ -283,7 +283,7 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) spec->dll_name = xstrdup( optarg ); break; case 'd': - add_import_dll( optarg, 1 ); + add_delayed_import( optarg ); break; case 'e': spec->init_func = xstrdup( optarg ); @@ -312,7 +312,7 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) kill_at = 1; break; case 'l': - add_import_dll( optarg, 0 ); + add_import_dll( optarg, NULL ); break; case 'o': if (unlink( optarg ) == -1 && errno != ENOENT) @@ -408,6 +408,21 @@ static void load_resources( char *argv[], DLLSPEC *spec ) } } +/* add input files that look like import libs to the import list */ +static void load_import_libs( char *argv[] ) +{ + char **ptr, **last; + + for (ptr = last = argv; *ptr; ptr++) + { + if (strendswith( *ptr, ".def" )) + add_import_dll( NULL, *ptr ); + else + *last++ = *ptr; /* not an import dll, keep it in the list */ + } + *last = NULL; +} + static int parse_input_file( DLLSPEC *spec ) { FILE *input_file = open_input_file( NULL, spec_file_name ); @@ -444,6 +459,7 @@ int main(int argc, char **argv) case MODE_DLL: spec->characteristics |= IMAGE_FILE_DLL; load_resources( argv, spec ); + load_import_libs( argv ); if (!spec_file_name) fatal_error( "missing .spec file\n" ); if (!parse_input_file( spec )) break; switch (spec->type) @@ -462,6 +478,7 @@ int main(int argc, char **argv) if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" ); if (!spec->file_name) fatal_error( "executable must be named via the -F option\n" ); load_resources( argv, spec ); + load_import_libs( argv ); if (spec_file_name && !parse_input_file( spec )) break; read_undef_symbols( argv ); BuildSpec32File( output_file, spec ); diff --git a/reactos/tools/winebuild/parser.c b/reactos/tools/winebuild/parser.c index a998777d873..424a0ef499b 100644 --- a/reactos/tools/winebuild/parser.c +++ b/reactos/tools/winebuild/parser.c @@ -511,6 +511,12 @@ static int parse_spec_ordinal( int ordinal, DLLSPEC *spec ) odp->ordinal = ordinal; } + if (spec->type == SPEC_WIN32 && odp->flags & FLAG_REGISTER) + { + error( "-register flag not supported for Win32 entry points\n" ); + goto error; + } + if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE)) { if (!strcmp( odp->name, "DllRegisterServer" ) || diff --git a/reactos/tools/winebuild/relay.c b/reactos/tools/winebuild/relay.c index 6548714b43d..abac75ae4d9 100644 --- a/reactos/tools/winebuild/relay.c +++ b/reactos/tools/winebuild/relay.c @@ -27,7 +27,7 @@ #include #include "thread.h" -#include "stackframe.h" +#include "wine/winbase16.h" #include "build.h" diff --git a/reactos/tools/winebuild/res16.c b/reactos/tools/winebuild/res16.c index a5fd5849132..87a16029687 100644 --- a/reactos/tools/winebuild/res16.c +++ b/reactos/tools/winebuild/res16.c @@ -20,6 +20,7 @@ #include "config.h" +#include #include #include #include @@ -39,9 +40,6 @@ #include "winglue.h" #include "build.h" -#define ALIGNMENT 2 /* alignment for resource data */ -#define ALIGN_MASK ((1 << ALIGNMENT) - 1) - /* Unicode string or integer id */ struct string_id { @@ -265,48 +263,115 @@ static void output_string( unsigned char **buffer, const char *str ) while (len--) put_byte( buffer, *str++ ); } -/* output the resource data */ -int output_res16_data( FILE *outfile, DLLSPEC *spec ) +/* get the resource data total size */ +unsigned int get_res16_data_size( DLLSPEC *spec, unsigned int res_offset, unsigned int alignment ) { const struct resource *res; - unsigned char *buffer, *p; - unsigned int i; - int total; + unsigned int i, total; + unsigned int align_mask = (1 << alignment) - 1; if (!spec->nb_resources) return 0; - for (i = total = 0, res = spec->resources; i < spec->nb_resources; i++, res++) - total += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK; + /* add padding at the beginning if needed so that resources are properly aligned */ + total = ((res_offset + align_mask) & ~align_mask) - res_offset; - buffer = p = xmalloc( total ); for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) - { - memcpy( p, res->data, res->data_size ); - p += res->data_size; - while ((int)p & ALIGN_MASK) *p++ = 0; - } - dump_bytes( outfile, buffer, total, "resource_data", 1 ); - free( buffer ); + total += (res->data_size + align_mask) & ~align_mask; + return total; } -/* output the resource definitions */ -int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) +/* output the resource data */ +unsigned int output_res16_data( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ) { - int offset, res_offset = 0; - unsigned int i, j; + const struct resource *res; + unsigned char *p; + unsigned int i, total, padding; + unsigned int align_mask = (1 << alignment) - 1; + + if (!spec->nb_resources) return 0; + + /* add padding at the beginning if needed so that resources are properly aligned */ + padding = ((res_offset + align_mask) & ~align_mask) - res_offset; + + for (i = total = 0, res = spec->resources; i < spec->nb_resources; i++, res++) + total += (res->data_size + align_mask) & ~align_mask; + + *ret_buf = p = xmalloc( total + padding ); + memset( p, 0, padding ); + p += padding; + for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) + { + unsigned int size = (res->data_size + align_mask) & ~align_mask; + memcpy( p, res->data, res->data_size ); + memset( p + res->data_size, 0, size - res->data_size ); + p += size; + } + return total; +} + +/* get the resource definitions total size */ +unsigned int get_res16_directory_size( DLLSPEC *spec ) +{ + unsigned int i, j, total_size; struct res_tree *tree; const struct res_type *type; const struct resource *res; - unsigned char *start = buffer; tree = build_resource_tree( spec ); + total_size = 4; /* alignment + terminator */ + total_size += tree->nb_types * 8; /* typeinfo structures */ + total_size += spec->nb_resources * 12; /* nameinfo structures */ + + for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) + { + if (type->type->str) total_size += strlen(type->type->str) + 1; + for (j = 0, res = type->res; j < type->nb_names; j++, res++) + if (res->name.str) total_size += strlen(res->name.str) + 1; + } + total_size++; /* final terminator */ + if (total_size & 1) total_size++; + return total_size; +} + +/* output the resource definitions */ +unsigned int output_res16_directory( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ) +{ + int offset; + unsigned int i, j, total_size; + unsigned int align_mask = (1 << alignment) - 1; + struct res_tree *tree; + const struct res_type *type; + const struct resource *res; + unsigned char *buffer; + + tree = build_resource_tree( spec ); + + /* make sure data offset is properly aligned */ + res_offset = (res_offset + align_mask) & ~align_mask; + + /* first compute total size */ + offset = 4; /* alignment + terminator */ offset += tree->nb_types * 8; /* typeinfo structures */ offset += spec->nb_resources * 12; /* nameinfo structures */ - put_word( &buffer, ALIGNMENT ); + total_size = offset; + + for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) + { + if (type->type->str) total_size += strlen(type->type->str) + 1; + for (j = 0, res = type->res; j < type->nb_names; j++, res++) + if (res->name.str) total_size += strlen(res->name.str) + 1; + } + total_size++; /* final terminator */ + if (total_size & 1) total_size++; + *ret_buf = buffer = xmalloc( total_size ); + + put_word( &buffer, alignment ); /* type and name structures */ @@ -326,8 +391,8 @@ int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) for (j = 0, res = type->res; j < type->nb_names; j++, res++) { - put_word( &buffer, res_offset >> ALIGNMENT ); - put_word( &buffer, (res->data_size + ALIGN_MASK) >> ALIGNMENT ); + put_word( &buffer, res_offset >> alignment ); + put_word( &buffer, (res->data_size + align_mask) >> alignment ); put_word( &buffer, res->memopt ); if (res->name.str) { @@ -338,7 +403,7 @@ int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) put_word( &buffer, res->name.id | 0x8000 ); put_word( &buffer, 0 ); put_word( &buffer, 0 ); - res_offset += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK; + res_offset += (res->data_size + align_mask) & ~align_mask; } } put_word( &buffer, 0 ); /* terminator */ @@ -354,8 +419,9 @@ int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) } } put_byte( &buffer, 0 ); /* names terminator */ - if ((buffer - start) & 1) put_byte( &buffer, 0 ); /* align on word boundary */ + if ((buffer - *ret_buf) & 1) put_byte( &buffer, 0 ); /* align on word boundary */ + assert( buffer - *ret_buf == total_size ); free_resource_tree( tree ); - return buffer - start; + return total_size; } diff --git a/reactos/tools/winebuild/spec16.c b/reactos/tools/winebuild/spec16.c index aae4d8f5b97..d8871ea0050 100644 --- a/reactos/tools/winebuild/spec16.c +++ b/reactos/tools/winebuild/spec16.c @@ -28,9 +28,7 @@ #include #include "wine/exception.h" -#include "stackframe.h" -#include "builtin16.h" -#include "module.h" +#include "wine/winbase16.h" #include "build.h" @@ -76,230 +74,95 @@ static void output_file_header( FILE *outfile ) /******************************************************************* - * StoreVariableCode - * - * Store a list of ints into a byte array. + * output_entry_table */ -static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp ) +static int output_entry_table( unsigned char **ret_buff, DLLSPEC *spec ) { - int i; + int i, prev = 0, prev_sel = -1; + unsigned char *pstr, *buffer; + unsigned char *bundle = NULL; - switch(size) - { - case 1: - for (i = 0; i < odp->u.var.n_values; i++) - buffer[i] = odp->u.var.values[i]; - break; - case 2: - for (i = 0; i < odp->u.var.n_values; i++) - ((unsigned short *)buffer)[i] = odp->u.var.values[i]; - break; - case 4: - for (i = 0; i < odp->u.var.n_values; i++) - ((unsigned int *)buffer)[i] = odp->u.var.values[i]; - break; - } - return odp->u.var.n_values * size; -} + buffer = xmalloc( spec->limit * 5 ); /* we use at most 5 bytes per entry-point */ + pstr = buffer; - -/******************************************************************* - * BuildModule16 - * - * Build the in-memory representation of a 16-bit NE module, and dump it - * as a byte stream into the assembly code. - */ -static int BuildModule16( FILE *outfile, int max_code_offset, - int max_data_offset, DLLSPEC *spec ) -{ - int i; - char *buffer; - NE_MODULE *pModule; - SEGTABLEENTRY *pSegment; - OFSTRUCT *pFileInfo; - BYTE *pstr; - ET_BUNDLE *bundle = 0; - ET_ENTRY entry; - - /* Module layout: - * NE_MODULE Module - * OFSTRUCT File information - * SEGTABLEENTRY Segment 1 (code) - * SEGTABLEENTRY Segment 2 (data) - * WORD[2] Resource table (empty) - * BYTE[2] Imported names (empty) - * BYTE[n] Resident names table - * BYTE[n] Entry table - */ - - buffer = xmalloc( 0x10000 ); - memset( buffer, 0, 0x10000 ); - - pModule = (NE_MODULE *)buffer; - pModule->magic = IMAGE_OS2_SIGNATURE; - pModule->count = 1; - pModule->next = 0; - pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE; - pModule->dgroup = 2; - pModule->heap_size = spec->heap_size; - pModule->stack_size = 0; - pModule->ip = 0; - pModule->cs = 0; - pModule->sp = 0; - pModule->ss = 0; - pModule->seg_count = 2; - pModule->modref_count = 0; - pModule->nrname_size = 0; - pModule->modref_table = 0; - pModule->nrname_fpos = 0; - pModule->moveable_entries = 0; - pModule->alignment = 0; - pModule->truetype = 0; - pModule->os_flags = NE_OSFLAGS_WINDOWS; - pModule->misc_flags = 0; - pModule->dlls_to_init = 0; - pModule->nrname_handle = 0; - pModule->min_swap_area = 0; - pModule->expected_version = 0; - pModule->module32 = 0; - pModule->self = 0; - pModule->self_loading_sel = 0; - - /* File information */ - - pFileInfo = (OFSTRUCT *)(pModule + 1); - pModule->fileinfo = (int)pFileInfo - (int)pModule; - memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) ); - pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) - + strlen(spec->file_name); - strcpy( pFileInfo->szPathName, spec->file_name ); - pstr = (char *)pFileInfo + pFileInfo->cBytes + 1; - - /* Segment table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pSegment = (SEGTABLEENTRY *)pstr; - pModule->seg_table = (int)pSegment - (int)pModule; - pSegment->filepos = 0; - pSegment->size = max_code_offset; - pSegment->flags = 0; - pSegment->minsize = max_code_offset; - pSegment->hSeg = 0; - pSegment++; - - pModule->dgroup_entry = (int)pSegment - (int)pModule; - pSegment->filepos = 0; - pSegment->size = max_data_offset; - pSegment->flags = NE_SEGFLAGS_DATA; - pSegment->minsize = max_data_offset; - pSegment->hSeg = 0; - pSegment++; - - /* Resource table */ - - pstr = (char *)pSegment; - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->res_table = (int)pstr - (int)pModule; - pstr += output_res16_directory( pstr, spec ); - - /* Imported names table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->import_table = (int)pstr - (int)pModule; - *pstr++ = 0; - *pstr++ = 0; - - /* Resident names table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->name_table = (int)pstr - (int)pModule; - /* First entry is module name */ - *pstr = strlen( spec->dll_name ); - strcpy( pstr + 1, spec->dll_name ); - strupper( pstr + 1 ); - pstr += *pstr + 1; - *pstr++ = 0; - *pstr++ = 0; - /* Store all ordinals */ - for (i = 1; i <= spec->limit; i++) - { - ORDDEF *odp = spec->ordinals[i]; - WORD ord = i; - if (!odp || !odp->name[0]) continue; - *pstr = strlen( odp->name ); - strcpy( pstr + 1, odp->name ); - strupper( pstr + 1 ); - pstr += *pstr + 1; - memcpy( pstr, &ord, sizeof(WORD) ); - pstr += sizeof(WORD); - } - *pstr++ = 0; - - /* Entry table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->entry_table = (int)pstr - (int)pModule; for (i = 1; i <= spec->limit; i++) { int selector = 0; + WORD offset; ORDDEF *odp = spec->ordinals[i]; if (!odp) continue; - switch (odp->type) - { + switch (odp->type) + { case TYPE_CDECL: case TYPE_PASCAL: case TYPE_VARARGS: case TYPE_STUB: selector = 1; /* Code selector */ break; - case TYPE_VARIABLE: selector = 2; /* Data selector */ break; - case TYPE_ABS: selector = 0xfe; /* Constant selector */ break; - default: - selector = 0; /* Invalid selector */ - break; + continue; } - if ( !selector ) - continue; - - if ( bundle && bundle->last+1 == i ) - bundle->last++; - else + if (!bundle || prev + 1 != i || prev_sel != selector || *bundle == 255) { - pstr = (char *)(((long)pstr + 1) & ~1); - if ( bundle ) - bundle->next = (char *)pstr - (char *)pModule; + /* need to start a new bundle */ - bundle = (ET_BUNDLE *)pstr; - bundle->first = i-1; - bundle->last = i; - bundle->next = 0; - pstr += sizeof(ET_BUNDLE); + if (prev + 1 != i) + { + int skip = i - (prev + 1); + while (skip > 255) + { + *pstr++ = 255; + *pstr++ = 0; + skip -= 255; + } + *pstr++ = skip; + *pstr++ = 0; + } + + bundle = pstr; + *pstr++ = 0; + *pstr++ = selector; + prev_sel = selector; } - - /* FIXME: is this really correct ?? */ - entry.type = 0xff; /* movable */ - entry.flags = 3; /* exported & public data */ - entry.segnum = selector; - entry.offs = odp->offset; - memcpy( pstr, &entry, sizeof(ET_ENTRY) ); - pstr += sizeof(ET_ENTRY); + /* output the entry */ + *pstr++ = 3; /* flags: exported & public data */ + offset = odp->offset; + memcpy( pstr, &offset, sizeof(WORD) ); + pstr += sizeof(WORD); + (*bundle)++; /* increment bundle entry count */ + prev = i; } *pstr++ = 0; + if ((pstr - buffer) & 1) *pstr++ = 0; + *ret_buff = xrealloc( buffer, pstr - buffer ); + return pstr - buffer; +} - /* Dump the module content */ - pstr = (char *)(((long)pstr + 3) & ~3); - dump_bytes( outfile, (char *)pModule, (int)pstr - (int)pModule, "Module", 0 ); - return (int)pstr - (int)pModule; +/******************************************************************* + * output_bytes + */ +static void output_bytes( FILE *outfile, const void *buffer, unsigned int size ) +{ + unsigned int i; + const unsigned char *ptr = buffer; + + fprintf( outfile, " {" ); + for (i = 0; i < size; i++) + { + if (!(i & 7)) fprintf( outfile, "\n " ); + fprintf( outfile, " 0x%02x", *ptr++ ); + if (i < size - 1) fprintf( outfile, "," ); + } + fprintf( outfile, "\n },\n" ); } @@ -510,25 +373,12 @@ static void output_stub_funcs( FILE *outfile, const DLLSPEC *spec ) fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" ); fprintf( outfile, "#endif\n" ); fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" ); - fprintf( outfile, " struct exc_record {\n" ); - fprintf( outfile, " unsigned int code, flags;\n" ); - fprintf( outfile, " void *rec, *addr;\n" ); - fprintf( outfile, " unsigned int params;\n" ); - fprintf( outfile, " const void *info[15];\n" ); - fprintf( outfile, " } rec;\n\n" ); - fprintf( outfile, " extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" ); - fprintf( outfile, " rec.code = 0x%08x;\n", EXCEPTION_WINE_STUB ); - fprintf( outfile, " rec.flags = %d;\n", EH_NONCONTINUABLE ); - fprintf( outfile, " rec.rec = 0;\n" ); - fprintf( outfile, " rec.params = 2;\n" ); - fprintf( outfile, " rec.info[0] = \"%s\";\n", spec->file_name ); - fprintf( outfile, " rec.info[1] = func;\n" ); - fprintf( outfile, "#ifdef __GNUC__\n" ); - fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" ); - fprintf( outfile, "#else\n" ); - fprintf( outfile, " rec.addr = 0;\n" ); - fprintf( outfile, "#endif\n" ); - fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n}\n\n" ); + fprintf( outfile, " extern void __stdcall RaiseException( unsigned int, unsigned int, unsigned int, const void ** );\n" ); + fprintf( outfile, " const void *args[2];\n" ); + fprintf( outfile, " args[0] = \"%s\";\n", spec->file_name ); + fprintf( outfile, " args[1] = func;\n" ); + fprintf( outfile, " for (;;) RaiseException( 0x%08x, %d, 2, args );\n}\n\n", + EXCEPTION_WINE_STUB, EH_NONCONTINUABLE ); break; } for (i = 0; i <= spec->limit; i++) @@ -554,8 +404,17 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) { ORDDEF **type, **typelist; int i, nFuncs, nTypes; - int code_offset, data_offset, module_size, res_size; - unsigned char *data; + unsigned char *resdir_buffer, *resdata_buffer, *et_buffer, *data_buffer; + unsigned char string[256]; + unsigned int ne_offset, segtable_offset, impnames_offset; + unsigned int entrypoint_size, callfrom_size; + unsigned int code_size, code_offset; + unsigned int data_size, data_offset; + unsigned int resnames_size, resnames_offset; + unsigned int resdir_size, resdir_offset; + unsigned int resdata_size, resdata_offset, resdata_align; + unsigned int et_size, et_offset; + char constructor[100], destructor[100]; #ifdef __i386__ unsigned short code_selector = get_cs(); @@ -569,9 +428,9 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, "extern void __wine_call_from_16_regs();\n" ); fprintf( outfile, "extern void __wine_call_from_16_thunk();\n" ); - data = (unsigned char *)xmalloc( 0x10000 ); - memset( data, 0, 16 ); - data_offset = 16; + data_buffer = xmalloc( 0x10000 ); + memset( data_buffer, 0, 16 ); + data_size = 16; if (!spec->dll_name) /* set default name from file name */ { @@ -624,28 +483,160 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) } #endif - /* Output the DLL functions prototypes */ + /* compute code and data sizes, set offsets, and output prototypes */ + +#ifdef __i386__ + entrypoint_size = 2 + 5 + 4; /* pushw bp + pushl target + call */ + callfrom_size = 5 + 7 + 4 + 8; /* pushl relay + lcall cs:glue + lret n + args */ +#else + entrypoint_size = 4 + 4; /* target + call */ + callfrom_size = 4 + 8; /* lret n + args */ +#endif + code_size = nTypes * callfrom_size; for (i = 0; i <= spec->limit; i++) { ORDDEF *odp = spec->ordinals[i]; if (!odp) continue; - switch(odp->type) + switch (odp->type) { + case TYPE_ABS: + odp->offset = LOWORD(odp->u.abs.value); + break; + case TYPE_VARIABLE: + odp->offset = data_size; + memcpy( data_buffer + data_size, odp->u.var.values, odp->u.var.n_values * sizeof(int) ); + data_size += odp->u.var.n_values * sizeof(int); + break; case TYPE_CDECL: case TYPE_PASCAL: case TYPE_VARARGS: fprintf( outfile, "extern void %s();\n", odp->link_name ); + /* fall through */ + case TYPE_STUB: + odp->offset = code_size; + code_size += entrypoint_size; break; default: + assert(0); break; } } + data_buffer = xrealloc( data_buffer, data_size ); /* free unneeded data */ - /* Output code segment */ + /* Output the module structure */ + + /* DOS header */ fprintf( outfile, "\n#include \"pshpack1.h\"\n" ); - fprintf( outfile, "\nstatic struct code_segment\n{\n" ); + fprintf( outfile, "static const struct module_data\n{\n" ); + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " unsigned short e_magic;\n" ); + fprintf( outfile, " unsigned short e_cblp;\n" ); + fprintf( outfile, " unsigned short e_cp;\n" ); + fprintf( outfile, " unsigned short e_crlc;\n" ); + fprintf( outfile, " unsigned short e_cparhdr;\n" ); + fprintf( outfile, " unsigned short e_minalloc;\n" ); + fprintf( outfile, " unsigned short e_maxalloc;\n" ); + fprintf( outfile, " unsigned short e_ss;\n" ); + fprintf( outfile, " unsigned short e_sp;\n" ); + fprintf( outfile, " unsigned short e_csum;\n" ); + fprintf( outfile, " unsigned short e_ip;\n" ); + fprintf( outfile, " unsigned short e_cs;\n" ); + fprintf( outfile, " unsigned short e_lfarlc;\n" ); + fprintf( outfile, " unsigned short e_ovno;\n" ); + fprintf( outfile, " unsigned short e_res[4];\n" ); + fprintf( outfile, " unsigned short e_oemid;\n" ); + fprintf( outfile, " unsigned short e_oeminfo;\n" ); + fprintf( outfile, " unsigned short e_res2[10];\n" ); + fprintf( outfile, " unsigned int e_lfanew;\n" ); + fprintf( outfile, " } dos_header;\n" ); + + /* NE header */ + + ne_offset = 64; + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " unsigned short ne_magic;\n" ); + fprintf( outfile, " unsigned char ne_ver;\n" ); + fprintf( outfile, " unsigned char ne_rev;\n" ); + fprintf( outfile, " unsigned short ne_enttab;\n" ); + fprintf( outfile, " unsigned short ne_cbenttab;\n" ); + fprintf( outfile, " int ne_crc;\n" ); + fprintf( outfile, " unsigned short ne_flags;\n" ); + fprintf( outfile, " unsigned short ne_autodata;\n" ); + fprintf( outfile, " unsigned short ne_heap;\n" ); + fprintf( outfile, " unsigned short ne_stack;\n" ); + fprintf( outfile, " unsigned int ne_csip;\n" ); + fprintf( outfile, " unsigned int ne_sssp;\n" ); + fprintf( outfile, " unsigned short ne_cseg;\n" ); + fprintf( outfile, " unsigned short ne_cmod;\n" ); + fprintf( outfile, " unsigned short ne_cbnrestab;\n" ); + fprintf( outfile, " unsigned short ne_segtab;\n" ); + fprintf( outfile, " unsigned short ne_rsrctab;\n" ); + fprintf( outfile, " unsigned short ne_restab;\n" ); + fprintf( outfile, " unsigned short ne_modtab;\n" ); + fprintf( outfile, " unsigned short ne_imptab;\n" ); + fprintf( outfile, " unsigned int ne_nrestab;\n" ); + fprintf( outfile, " unsigned short ne_cmovent;\n" ); + fprintf( outfile, " unsigned short ne_align;\n" ); + fprintf( outfile, " unsigned short ne_cres;\n" ); + fprintf( outfile, " unsigned char ne_exetyp;\n" ); + fprintf( outfile, " unsigned char ne_flagsothers;\n" ); + fprintf( outfile, " unsigned short ne_pretthunks;\n" ); + fprintf( outfile, " unsigned short ne_psegrefbytes;\n" ); + fprintf( outfile, " unsigned short ne_swaparea;\n" ); + fprintf( outfile, " unsigned short ne_expver;\n" ); + fprintf( outfile, " } os2_header;\n" ); + + /* segment table */ + + segtable_offset = 64; + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " unsigned short filepos;\n" ); + fprintf( outfile, " unsigned short size;\n" ); + fprintf( outfile, " unsigned short flags;\n" ); + fprintf( outfile, " unsigned short minsize;\n" ); + fprintf( outfile, " } segtable[2];\n" ); + + /* resource directory */ + + resdir_offset = segtable_offset + 2 * 8; + resdir_size = get_res16_directory_size( spec ); + fprintf( outfile, " unsigned char resdir[%d];\n", resdir_size ); + + /* resident names table */ + + resnames_offset = resdir_offset + resdir_size; + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " struct { unsigned char len; char name[%d]; unsigned short ord; } name_0;\n", + strlen( spec->dll_name ) ); + resnames_size = 3 + strlen( spec->dll_name ); + for (i = 1; i <= spec->limit; i++) + { + ORDDEF *odp = spec->ordinals[i]; + if (!odp || !odp->name[0]) continue; + fprintf( outfile, " struct { unsigned char len; char name[%d]; unsigned short ord; } name_%d;\n", + strlen(odp->name), i ); + resnames_size += 3 + strlen( odp->name ); + } + fprintf( outfile, " unsigned char name_last[%d];\n", 2 - (resnames_size & 1) ); + resnames_size = (resnames_size + 2) & ~1; + fprintf( outfile, " } resnames;\n" ); + + /* imported names table */ + + impnames_offset = resnames_offset + resnames_size; + fprintf( outfile, " unsigned char impnames[2];\n" ); + + /* entry table */ + + et_offset = impnames_offset + 2; + et_size = output_entry_table( &et_buffer, spec ); + fprintf( outfile, " unsigned char entry_table[%d];\n", et_size ); + + /* code segment */ + + code_offset = et_offset + et_size; fprintf( outfile, " struct {\n" ); #ifdef __i386__ fprintf( outfile, " unsigned char pushl;\n" ); /* pushl $relay */ @@ -667,10 +658,110 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, " unsigned short call;\n" ); /* call CALLFROM16 */ fprintf( outfile, " short callfrom16;\n" ); fprintf( outfile, " } entry[%d];\n", nFuncs ); - fprintf( outfile, "} code_segment =\n{\n {\n" ); - code_offset = 0; + /* data segment */ + data_offset = code_offset + code_size; + fprintf( outfile, " unsigned char data_segment[%d];\n", data_size ); + if (data_offset + data_size >= 0x10000) + fatal_error( "Not supported yet: 16-bit module data larger than 64K\n" ); + + /* resource data */ + + resdata_offset = ne_offset + data_offset + data_size; + for (resdata_align = 0; resdata_align < 16; resdata_align++) + { + unsigned int size = get_res16_data_size( spec, resdata_offset, resdata_align ); + if ((resdata_offset + size) >> resdata_align <= 0xffff) break; + } + output_res16_directory( &resdir_buffer, spec, resdata_offset, resdata_align ); + resdata_size = output_res16_data( &resdata_buffer, spec, resdata_offset, resdata_align ); + if (resdata_size) fprintf( outfile, " unsigned char resources[%d];\n", resdata_size ); + + /* Output the module data */ + + /* DOS header */ + + fprintf( outfile, "} module =\n{\n {\n" ); + fprintf( outfile, " 0x%04x,\n", IMAGE_DOS_SIGNATURE ); /* e_magic */ + fprintf( outfile, " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" ); + fprintf( outfile, " { 0, 0, 0, 0, }, 0, 0,\n" ); + fprintf( outfile, " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n" ); + fprintf( outfile, " sizeof(module.dos_header)\n" ); /* e_lfanew */ + + /* NE header */ + + fprintf( outfile, " },\n {\n" ); + fprintf( outfile, " 0x%04x,\n", IMAGE_OS2_SIGNATURE ); /* ne_magic */ + fprintf( outfile, " 0, 0,\n" ); + fprintf( outfile, " %d,\n", et_offset ); /* ne_enttab */ + fprintf( outfile, " sizeof(module.entry_table),\n" ); /* ne_cbenttab */ + fprintf( outfile, " 0,\n" ); /* ne_crc */ + fprintf( outfile, " 0x%04x,\n", /* ne_flags */ + NE_FFLAGS_SINGLEDATA | NE_FFLAGS_LIBMODULE ); + fprintf( outfile, " 2,\n" ); /* ne_autodata */ + fprintf( outfile, " %d,\n", spec->heap_size ); /* ne_heap */ + fprintf( outfile, " 0, 0, 0,\n" ); + fprintf( outfile, " 2,\n" ); /* ne_cseg */ + fprintf( outfile, " 0,\n" ); /* ne_cmod */ + fprintf( outfile, " 0,\n" ); /* ne_cbnrestab */ + fprintf( outfile, " %d,\n", segtable_offset ); /* ne_segtab */ + fprintf( outfile, " %d,\n", resdir_offset ); /* ne_rsrctab */ + fprintf( outfile, " %d,\n", resnames_offset ); /* ne_restab */ + fprintf( outfile, " %d,\n", impnames_offset ); /* ne_modtab */ + fprintf( outfile, " %d,\n", impnames_offset ); /* ne_imptab */ + fprintf( outfile, " 0,\n" ); /* ne_nrestab */ + fprintf( outfile, " 0,\n" ); /* ne_cmovent */ + fprintf( outfile, " 0,\n" ); /* ne_align */ + fprintf( outfile, " 0,\n" ); /* ne_cres */ + fprintf( outfile, " 0x%04x,\n", NE_OSFLAGS_WINDOWS ); /* ne_exetyp */ + fprintf( outfile, " 0x%04x,\n", NE_AFLAGS_FASTLOAD ); /* ne_flagsothers */ + fprintf( outfile, " 0,\n" ); /* ne_pretthunks */ + fprintf( outfile, " 0,\n" ); /* ne_psegrefbytes */ + fprintf( outfile, " 0,\n" ); /* ne_swaparea */ + fprintf( outfile, " 0\n" ); /* ne_expver */ + fprintf( outfile, " },\n" ); + + /* segment table */ + + fprintf( outfile, " {\n" ); + fprintf( outfile, " { %d, %d, 0x%04x, %d },\n", + ne_offset + code_offset, code_size, NE_SEGFLAGS_32BIT, code_size ); + fprintf( outfile, " { %d, %d, 0x%04x, %d },\n", + ne_offset + data_offset, data_size, NE_SEGFLAGS_DATA, data_size ); + fprintf( outfile, " },\n" ); + + /* resource directory */ + + output_bytes( outfile, resdir_buffer, resdir_size ); + free( resdir_buffer ); + + /* resident names table */ + + fprintf( outfile, " {\n" ); + strcpy( string, spec->dll_name ); + fprintf( outfile, " { %d, \"%s\", 0 },\n", strlen(string), strupper(string) ); + for (i = 1; i <= spec->limit; i++) + { + ORDDEF *odp = spec->ordinals[i]; + if (!odp || !odp->name[0]) continue; + strcpy( string, odp->name ); + fprintf( outfile, " { %d, \"%s\", %d },\n", strlen(string), strupper(string), i ); + } + fprintf( outfile, " { 0 }\n },\n" ); + + /* imported names table */ + + fprintf( outfile, " { 0, 0 },\n" ); + + /* entry table */ + + output_bytes( outfile, et_buffer, et_size ); + free( et_buffer ); + + /* code segment */ + + fprintf( outfile, " {\n" ); for ( i = 0; i < nTypes; i++ ) { char profile[101], *arg; @@ -732,7 +823,6 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, " { 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n", arg_types[0], arg_types[1] ); #endif - code_offset += sizeof(CALLFROM16); } fprintf( outfile, " },\n {\n" ); @@ -742,15 +832,6 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) if (!odp) continue; switch (odp->type) { - case TYPE_ABS: - odp->offset = LOWORD(odp->u.abs.value); - break; - - case TYPE_VARIABLE: - odp->offset = data_offset; - data_offset += StoreVariableCode( data + data_offset, 4, odp); - break; - case TYPE_CDECL: case TYPE_PASCAL: case TYPE_VARARGS: @@ -759,57 +840,38 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) assert( type ); fprintf( outfile, " /* %s.%d */ ", spec->dll_name, i ); + fprintf( outfile, #ifdef __i386__ - fprintf( outfile, "{ 0x5566, 0x68, %s, 0xe866, %d /* %s */ },\n", + "{ 0x5566, 0x68, %s, 0xe866, %d /* %s */ },\n", #else - fprintf( outfile, "{ %s, 0xe866, %d, /* %s */ },\n", + "{ %s, 0xe866, %d, /* %s */ },\n", #endif odp->link_name, - (type-typelist)*sizeof(CALLFROM16) - - (code_offset + sizeof(ENTRYPOINT16)), + (type - typelist) * callfrom_size - (odp->offset + entrypoint_size), get_function_name( odp ) ); - - odp->offset = code_offset; - code_offset += sizeof(ENTRYPOINT16); break; - - default: - fprintf(stderr,"build: function type %d not available for Win16\n", - odp->type); - exit(1); + default: + break; } } + fprintf( outfile, " },\n" ); - fprintf( outfile, " }\n};\n" ); - /* Output data segment */ + /* data_segment */ - dump_bytes( outfile, data, data_offset, "Data_Segment", 0 ); + output_bytes( outfile, data_buffer, data_size ); + free( data_buffer ); - /* Build the module */ + /* resource data */ - module_size = BuildModule16( outfile, code_offset, data_offset, spec ); - res_size = output_res16_data( outfile, spec ); + if (resdata_size) + { + output_bytes( outfile, resdata_buffer, resdata_size ); + free( resdata_buffer ); + } - /* Output the DLL descriptor */ - - fprintf( outfile, "#include \"poppack.h\"\n\n" ); - - fprintf( outfile, "static const struct dll_descriptor\n{\n" ); - fprintf( outfile, " unsigned char *module_start;\n" ); - fprintf( outfile, " int module_size;\n" ); - fprintf( outfile, " struct code_segment *code_start;\n" ); - fprintf( outfile, " unsigned char *data_start;\n" ); - fprintf( outfile, " const char *owner;\n" ); - fprintf( outfile, " const unsigned char *rsrc;\n" ); - fprintf( outfile, "} descriptor =\n{\n" ); - fprintf( outfile, " Module,\n" ); - fprintf( outfile, " sizeof(Module),\n" ); - fprintf( outfile, " &code_segment,\n" ); - fprintf( outfile, " Data_Segment,\n" ); - fprintf( outfile, " \"%s\",\n", spec->owner_name ); - fprintf( outfile, " %s\n", res_size ? "resource_data" : "0" ); fprintf( outfile, "};\n" ); + fprintf( outfile, "#include \"poppack.h\"\n\n" ); /* Output the DLL constructor */ @@ -820,13 +882,13 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, "void %s(void)\n" "{\n" - " extern void __wine_register_dll_16( const struct dll_descriptor *descr );\n" - " __wine_register_dll_16( &descriptor );\n" - "}\n", constructor ); + " extern void __wine_dll_register_16( const struct module_data *, const char * );\n" + " __wine_dll_register_16( &module, \"%s\" );\n" + "}\n", constructor, spec->file_name ); fprintf( outfile, "void %s(void)\n" "{\n" - " extern void __wine_unregister_dll_16( const struct dll_descriptor *descr );\n" - " __wine_unregister_dll_16( &descriptor );\n" + " extern void __wine_dll_unregister_16( const struct module_data * );\n" + " __wine_dll_unregister_16( &module );\n" "}\n", destructor ); } diff --git a/reactos/tools/winebuild/spec32.c b/reactos/tools/winebuild/spec32.c index 6fb1f4ae0ef..6c3e1ee88dd 100644 --- a/reactos/tools/winebuild/spec32.c +++ b/reactos/tools/winebuild/spec32.c @@ -176,9 +176,7 @@ static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec ) case TYPE_CDECL: if (!(odp->flags & FLAG_FORWARD)) { - fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", - (odp->flags & FLAG_REGISTER) ? make_internal_name( odp, spec, "regs" ) - : odp->link_name ); + fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", odp->link_name ); } else { @@ -261,7 +259,6 @@ static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec ) { ORDDEF *odp = spec->ordinals[i]; unsigned int j, args, mask = 0; - const char *name; /* skip nonexistent entry points */ if (!odp) goto ignore; @@ -277,22 +274,20 @@ static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec ) } if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000; - name = odp->link_name; args = strlen(odp->u.func.arg_types) * sizeof(int); - if (odp->flags & FLAG_REGISTER) name = make_internal_name( odp, spec, "regs" ); switch(odp->type) { case TYPE_STDCALL: - fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name ); + fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", odp->link_name ); fprintf( outfile, " \"\\tret $%d\\n\"\n", args ); - fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask ); + fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", odp->link_name, mask ); break; case TYPE_CDECL: - fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name ); + fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", odp->link_name ); fprintf( outfile, " \"\\tret\\n\"\n" ); fprintf( outfile, " \"\\t" __ASM_SHORT " %d\\n\"\n", args ); - fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask ); + fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", odp->link_name, mask ); break; default: assert(0); @@ -367,38 +362,6 @@ static void output_stub_funcs( FILE *outfile, DLLSPEC *spec ) } -/******************************************************************* - * output_register_funcs - * - * Output the functions for register entry points - */ -static void output_register_funcs( FILE *outfile, DLLSPEC *spec ) -{ - const char *name; - int i; - - for (i = 0; i < spec->nb_entry_points; i++) - { - const ORDDEF *odp = &spec->entry_points[i]; - if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue; - if (!(odp->flags & FLAG_REGISTER)) continue; - if (odp->flags & FLAG_FORWARD) continue; - name = make_internal_name( odp, spec, "regs" ); - fprintf( outfile, - "asm(\".align %d\\n\\t\"\n" - " \"" __ASM_FUNC("%s") "\\n\\t\"\n" - " \"" __ASM_NAME("%s") ":\\n\\t\"\n" - " \"call " __ASM_NAME("__wine_call_from_32_regs") "\\n\\t\"\n" - " \".long " __ASM_NAME("%s") "\\n\\t\"\n" - " \".byte %d,%d\");\n", - get_alignment(4), - name, name, odp->link_name, - strlen(odp->u.func.arg_types) * sizeof(int), - (odp->type == TYPE_CDECL) ? 0 : (strlen(odp->u.func.arg_types) * sizeof(int)) ); - } -} - - /******************************************************************* * output_dll_init * @@ -499,7 +462,7 @@ void output_dll_init( FILE *outfile, const char *constructor, const char *destru void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) { int exports_size = 0; - int nr_exports, nr_imports; + int nr_exports, nr_imports, nr_delayed; DWORD page_size; const char *init_func = spec->init_func; @@ -561,10 +524,6 @@ void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, "static void __asm__dummy(void) {\n" ); fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" ); - /* Output code for all register functions */ - - output_register_funcs( outfile, spec ); - /* Output the exports and relay entry points */ exports_size = output_exports( outfile, nr_exports, spec ); @@ -576,7 +535,7 @@ void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) /* Output the DLL imports */ - nr_imports = output_imports( outfile, spec ); + nr_imports = output_imports( outfile, spec, &nr_delayed ); /* Output the resources */ @@ -626,10 +585,20 @@ void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) " if (reason == %d && __wine_spec_init_state == 1)\n" " _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" " ret = %s ? %s( inst, reason, reserved ) : 1;\n" - " if (reason == %d && __wine_spec_init_state == 1) _fini();\n" - " return ret;\n" - "}\n", + " if (reason == %d && __wine_spec_init_state == 1)\n", DLL_PROCESS_ATTACH, init_func, init_func, DLL_PROCESS_DETACH ); + if (!nr_delayed) + fprintf( outfile, " _fini();\n" ); + else + fprintf( outfile, + " {\n" + " extern int __stdcall FreeLibrary(void *);\n" + " unsigned int i;\n" + " _fini();\n" + " for (i = 0; i < sizeof(__wine_delay_imp_hmod)/sizeof(__wine_delay_imp_hmod[0]); i++)\n" + " if (__wine_delay_imp_hmod[i]) FreeLibrary( __wine_delay_imp_hmod[i] );\n" + " }\n" ); + fprintf( outfile, " return ret;\n}\n" ); init_func = "__wine_dll_main"; } else switch(spec->subsystem) diff --git a/reactos/tools/winebuild/utils.c b/reactos/tools/winebuild/utils.c index 79b3899d97e..1fe09aa30f8 100644 --- a/reactos/tools/winebuild/utils.c +++ b/reactos/tools/winebuild/utils.c @@ -74,6 +74,13 @@ char *strupper(char *s) return s; } +int strendswith(const char* str, const char* end) +{ + int l = strlen(str); + int m = strlen(end); + return l >= m && strcmp(str + l - m, end) == 0; +} + void fatal_error( const char *msg, ... ) { va_list valist; diff --git a/reactos/tools/winebuild/winebuild.man.in b/reactos/tools/winebuild/winebuild.man.in index cca9dcf34c9..19fddf5a648 100644 --- a/reactos/tools/winebuild/winebuild.man.in +++ b/reactos/tools/winebuild/winebuild.man.in @@ -69,6 +69,12 @@ Change to the specified directory before reading source files. Only meaningful in .BR \--debug\ mode. .TP +.BI \-d,\ --delay-lib= name +Set the delayed import mode for the specified library, which must be +one of the libraries imported with the \fB-l\fR option. Delayed mode +means that the library won't be loaded until a function imported from +it is actually called. +.TP .BI \-D\ symbol Ignored for compatibility with the C compiler. .TP @@ -138,11 +144,6 @@ Import the specified library, looking for a corresponding \fIlibname.def\fR file in the directories specified with the \fB-L\fR option. .TP -.BI \-d,\ --delay-lib= name -Same as the \fB-l\fR option, but import the specified library in -delayed mode (i.e. the library won't be loaded until a function -imported from it is actually called). -.TP .BI \-M,\ --main-module= module Specify that we are building a 16-bit dll, that will ultimately be linked together with the 32-bit dll specified in \fImodule\fR. Only @@ -249,7 +250,7 @@ The function returns a 64-bit value (Win32 only). The entry point is only available on i386 platforms. .TP .B -register -The function uses CPU register to pass arguments. +The function uses CPU register to pass arguments (Win16 only). .TP .B -private The function cannot be imported from other dlls, it can only be