From 2c25c3e9442c69bd2402f94f264f0aafa58b00e0 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 29 Jun 1993 16:33:12 +0000 Subject: [PATCH] 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. --- COPYRIGHT | 3 + Makefile | 49 +++ README | 73 +++++ build | Bin 0 -> 109606 bytes build-spec.txt | 81 +++++ build.c | 707 ++++++++++++++++++++++++++++++++++++++++++ dlls.h | 56 ++++ dump.c | 92 ++++++ gdi.spec | 3 + heap.c | 93 ++++++ if1632.S | 294 ++++++++++++++++++ kernel.c | 106 +++++++ kernel.spec | 16 + ldt.c | 74 +++++ ldt.tar | Bin 0 -> 10240 bytes ldtlib.c | 37 +++ neexe.h | 158 ++++++++++ prototypes.h | 32 ++ relay.c | 201 ++++++++++++ segmem.h | 26 ++ selector.c | 264 ++++++++++++++++ test.exe | Bin 0 -> 6656 bytes unixlib.spec | 5 + user.c | 17 + user.spec | 5 + wine | Bin 0 -> 306818 bytes wine.c | 348 +++++++++++++++++++++ winetest/main.c | 101 ++++++ winetest/makefile | 47 +++ winetest/winetest.def | 11 + winetest/winetest.h | 2 + winetest/winetest.rc | 11 + 32 files changed, 2912 insertions(+) create mode 100644 COPYRIGHT create mode 100644 Makefile create mode 100644 README create mode 100755 build create mode 100644 build-spec.txt create mode 100644 build.c create mode 100644 dlls.h create mode 100644 dump.c create mode 100644 gdi.spec create mode 100644 heap.c create mode 100644 if1632.S create mode 100644 kernel.c create mode 100644 kernel.spec create mode 100644 ldt.c create mode 100644 ldt.tar create mode 100644 ldtlib.c create mode 100644 neexe.h create mode 100644 prototypes.h create mode 100644 relay.c create mode 100644 segmem.h create mode 100644 selector.c create mode 100755 test.exe create mode 100644 unixlib.spec create mode 100644 user.c create mode 100644 user.spec create mode 100755 wine create mode 100644 wine.c create mode 100755 winetest/main.c create mode 100755 winetest/makefile create mode 100755 winetest/winetest.def create mode 100755 winetest/winetest.h create mode 100755 winetest/winetest.rc 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 0000000000000000000000000000000000000000..d47f5423726ff99b42700158d8db69073375d78c GIT binary patch literal 109606 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%0AS_-RZjYmXRuxMgB(b(A{ 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

Po6!}#vs}>ycnAHPL)6FC=nd3M2O;bS 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 +#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 0000000000000000000000000000000000000000..a4c8dde4b674d8b4f4abc1c4f4029ba396fbf5a7 GIT binary patch literal 10240 zcmeHMZBye$66UM)EBdlkdy-dxB)@h|iaqAY2;r`7XJ_w);QB1=TP8wbVCaO;IGBIcgV_nZz< zw`2F*ZrkZ}i5$n>Yj2VLLi#ks&ho;~h_h2>EaO3F;$kx%h%E9t)^XQBqJo&%H?+MB&^6 z)!?CUmJBVrPoscZ(;_qV_c|M6USzXjK}%+y;N`@>Q4*#Hl53Xa(I^oC#c494Ryth=zVH$R6mLWT&@uFEZB7&xCLMaCUY6&5z#Sug-7I zEP`?t<NerpK0Cko;rJaED*>$}#?d6=ZTF`BNaUFFUZKpWS4_9qO3x31 zjNa5nsv=ZOy!`erfLY#}wf1>)X`ogc0tZVTUHfF4ttx2!z z*6`0tbRDmMDbt2+X|QvavTo_Gu|8g1h|8qILvpa{4+<^%1Qy9HSz*F0Bc8r-OqN_J zu*8&E!>|NyDUogc8Aa3#^XRBl1HQ2ou7Hz*S+3Nx!B80zuVYDHN`R9Fo_G{PFHPb( z{hOdZc>AAOy6b+*&@?g0)n+bUATH_D>Jd0VTL8B7O(uMltn#Nas*B6( zAFmJekNWS4IpvYPTRTjDkC3Q9-pX+qngc1D?JPk_jwEm3 zI0F>&s07>k_V)G@6IbWB17}ao!N=;Cju*uGzU8z#!~`i+4Ri?~*hZqWI4M2v;>sK1 z^bwloxb`X~7e$ax{3uEMi2#GM$}p1zP+a{@Q|Pk#W65ny#9!@9M0u6SN>J+C1Pj6M z38Z=h*L?~pIco)`b{ptE2h$#4a_cbhKzjjGOYNFZboH)DZf7nN;2G02fL_yy93IHp^Hx^ma3`35bS7w_Sc zDv?l(Q96y))BV^_Mzd)-9K?utJoA3C-?K_74}Mg1)NuabPt!0gU*te7 zn9sQj!H;MtsQlg1|0D;bWtX(NDXSr9D^*15AgvQw+jUA0f`T;pb3tSO9w4T8BR`oV zIRpA=%*_0lX4AkgqGYs#i<>kgBQabFTJZLweqOX2ST7#(3ja11=5E=A2vHEDV{)LJ zv)8elJ$qqwaw-4M8=|&n=??$Z4PuWedwAdbcgVM6vGx$(8+7-VN7KrTm1D`-AGp1z zk0sZ!+`WZ+UVi=UHL*R(CSI!Sn#+Qeip-zpxJTK4@Ec5g{Dx_EhucrENo|TY;t(&> z47nta-skc$#3PIhzv3|}aFg8Jj`LaUw$PaMeG-F0}65!z{c$miCxRWa9 zfkuN8Cy>?h(aQ{?EN2D|Y-(9$1p4BaB`dgJw>UPDMFf+LRav~P3t|0%;|@Ay;ATwL zO{?UK_TwD$&f|7m0Cxz=78=&|J-qr8z{2*bA=*J@kbRpY)X{;HtQJY1p$A|D#e zEPHQOF`o)6z(Fkw5m_;q^j_|CYsn_NOa`-{_toqyDLc{(qekX_mTVD~jiidFlwa>5 zRWvAJ9v(W}#aWDTZ>(eQt7g+;&|sCpxo;j|2o~8gYKoQ}v8Fao& z2eK=)idvE9++dTyB@$ap&Xm}hkj8tecBHiPm)nswEB#`3r7|*QJq`PK;T?f<)-N3| zwBNP*_TqrmR@{TV1N&UxWRs*{)py@8hGYDTt7Vdrn5JcLS#KKB+f2)CJJwhB<9`1u z6IQwKI~KfRJ-=PBl3JEv#-qFB?Q(^qRWewTr5%sm;R%feiv11U3k4 S5ZEBFL12Tx27xadfnNZ7#LjO3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3a75f7cb100e415e0862dbab57c761f20f28c362 GIT binary patch literal 6656 zcmeHLdu$W;9sl0LXUBPvvEX*2I0s8z$|DLj^&SZ+Nw9<4#5ivtKnTe}yg(f6yM#^? zP33CCI~F3=!PZsXAl-%{nq?JQ9om8O07fO+gib00RboKf%Z>pGQbN(0gNdw>A|9&b%E0#L$AYyx>ur15nZ`*p$@*@J+9QU>J>z98Qm z@NWy$?%)H$PRSP#f_$;BF5nOPw~Bm~uc_YO8q7>KXYk+fTAz}BEaBYz2vu}${)2$R z!<(bWX|TQnoDKlR&}1Xv8}yY=1C2YwEZhmauoL#duc2RG?+K_&n;0Mz7#3bNdgr}r zOaK$TGs#3J0NWPdHTwoP6g3+l5$C7CmkU8r z2(A%zH5e#3i-P1N?I+>T`gv4Eh$<{lGb9@T1;9C zrz@UCrNK>{O)g|RIa)RTIBsu`{+3AYzcj5!^D28N`+qBR>%^#dV=q?;FZKZyxE4;~ zA?#QH;oJ-eTWzqHTL@vxqPWM-wQwvebDZ0ZyMk!ctyTKm{Lb|-$&?H|aCjrwqh4L8 zIWppg7~>a89w@gcrIArGSRc#w&A@9 zluu$C2O{wF-SAyl83`Y@=3|Y&ig(FGH!93~;Fz`SE#DZDcOkP8;Dk1t%#u@glTaE8%DkFMghrAdcrGi+*!d zY%KH;mV&Hn$l8FcwK)sKjGPT3ldoR0pUpdp%?V_&%&_`_+&4V(?cpPo^sY*wVY0Xw z4W2;h@wfqEKh5CMmj>t6gO>DgZaXj^77l;Pe3;*MCARpAJlNR*@&)E|i}94>WpISQ zUr^v6d1AUMV~=*-o9|CC)-Ff*nSug6=YM0)A7Khxki7|0c!H$RH7#eZXT$9-b+~84 z@W}11AlI{?OFgBhoryM!(B`eU&An;IZT>ZBbAZ^K!$d6UXYi{*v%Lm@V`80JXs(tGb=M zuUEPJKScz^g-Z_if_d_tNCLF2D3+MWEMV?bS&co(y$fKpd(TE~ZJ9MbE66m`lgBD> z>8HWS-!zEOF!C2oUm;ebT*;nz2j0l;7gJXr5R(qtqgdByw>++@2WmFq{OhL)1XZEj zKVX$st%X$vHH@FOU!IuM9Upef*3F>&UaN`g6N56Yq!&_uo^lvUyvh=)dLMTf*6qEB zmaMT_HOPGGS_UQ3j+SM%e z8H>?&=rF8+RMB!A+OmfN-0**-JL-bagefp@_=?=WS{`Ehg0ww4e*Sy?rAj8O4ughAsc?dEVm{-8&1n-M$fP@E!>(^vu;2h!dzI9R!d4t%H&oq zlhkEDn|NL_jt``Qv@#E|8y}zmLFb{eq%;mL7G=vmEj?BlpC?1&?CN#v<$m24`)s%> zc1JZwX2ZyjV#xn&ph|8vXSXIvjNEE^BXlPwn&enUjJc(b;_fhBLw14Cbvm@01<7#6 z#ZnN_H18|xa6)2GFOGm7ChUso{1=fQ+8qOFPAKs!w<5!N{44Y$6vq*~O`B zM}z`zWXt3HP(%1uZb0fp${|fLFsQ*$2T_hc zs)S`Ag!D4U=z5Zo(e=`i8j){6{V>vBVc(3j5%p4$K94jF=|7P^g7iAlN0FXEuU4ct zX$F=d-H!cgq?s7M5$Rs!Z@vG}pXonP2pI0kmV8W+Zz)(UY~Svm{ysZ|2f_Sc>n+a literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..57d7234508c80bea54543fe93dca7cb50d426d0a GIT binary patch literal 306818 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 z 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 J1{h1L{sS|0+hPC! literal 0 HcmV?d00001 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