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 0000000..45db164
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,3 @@
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..54dff6d
--- /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 0000000..09eb3de
--- /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 0000000..d47f542
--- /dev/null
+++ b/build
Binary files differ
diff --git a/build-spec.txt b/build-spec.txt
new file mode 100644
index 0000000..61937bf
--- /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 0000000..f7dd03d
--- /dev/null
+++ b/build.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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 <stdio.h>\n");
+    fprintf(fp, "#include <stdlib.h>\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 0000000..a43a9e0
--- /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 0000000..72edc7a
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,92 @@
+/* $Id$
+ */
+
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include <errno.h>
+#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 0000000..9f87b18
--- /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 0000000..156e9c8
--- /dev/null
+++ b/heap.c
@@ -0,0 +1,93 @@
+static char RCSId[] = "$Id$";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#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 0000000..7d2bbed
--- /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 0000000..4c57006
--- /dev/null
+++ b/kernel.c
@@ -0,0 +1,106 @@
+static char RCSId[] = "$Id$";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#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 0000000..58a0f0a
--- /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 0000000..facad91
--- /dev/null
+++ b/ldt.c
@@ -0,0 +1,74 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#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 0000000..a4c8dde
--- /dev/null
+++ b/ldt.tar
Binary files differ
diff --git a/ldtlib.c b/ldtlib.c
new file mode 100644
index 0000000..137130d
--- /dev/null
+++ b/ldtlib.c
@@ -0,0 +1,37 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+
+_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 0000000..d92b4a6
--- /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 0000000..0b6b8ed
--- /dev/null
+++ b/prototypes.h
@@ -0,0 +1,32 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#ifndef PROTOTYPES_H
+#define PROTOTYPES_H
+
+#include <sys/types.h>
+#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 0000000..067d0ab
--- /dev/null
+++ b/relay.c
@@ -0,0 +1,201 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include <linux/segment.h>
+#include <errno.h>
+#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 0000000..39a0225
--- /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 0000000..449e9ba
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/ldt.h>
+#include <errno.h>
+#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 0000000..3a75f7c
--- /dev/null
+++ b/test.exe
Binary files differ
diff --git a/unixlib.spec b/unixlib.spec
new file mode 100644
index 0000000..7b5b9dd
--- /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 0000000..7b3ceed
--- /dev/null
+++ b/user.c
@@ -0,0 +1,17 @@
+static char RCSId[] = "$Id$";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#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 0000000..152ef18
--- /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 0000000..57d7234
--- /dev/null
+++ b/wine
Binary files differ
diff --git a/wine.c b/wine.c
new file mode 100644
index 0000000..85d3844
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include <linux/segment.h>
+#include <errno.h>
+#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 0000000..de7d738
--- /dev/null
+++ b/winetest/main.c
@@ -0,0 +1,101 @@
+/*	MAIN.C

+ *

+ *	PURPOSE: 

+ *

+ *	FUNCTIONS:

+ *          WinMain() - Initializes app, calls all other functions.

+ */

+

+#include <windows.h>

+#include <stdarg.h>

+#include <stdio.h>

+#include <stdlib.h>

+

+/*

+ *	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 0000000..5f111dd
--- /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 0000000..bd9dbcc
--- /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 0000000..c280412
--- /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 0000000..af8228e
--- /dev/null
+++ b/winetest/winetest.rc
@@ -0,0 +1,11 @@
+#include <windows.h>

+

+MainMenu MENU

+BEGIN

+    POPUP "&File"

+    BEGIN

+        MENUITEM "E&xit",               	100

+        MENUITEM SEPARATOR

+        MENUITEM "&About...",           	101

+    END

+END