Commit 2c25c3e9 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parents
/*
* Copyright Robert J. Amstadt, 1993
*/
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
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
File added
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.
This diff is collapsed. Click to expand it.
/* $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 */
/* $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);
}
}
name gdi
id 3
length 256
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;
}
/*
* 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
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;
}
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
/* $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));
}
}
}
File added
/* $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);
}
/* $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 */
/* $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 */
/* $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;
}
/* $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 */
/* $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;
}
File added
name unixlib
id 4
length 256
1 c _DebugPrintString(ptr) DebugPrintString(1)
\ No newline at end of file
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;
}
name user
id 2
length 256
5 pascal InitApp(word) USER_InitApp(1)
\ No newline at end of file
File added
/* $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;
}
/* 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);
}
####################################################################
#
# 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
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
#include <windows.h>
MainMenu MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", 100
MENUITEM SEPARATOR
MENUITEM "&About...", 101
END
END
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment