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.
This commit is contained in:
commit
2c25c3e944
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
name unixlib
|
||||
id 4
|
||||
length 256
|
||||
|
||||
1 c _DebugPrintString(ptr) DebugPrintString(1)
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
name user
|
||||
id 2
|
||||
length 256
|
||||
|
||||
5 pascal InitApp(word) USER_InitApp(1)
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
/* $Id$
|
||||
*/
|
|
@ -0,0 +1,11 @@
|
|||
#include <windows.h>
|
||||
|
||||
MainMenu MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "E&xit", 100
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&About...", 101
|
||||
END
|
||||
END
|
Loading…
Reference in New Issue