commit 2c25c3e9442c69bd2402f94f264f0aafa58b00e0 Author: Alexandre Julliard Date: Tue Jun 29 16:33:12 1993 +0000 Release 0.0.2 WHAT'S NEW with version 0.0.2: - Again thanks to Eric Youngdale for some very useful comments. - The Windows startup code created by Micrsoft C 7.0 now runs to completion. - Added a new patch to the kernel to increase the usable size of the ldt to the full 32 entries currently allowed. - Imported name relocations are now supported. - Source code for my infamous test program is now included. - A handful of basic Windows functions are now emulated. See "kernel.spec" for examples of how to use the build program. WHAT'S NEW with version 0.0.1: - Eric Youngdale contributed countless improvements in memory efficiency, bug fixes, and relocation. - The build program has been completed. It now lets you specify how the main DLL entry point should interface to your emulation library routines. A brief description of how to build these specifications is included in the file "build-spec.txt". - The code to dispatch builtin DLL calls is complete, but untested. diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 00000000000..45db164e368 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,3 @@ +/* + * Copyright Robert J. Amstadt, 1993 + */ diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..54dff6defb5 --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +CFLAGS=-g + +###################################################################### +# FILES: +# +# Be very careful if you change the order of the files listed +# here. if1632.o must linked first to guarrantee that it sits at a low +# enough address. I intend to change this requirement someday, but +# for now live with it. +# +DLL_LENGTH=256 + +BUILDOBJS=dll_kernel.o dll_user.o dll_gdi.o dll_unixlib.o \ + dll_kernel_tab.o dll_user_tab.o dll_gdi_tab.o dll_unixlib_tab.o + +MUST_BE_LINKED_FIRST=if1632.o $(BUILDOBJS) + +OBJS=$(MUST_BE_LINKED_FIRST) \ + dump.o heap.o ldt.o kernel.o relay.o selector.o user.o wine.o + +TARGET=wine +LIBS=-lldt + +all: $(TARGET) libldt.a + +clean: + rm -f *.o *~ *.s dll_* + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LIBS) + +build: build.c + cc -g -o build build.c + +libldt.a: ldtlib.c + $(CC) -O6 -c ldtlib.c + ar rcs libldt.a ldtlib.o + +dll_kernel.S dll_kernel_tab.c: build kernel.spec + build kernel.spec + +dll_user.S dll_user_tab.c: build user.spec + build user.spec + +dll_gdi.S dll_gdi_tab.c: build gdi.spec + build gdi.spec + +dll_unixlib.S dll_unixlib_tab.c: build unixlib.spec + build unixlib.spec diff --git a/README b/README new file mode 100644 index 00000000000..09eb3dee57f --- /dev/null +++ b/README @@ -0,0 +1,73 @@ +Copyright Robert J. Amstadt, 1993. All code is provided without +warranty. It is my intent to cover this code with the Gnu Public +License. + +So here goes release 0.0.2 of the Windows loader. It will do some +relocations and then run the program. The program test.exe is a +Windows executable. Try the command "wine test.exe". + +WHAT'S NEW with version 0.0.2: + + - Again thanks to Eric Youngdale for some very useful comments. + - The Windows startup code created by Micrsoft C 7.0 now runs + to completion. + - Added a new patch to the kernel to increase the usable size of + the ldt to the full 32 entries currently allowed. + - Imported name relocations are now supported. + - Source code for my infamous test program is now included. + - A handful of basic Windows functions are now emulated. See + "kernel.spec" for examples of how to use the build program. + +WHAT'S NEW with version 0.0.1: + + - Eric Youngdale contributed countless improvements in memory + efficiency, bug fixes, and relocation. + - The build program has been completed. It now lets you specify + how the main DLL entry point should interface to your emulation + library routines. A brief description of how to build these + specifications is included in the file "build-spec.txt". + - The code to dispatch builtin DLL calls is complete, but untested. + +TODO: + + - Segment fixup code completion. + - Make changes to the kernel to allow more than 32 LDT entries. + - Trap and handle DOS and DPMI calls. + - Windows emulation library (connect to Peter MacDonald's library). + - Set registers correctly when starting Windows program. + - Allowing loading of 16-bit DLLs for use with program. + - global memory allocation + - complete and improve local heap allocation + +INSTALLATION: + + Uncompress and untar this archive into the directory of your +choice. The file "ldt.tar" contains a necessary kernel patch against +Linux 0.99.10. If you installed the "ldt.tar" from the first release +of this package, then you MUST to replace it. In the directory +/usr/src/linux (or whereever you keep your kernel sources), untar +this file it contains three files: + + kernel/ldt.c + - This is source for a new system call. + + include/linux/ldt.h + - This contains structures defining the system call + interface. + + ldt.patch + - This is a patch that must be applied to the kernel. + It updates two header files, and the kernel Makefile. + +BUILD: + + The documentation for the build program is in the file build-spec.txt + +FINALE: + +Good luck, + + If you successfully add anything, please send me a copy. + +Bob Amstadt +bob@amscons.com diff --git a/build b/build new file mode 100755 index 00000000000..d47f5423726 Binary files /dev/null and b/build differ diff --git a/build-spec.txt b/build-spec.txt new file mode 100644 index 00000000000..61937bf2b9c --- /dev/null +++ b/build-spec.txt @@ -0,0 +1,81 @@ +name NAME +id ID_NUMBER +length NUMBER_OF_ORDINALS + +ORDINAL VARTYPE EXPORTNAME (DATA [DATA [DATA [...]]]) + +ORDINAL FUNCTYPE EXPORTNAME([ARGTYPE [ARGTYPE [...]]]) + HANDLERNAME([ARGNUM [ARGNUM [...]]]) + +ORDINAL equate EXPORTNAME DATA +-------------------- +General: + + "name", "id" and "length" fields are mandatory. Specific ordinal +declarations are optional, but the default handler will print an +error message. + +Variable ordinals: + + This type defines data storage at the ordinal specified. You may +store items as bytes, 16-bit words, or 32-bit words. + "ORDINAL" is replaced by the ordinal number corresponding to the +variable. "VARTYPE" should be "byte", "word" or "long" for 8, 16, or +32 bits respectively. "EXPORTNAME" will be the name available for +dynamic linking. "DATA" can be a decimal number or a hex number preceeded +by "0x". The following example defines the variable "VariableA" at +ordinal 2 and containing 4 bytes: + + 2 byte VariableA -1 0xff 0 0 + +Function ordinals: + + This type defines a function entry point. The prototype defined +by "EXPORTNAME ([ARGTYPE [ARGTYPE [...]]])" specifies the name available +for dynamic linking and the format of the 16-bit stack. By specifying +"FUNCTYPE", the loader can automatically determine which order the +parameters were pushed by the calling routine. The prototype +specified by "HANDLERNAME([ARGNUM [ARGNUM [...]]])" specifies to +the loader how to call the 32-bit library routine which will handle this +call. Note that specifying "ARGNUM" as 1 means the leftmost argument +given to the function call, and not the first argument on the stack. +For "pascal" functions, "ARGNUM" equal to 1 specifies the last +argument on the stack. If you do not specify any arguments to the +handler function, then address of the 16-bit argument stack is +passed to the handler function. + "ORDINAL" is replaced by the ordinal number corresponding to the +function. "FUNCTYPE" should be "c" or "pascal" ("pascal" may be +shortened to "p"). "EXPORTNAME" will be the name available for +dynamic linking. "ARGTYPE" should be "byte", "word", "long", "ptr", +"s_byte" (signed byte), "s_word" (signed word) or "s_long" +(signed long). "HANDLERNAME" is the name of the actual function +that will process the request in 32-bit mode. "ARGNUM" is the +original argument number. The first argument is numbered "1". + + This first example defines an entry point for the CreateWindow() +call (the ordinal 100 is just an example): + + 100 pascal CreateWindow(ptr ptr long s_word s_word s_word s_word + word word word ptr) + WIN_CreateWindow(1 2 3 4 5 6 7 8 9 10 11) + + This second example defines an entry point for the GetFocus() +call (the ordinal 100 is just an example): + + 100 pascal GetFocus() WIN_GetFocus() + +Equate ordinals: + + This type defines an ordinal as an absolute value. +"ORDINAL" is replaced by the ordinal number corresponding to the +variable. "EXPORTNAME" will be the name available for dynamic linking. +"DATA" can be a decimal number or a hex number preceeded by "0x". + +Return ordinals: + + This type defines a function entry point whose handler should do +nothing but return a value. + "ORDINAL" is replaced by the ordinal number corresponding to the +variable. ARGLENGTH is the number of bytes that need to be removed +from the stack before returning to the caller. RETVALUE is the +return value which will be passed back to the caller. diff --git a/build.c b/build.c new file mode 100644 index 00000000000..f7dd03d6c81 --- /dev/null +++ b/build.c @@ -0,0 +1,707 @@ +/* + * Copyright Robert J. Amstadt, 1993 + */ +#include +#include +#include +#include + +#define VARTYPE_BYTE 0 +#define VARTYPE_SIGNEDWORD 0 +#define VARTYPE_WORD 1 +#define VARTYPE_LONG 2 +#define VARTYPE_FARPTR 3 + +#define FUNCTYPE_PASCAL 16 +#define FUNCTYPE_C 17 +#define FUNCTYPE_REG 19 + +#define EQUATETYPE_ABS 18 + +#define MAX_ORDINALS 1024 + +typedef struct ordinal_definition_s +{ + int valid; + int type; + char export_name[80]; + void *additional_data; +} ORDDEF; + +typedef struct ordinal_variable_definition_s +{ + int n_values; + int *values; +} ORDVARDEF; + +typedef struct ordinal_function_definition_s +{ + int n_args_16; + int arg_types_16[16]; + int arg_16_offsets[16]; + int arg_16_size; + char internal_name[80]; + int n_args_32; + int arg_indices_32[16]; +} ORDFUNCDEF; + +ORDDEF OrdinalDefinitions[MAX_ORDINALS]; + +char LowerDLLName[80]; +char UpperDLLName[80]; +int Limit; +int DLLId; +FILE *SpecFp; + +char *ParseBuffer = NULL; +char *ParseNext; +char ParseSaveChar; +int Line; + +int IsNumberString(char *s) +{ + while (*s != '\0') + if (!isdigit(*s++)) + return 0; + + return 1; +} + +char *strlower(char *s) +{ + char *p; + + for(p = s; *p != '\0'; p++) + *p = tolower(*p); + + return s; +} + +char *strupper(char *s) +{ + char *p; + + for(p = s; *p != '\0'; p++) + *p = toupper(*p); + + return s; +} + +int stricmp(char *s1, char *s2) +{ + if (strlen(s1) != strlen(s2)) + return -1; + + while (*s1 != '\0') + if (*s1++ != *s2++) + return -1; + + return 0; +} + +char * +GetTokenInLine(void) +{ + char *p; + char *token; + + if (ParseNext != ParseBuffer) + { + if (ParseSaveChar == '\0') + return NULL; + *ParseNext = ParseSaveChar; + } + + /* + * Remove initial white space. + */ + for (p = ParseNext; isspace(*p); p++) + ; + + if (*p == '\0') + return NULL; + + /* + * Find end of token. + */ + token = p++; + if (*token != '(' && *token != ')') + while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p)) + p++; + + ParseSaveChar = *p; + ParseNext = p; + *p = '\0'; + + return token; +} + +char * +GetToken(void) +{ + char *token; + + if (ParseBuffer == NULL) + { + ParseBuffer = malloc(512); + ParseNext = ParseBuffer; + Line++; + if (fgets(ParseBuffer, 511, SpecFp) == NULL) + return NULL; + } + + while ((token = GetTokenInLine()) == NULL) + { + ParseNext = ParseBuffer; + Line++; + if (fgets(ParseBuffer, 511, SpecFp) == NULL) + return NULL; + } + + return token; +} + +int +ParseVariable(int ordinal, int type) +{ + ORDDEF *odp; + ORDVARDEF *vdp; + char export_name[80]; + char *token; + char *endptr; + int *value_array; + int n_values; + int value_array_size; + + strcpy(export_name, GetToken()); + + token = GetToken(); + if (*token != '(') + { + fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token); + exit(1); + } + + n_values = 0; + value_array_size = 25; + value_array = malloc(sizeof(*value_array) * value_array_size); + + while ((token = GetToken()) != NULL) + { + if (*token == ')') + break; + + value_array[n_values++] = strtol(token, &endptr, 0); + if (n_values == value_array_size) + { + value_array_size += 25; + value_array = realloc(value_array, + sizeof(*value_array) * value_array_size); + } + + if (endptr == NULL || *endptr != '\0') + { + fprintf(stderr, "%d: Expected number value, got '%s'\n", Line, + token); + exit(1); + } + } + + if (token == NULL) + { + fprintf(stderr, "%d: End of file in variable declaration\n", Line); + exit(1); + } + + if (ordinal >= MAX_ORDINALS) + { + fprintf(stderr, "%d: Ordinal number too large\n", Line); + exit(1); + } + + odp = &OrdinalDefinitions[ordinal]; + odp->valid = 1; + odp->type = type; + strcpy(odp->export_name, export_name); + + vdp = malloc(sizeof(*vdp)); + odp->additional_data = vdp; + + vdp->n_values = n_values; + vdp->values = realloc(value_array, sizeof(*value_array) * n_values); + + return 0; +} + +int +ParseExportFunction(int ordinal, int type) +{ + char *token; + ORDDEF *odp; + ORDFUNCDEF *fdp; + int arg_types[16]; + int i; + int arg_num; + int current_offset; + int arg_size; + + + if (ordinal >= MAX_ORDINALS) + { + fprintf(stderr, "%d: Ordinal number too large\n", Line); + exit(1); + } + + odp = &OrdinalDefinitions[ordinal]; + strcpy(odp->export_name, GetToken()); + odp->valid = 1; + odp->type = type; + fdp = malloc(sizeof(*fdp)); + odp->additional_data = fdp; + + token = GetToken(); + if (*token != '(') + { + fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token); + exit(1); + } + + fdp->arg_16_size = 0; + for (i = 0; i < 16; i++) + { + token = GetToken(); + if (*token == ')') + break; + + if (stricmp(token, "byte") == 0 || stricmp(token, "word") == 0) + { + fdp->arg_types_16[i] = VARTYPE_WORD; + fdp->arg_16_size += 2; + fdp->arg_16_offsets[i] = 2; + } + else if (stricmp(token, "s_byte") == 0 || + stricmp(token, "s_word") == 0) + { + fdp->arg_types_16[i] = VARTYPE_SIGNEDWORD; + fdp->arg_16_size += 2; + fdp->arg_16_offsets[i] = 2; + } + else if (stricmp(token, "long") == 0 || stricmp(token, "s_long") == 0) + { + fdp->arg_types_16[i] = VARTYPE_LONG; + fdp->arg_16_size += 4; + fdp->arg_16_offsets[i] = 4; + } + else if (stricmp(token, "ptr") == 0) + { + fdp->arg_types_16[i] = VARTYPE_FARPTR; + fdp->arg_16_size += 4; + fdp->arg_16_offsets[i] = 4; + } + else + { + fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token); + exit(1); + } + } + fdp->n_args_16 = i; + + if (type == FUNCTYPE_PASCAL || type == FUNCTYPE_REG) + { + current_offset = 0; + for (i--; i >= 0; i--) + { + arg_size = fdp->arg_16_offsets[i]; + fdp->arg_16_offsets[i] = current_offset; + current_offset += arg_size; + } + } + else + { + current_offset = 0; + for (i = 0; i < fdp->n_args_16; i++) + { + arg_size = fdp->arg_16_offsets[i]; + fdp->arg_16_offsets[i] = current_offset; + current_offset += arg_size; + } + } + + strcpy(fdp->internal_name, GetToken()); + token = GetToken(); + if (*token != '(') + { + fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token); + exit(1); + } + for (i = 0; i < 16; i++) + { + token = GetToken(); + if (*token == ')') + break; + + fdp->arg_indices_32[i] = atoi(token); + if (fdp->arg_indices_32[i] < 1 || + fdp->arg_indices_32[i] > fdp->n_args_16) + { + fprintf(stderr, "%d: Bad argument index %d\n", Line, + fdp->arg_indices_32[i]); + exit(1); + } + } + fdp->n_args_32 = i; + + return 0; +} + +int +ParseEquate(int ordinal) +{ + ORDDEF *odp; + char *token; + char *endptr; + int value; + + if (ordinal >= MAX_ORDINALS) + { + fprintf(stderr, "%d: Ordinal number too large\n", Line); + exit(1); + } + + odp = &OrdinalDefinitions[ordinal]; + strcpy(odp->export_name, GetToken()); + + token = GetToken(); + value = strtol(token, &endptr, 0); + if (endptr == NULL || *endptr != '\0') + { + fprintf(stderr, "%d: Expected number value, got '%s'\n", Line, + token); + exit(1); + } + + odp->valid = 1; + odp->type = EQUATETYPE_ABS; + odp->additional_data = (void *) value; + + return 0; +} + +int +ParseOrdinal(int ordinal) +{ + char *token; + + token = GetToken(); + if (token == NULL) + { + fprintf(stderr, "%d: Expected type after ordinal\n", Line); + exit(1); + } + + if (stricmp(token, "byte") == 0) + return ParseVariable(ordinal, VARTYPE_BYTE); + else if (stricmp(token, "word") == 0) + return ParseVariable(ordinal, VARTYPE_WORD); + else if (stricmp(token, "long") == 0) + return ParseVariable(ordinal, VARTYPE_LONG); + else if (stricmp(token, "c") == 0) + return ParseExportFunction(ordinal, FUNCTYPE_C); + else if (stricmp(token, "p") == 0) + return ParseExportFunction(ordinal, FUNCTYPE_PASCAL); + else if (stricmp(token, "pascal") == 0) + return ParseExportFunction(ordinal, FUNCTYPE_PASCAL); + else if (stricmp(token, "register") == 0) + return ParseExportFunction(ordinal, FUNCTYPE_REG); + else if (stricmp(token, "equate") == 0) + return ParseEquate(ordinal); + else + { + fprintf(stderr, + "%d: Expected type after ordinal, found '%s' instead\n", + Line, token); + exit(1); + } +} + +int +ParseTopLevel(void) +{ + char *token; + + while ((token = GetToken()) != NULL) + { + if (stricmp(token, "name") == 0) + { + strcpy(LowerDLLName, GetToken()); + strlower(LowerDLLName); + + strcpy(UpperDLLName, LowerDLLName); + strupper(UpperDLLName); + } + else if (stricmp(token, "id") == 0) + { + token = GetToken(); + if (!IsNumberString(token)) + { + fprintf(stderr, "%d: Expected number after id\n", Line); + exit(1); + } + + DLLId = atoi(token); + } + else if (stricmp(token, "length") == 0) + { + token = GetToken(); + if (!IsNumberString(token)) + { + fprintf(stderr, "%d: Expected number after length\n", Line); + exit(1); + } + + Limit = atoi(token); + } + else if (IsNumberString(token)) + { + int ordinal; + int rv; + + ordinal = atoi(token); + if ((rv = ParseOrdinal(ordinal)) < 0) + return rv; + } + else + { + fprintf(stderr, + "%d: Expected name, id, length or ordinal\n", Line); + exit(1); + } + } + + return 0; +} + +void +OutputVariableCode(FILE *fp, char *storage, ORDDEF *odp) +{ + ORDVARDEF *vdp; + int i; + + fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); + + vdp = odp->additional_data; + for (i = 0; i < vdp->n_values; i++) + { + if ((i & 7) == 0) + fprintf(fp, "\t%s\t", storage); + + fprintf(fp, "%d", vdp->values[i]); + + if ((i & 7) == 7 || i == vdp->n_values - 1) + fprintf(fp, "\n"); + else + fprintf(fp, ", "); + } + fprintf(fp, "\n"); +} + +main(int argc, char **argv) +{ + ORDDEF *odp; + ORDFUNCDEF *fdp; + FILE *fp; + char filename[80]; + char buffer[80]; + char *p; + int i; + + if (argc < 2) + { + fprintf(stderr, "usage: build SPECNAME\n"); + exit(1); + } + + SpecFp = fopen(argv[1], "r"); + if (SpecFp == NULL) + { + fprintf(stderr, "Could not open specification file, '%s'\n", argv[1]); + exit(1); + } + + ParseTopLevel(); + + sprintf(filename, "dll_%s.S", LowerDLLName); + fp = fopen(filename, "w"); + + fprintf(fp, "\t.globl _%s_Dispatch\n", UpperDLLName); + fprintf(fp, "_%s_Dispatch:\n", UpperDLLName); + fprintf(fp, "\torl\t$0x%08x,%%eax\n", DLLId << 16); + fprintf(fp, "\tjmp\t_CallTo32\n\n"); + + odp = OrdinalDefinitions; + for (i = 0; i <= Limit; i++, odp++) + { + fprintf(fp, "\t.globl _%s_Ordinal_%d\n", UpperDLLName, i); + + if (!odp->valid) + { + fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); + fprintf(fp, "\tmovl\t$%d,%%eax\n", i); + fprintf(fp, "\tpushw\t$0\n"); + fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); + } + else + { + fdp = odp->additional_data; + + switch (odp->type) + { + case EQUATETYPE_ABS: + fprintf(fp, "_%s_Ordinal_%d = %d\n\n", + UpperDLLName, i, (int) odp->additional_data); + break; + + case VARTYPE_BYTE: + OutputVariableCode(fp, ".byte", odp); + break; + + case VARTYPE_WORD: + OutputVariableCode(fp, ".word", odp); + break; + + case VARTYPE_LONG: + OutputVariableCode(fp, ".long", odp); + break; + + case FUNCTYPE_REG: + fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); + fprintf(fp, "\tpushw\t%%ax\n"); + fprintf(fp, "\tpushw\t%%cx\n"); + fprintf(fp, "\tpushw\t%%dx\n"); + fprintf(fp, "\tpushw\t%%bx\n"); + fprintf(fp, "\tpushw\t%%sp\n"); + fprintf(fp, "\tpushw\t%%bp\n"); + fprintf(fp, "\tpushw\t%%si\n"); + fprintf(fp, "\tpushw\t%%di\n"); + fprintf(fp, "\tpushw\t%%ds\n"); + fprintf(fp, "\tpushw\t%%es\n"); + fprintf(fp, "\tmovl\t%%ebp,%%eax\n"); + fprintf(fp, "\tmovw\t%%esp,%%ebp\n"); + fprintf(fp, "\tpushl\t20(%%ebp)\n"); + fprintf(fp, "\tmovl\t%%eax,%%ebp\n"); + fprintf(fp, "\tmovl\t$%d,%%eax\n", i); + fprintf(fp, "\tpushw\t$24\n"); + fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); + break; + + case FUNCTYPE_PASCAL: + fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); + fprintf(fp, "\tmovl\t$%d,%%eax\n", i); + fprintf(fp, "\tpushw\t$%d\n", fdp->arg_16_size); + fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); + break; + + case FUNCTYPE_C: + default: + fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); + fprintf(fp, "\tmovl\t$%d,%%eax\n", i); + fprintf(fp, "\tpushw\t$0\n"); + fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); + break; + } + } + } + + fclose(fp); + + sprintf(filename, "dll_%s_tab.c", LowerDLLName); + fp = fopen(filename, "w"); + + fprintf(fp, "#include \n"); + fprintf(fp, "#include \n"); + fprintf(fp, "#include \042dlls.h\042\n\n"); + + for (i = 0; i <= Limit; i++) + { + fprintf(fp, "extern void %s_Ordinal_%d();\n", UpperDLLName, i); + } + + odp = OrdinalDefinitions; + for (i = 0; i <= Limit; i++, odp++) + { + if (odp->valid && + (odp->type == FUNCTYPE_PASCAL || odp->type == FUNCTYPE_C || + odp->type == FUNCTYPE_REG)) + { + fdp = odp->additional_data; + fprintf(fp, "extern int %s();\n", fdp->internal_name); + } + } + + fprintf(fp, "\nstruct dll_table_entry_s %s_table[%d] =\n", + UpperDLLName, Limit + 1); + fprintf(fp, "{\n"); + odp = OrdinalDefinitions; + for (i = 0; i <= Limit; i++, odp++) + { + fdp = odp->additional_data; + + if (!odp->valid) + odp->type = -1; + + switch (odp->type) + { + case FUNCTYPE_PASCAL: + case FUNCTYPE_REG: + fprintf(fp, " { 0x23, %s_Ordinal_%d, ", UpperDLLName, i); + fprintf(fp, "\042%s\042, ", odp->export_name); + fprintf(fp, "%s, DLL_HANDLERTYPE_PASCAL, ", fdp->internal_name); + fprintf(fp, "%d, ", fdp->n_args_32); + if (fdp->n_args_32 > 0) + { + int argnum; + + fprintf(fp, "\n {\n"); + for (argnum = 0; argnum < fdp->n_args_32; argnum++) + { + fprintf(fp, " { %d, %d },\n", + fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1], + fdp->arg_types_16[argnum]); + } + fprintf(fp, " }\n "); + } + fprintf(fp, "}, \n"); + break; + + case FUNCTYPE_C: + fprintf(fp, " { 0x23, %s_Ordinal_%d, ", UpperDLLName, i); + fprintf(fp, "\042%s\042, ", odp->export_name); + fprintf(fp, "%s, DLL_HANDLERTYPE_C, ", fdp->internal_name); + fprintf(fp, "%d, ", fdp->n_args_32); + if (fdp->n_args_32 > 0) + { + int argnum; + + fprintf(fp, "\n {\n"); + for (argnum = 0; argnum < fdp->n_args_32; argnum++) + { + fprintf(fp, " { %d, %d },\n", + fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1], + fdp->arg_types_16[argnum]); + } + fprintf(fp, " }\n "); + } + fprintf(fp, "}, \n"); + break; + + default: + fprintf(fp, " { 0x23, %s_Ordinal_%d, \042\042, NULL },\n", + UpperDLLName, i); + break; + } + } + fprintf(fp, "};\n"); + + fclose(fp); +} + diff --git a/dlls.h b/dlls.h new file mode 100644 index 00000000000..a43a9e0cd53 --- /dev/null +++ b/dlls.h @@ -0,0 +1,56 @@ +/* $Id$ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ + +#ifndef DLLS_H +#define DLLS_H + +typedef struct dll_arg_relocation_s +{ + unsigned short dst_arg; /* Offset to argument on stack */ + unsigned char src_type; /* Argument type */ +} DLL_ARG; + +#define DLL_ARGTYPE_SIGNEDWORD 0 +#define DLL_ARGTYPE_WORD 1 +#define DLL_ARGTYPE_LONG 2 +#define DLL_ARGTYPE_FARPTR 3 +#define DLL_MAX_ARGS 16 + +#define DLL_HANDLERTYPE_PASCAL 16 +#define DLL_HANDLERTYPE_C 17 + +struct dll_table_entry_s +{ + /* + * Relocation data + */ + unsigned int selector; /* Selector to access this entry point */ + void *address; /* Offset in segment of entry point */ + + /* + * 16->32 bit interface data + */ + char *export_name; + void *handler; /* Address of function to process request */ + int handler_type; /* C or PASCAL calling convention */ + int n_args; /* Number of arguments passed to function */ + DLL_ARG args[DLL_MAX_ARGS]; /* Argument conversion data */ +}; + +struct dll_name_table_entry_s +{ + char *dll_name; + struct dll_table_entry_s *dll_table; + int dll_table_length; + int dll_number; +}; + +extern struct dll_table_entry_s KERNEL_table[]; +extern struct dll_table_entry_s USER_table[]; +extern struct dll_table_entry_s GDI_table[]; +extern struct dll_table_entry_s UNIXLIB_table[]; + +#endif /* DLLS_H */ diff --git a/dump.c b/dump.c new file mode 100644 index 00000000000..72edc7a9003 --- /dev/null +++ b/dump.c @@ -0,0 +1,92 @@ +/* $Id$ + */ + +/* + * Copyright Robert J. Amstadt, 1993 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "neexe.h" +#include "segmem.h" +#include "prototypes.h" + +/********************************************************************** + * PrintFileHeader + */ +void +PrintFileHeader(struct ne_header_s *ne_header) +{ + printf("ne_header: %c%c\n", + ne_header->header_type[0], + ne_header->header_type[1]); + printf("linker version: %d.%d\n", ne_header->linker_version, + ne_header->linker_revision); + printf("format flags: %04.4x\n", ne_header->format_flags); + printf("automatic data segment: %04.4x\n", ne_header->auto_data_seg); + printf("CS:IP %04.4x:%04.4x\n", ne_header->cs, ne_header->ip); + printf("SS:SP %04.4x:%04.4x\n", ne_header->ss, ne_header->sp); + printf("additional flags: %02.2x\n", ne_header->additional_flags); + printf("operating system: %02.2x\n", ne_header->operating_system); + printf("fast load offset: %04.4x\n", ne_header->fastload_offset); + printf("fast load length: %04.4x\n", ne_header->fastload_length); +} + +/********************************************************************** + * PrintSegmentTable + */ +void +PrintSegmentTable(struct ne_segment_table_entry_s *seg_table, int nentries) +{ + int i; + + for (i = 0; i < nentries; i++) + { + printf(" %2d: OFFSET %04.4x, LENGTH %04.4x, ", + i + 1, seg_table[i].seg_data_offset, + seg_table[i].seg_data_length); + printf("FLAGS %04.4x, MIN ALLOC %04.4x\n", + seg_table[i].seg_flags, seg_table[i].min_alloc); + } +} + +/********************************************************************** + * PrintRelocationTable + */ +void +PrintRelocationTable(char *exe_ptr, + struct ne_segment_table_entry_s *seg_entry_p, + int segment) +{ + struct relocation_entry_s *rep; + int i; + int offset; + u_short n_entries, *sp; + + printf("RELOCATION TABLE %d:\n", segment + 1); + + if (seg_entry_p->seg_data_offset == 0) + return; + + offset = seg_entry_p->seg_data_length; + if (offset == 0) + offset = 0x10000; + + sp = (u_short *) (exe_ptr + seg_entry_p->seg_data_offset * 512 + offset); + n_entries = *sp; + + rep = (struct relocation_entry_s *) (sp + 1); + for (i = 0; i < n_entries; i++, rep++) + { + printf(" ADDR TYPE %d, TYPE %d, OFFSET %04.4x,", + rep->address_type, rep->relocation_type, rep->offset); + printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2); + } +} diff --git a/gdi.spec b/gdi.spec new file mode 100644 index 00000000000..9f87b181f52 --- /dev/null +++ b/gdi.spec @@ -0,0 +1,3 @@ +name gdi +id 3 +length 256 diff --git a/heap.c b/heap.c new file mode 100644 index 00000000000..156e9c83c27 --- /dev/null +++ b/heap.c @@ -0,0 +1,93 @@ +static char RCSId[] = "$Id$"; +static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; + +#include +#include +#include "prototypes.h" + +typedef struct heap_mem_desc_s +{ + struct heap_mem_desc_s *prev, *next; + int length; +} MDESC; + +MDESC *FreeList; + +/********************************************************************** + * HEAP_LocalInit + */ +void +HEAP_LocalInit(void *start, int length) +{ + FreeList = (MDESC *) start; + FreeList->prev = NULL; + FreeList->next = NULL; + FreeList->length = length - sizeof(MDESC); +} + +/********************************************************************** + * HEAP_LocalAlloc + */ +void * +HEAP_LocalAlloc(int flags, int bytes) +{ + MDESC *m, *m_new; + +#ifdef HEAP_DEBUG + fprintf(stderr, "LocalAlloc: flags %x, bytes %d, ", flags, bytes); +#endif + + /* + * Find free block big enough. + */ + for (m = FreeList; m != NULL; m = m->next) + { + if (m->length == bytes && m->length < bytes + 4 * sizeof(MDESC)) + { + break; + } + else if (m->length > bytes) + { + m_new = m + (bytes / sizeof(MDESC)) + 2; + if (m->prev == NULL) + FreeList = m_new; + else + m->prev->next = m_new; + + if (m->next != NULL) + m->next->prev = m_new; + + m_new->next = m->next; + m_new->prev = m->prev; + m_new->length = m->length - ((int) m_new - (int) m); + m->length -= (m_new->length + sizeof(MDESC)); + +#ifdef HEAP_DEBUG + fprintf(stderr, "Returning %x\n", (int) (m + 1)); +#endif + return (void *) (m + 1); + } + } + + if (m != NULL) + { + if (m->prev == NULL) + FreeList = m->next; + else + m->prev->next = m->next; + + if (m->next != NULL) + m->next->prev = m->prev; + +#ifdef HEAP_DEBUG + fprintf(stderr, "Returning %x\n", (int) (m + 1)); +#endif + return (void *) (m + 1); + } + +#ifdef HEAP_DEBUG + fprintf(stderr, "Returning 0\n"); +#endif + return 0; +} + diff --git a/if1632.S b/if1632.S new file mode 100644 index 00000000000..7d2bbed2960 --- /dev/null +++ b/if1632.S @@ -0,0 +1,294 @@ +/* + * Copyright Robert J. Amstadt, 1993 + */ + .data +jump_target: +return_value: + .long 0 + +/********************************************************************** + * Places to keep info about the current 32-bit stack frame. + */ +saved_esp: + .long 0 +saved_ebp: + .long 0 +saved_ss: + .word 0 + +/********************************************************************** + * Places to keep info about the current 16-bit stack frame. + */ +saved_16esp: + .long 0 +saved_16ebp: + .long 0 +saved_16ss: + .word 0 + +nbytes: + .word 0 +selector: + .word 0 +offset: + .word 0 + + .text + +/********************************************************************** + * int CallTo16(unsigned long csip, unsigned long sssp, + * unsigned short ds) + * + * Stack: 0 ebp + * 4 eip + * 8 target ip + * 10 target cs + * 12 target sp + * 14 target ss + * 16 target ds + */ + .align 4 + .globl _CallTo16 +_CallTo16: + pushl %ebp + movl %esp,%ebp + + /* + * Save our registers + */ + pushal + pushl saved_esp + pushl saved_ebp + pushw saved_ss + + /* + * Get target address. + */ + movl 8(%ebp),%eax + movl %eax,jump_target + lea jump_target,%edx + + /* + * Put stack registers where we can get them after stack switch. + */ + movw %ss,saved_ss + movl %esp,saved_esp + movl %ebp,saved_ebp + + /* + * Load ds, es, sp, ss & bp + */ + movl $0,%eax + movw _PSPSelector,%ax + movw %ax,%es + movw 16(%ebp),%ax + movw %ax,%ds + xorl %eax,%eax + movw 12(%ebp),%ax + movl %eax,%esp + movw 14(%ebp),%ax + movw %ax,%ss + movl %eax,%ebp + + /* + * Call entry point + */ + .byte 0x66 + lcall %fs:(%edx) + + /* + * Restore old stack and segment registers. + * + * Two choices here: + * 1. Trust that fs or gs hasn't changed. + * 2. Rely on knowledge of Linux use of segments. + * + * I'll opt for choice 2 because who knows what programs we + * going to run. Linux should be fairly stable in terms of + * GDT usage. + */ + pushl %eax + movw $0x2b,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + popl %eax + movw saved_ss,%ss + movl saved_esp,%esp + movl saved_ebp,%ebp + + /* + * Restore registers, but do not destroy return value. + */ + popw saved_ss + popl saved_ebp + popl saved_esp + movl %eax,return_value + popal + movl return_value,%eax + .align 2,0x90 + leave + ret + +/********************************************************************** + * CallTo32() + * + * This function is called as a relay point to the built function + * handler. KERNEL, USER and GDI calls are dealt with by this + * handler. Calls to these DLLs will be mapped to a call handler + * which will set EAX to a number indicating which DLL and which + * function within that DLL. + * + * This function will pass to the function handler two arguments. + * The first argument will be the contents of EAX, the second + * argument will be a segment:offset pair that points to the + * 16-bit stack. + */ + .align 4 + .globl _CallTo32 +_CallTo32: + pushl %ebp + movl %esp,%ebp + + /* + * Save registers. 286 mode does not have fs or gs. + */ + pushw %ds + pushw %es + + /* + * Restore segment registers. + */ + pushl %eax + movw $0x2b,%ax + movw %ax,%ds + movw %ax,%es + popl %eax + + /* + * Save old stack save variables, save stack registers, reload + * stack registers. + */ + pushl saved_16esp + pushl saved_16ebp + pushw saved_16ss + + movw %ss,saved_16ss + movl %esp,saved_16esp + movl %ebp,saved_16ebp + + movw saved_ss,%ss + movl saved_esp,%esp + movl saved_ebp,%ebp + + /* + * Call entry point + */ + pushw saved_16ss + pushw saved_16esp + pushl %eax + call _DLLRelay + + /* + * Restore registers, but do not destroy return value. + */ + movw saved_16ss,%ss + movl saved_16esp,%esp + movl saved_16ebp,%ebp + + popw saved_16ss + popl saved_16ebp + popl saved_16esp + + popw %es + popw %ds + + .align 2,0x90 + leave + /* + * Now we need to ditch the parameter bytes that were left on the + * stack. We do this by effectively popping the number of bytes, + * and the return address, removing the parameters and then putting + * the return address back on the stack. + * Normally this field is filled in by the relevant function in + * the emulation library, since it should know how many bytes to + * expect. + */ + popw %gs:nbytes + cmpw $0,%gs:nbytes + je noargs + popw %gs:offset + popw %gs:selector + addw %gs:nbytes,%esp + pushw %gs:selector + pushw %gs:offset +noargs: + + /* + * Last, but not least we need to move the high word from eax to dx + */ + pushl %eax + popw %dx + popw %dx + + .byte 0x66 + lret + +/********************************************************************** + * KERNEL_InitTask() + * + * This interface functions is special because it returns all + * of its values in registers. Thus we can't just fall back through + * the C functions that called us. Instead we simply abandon + * the 32-bit stack, set up the registers and return. + */ + .globl _KERNEL_InitTask +_KERNEL_InitTask: + /* + * Restore stack + */ + movw saved_16ss,%ss + movl saved_16esp,%esp + movl saved_16ebp,%ebp + + popw saved_16ss + popl saved_16ebp + popl saved_16esp + + popw %es + popw %ds + + .align 2,0x90 + leave + /* + * Now we need to ditch the parameter bytes that were left on the + * stack. We do this by effectively popping the number of bytes, + * and the return address, removing the parameters and then putting + * the return address back on the stack. + * Normally this field is filled in by the relevant function in + * the emulation library, since it should know how many bytes to + * expect. + */ + popw %gs:nbytes + cmpw $0,%gs:nbytes + je noargs_2 + popw %gs:offset + popw %gs:selector + addw %gs:nbytes,%esp + pushw %gs:selector + pushw %gs:offset +noargs_2: + + /* + * Last, we need to load the return values. + */ + movw $1,%ax + movw %gs:_WIN_StackSize,%cx + movw $1,%dx + movw 0x80,%bx + movl $0,%esi + movl $1,%edi + + .byte 0x66 + lret diff --git a/kernel.c b/kernel.c new file mode 100644 index 00000000000..4c570065290 --- /dev/null +++ b/kernel.c @@ -0,0 +1,106 @@ +static char RCSId[] = "$Id$"; +static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; + +#include +#include +#include "prototypes.h" + +extern unsigned short *Stack16Frame; + +/********************************************************************** + * KERNEL_GetVersion + * + * Return the version of Windows that we emulate. + */ +int +KERNEL_GetVersion(void) +{ + return 0x0301; +} + +/********************************************************************** + * KERNEL_LockSegment + */ +int +KERNEL_LockSegment(int segment) +{ + if (segment == -1) + segment = *(Stack16Frame + 6); + +#ifdef RELAY_DEBUG + fprintf(stderr, "LockSegment: segment %x\n", segment); +#endif + + return segment; +} + +/********************************************************************** + * KERNEL_UnlockSegment + */ +int +KERNEL_UnlockSegment(int segment) +{ + if (segment == -1) + segment = *(Stack16Frame + 6); + +#ifdef RELAY_DEBUG + fprintf(stderr, "UnlockSegment: segment %x\n", segment); +#endif + + return segment; +} + +/********************************************************************** + * KERNEL_WaitEvent + */ +int +KERNEL_WaitEvent(int task) +{ +#ifdef RELAY_DEBUG + fprintf(stderr, "WaitEvent: task %d\n", task); +#endif + return 0; +} +/********************************************************************** + * KERNEL_GetModuleFileName + */ +int +KERNEL_GetModuleFileName(int module, char *filename, int bytes) +{ +#ifdef RELAY_DEBUG + fprintf(stderr, "GetModuleFileName: module %d, filename %x, bytes %d\n", + module, filename, bytes); +#endif + + strcpy(filename, "TEST.EXE"); + + return strlen(filename); +} + +/********************************************************************** + * KERNEL_DOS3Call + */ +int +KERNEL_DOS3Call(int ax, int cx, int dx, int bx, int sp, int bp, + int si, int di, int ds, int es) +{ + switch ((ax >> 8) & 0xff) + { + case 0x30: + return 0x0303; + + case 0x25: + case 0x35: + return 0; + + default: + fprintf(stderr, "DOS: AX %04x, BX %04x, CX %04x, DX %04x\n", + ax, bx, cx, dx); + fprintf(stderr, " SP %04x, BP %04x, SI %04x, DI %04x\n", + sp, bp, si, di); + fprintf(stderr, " DS %04x, ES %04x\n", + ds, es); + } + + return 0; +} diff --git a/kernel.spec b/kernel.spec new file mode 100644 index 00000000000..58a0f0aeacd --- /dev/null +++ b/kernel.spec @@ -0,0 +1,16 @@ +name kernel +id 1 +length 256 + +3 pascal GetVersion() KERNEL_GetVersion() +5 pascal LocalAlloc(word word) HEAP_LocalAlloc(1 2) +23 pascal LockSegment(s_word) KERNEL_LockSegment(1) +24 pascal UnlockSegment(s_word) KERNEL_UnlockSegment(1) +30 pascal WaitEvent(word) KERNEL_WaitEvent(1) +49 pascal GetModuleFileName(word ptr s_word) KERNEL_GetModuleFileName(1 2 3) +91 pascal InitTask() KERNEL_InitTask() +102 register DOS3Call(word word word word word + word word word word word) + KERNEL_DOS3Call(1 2 3 4 5 6 7 8 9 10) +131 pascal GetDOSEnvironment() GetDOSEnvironment() +178 equate __WINFLAGS 0x413 diff --git a/ldt.c b/ldt.c new file mode 100644 index 00000000000..facad912f24 --- /dev/null +++ b/ldt.c @@ -0,0 +1,74 @@ +/* $Id$ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ +#include +#include +#include +#include +#include +#include +#include "prototypes.h" + +/********************************************************************** + * print_ldt + */ +void +print_ldt() +{ + char buffer[0x10000]; + struct modify_ldt_ldt_s ldt_info; + unsigned long *lp; + unsigned long base_addr, limit; + int type, dpl, i; + + if (get_ldt(buffer) < 0) + exit(1); + + lp = (unsigned long *) buffer; + for (i = 0; i < 32; i++, lp++) + { + /* First 32 bits of descriptor */ + base_addr = (*lp >> 16) & 0x0000FFFF; + limit = *lp & 0x0000FFFF; + lp++; + + /* First 32 bits of descriptor */ + base_addr |= (*lp & 0xFF000000) | ((*lp << 16) & 0x00FF0000); + limit |= (*lp & 0x000F0000); + type = (*lp >> 9) & 7; + dpl = (*lp >> 13) & 3; + + if (*lp & 1000) + { + printf("Entry %2d: Base %08.8x, Limit %05.5x, DPL %d, Type %d\n", + i, base_addr, limit, dpl, type); + printf(" "); + if (*lp & 0x100) + printf("Accessed, "); + if (*lp & 8000) + printf("Present, "); + if (*lp & 0x100000) + printf("User, "); + if (*lp & 0x200000) + printf("X, "); + if (*lp & 0x400000) + printf("32, "); + else + printf("16, "); + if (*lp & 0x800000) + printf("page limit, "); + else + printf("byte limit, "); + printf("\n"); + printf(" %08.8x %08.8x\n", *(lp), *(lp-1)); + } + else + { + printf("Entry %2d: Base %08.8x, Limit %05.5x, DPL %d, Type %d\n", + i, base_addr, limit, dpl, type); + printf(" SYSTEM: %08.8x %08.8x\n", *lp, *(lp-1)); + } + } +} diff --git a/ldt.tar b/ldt.tar new file mode 100644 index 00000000000..a4c8dde4b67 Binary files /dev/null and b/ldt.tar differ diff --git a/ldtlib.c b/ldtlib.c new file mode 100644 index 00000000000..137130dade1 --- /dev/null +++ b/ldtlib.c @@ -0,0 +1,37 @@ +/* $Id$ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ +#include +#include +#include +#include +#include +#include + +_syscall2(int, modify_ldt, int, func, void *, ptr) + +int +get_ldt(void *buffer) +{ + return modify_ldt(0, buffer); +} + +int +set_ldt_entry(int entry, unsigned long base, unsigned int limit, + int seg_32bit_flag, int contents, int read_only_flag, + int limit_in_pages_flag) +{ + struct modify_ldt_ldt_s ldt_info; + + ldt_info.entry_number = entry; + ldt_info.base_addr = base; + ldt_info.limit = limit; + ldt_info.seg_32bit = seg_32bit_flag; + ldt_info.contents = contents; + ldt_info.read_exec_only = read_only_flag; + ldt_info.limit_in_pages = limit_in_pages_flag; + + return modify_ldt(1, &ldt_info); +} diff --git a/neexe.h b/neexe.h new file mode 100644 index 00000000000..d92b4a6a0c7 --- /dev/null +++ b/neexe.h @@ -0,0 +1,158 @@ +/* $Id: neexe.h,v 1.1 1993/06/09 03:28:10 root Exp root $ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ +#ifndef NEEXE_H +#define NEEXE_H + +/* + * Old MZ header for DOS programs. Actually just a couple of fields + * from it, so that we can find the start of the NE header. + */ +struct mz_header_s +{ + u_char dont_care1[0x18]; /* MZ Header stuff */ + u_char must_be_0x40; /* 0x40 for non-MZ program */ + u_char dont_care2[0x23]; /* More MZ header stuff */ + u_short ne_offset; /* Offset to extended header */ +}; + +/* + * This is the Windows executable (NE) header. + */ +struct ne_header_s +{ + char header_type[2]; /* Must contain 'N' 'E' */ + u_char linker_version; /* Linker version number */ + u_char linker_revision; /* Linker revision number */ + u_short entry_tab_offset; /* Offset to entry table relative to NE */ + u_short entry_tab_length; /* Length of etnry table in bytes */ + u_long reserved1; /* Reserved by Microsoft */ + u_short format_flags; /* Flags that segments in this file */ + u_short auto_data_seg; /* Automatic data segment number */ + u_short local_heap_length; /* Initial size of local heap */ + u_short stack_length; /* Initial size of stack */ + u_short ip; /* Initial IP */ + u_short cs; /* Initial CS */ + u_short sp; /* Initial SP */ + u_short ss; /* Initial SS */ + u_short n_segment_tab; /* # of entries in segment table */ + u_short n_mod_ref_tab; /* # of entries in module reference tab.*/ + u_short nrname_tab_length; /* Length of nonresident-name table */ + u_short segment_tab_offset; /* Offset to segment table */ + u_short resource_tab_offset;/* Offset to resource table */ + u_short rname_tab_offset; /* Offset to resident-name table */ + u_short moduleref_tab_offset;/* Offset to module reference table */ + u_short iname_tab_offset; /* Offset to imported name table */ + u_long nrname_tab_offset; /* Offset to nonresident-name table */ + u_short n_mov_entry_points; /* # of movable entry points */ + u_short align_shift_count; /* Logical sector alignment shift count */ + u_short n_resource_seg; /* # of resource segments */ + u_char operating_system; /* Flags indicating target OS */ + u_char additional_flags; /* Additional information flags */ + u_short fastload_offset; /* Offset to fast load area */ + u_short fastload_length; /* Length of fast load area */ + u_short reserved2; /* Reserved by Microsoft */ + u_short expect_version; /* Expected Windows version number */ +}; + +/* + * NE Header FORMAT FLAGS + */ +#define NE_FFLAGS_SINGLEDATA 0x0001 +#define NE_FFLAGS_MULTIPLEDATA 0x0002 +#define NE_FFLAGS_SELFLOAD 0x0800 +#define NE_FFLAGS_LINKERROR 0x2000 +#define NE_FFLAGS_LIBMODULE 0x8000 + +/* + * NE Header OPERATING SYSTEM + */ +#define NE_OSFLAGS_UNKNOWN 0x01 +#define NE_OSFLAGS_WINDOWS 0x04 + +/* + * NE Header ADDITIONAL FLAGS + */ +#define NE_AFLAGS_WIN2_PROTMODE 0x02 +#define NE_AFLAGS_WIN2_PROFONTS 0x04 +#define NE_AFLAGS_FASTLOAD 0x08 + +/* + * Segment table entry + */ +struct ne_segment_table_entry_s +{ + u_short seg_data_offset; /* Sector offset of segment data */ + u_short seg_data_length; /* Length of segment data */ + u_short seg_flags; /* Flags associated with this segment */ + u_short min_alloc; /* Minimum allocation size for this */ +}; + +/* + * Segment Flags + */ +#define NE_SEGFLAGS_DATA 0x0001 +#define NE_SEGFLAGS_ALLOCATED 0x0002 +#define NE_SEGFLAGS_LOADED 0x0004 +#define NE_SEGFLAGS_MOVEABLE 0x0010 +#define NE_SEGFLAGS_SHAREABLE 0x0020 +#define NE_SEGFLAGS_PRELOAD 0x0040 +#define NE_SEGFLAGS_EXECUTEONLY 0x0080 +#define NE_SEGFLAGS_READONLY 0x0080 +#define NE_SEGFLAGS_RELOC_DATA 0x0100 +#define NE_SEGFLAGS_DISCARDABLE 0x1000 + +/* + * Relocation table entry + */ +struct relocation_entry_s +{ + u_char address_type; /* Relocation address type */ + u_char relocation_type; /* Relocation type */ + u_short offset; /* Offset in segment to fixup */ + u_short target1; /* Target specification */ + u_short target2; /* Target specification */ +}; + +/* + * Relocation address types + */ +#define NE_RADDR_LOWBYTE 0 +#define NE_RADDR_SELECTOR 2 +#define NE_RADDR_POINTER32 3 +#define NE_RADDR_OFFSET16 5 +#define NE_RADDR_POINTER48 11 +#define NE_RADDR_OFFSET32 13 + +/* + * Relocation types + */ +#define NE_RELTYPE_INTERNAL 0 +#define NE_RELTYPE_ORDINAL 1 +#define NE_RELTYPE_NAME 2 +#define NE_RELTYPE_OSFIXUP 3 + +/* + * DOS PSP + */ +struct dos_psp_s +{ + unsigned short pspInt20; + unsigned short pspNextParagraph; + unsigned char pspReserved1; + unsigned char pspDispatcher[5]; + unsigned long pspTerminateVector; + unsigned long pspControlCVector; + unsigned long pspCritErrorVector; + unsigned short pspReserved2[11]; + unsigned short pspEnvironment; + unsigned short pspReserved3[23]; + unsigned char pspFCB_1[16]; + unsigned char pspFCB_2[16]; + unsigned char pspCommandTailCount; + unsigned char pspCommandTail[128]; +}; + +#endif /* NEEXE_H */ diff --git a/prototypes.h b/prototypes.h new file mode 100644 index 00000000000..0b6b8edd510 --- /dev/null +++ b/prototypes.h @@ -0,0 +1,32 @@ +/* $Id$ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ +#ifndef PROTOTYPES_H +#define PROTOTYPES_H + +#include +#include "neexe.h" +#include "segmem.h" + +extern struct segment_descriptor_s * + CreateSelectors(int fd, struct ne_segment_table_entry_s *seg_table, + struct ne_header_s *ne_header); + +extern void PrintFileHeader(struct ne_header_s *ne_header); +extern void PrintSegmentTable(struct ne_segment_table_entry_s *seg_table, + int nentries); +extern void PrintRelocationTable(char *exe_ptr, + struct ne_segment_table_entry_s *seg_entry_p, + int segment); +extern int FixupSegment(int fd, struct mz_header_s * mz_header, + struct ne_header_s *ne_header, + struct ne_segment_table_entry_s *seg_table, + struct segment_descriptor_s *selecetor_table, + int segment_num); +extern struct dll_table_entry_s *FindDLLTable(char *dll_name); + +extern char WIN_CommandLine[]; + +#endif /* PROTOTYPES_H */ diff --git a/relay.c b/relay.c new file mode 100644 index 00000000000..067d0ab3dc8 --- /dev/null +++ b/relay.c @@ -0,0 +1,201 @@ +/* $Id$ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "neexe.h" +#include "segmem.h" +#include "prototypes.h" +#include "dlls.h" + +struct dll_name_table_entry_s dll_builtin_table[4] = +{ + { "KERNEL", KERNEL_table, 256, 1 }, + { "USER", USER_table, 256, 2 }, + { "GDI", GDI_table, 256, 3 }, + { "UNIXLIB", UNIXLIB_table, 256, 4 }, +}; + +unsigned short *Stack16Frame; + +/********************************************************************** + * DLLRelay + * + * We get a stack frame pointer to data that looks like this: + * + * Hex Offset Contents + * ---------- ------- + * +00 previous saved_16ss + * +02 previous saved_16ebp + * +06 previous saved_16esp + * +0A 16-bit es + * +0C 16-bit ds + * +0E 16-bit ebp + * +12 length of 16-bit arguments + * +14 16-bit ip + * +16 16-bit cs + * +18 arguments + */ +int +DLLRelay(unsigned int func_num, unsigned int seg_off) +{ + struct dll_table_entry_s *dll_p; + unsigned int segment; + unsigned int offset; + unsigned int dll_id; + unsigned int ordinal; + int arg_table[DLL_MAX_ARGS]; + void *arg_ptr; + int (*func_ptr)(); + int i; + + /* + * Determine address of arguments. + */ + Stack16Frame = (unsigned short *) seg_off; + arg_ptr = (void *) (seg_off + 0x18); + + /* + * Extract the DLL number and ordinal number. + */ + dll_id = ((func_num >> 16) & 0xffff) - 1; + ordinal = func_num & 0xffff; + dll_p = &dll_builtin_table[dll_id].dll_table[ordinal]; + +#ifdef RELAY_DEBUG + { + unsigned int *ret_addr; + unsigned short *stack_p; + + ret_addr = (unsigned int *) ((char *) seg_off + 0x14); + printf("RELAY: Calling %s.%d, 16-bit stack at %04x:%04x, ", + dll_builtin_table[dll_id].dll_name, ordinal, + seg_off >> 16, seg_off & 0xffff); + printf("return to %08x\n", *ret_addr); + +#ifdef STACK_DEBUG + stack_p = (unsigned short *) seg_off; + for (i = 0; i < 24; i++, stack_p++) + { + printf("%04x ", *stack_p); + if ((i & 7) == 7) + printf("\n"); + } + printf("\n"); +#endif /* STACK_DEBUG */ + } +#endif /* RELAY_DEBUG */ + + /* + * Make sure we have a handler defined for this call. + */ + if (dll_p->handler == NULL) + { + char buffer[100]; + + sprintf(buffer, "No handler for routine %s.%d", + dll_builtin_table[dll_id].dll_name, ordinal); + myerror(buffer); + } + func_ptr = dll_p->handler; + + /* + * OK, special case. If the handler is define as taking no arguments + * then pass the address of the arguments on the 16-bit stack to the + * handler. It will just ignore the pointer if it really takes no + * arguments. This allows us to write slightly faster library routines + * if we choose. + */ + if (dll_p->n_args == 0) + return (*func_ptr)(arg_ptr); + + /* + * Getting this far means we need to convert the 16-bit argument stack. + */ + for (i = 0; i < dll_p->n_args; i++) + { + short *sp; + int *ip; + + offset = dll_p->args[i].dst_arg; + + switch (dll_p->args[i].src_type) + { + case DLL_ARGTYPE_SIGNEDWORD: + sp = (short *) ((char *) arg_ptr + offset); + arg_table[i] = *sp; + break; + + case DLL_ARGTYPE_WORD: + sp = (short *) ((char *) arg_ptr + offset); + arg_table[i] = (int) *sp & 0xffff; + break; + + case DLL_ARGTYPE_LONG: + case DLL_ARGTYPE_FARPTR: + ip = (int *) ((char *) arg_ptr + offset); + arg_table[i] = *ip; + break; + } + } + + /* + * Call the handler + */ + return (*func_ptr)(arg_table[0], arg_table[1], arg_table[2], + arg_table[3], arg_table[4], arg_table[5], + arg_table[6], arg_table[7], arg_table[8], + arg_table[9], arg_table[10], arg_table[11], + arg_table[12], arg_table[13], arg_table[14], + arg_table[15]); +} + +/********************************************************************** + * FindDLLTable + */ +struct dll_table_entry_s * +FindDLLTable(char *dll_name) +{ + int i; + + for (i = 0; i < 4; i++) + if (strcmp(dll_builtin_table[i].dll_name, dll_name) == 0) + return dll_builtin_table[i].dll_table; + + return NULL; +} + +/********************************************************************** + * FindOrdinalFromName + */ +int +FindOrdinalFromName(struct dll_table_entry_s *dll_table, char *func_name) +{ + int i, limit; + + for (i = 0; i < 4; i++) + if (dll_table == dll_builtin_table[i].dll_table) + break; + + if (i == 4) + return 0; + + limit = dll_builtin_table[i].dll_table_length; + for (i = 0; i < limit; i++) + if (strcasecmp(dll_table[i].export_name, func_name) == 0) + return i; + + return 0; +} diff --git a/segmem.h b/segmem.h new file mode 100644 index 00000000000..39a02255eb7 --- /dev/null +++ b/segmem.h @@ -0,0 +1,26 @@ +/* $Id$ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ +#ifndef SEGMEM_H +#define SEGMEM_H + +/* + * Structure to hold info about each selector we create. + */ + +struct segment_descriptor_s +{ + void *base_addr; /* Pointer to segment in flat memory */ + unsigned int length; /* Length of segment */ + unsigned int flags; /* Segment flags (see neexe.h and below)*/ + unsigned short selector; /* Selector used to access this segment */ +}; + +/* + * Additional flags + */ +#define NE_SEGFLAGS_MALLOCED 0x00010000 /* Memory allocated with malloc() */ + +#endif /* SEGMEM_H */ diff --git a/selector.c b/selector.c new file mode 100644 index 00000000000..449e9ba3884 --- /dev/null +++ b/selector.c @@ -0,0 +1,264 @@ +/* $Id: exedump.c,v 1.1 1993/06/09 03:28:10 root Exp root $ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "neexe.h" +#include "segmem.h" +#include "prototypes.h" + +struct segment_descriptor_s *SelectorTable; +int SelectorTableLength; +int EnvironmentSelectorIdx; +int PSPSelectorIdx; +unsigned short PSPSelector; + +extern void KERNEL_Ordinal_102(); +extern void UNIXLIB_Ordinal_0(); + + +/********************************************************************** + * GetDOSEnvironment + */ +void * +GetDOSEnvironment() +{ + return SelectorTable[EnvironmentSelectorIdx].base_addr; +} + +/********************************************************************** + * CreateEnvironment + */ +void +CreateEnvironment(int sel_idx, struct segment_descriptor_s *s, FILE *zfile) +{ + char *p; + + EnvironmentSelectorIdx = sel_idx; + + /* + * Create memory to hold environment. + */ + s->flags = NE_SEGFLAGS_DATA; + s->selector = (sel_idx << 3) | 0x0007; + s->length = PAGE_SIZE; + s->base_addr = (void *) mmap((char *) (s->selector << 16), + PAGE_SIZE, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0); + + /* + * Fill environment with meaningless babble. + */ + p = (char *) s->base_addr; + strcpy(p, "PATH=C:\\WINDOWS"); + p += strlen(p) + 1; + *p++ = '\0'; + *p++ = 11; + *p++ = 0; + strcpy(p, "C:\\TEST.EXE"); + + /* + * Create entry in LDT for this segment. + */ + if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr, s->length, 0, + MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0) + { + myerror("Could not create LDT entry for environment"); + } +} + +/********************************************************************** + * CreatePSP + */ +void +CreatePSP(int sel_idx, struct segment_descriptor_s *s, FILE *zfile) +{ + struct dos_psp_s *psp; + unsigned short *usp; + + PSPSelectorIdx = sel_idx; + + /* + * Create memory to hold PSP. + */ + s->flags = NE_SEGFLAGS_DATA; + s->selector = (sel_idx << 3) | 0x0007; + s->length = PAGE_SIZE; + s->base_addr = (void *) mmap((char *) (s->selector << 16), + PAGE_SIZE, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0); + + /* + * Fill PSP + */ + PSPSelector = s->selector; + psp = (struct dos_psp_s *) s->base_addr; + psp->pspInt20 = 0x20cd; + psp->pspDispatcher[0] = 0x9a; + usp = (unsigned short *) &psp->pspDispatcher[1]; + *usp = (unsigned short) KERNEL_Ordinal_102; + *(usp + 1) = 0x23; + psp->pspTerminateVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff); + psp->pspControlCVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff); + psp->pspCritErrorVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff); + psp->pspEnvironment = SelectorTable[EnvironmentSelectorIdx].selector; + psp->pspCommandTailCount = 1; + strcpy(psp->pspCommandTail, "\r"); + + + /* + * Create entry in LDT for this segment. + */ + if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr, s->length, 0, + MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0) + { + myerror("Could not create LDT entry for PSP"); + } +} + +/********************************************************************** + * CreateSelectors + */ +struct segment_descriptor_s * +CreateSelectors(int fd, struct ne_segment_table_entry_s *seg_table, + struct ne_header_s *ne_header) +{ + struct segment_descriptor_s *selectors, *s; + int contents, read_only; + int i; + int status; + FILE * zfile; + int old_length; + + /* + * Allocate memory for the table to keep track of all selectors. + */ + SelectorTableLength = ne_header->n_segment_tab + 2; + selectors = malloc(SelectorTableLength * sizeof(*selectors)); + if (selectors == NULL) + return NULL; + SelectorTable = selectors; + + /* + * Step through the segment table in the exe header. + */ + s = selectors; + zfile = fopen("/dev/zero","r"); + for (i = 0; i < ne_header->n_segment_tab; i++, s++) + { + /* + * Store the flags in our table. + */ + s->flags = seg_table[i].seg_flags; + s->selector = (i << 3) | 0x0007; + + /* + * Is there an image for this segment in the file? + */ + if (seg_table[i].seg_data_offset == 0) + { + /* + * No image in exe file, let's allocate some memory for it. + */ + s->length = seg_table[i].min_alloc; + } + else + { + /* + * Image in file, let's just point to the image in memory. + */ + s->length = seg_table[i].seg_data_length; + } + + if (s->length == 0) + s->length = 0x10000; + old_length = s->length; + + /* + * If this is the automatic data segment, its size must be adjusted. + * First we need to check for local heap. Second we nee to see if + * this is also the stack segment. + */ + if (i + 1 == ne_header->auto_data_seg) + { + s->length += ne_header->local_heap_length; + + if (i + 1 == ne_header->ss) + { + s->length += ne_header->stack_length; + ne_header->sp = s->length; + } + } + + /* + * Is this a DATA or CODE segment? + */ + read_only = 0; + if (s->flags & NE_SEGFLAGS_DATA) + { + contents = MODIFY_LDT_CONTENTS_DATA; + if (s->flags & NE_SEGFLAGS_READONLY) + read_only = 1; + } + else + { + contents = MODIFY_LDT_CONTENTS_CODE; + if (s->flags & NE_SEGFLAGS_EXECUTEONLY) + read_only = 1; + } + s->base_addr = + (void *) mmap((char *) (s->selector << 16), + (s->length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1), + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0); + if (seg_table[i].seg_data_offset != 0) + { + /* + * Image in file. + */ + status = lseek(fd, seg_table[i].seg_data_offset * 512, SEEK_SET); + if(read(fd, s->base_addr, old_length) != old_length) + myerror("Unable to read segment from file"); + } + /* + * Create entry in LDT for this segment. + */ + if (set_ldt_entry(i, (unsigned long) s->base_addr, s->length, 0, + contents, read_only, 0) < 0) + { + free(selectors); + return NULL; + } + /* + * If this is the automatic data segment, then we must initialize + * the local heap. + */ + if (i + 1 == ne_header->auto_data_seg) + { + HEAP_LocalInit(s->base_addr + old_length, + ne_header->local_heap_length); + } + } + + CreateEnvironment(i++, s++, zfile); + CreatePSP(i++, s++, zfile); + + fclose(zfile); + + return selectors; +} diff --git a/test.exe b/test.exe new file mode 100755 index 00000000000..3a75f7cb100 Binary files /dev/null and b/test.exe differ diff --git a/unixlib.spec b/unixlib.spec new file mode 100644 index 00000000000..7b5b9dd0608 --- /dev/null +++ b/unixlib.spec @@ -0,0 +1,5 @@ +name unixlib +id 4 +length 256 + +1 c _DebugPrintString(ptr) DebugPrintString(1) \ No newline at end of file diff --git a/user.c b/user.c new file mode 100644 index 00000000000..7b3ceed060a --- /dev/null +++ b/user.c @@ -0,0 +1,17 @@ +static char RCSId[] = "$Id$"; +static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; + +#include +#include +#include "prototypes.h" + +/********************************************************************** + * USER_InitApp + * + * Load necessary resources? + */ +int +USER_InitApp(int hInstance) +{ + return 1; +} diff --git a/user.spec b/user.spec new file mode 100644 index 00000000000..152ef1838bb --- /dev/null +++ b/user.spec @@ -0,0 +1,5 @@ +name user +id 2 +length 256 + +5 pascal InitApp(word) USER_InitApp(1) \ No newline at end of file diff --git a/wine b/wine new file mode 100755 index 00000000000..57d7234508c Binary files /dev/null and b/wine differ diff --git a/wine.c b/wine.c new file mode 100644 index 00000000000..85d3844070b --- /dev/null +++ b/wine.c @@ -0,0 +1,348 @@ +/* $Id: exedump.c,v 1.1 1993/06/09 03:28:10 root Exp root $ + */ +/* + * Copyright Robert J. Amstadt, 1993 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "neexe.h" +#include "segmem.h" +#include "prototypes.h" +#include "dlls.h" + +extern int CallTo16(unsigned long csip, unsigned long sssp, unsigned short ds); +extern void CallTo32(); + +unsigned short WIN_StackSize; + +char **Argv; +int Argc; + +/********************************************************************** + * DebugPrintString + */ +int +DebugPrintString(char *str) +{ + fprintf(stderr, "%s", str); + return 0; +} + +/********************************************************************** + * myerror + */ +void +myerror(const char *s) +{ + char buffer[200]; + + sprintf(buffer, "%s", Argv[0]); + if (s == NULL) + perror(buffer); + else + fprintf(stderr, "%s: %s\n", buffer, s); + + exit(1); +} + +/********************************************************************** + * main + */ +main(int argc, char **argv) +{ + struct stat finfo; + struct mz_header_s *mz_header; + struct ne_header_s *ne_header; + struct ne_segment_table_entry_s *seg_table; + unsigned int status; + unsigned int read_size; + struct segment_descriptor_s *selector_table; + int fd; + int segment; + int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg; + int rv; + + Argc = argc; + Argv = argv; + + if (argc < 2) + { + fprintf(stderr, "usage: %s FILENAME\n", argv[0]); + exit(1); + } + + /* + * Open file for reading. + */ + fd = open(argv[1], O_RDONLY); + if (fd < 0) + { + myerror(NULL); + } + + /* + * Allocate memory to hold entire executable. + */ + if (fstat(fd, &finfo) < 0) + myerror(NULL); + + /* + * Establish header pointers. + */ + mz_header = (struct mz_header_s *) malloc(sizeof(struct mz_header_s));; + status = lseek(fd, 0, SEEK_SET); + if (read(fd, mz_header, sizeof(struct mz_header_s)) != + sizeof(struct mz_header_s)) + { + myerror("Unable to read MZ header from file"); + } + if (mz_header->must_be_0x40 != 0x40) + myerror("This is not a Windows program"); + + ne_header = (struct ne_header_s *) malloc(sizeof(struct ne_header_s)); + status = lseek(fd, mz_header->ne_offset, SEEK_SET); + if (read(fd, ne_header, sizeof(struct ne_header_s)) + != sizeof(struct ne_header_s)) + { + myerror("Unable to read NE header from file"); + } + if (ne_header->header_type[0] != 'N' || ne_header->header_type[1] != 'E') + myerror("This is not a Windows program"); + + WIN_StackSize = ne_header->stack_length; + + + /* + * Create segment selectors. + */ + status = lseek(fd, mz_header->ne_offset + ne_header->segment_tab_offset, + SEEK_SET); + read_size = ne_header->n_segment_tab * + sizeof(struct ne_segment_table_entry_s); + seg_table = (struct ne_segment_table_entry_s *) malloc(read_size); + if (read(fd, seg_table, read_size) != read_size) + myerror("Unable to read segment table header from file"); + selector_table = CreateSelectors(fd, seg_table, ne_header); + + /* + * Fixup references. + */ + for (segment = 0; segment < ne_header->n_segment_tab; segment++) + { + if (FixupSegment(fd, mz_header, ne_header, seg_table, + selector_table, segment) < 0) + { + myerror("fixup failed."); + } + } + + close(fd); + /* + * Fixup stack and jump to start. + */ + ds_reg = selector_table[ne_header->auto_data_seg-1].selector; + cs_reg = selector_table[ne_header->cs-1].selector; + ip_reg = ne_header->ip; + ss_reg = selector_table[ne_header->ss-1].selector; + sp_reg = ne_header->sp; + + rv = CallTo16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg); + printf ("rv = %x\n", rv); +} + + +/********************************************************************** + * GetImportedName + */ +char * +GetImportedName(int fd, struct mz_header_s *mz_header, + struct ne_header_s *ne_header, int name_offset, char *buffer) +{ + char *p; + int length; + int status; + int i; + + status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset + + name_offset, SEEK_SET); + length = 0; + read(fd, &length, 1); /* Get the length byte */ + read(fd, buffer, length); + buffer[length] = 0; + return buffer; +} + +/********************************************************************** + * GetModuleName + */ +char * +GetModuleName(int fd, struct mz_header_s *mz_header, + struct ne_header_s *ne_header, int index, char *buffer) +{ + char *p; + int length; + int name_offset, status; + int i; + + status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset + + 2*(index - 1), SEEK_SET); + name_offset = 0; + read(fd, &name_offset, 2); + status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset + + name_offset, SEEK_SET); + length = 0; + read(fd, &length, 1); /* Get the length byte */ + read(fd, buffer, length); + buffer[length] = 0; + return buffer; +} + + +/********************************************************************** + * FixupSegment + */ +int +FixupSegment(int fd, struct mz_header_s * mz_header, + struct ne_header_s *ne_header, + struct ne_segment_table_entry_s *seg_table, + struct segment_descriptor_s *selector_table, + int segment_num) +{ + struct relocation_entry_s *rep, *rep1; + struct ne_segment_table_entry_s *seg; + struct segment_descriptor_s *sel; + struct dll_table_entry_s *dll_table; + unsigned short *sp; + unsigned int selector, address; + unsigned int next_addr; + int ordinal; + int status; + char dll_name[257]; + char func_name[257]; + int i, n_entries; + + seg = &seg_table[segment_num]; + sel = &selector_table[segment_num]; + + if (seg->seg_data_offset == 0) + return 0; + + /* + * Go through the relocation table on entry at a time. + */ + i = seg->seg_data_length; + if (i == 0) + i = 0x10000; + + status = lseek(fd, seg->seg_data_offset * 512 + i, SEEK_SET); + n_entries = 0; + read(fd, &n_entries, sizeof(short int)); + rep = (struct relocation_entry_s *) + malloc(n_entries * sizeof(struct relocation_entry_s)); + + if (read(fd,rep, n_entries * sizeof(struct relocation_entry_s)) != + n_entries * sizeof(struct relocation_entry_s)) + { + myerror("Unable to read relocation information"); + } + + rep1 = rep; + + for (i = 0; i < n_entries; i++, rep++) + { + /* + * Get the target address corresponding to this entry. + */ + switch (rep->relocation_type) + { + case NE_RELTYPE_ORDINAL: + if (GetModuleName(fd, mz_header, ne_header, rep->target1, + dll_name) == NULL) + { + return -1; + } + + dll_table = FindDLLTable(dll_name); + ordinal = rep->target2; + selector = dll_table[ordinal].selector; + address = (unsigned int) dll_table[ordinal].address; +#ifdef DEBUG_FIXUP + printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal, + selector, address); +#endif + break; + + case NE_RELTYPE_NAME: + if (GetModuleName(fd, mz_header, ne_header, rep->target1, dll_name) + == NULL) + { + return -1; + } + dll_table = FindDLLTable(dll_name); + + if (GetImportedName(fd, mz_header, ne_header, + rep->target2, func_name) == NULL) + { + return -1; + } + ordinal = FindOrdinalFromName(dll_table, func_name); + selector = dll_table[ordinal].selector; + address = (unsigned int) dll_table[ordinal].address; +#ifdef DEBUG_FIXUP + printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name, + dll_name, ordinal, selector, address); +#endif + break; + + case NE_RELTYPE_INTERNAL: + default: + free(rep1); + return -1; + } + + /* + * Stuff the right size result in. + */ + sp = (unsigned short *) ((char *) sel->base_addr + rep->offset); + switch (rep->address_type) + { + case NE_RADDR_OFFSET16: + do { + next_addr = *sp; + *sp = (unsigned short) address; + sp = (unsigned short *) ((char *) sel->base_addr + next_addr); + } + while (next_addr != 0xffff); + + break; + + case NE_RADDR_POINTER32: + do { + next_addr = *sp; + *sp = (unsigned short) address; + *(sp+1) = (unsigned short) selector; + sp = (unsigned short *) ((char *) sel->base_addr + next_addr); + } + while (next_addr != 0xffff); + + break; + + default: + free(rep1); + return -1; + } + } + + free(rep1); + return 0; +} diff --git a/winetest/main.c b/winetest/main.c new file mode 100755 index 00000000000..de7d73839d7 --- /dev/null +++ b/winetest/main.c @@ -0,0 +1,101 @@ +/* MAIN.C + * + * PURPOSE: + * + * FUNCTIONS: + * WinMain() - Initializes app, calls all other functions. + */ + +#include +#include +#include +#include + +/* + * Globals + */ +char szAppName[] = "WineTest"; + +extern long FAR PASCAL WineTestWndProc(HWND hwnd, unsigned message, + WORD wParam, LONG lParam); +/* extern void FAR __cdecl DebugPrintString(const char FAR *str); */ + +/* WinMain + */ +int PASCAL +WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int cmdShow) +{ + DebugPrintString("Hello\n"); + + return 0; +#if 0 + HWND hwnd; + MSG msg; + WNDCLASS wndclass; + + if (hPrevInstance) + { + MessageBox(NULL, "This application is already running.", szAppName, + MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); + return NULL; + } + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WineTestWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = "MainMenu"; + wndclass.lpszClassName = szAppName; + + RegisterClass(&wndclass); + + hwnd = CreateWindow(szAppName, "Wine Tester", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + hInstance, + NULL); + ShowWindow(hwnd, cmdShow); + UpdateWindow(hwnd); + + while (GetMessage(&msg, NULL, NULL, NULL)) + { + TranslateMessage((LPMSG) &msg); + DispatchMessage((LPMSG) &msg); + } + + return msg.wParam; +#endif /* 0 */ +} + + +/* WineTestWndProc + */ +long FAR PASCAL +WineTestWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam) +{ + static HANDLE hInstance; + FARPROC DlgProcInst; + LONG parm; + + switch (message) + { + case WM_CREATE: + hInstance = ((LPCREATESTRUCT) lParam)->hInstance; + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} diff --git a/winetest/makefile b/winetest/makefile new file mode 100755 index 00000000000..5f111ddd453 --- /dev/null +++ b/winetest/makefile @@ -0,0 +1,47 @@ +#################################################################### +# +# PPI standard windows makefile +# +#################################################################### + +#################################################################### +# +# Compiler options +# +AFLAGS=/ML /LA +CFLAGS=-AM -Ozaxb2 -Gr -G2 -Zpei -W3 -DWINVER=0x0301 +LFLAGS=/CO + +#################################################################### +# +# Object files and target +# +OBJS=main.obj +DIALOGS= +TARGET=winetest + +#################################################################### +# +# Standard rules +# +ROOTS=$(OBJS:.obj=) + +all: $(TARGET).exe + +version: + coall -r$(RELEASE) + $(MAKE) all + +$(TARGET).res: $(TARGET).rc $(TARGET).h $(DIALOGS) + rc -r $(TARGET).rc + +$(TARGET).exe: $(TARGET).res $(TARGET).def $(TARGET).h $(OBJS) + link @<< +$(ROOTS) /NOD $(LFLAGS) +$@ +$(TARGET) /MAP:FULL +libw slibcewn oldnames +$(TARGET).def +<< + rc -30 $(TARGET).res + diff --git a/winetest/winetest.def b/winetest/winetest.def new file mode 100755 index 00000000000..bd9dbcc9ba5 --- /dev/null +++ b/winetest/winetest.def @@ -0,0 +1,11 @@ +NAME WINETEST + +DESCRIPTION 'Wine Tester' +EXETYPE WINDOWS +STUB 'WINSTUB.EXE' +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE SINGLE +HEAPSIZE 8192 +STACKSIZE 8192 +EXPORTS WineTestWndProc +IMPORTS UNIXLIB._DebugPrintString diff --git a/winetest/winetest.h b/winetest/winetest.h new file mode 100755 index 00000000000..c2804128f8a --- /dev/null +++ b/winetest/winetest.h @@ -0,0 +1,2 @@ +/* $Id$ + */ diff --git a/winetest/winetest.rc b/winetest/winetest.rc new file mode 100755 index 00000000000..af8228ee98b --- /dev/null +++ b/winetest/winetest.rc @@ -0,0 +1,11 @@ +#include + +MainMenu MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", 100 + MENUITEM SEPARATOR + MENUITEM "&About...", 101 + END +END