Skip to content

Commit

Permalink
Bunch More Work on getting an EMX-based "hello world" to run.
Browse files Browse the repository at this point in the history
It looks like most of the remaining work for that is filling in dozens of
OS/2 APIs that EMX uses at startup just so we can get to our single
printf() call.  :)
  • Loading branch information
icculus committed Sep 30, 2016
1 parent 08eaf1f commit 6220544
Show file tree
Hide file tree
Showing 10 changed files with 517 additions and 86 deletions.
131 changes: 92 additions & 39 deletions lx_loader.c
Expand Up @@ -12,8 +12,9 @@

#include "lx_loader.h"

static LxModule *GLoadedModules = NULL;
static LxModule *GProgramModule = NULL;
static LxLoaderState _GLoaderState;
static LxLoaderState *GLoaderState = &_GLoaderState;


// !!! FIXME: move this into an lx_common.c file.
static int sanityCheckLxModule(uint8 **_exe, uint32 *_exelen)
Expand Down Expand Up @@ -74,6 +75,28 @@ static int sanityCheckLxModule(uint8 **_exe, uint32 *_exelen)
return 1;
} // sanityCheckLxModule

static char *makeOS2Path(const char *fname)
{
char *full = realpath(fname, NULL);
if (!full)
return NULL;

char *retval = (char *) malloc(strlen(full) + 3);
if (!retval)
return NULL;

retval[0] = 'C';
retval[1] = ':';
strcpy(retval + 2, full);
free(full);
for (char *ptr = retval + 2; *ptr; ptr++) {
if (*ptr == '/')
*ptr = '\\';
} // for

return retval;
} // makeOS2Path

/* this algorithm is from lxlite 138u. */
static int decompressExePack2(uint8 *dst, const uint32 dstlen, const uint8 *src, const uint32 srclen)
{
Expand Down Expand Up @@ -243,7 +266,7 @@ static uint32 generateMissingTrampoline(const char *_module, const char *_entry)
return (uint32) (size_t) trampoline;
} // generateMissingTrampoline

static __attribute__((noreturn)) void runLxModule(const LxModule *lxmod, const int argc, char **argv)
static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int argc, char **argv)
{
// !!! FIXME: right now, we don't list any environment variables, because they probably don't make sense to drop in (even PATH uses a different separator on Unix).
// !!! FIXME: eventually, the environment table looks like this (double-null to terminate list): var1=a\0var2=b\0var3=c\0\0
Expand Down Expand Up @@ -280,6 +303,9 @@ static __attribute__((noreturn)) void runLxModule(const LxModule *lxmod, const i
} // for
*(ptr++) = '\0';

lxmod->env = env;
lxmod->cmd = cmd;

// ...and you pass it the pointer to argv0. This is (at least as far as the docs suggest) appended to the environment table.
printf("jumping into LX land...! eip=0x%X esp=0x%X\n", (unsigned int) lxmod->eip, (unsigned int) lxmod->esp); fflush(stdout);

Expand Down Expand Up @@ -318,7 +344,7 @@ static __attribute__((noreturn)) void runLxModule(const LxModule *lxmod, const i
static void runLxLibraryInitOrTerm(LxModule *lxmod, const int isTermination)
{
// ...and you pass it the pointer to argv0. This is (at least as far as the docs suggest) appended to the environment table.
printf("jumping into LX land to %s library...! eip=0x%X esp=0x%X\n", isTermination ? "terminate" : "initialize", (unsigned int) lxmod->eip, (unsigned int) GProgramModule->esp); fflush(stdout);
printf("jumping into LX land to %s library...! eip=0x%X esp=0x%X\n", isTermination ? "terminate" : "initialize", (unsigned int) lxmod->eip, (unsigned int) GLoaderState->main_module->esp); fflush(stdout);

// !!! FIXME: need to set up OS/2 TIB and put it in FS register.
__asm__ __volatile__ (
Expand Down Expand Up @@ -347,7 +373,7 @@ static void runLxLibraryInitOrTerm(LxModule *lxmod, const int isTermination)
"popfl \n\t" // restore our original flags.
"popal \n\t" // restore our original registers.
: // no outputs
: "a" (isTermination), "S" (GProgramModule->esp), "D" (lxmod->eip)
: "a" (isTermination), "S" (GLoaderState->main_module->esp), "D" (lxmod->eip)
: "memory"
);

Expand Down Expand Up @@ -378,11 +404,11 @@ static void freeLxModule(LxModule *lxmod)
if (lxmod->prev)
lxmod->prev->next = lxmod->next;

if (lxmod == GLoadedModules)
GLoadedModules = lxmod->next;
if (lxmod == GLoaderState->loaded_modules)
GLoaderState->loaded_modules = lxmod->next;

if (GProgramModule == lxmod)
GProgramModule = NULL;
if (GLoaderState->main_module == lxmod)
GLoaderState->main_module = NULL;
// !!! FIXME: mutex to here

for (uint32 i = 0; i < lxmod->lx.num_import_mod_entries; i++)
Expand Down Expand Up @@ -613,7 +639,7 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
} // fixupPage

// !!! FIXME: break up this function.
static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_depth)
static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int dependency_tree_depth)
{
LxModule *retval = NULL;
const uint8 *origexe = exe;
Expand All @@ -632,10 +658,10 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep

const int isDLL = (module_type == 0x8000);

if (isDLL && !GProgramModule) {
if (isDLL && !GLoaderState->main_module) {
fprintf(stderr, "uhoh, need to load an .exe before a .dll!\n");
goto loadlx_failed;
} else if (!isDLL && GProgramModule) {
} else if (!isDLL && GLoaderState->main_module) {
fprintf(stderr, "uhoh, loading an .exe after already loading one!\n");
goto loadlx_failed;
} // if else if
Expand Down Expand Up @@ -669,7 +695,7 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep
} // if

if (!isDLL) { // !!! FIXME: mutex?
GProgramModule = retval;
GLoaderState->main_module = retval;
} // else if

const char *modname = retval->name;
Expand Down Expand Up @@ -768,10 +794,12 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep

// !!! FIXME: esp==0 means something special for programs (and is ignored for library init).
// !!! FIXME: "A zero value in this field indicates that the stack pointer is to be initialized to the highest address/offset in the object"
retval->esp = lx->esp;
if (lx->esp_object != 0) { // !!! FIXME: ignore for libraries
const uint32 base = (uint32) ((size_t)retval->mmaps[lx->esp_object - 1].addr);
retval->esp += base;
if (!isDLL) {
retval->esp = lx->esp;
if (lx->esp_object != 0) {
const uint32 base = (uint32) ((size_t)retval->mmaps[lx->esp_object - 1].addr);
retval->esp += base;
} // if
} // if

// Set up our exports...
Expand Down Expand Up @@ -812,7 +840,7 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep
for (uint8 i = 0; i < numentries; i++) {
entryptr++;
expord->ordinal = ordinal++;
expord->addr = ((uint8 *) retval->mmaps[objidx].addr) + *((const uint16 *) entryptr);
expord->addr = (uint32) (size_t) ((uint8 *) retval->mmaps[objidx].addr) + *((const uint16 *) entryptr);
expord++;
entryptr += 2;
} // for
Expand All @@ -824,7 +852,7 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep
for (uint8 i = 0; i < numentries; i++) {
entryptr++;
expord->ordinal = ordinal++;
expord->addr = ((uint8 *) retval->mmaps[objidx].addr) + *((const uint32 *) entryptr);
expord->addr = (uint32) (size_t) ((uint8 *) retval->mmaps[objidx].addr) + *((const uint32 *) entryptr);
expord++;
entryptr += 4;
}
Expand Down Expand Up @@ -878,6 +906,14 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep
dst += lx->page_size;
} // for

// !!! FIXME: hack to nop out some 16-bit code in emx.dll startup...
if ((i == 1) && (strcmp(modname, "EMX") == 0)) {
uint8 *ptr = ((uint8 *) retval->mmaps[1].addr) + 28596;
for (uint32 i = 0; i < 37; i++)
*(ptr++) = 0x90; // nop
}


// Now set all the pages of this object to the proper final permissions...
const int prot = ((obj->object_flags & 0x1) ? PROT_READ : 0) |
((obj->object_flags & 0x2) ? PROT_WRITE : 0) |
Expand All @@ -894,25 +930,29 @@ static LxModule *loadLxModule(uint8 *exe, uint32 exelen, int dependency_tree_dep
} // if
} // for

retval->os2path = makeOS2Path(fname);
if (!retval->os2path)
goto loadlx_failed;

if (!isDLL) {
retval->initialized = 1;
} else {
// call library init code...
if (retval->eip) {
assert(GProgramModule != NULL);
assert(GProgramModule != retval);
assert(GLoaderState->main_module != NULL);
assert(GLoaderState->main_module != retval);
runLxLibraryInit(retval);
} // if

retval->initialized = 1;

// module is ready to use, put it in the loaded list.
// !!! FIXME: mutex this
if (GLoadedModules) {
retval->next = GLoadedModules;
GLoadedModules->prev = retval;
if (GLoaderState->loaded_modules) {
retval->next = GLoaderState->loaded_modules;
GLoaderState->loaded_modules->prev = retval;
} // if
GLoadedModules = retval;
GLoaderState->loaded_modules = retval;
} // if

return retval;
Expand Down Expand Up @@ -943,7 +983,7 @@ static LxModule *loadLxModuleByPathInternal(const char *fname, const int depende

#undef LOADFAIL

LxModule *retval = loadLxModule(module, modulelen, dependency_tree_depth);
LxModule *retval = loadLxModule(fname, module, modulelen, dependency_tree_depth);
free(module);
return retval;

Expand All @@ -962,30 +1002,43 @@ static inline LxModule *loadLxModuleByPath(const char *fname)

static LxModule *loadNativeReplacement(const char *fname)
{
LxModule *retval = NULL;
void *lib = NULL;
LxNativeReplacementEntryPoint fn = NULL;
char *os2path = makeOS2Path(fname);

if (!os2path)
goto loadnative_failed;

// !!! FIXME: mutex this.
void *lib = dlopen(fname, RTLD_LOCAL | RTLD_NOW);
lib = dlopen(fname, RTLD_LOCAL | RTLD_NOW);
if (lib == NULL)
return NULL;
goto loadnative_failed;

LxNativeReplacementEntryPoint fn = (LxNativeReplacementEntryPoint) dlsym(lib, "loadNativeLxModule");
if (!fn) {
dlclose(lib);
return NULL;
} // if
fn = (LxNativeReplacementEntryPoint) dlsym(lib, "loadNativeLxModule");
if (!fn)
goto loadnative_failed;

LxModule *retval = fn();
if (retval) {
printf("Loaded native replacement library '%s' (%u exports).\n", fname, (unsigned int) retval->num_ordinals);
retval->nativelib = lib;
} // if
retval = fn(GLoaderState);
if (!retval)
goto loadnative_failed;

printf("Loaded native replacement library '%s' (%u exports).\n", fname, (unsigned int) retval->num_ordinals);
retval->nativelib = lib;
retval->os2path = os2path;

return retval;

loadnative_failed:
if (lib) dlclose(lib);
free(os2path);
return NULL;
} // loadNativeReplacement

static LxModule *loadLxModuleByModuleNameInternal(const char *modname, const int dependency_tree_depth)
{
// !!! FIXME: mutex this
for (LxModule *i = GLoadedModules; i != NULL; i = i->next) {
for (LxModule *i = GLoaderState->loaded_modules; i != NULL; i = i->next) {
if (strcasecmp(i->name, modname) == 0) {
i->refcount++;
printf("ref'd module '%s' to %u\n", i->name, (unsigned int) i->refcount);
Expand Down
48 changes: 11 additions & 37 deletions lx_loader.h
Expand Up @@ -132,47 +132,21 @@ struct LxModule
uint32 eip;
uint32 esp;
int initialized;
char *env;
char *cmd;
char *os2path; // absolute path to module, in OS/2 format
uint32 signal_exception_focus_count;
LxModule *prev; // all loaded modules are in a doubly-linked list.
LxModule *next; // all loaded modules are in a doubly-linked list.
};

typedef LxModule *(*LxNativeReplacementEntryPoint)(void);

// !!! FIXME: this is nasty for several reasons.
#define NATIVE_REPLACEMENT_TABLE(modname) \
LxModule *loadNativeLxModule(void) { \
LxModule *retval = (LxModule *) malloc(sizeof (LxModule)); \
if (!retval) goto loadnative_failed; \
memset(retval, '\0', sizeof (LxModule)); \
retval->refcount = 1; \
strcpy(retval->name, modname); \

#define NATIVE_REPLACEMENT(fn, ord) { \
void *ptr = realloc(retval->exported_names, (retval->num_names+1) * sizeof (LxExportedName)); \
if (!ptr) { goto loadnative_failed; } \
retval->exported_names = (LxExportedName *) ptr; \
strcpy(retval->exported_names[retval->num_names].name, #fn); \
retval->exported_names[retval->num_names].addr = (uint32) ((size_t) fn); \
retval->num_names++; \
ptr = realloc(retval->exported_ordinals, (retval->num_ordinals+1) * sizeof (LxExportedOrdinal)); \
if (!ptr) { goto loadnative_failed; } \
retval->exported_ordinals = (LxExportedOrdinal *) ptr; \
retval->exported_ordinals[retval->num_ordinals].ordinal = ord; \
retval->exported_ordinals[retval->num_ordinals].addr = (uint32) ((size_t) fn); \
retval->num_ordinals++; \
}

#define END_NATIVE_REPLACEMENT_TABLE() \
return retval; \
\
loadnative_failed: \
if (retval) { \
free(retval->exported_ordinals); \
free(retval->exported_names); \
free(retval); \
} \
return NULL; \
}
typedef struct
{
LxModule *loaded_modules;
LxModule *main_module;
} LxLoaderState;

typedef LxModule *(*LxNativeReplacementEntryPoint)(LxLoaderState *state);

#endif

Expand Down
7 changes: 4 additions & 3 deletions make.sh
Expand Up @@ -16,12 +16,13 @@ set -e
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,msg.so -o native/msg.so native/msg.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,doscalls.so.so -o native/doscalls.so native/doscalls.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,nls.so -o native/nls.so native/nls.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,quecalls.so -o native/queecalls.so native/quecalls.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,quecalls.so -o native/quecalls.so native/quecalls.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,viocalls.so -o native/viocalls.so native/viocalls.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,kdbcalls.so -o native/kbdcalls.so native/kbdcalls.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -fPIC -shared -Wl,-soname,sesmgr.so -o native/sesmgr.so native/sesmgr.c

gcc -std=c99 -Wall -O0 -ggdb3 -o lx_dump lx_dump.c
gcc -m32 -std=c99 -Wall -O0 -ggdb3 -o lx_loader lx_loader.c -ldl
./lx_dump tests/hello.exe
./lx_loader tests/hello.exe
#./lx_dump tests/hello.exe
./lx_loader tests/helloc.exe

0 comments on commit 6220544

Please sign in to comment.