Work to make OS/2 API available to native apps, not just OS/2 binaries.
GLoaderState is moved to a new lib2ine library, which everything links to and sets up what it can in a DLL constructor, so your app can just link to doscalls or whatever and it'll have what it needs without something like lx_loader doing a lot of heavy lifting before your main() runs.
This commit is contained in:
1 parent
12204217cc
commit
aa8f842232
8 files changed
+220
-370
No files matched your search
@@ -67,10 +67,16 @@ endif()
|
||||
# !!! FIXME
|
||||
include_directories("/usr/local/include/SDL2")
|
||||
|
||||
add_library(2ine SHARED "lib2ine.c")
|
||||
set_target_properties(2ine PROPERTIES COMPILE_FLAGS "-m32")
|
||||
set_target_properties(2ine PROPERTIES LINK_FLAGS "-m32 -ggdb3")
|
||||
target_link_libraries(2ine "pthread")
|
||||
|
||||
foreach(_I doscalls;msg;nls;quecalls;viocalls;kbdcalls;sesmgr;som;pmwin;pmshapi;pmgpi;tcpip32)
|
||||
add_library(${_I} SHARED "native/${_I}.c")
|
||||
set_target_properties(${_I} PROPERTIES COMPILE_FLAGS "-m32")
|
||||
set_target_properties(${_I} PROPERTIES LINK_FLAGS "-m32 -ggdb3")
|
||||
target_link_libraries(${_I} 2ine)
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(doscalls "pthread")
|
||||
@@ -81,6 +87,7 @@ target_link_libraries(pmwin "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0")
|
||||
add_executable(lx_dump lx_dump.c)
|
||||
|
||||
add_executable(lx_loader lx_loader.c)
|
||||
target_link_libraries(lx_loader 2ine)
|
||||
target_link_libraries(lx_loader "dl")
|
||||
set_target_properties(lx_loader PROPERTIES COMPILE_FLAGS "-m32")
|
||||
set_target_properties(lx_loader PROPERTIES LINK_FLAGS "-m32 -ggdb3")
|
||||
|
||||
+21
-8
@@ -6,8 +6,11 @@
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#ifndef _INCL_LX_LOADER_H_
|
||||
#define _INCL_LX_LOADER_H_ 1
|
||||
/* lib2ine is support code and data that is common between various native
|
||||
reimplementations of the OS/2 API, and the OS/2 binary loader. */
|
||||
|
||||
#ifndef _INCL_LIB2INE_H_
|
||||
#define _INCL_LIB2INE_H_ 1
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
@@ -219,44 +222,54 @@ typedef struct LxPostTIB
|
||||
|
||||
#define LXTIBSIZE (sizeof (LxTIB) + sizeof (LxTIB2) + sizeof (LxPostTIB))
|
||||
|
||||
#define LX_MAX_LDT_SLOTS 8192
|
||||
|
||||
typedef struct LxLoaderState
|
||||
{
|
||||
LxModule *loaded_modules;
|
||||
LxModule *main_module;
|
||||
uint8 main_tibspace[LXTIBSIZE];
|
||||
LxPIB pib;
|
||||
int using_lx_loader;
|
||||
int subprocess;
|
||||
int running;
|
||||
int trace_native;
|
||||
int trace_events;
|
||||
uint8 main_tib_selector;
|
||||
uint16 original_cs;
|
||||
uint16 original_ds;
|
||||
uint16 original_es;
|
||||
uint16 original_ss;
|
||||
uint32 ldt[8192];
|
||||
uint32 *ldt; //[LX_MAX_LDT_SLOTS];
|
||||
char *libpath;
|
||||
uint32 libpathlen;
|
||||
uint32 *tlspage;
|
||||
uint32 tlsmask; // one bit for each TLS slot in use.
|
||||
uint8 tlsallocs[32]; // number of TLS slots allocated in one block, indexed by starting block (zero if not the starting block).
|
||||
void (*dosExit)(uint32 action, uint32 result);
|
||||
uint16 (*initOs2Tib)(uint8 *tibspace, void *_topOfStack, const size_t stacklen, const uint32 tid);
|
||||
void (*initOs2Tib)(uint8 *tibspace, void *_topOfStack, const size_t stacklen, const uint32 tid);
|
||||
uint16 (*setOs2Tib)(uint8 *tibspace);
|
||||
LxTIB *(*getOs2Tib)(void);
|
||||
void (*deinitOs2Tib)(const uint16 selector);
|
||||
int (*findSelector)(const uint32 addr, uint16 *outselector, uint16 *outoffset, int iscode);
|
||||
void (*freeSelector)(const uint16 selector);
|
||||
void *(*convert1616to32)(const uint32 addr1616);
|
||||
uint32 (*convert32to1616)(void *addr32);
|
||||
LxModule *(*loadModule)(const char *modname);
|
||||
int (*locatePathCaseInsensitive)(char *buf);
|
||||
char *(*makeUnixPath)(const char *os2path, uint32 *err);
|
||||
char *(*makeOS2Path)(const char *fname);
|
||||
void __attribute__((noreturn)) (*terminate)(const uint32 exitcode);
|
||||
} LxLoaderState;
|
||||
|
||||
typedef const LxExport *(*LxNativeModuleInitEntryPoint)(LxLoaderState *lx_state, uint32 *lx_num_exports);
|
||||
typedef const LxExport *(*LxNativeModuleInitEntryPoint)(uint32 *lx_num_exports);
|
||||
typedef void (*LxNativeModuleDeinitEntryPoint)(void);
|
||||
|
||||
// !!! FIXME: need to change this symbol name.
|
||||
extern __attribute__((visibility("default"))) LxLoaderState GLoaderState;
|
||||
|
||||
#define LX_NATIVE_CONSTRUCTOR(modname) void __attribute__((constructor)) lxNativeConstructor_##modname(void)
|
||||
#define LX_NATIVE_DESTRUCTOR(modname) void __attribute__((destructor)) lxNativeDestructor_##modname(void)
|
||||
|
||||
#endif
|
||||
|
||||
// end of lx_loader.h ...
|
||||
// end of lib2ine.h ...
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "lx_loader.h"
|
||||
|
||||
#include "lib2ine.h"
|
||||
|
||||
// !!! FIXME: some cut-and-paste with lx_loader.c ...
|
||||
|
||||
|
||||
+129
-260
@@ -27,10 +27,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <asm/ldt.h>
|
||||
|
||||
#include "lx_loader.h"
|
||||
|
||||
static LxLoaderState _GLoaderState;
|
||||
static LxLoaderState *GLoaderState = &_GLoaderState;
|
||||
#include "lib2ine.h"
|
||||
|
||||
// !!! FIXME: move this into an lx_common.c file.
|
||||
static int sanityCheckLxModule(uint8 **_exe, uint32 *_exelen)
|
||||
@@ -173,7 +170,7 @@ static int locatePathCaseInsensitive(char *buf)
|
||||
return locateOneElement(buf) ? 0 : -1;
|
||||
} // locatePathCaseInsensitive
|
||||
|
||||
static char *makeUnixPath(const char *os2path, uint32 *err)
|
||||
static char *lxMakeUnixPath(const char *os2path, uint32 *err)
|
||||
{
|
||||
if ((strcasecmp(os2path, "NUL") == 0) || (strcasecmp(os2path, "\\DEV\\NUL") == 0))
|
||||
os2path = "/dev/null";
|
||||
@@ -211,7 +208,7 @@ static char *makeUnixPath(const char *os2path, uint32 *err)
|
||||
locatePathCaseInsensitive(retval);
|
||||
|
||||
return retval;
|
||||
} // makeUnixPath
|
||||
} // lxMakeUnixPath
|
||||
|
||||
|
||||
/* this algorithm is from lxlite 138u. */
|
||||
@@ -352,9 +349,9 @@ static int decompressIterated(uint8 *dst, uint32 dstlen, const uint8 *src, uint3
|
||||
// !!! FIXME: mutex this
|
||||
static int allocateSelector(const uint16 selector, const int pages, const uint32 addr, const unsigned int contents, const int is32bit)
|
||||
{
|
||||
assert(selector < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])));
|
||||
assert(selector < LX_MAX_LDT_SLOTS);
|
||||
|
||||
if (GLoaderState->ldt[selector])
|
||||
if (GLoaderState.ldt[selector])
|
||||
return 0; // already in use.
|
||||
|
||||
//const int expand_down = (contents == MODIFY_LDT_CONTENTS_STACK);
|
||||
@@ -372,18 +369,18 @@ static int allocateSelector(const uint16 selector, const int pages, const uint32
|
||||
if (syscall(SYS_modify_ldt, 1, &entry, sizeof (entry)) != 0)
|
||||
return 0;
|
||||
|
||||
GLoaderState->ldt[selector] = addr;
|
||||
GLoaderState.ldt[selector] = addr;
|
||||
return 1;
|
||||
} // allocateSelector
|
||||
|
||||
// !!! FIXME: mutex this
|
||||
static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffset, int iscode)
|
||||
static int lxFindSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffset, int iscode)
|
||||
{
|
||||
uint32 addr = _addr;
|
||||
if (addr < 4096)
|
||||
return 0; // we won't map the NULL page.
|
||||
|
||||
const uint32 *ldt = GLoaderState->ldt;
|
||||
const uint32 *ldt = GLoaderState.ldt;
|
||||
|
||||
int available = -1;
|
||||
int preferred = -1;
|
||||
@@ -403,7 +400,7 @@ static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffs
|
||||
} // if
|
||||
} // if
|
||||
|
||||
for (int i = 0; i < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])); i++) {
|
||||
for (int i = 0; i < LX_MAX_LDT_SLOTS; i++) {
|
||||
const uint32 tile = ldt[i];
|
||||
if (tile == 0)
|
||||
available = i;
|
||||
@@ -423,7 +420,7 @@ static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffs
|
||||
|
||||
// decide if there is code or data mapped here. If there's an OS/2 API to
|
||||
// change page permissions, we'll need to update the mapping and our state.
|
||||
for (LxModule *lxmod = GLoaderState->loaded_modules; (iscode == -1) && lxmod; lxmod = lxmod->next) {
|
||||
for (LxModule *lxmod = GLoaderState.loaded_modules; (iscode == -1) && lxmod; lxmod = lxmod->next) {
|
||||
LxMmaps *mmaps = lxmod->mmaps;
|
||||
for (uint32 i = 0; i < lxmod->lx.module_num_objects; i++, mmaps++) {
|
||||
const size_t lo = (size_t) mmaps->addr;
|
||||
@@ -454,14 +451,14 @@ static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffs
|
||||
*outselector = selector;
|
||||
*outoffset = (uint16) diff;
|
||||
return 1;
|
||||
} // findSelector
|
||||
} // lxFindSelector
|
||||
|
||||
// !!! FIXME: mutex this
|
||||
static void freeSelector(const uint16 selector)
|
||||
static void lxFreeSelector(const uint16 selector)
|
||||
{
|
||||
assert(selector < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])));
|
||||
assert(selector < LX_MAX_LDT_SLOTS);
|
||||
|
||||
if (!GLoaderState->ldt[selector])
|
||||
if (!GLoaderState.ldt[selector])
|
||||
return; // already free.
|
||||
|
||||
struct user_desc entry;
|
||||
@@ -472,29 +469,29 @@ static void freeSelector(const uint16 selector)
|
||||
if (syscall(SYS_modify_ldt, 1, &entry, sizeof (entry)) != 0)
|
||||
return; // oh well.
|
||||
|
||||
GLoaderState->ldt[selector] = 0;
|
||||
} // freeSelector
|
||||
GLoaderState.ldt[selector] = 0;
|
||||
} // lxFreeSelector
|
||||
|
||||
static void *convert1616to32(const uint32 addr1616)
|
||||
static void *lxConvert1616to32(const uint32 addr1616)
|
||||
{
|
||||
if (addr1616 == 0)
|
||||
return NULL;
|
||||
|
||||
const uint16 selector = (uint16) (addr1616 >> 19); // slide segment down, and shift out control bits.
|
||||
const uint16 offset = (uint16) (addr1616 % 0x10000); // all our LDT segments start at 64k boundaries (at the moment!).
|
||||
assert(GLoaderState->ldt[selector] != 0);
|
||||
//printf("convert1616to32: 0x%X -> %p\n", (uint) addr1616, (void *) (size_t) (GLoaderState->ldt[selector] + offset));
|
||||
return (void *) (size_t) (GLoaderState->ldt[selector] + offset);
|
||||
} // convert1616to32
|
||||
assert(GLoaderState.ldt[selector] != 0);
|
||||
//printf("lxConvert1616to32: 0x%X -> %p\n", (uint) addr1616, (void *) (size_t) (GLoaderState.ldt[selector] + offset));
|
||||
return (void *) (size_t) (GLoaderState.ldt[selector] + offset);
|
||||
} // lxConvert1616to32
|
||||
|
||||
static uint32 convert32to1616(void *addr32)
|
||||
static uint32 lxConvert32to1616(void *addr32)
|
||||
{
|
||||
if (addr32 == NULL)
|
||||
return 0;
|
||||
|
||||
uint16 selector = 0;
|
||||
uint16 offset = 0;
|
||||
if (!findSelector((uint32) addr32, &selector, &offset, -1)) {
|
||||
if (!lxFindSelector((uint32) addr32, &selector, &offset, -1)) {
|
||||
fprintf(stderr, "Uhoh, ran out of LDT entries?!\n");
|
||||
return 0; // oh well, crash, probably.
|
||||
} // if
|
||||
@@ -503,7 +500,7 @@ static uint32 convert32to1616(void *addr32)
|
||||
selector = (selector << 3) | 7;
|
||||
//printf("shifted selector: 0x%X\n", (uint) selector);
|
||||
return (((uint32)selector) << 16) | ((uint32) offset);
|
||||
} // convert32to1616
|
||||
} // lxConvert32to1616
|
||||
|
||||
|
||||
// EMX (and probably many other things) occasionally has to call a 16-bit
|
||||
@@ -528,7 +525,7 @@ static void initOs2StackSegments(uint32 addr, uint32 stacklen, const int deinit)
|
||||
while (stacklen) {
|
||||
//printf("Allocating selector 0x%X for stack %p ... \n", (uint) (addr >> 16), (void *) addr);
|
||||
if (deinit) {
|
||||
freeSelector((uint16) (addr >> 16));
|
||||
lxFreeSelector((uint16) (addr >> 16));
|
||||
} else {
|
||||
if (!allocateSelector((uint16) (addr >> 16), 16, addr, MODIFY_LDT_CONTENTS_DATA, 0)) {
|
||||
FIXME("uhoh, couldn't set up an LDT entry for a stack segment! Might crash later!");
|
||||
@@ -547,31 +544,12 @@ static void initOs2StackSegments(uint32 addr, uint32 stacklen, const int deinit)
|
||||
// the EMX runtime) touch the register directly, so we have to deal with it.
|
||||
// You must call this once for each thread that will go into LX land, from
|
||||
// that thread, as soon as possible after starting.
|
||||
static uint16 initOs2Tib(uint8 *tibspace, void *_topOfStack, const size_t stacklen, const uint32 tid)
|
||||
static uint16 lxSetOs2Tib(uint8 *tibspace)
|
||||
{
|
||||
uint8 *topOfStack = (uint8 *) _topOfStack;
|
||||
|
||||
LxTIB *tib = (LxTIB *) tibspace;
|
||||
LxTIB2 *tib2 = (LxTIB2 *) (tib + 1);
|
||||
|
||||
FIXME("This is probably 50% wrong");
|
||||
tib->tib_pexchain = NULL;
|
||||
tib->tib_pstack = topOfStack - stacklen;
|
||||
tib->tib_pstacklimit = (void *) topOfStack;
|
||||
tib->tib_ptib2 = tib2;
|
||||
tib->tib_version = 20; // !!! FIXME
|
||||
tib->tib_ordinal = 79; // !!! FIXME
|
||||
|
||||
tib2->tib2_ultid = tid;
|
||||
tib2->tib2_ulpri = 512;
|
||||
tib2->tib2_version = 20;
|
||||
tib2->tib2_usMCCount = 0;
|
||||
tib2->tib2_fMCForceFlag = 0;
|
||||
|
||||
// !!! FIXME: I barely know what I'm doing here, this could all be wrong.
|
||||
struct user_desc entry;
|
||||
entry.entry_number = -1;
|
||||
entry.base_addr = (unsigned int) ((size_t)tib);
|
||||
entry.base_addr = (unsigned int) ((size_t)tibspace);
|
||||
entry.limit = LXTIBSIZE;
|
||||
entry.seg_32bit = 1;
|
||||
entry.contents = MODIFY_LDT_CONTENTS_DATA;
|
||||
@@ -584,13 +562,30 @@ static uint16 initOs2Tib(uint8 *tibspace, void *_topOfStack, const size_t stackl
|
||||
|
||||
// The "<< 3 | 3" makes this a GDT selector at ring 3 permissions.
|
||||
// If this did "| 7" instead of "| 3", it'd be an LDT selector.
|
||||
// Use findSelector() or allocateSelector() for LDT entries, though!
|
||||
// Use lxFindSelector() or allocateSelector() for LDT entries, though!
|
||||
const unsigned int segment = (entry.entry_number << 3) | 3;
|
||||
__asm__ __volatile__ ( "movw %%ax, %%fs \n\t" : : "a" (segment) );
|
||||
return (uint16) entry.entry_number;
|
||||
} // initOs2Tib
|
||||
} // lxSetOs2Tib
|
||||
|
||||
static void deinitOs2Tib(const uint16 selector)
|
||||
static LxTIB2 *lxGetOs2Tib2(void)
|
||||
{
|
||||
// just read the FS register, since we have to stick it there anyhow...
|
||||
LxTIB2 *ptib2;
|
||||
__asm__ __volatile__ ( "movl %%fs:0xC, %0 \n\t" : "=r" (ptib2) );
|
||||
return ptib2;
|
||||
} // lxGetTib2
|
||||
|
||||
static LxTIB *lxGetOs2Tib(void)
|
||||
{
|
||||
// we store the TIB2 struct right after the TIB struct on the stack,
|
||||
// so get the TIB2's linear address from %fs:0xC, then step back
|
||||
// to the TIB's linear address.
|
||||
uint8 *ptib2 = (uint8 *) lxGetOs2Tib2();
|
||||
return (LxTIB *) (ptib2 - sizeof (LxTIB));
|
||||
} // lxGetOs2Tib
|
||||
|
||||
static void lxDeinitOs2Tib(const uint16 selector)
|
||||
{
|
||||
// !!! FIXME: I barely know what I'm doing here, this could all be wrong.
|
||||
struct user_desc entry;
|
||||
@@ -601,14 +596,14 @@ static void deinitOs2Tib(const uint16 selector)
|
||||
|
||||
const long rc = syscall(SYS_set_thread_area, &entry);
|
||||
assert(rc == 0); FIXME("this can legit fail, though!");
|
||||
} // deinitOs2Tib
|
||||
} // lsDeinitOs2Tib
|
||||
|
||||
static void freeLxModule(LxModule *lxmod);
|
||||
|
||||
static __attribute__((noreturn)) void terminate(const uint32 exitcode)
|
||||
static __attribute__((noreturn)) void lxTerminate(const uint32 exitcode)
|
||||
{
|
||||
// free the actual .exe
|
||||
freeLxModule(GLoaderState->main_module);
|
||||
freeLxModule(GLoaderState.main_module);
|
||||
|
||||
// clear out anything that is still loaded...
|
||||
// presumably everything in the loaded_modules list is sorted in order
|
||||
@@ -617,12 +612,15 @@ static __attribute__((noreturn)) void terminate(const uint32 exitcode)
|
||||
// module, pushing it futher down.
|
||||
// if this doesn't work out, maybe just run everything's termination code
|
||||
// and free everything after there's nothing left to run.
|
||||
while (GLoaderState->loaded_modules) {
|
||||
LxModule *lxmod = GLoaderState->loaded_modules;
|
||||
while (GLoaderState.loaded_modules) {
|
||||
LxModule *lxmod = GLoaderState.loaded_modules;
|
||||
lxmod->refcount = 1; // force it to free now.
|
||||
freeLxModule(lxmod);
|
||||
} // while
|
||||
|
||||
free(GLoaderState.ldt);
|
||||
GLoaderState.ldt = NULL;
|
||||
|
||||
// OS/2's docs say this only keeps the lower 16 bits of exitcode.
|
||||
// !!! FIXME: ...but Unix only keeps the lowest 8 bits. Will have to
|
||||
// !!! FIXME: tapdance to pass larger values back to OS/2 parent processes.
|
||||
@@ -630,13 +628,13 @@ static __attribute__((noreturn)) void terminate(const uint32 exitcode)
|
||||
FIXME("deal with process exit codes > 255. We clamped this one!");
|
||||
|
||||
_exit((int) (exitcode & 0xFF));
|
||||
} // terminate
|
||||
} // lxTerminate
|
||||
|
||||
static __attribute__((noreturn)) void endLxProcess(const uint32 exitcode)
|
||||
{
|
||||
if (GLoaderState->dosExit)
|
||||
GLoaderState->dosExit(1, exitcode); // let exit lists run. Should call terminate!
|
||||
terminate(exitcode); // just in case.
|
||||
if (GLoaderState.dosExit)
|
||||
GLoaderState.dosExit(1, exitcode); // let exit lists run. Should call lxTerminate!
|
||||
lxTerminate(exitcode); // just in case.
|
||||
} // endLxProcess
|
||||
|
||||
static void missingEntryPointCalled(const char *module, const char *entry)
|
||||
@@ -646,7 +644,7 @@ static void missingEntryPointCalled(const char *module, const char *entry)
|
||||
fprintf(stderr, "\n\nMissing entry point '%s' in module '%s'! Aborting.\n\n\n", entry, module);
|
||||
//STUBBED("output backtrace");
|
||||
fflush(stderr);
|
||||
terminate(1);
|
||||
lxTerminate(1);
|
||||
} // missingEntryPointCalled
|
||||
|
||||
static void *generateMissingTrampoline(const char *_module, const char *_entry)
|
||||
@@ -723,7 +721,7 @@ static void *generateMissingTrampoline16(const char *_module, const char *_entry
|
||||
pageused = 0;
|
||||
uint16 offset = 0xFFFF;
|
||||
selector = 0xFFFF;
|
||||
findSelector((uint32) page, &selector, &offset, 1);
|
||||
lxFindSelector((uint32) page, &selector, &offset, 1);
|
||||
assert(selector != 0xFFFF);
|
||||
assert(offset == 0);
|
||||
} // if
|
||||
@@ -750,21 +748,21 @@ static void *generateMissingTrampoline16(const char *_module, const char *_entry
|
||||
*(ptr++) = 0xEA; /* ...jmp dword 0x7788:0x33332222 */
|
||||
const uint32 jmp32addr = (uint32) (ptr + 6);
|
||||
memcpy(ptr, &jmp32addr, 4); ptr += 4;
|
||||
memcpy(ptr, &GLoaderState->original_cs, 2); ptr += 2;
|
||||
memcpy(ptr, &GLoaderState.original_cs, 2); ptr += 2;
|
||||
// now we're in 32-bit land again.
|
||||
*(ptr++) = 0x66; /* mov cx,0xabcd... */
|
||||
*(ptr++) = 0xB9; /* ...mov cx,0xabcd */
|
||||
memcpy(ptr, &GLoaderState->original_ss, 2); ptr += 2;
|
||||
memcpy(ptr, &GLoaderState.original_ss, 2); ptr += 2;
|
||||
*(ptr++) = 0x8E; /* mov ss,ecx... */
|
||||
*(ptr++) = 0xD1; /* ...mov ss,ecx */
|
||||
*(ptr++) = 0x89; /* mov esp,eax... */
|
||||
*(ptr++) = 0xC4; /* ...mov esp,eax */
|
||||
*(ptr++) = 0x66; /* mov cx,0x8888... */
|
||||
*(ptr++) = 0xB9; /* ...mov cx,0x8888 */
|
||||
memcpy(ptr, &GLoaderState->original_ds, 2); ptr += 2;
|
||||
memcpy(ptr, &GLoaderState.original_ds, 2); ptr += 2;
|
||||
*(ptr++) = 0x66; /* mov cx,0x8888... */
|
||||
*(ptr++) = 0xB9; /* ...mov cx,0x8888 */
|
||||
memcpy(ptr, &GLoaderState->original_es, 2); ptr += 2;
|
||||
memcpy(ptr, &GLoaderState.original_es, 2); ptr += 2;
|
||||
*(ptr++) = 0x8E; /* mov es,ecx... */ \
|
||||
*(ptr++) = 0xC1; /* ...mov es,ecx */ \
|
||||
// okay, CPU is in a sane state again, call the trampoline. Don't bother cleaning up.
|
||||
@@ -805,14 +803,14 @@ static void *generateMissingTrampoline16(const char *_module, const char *_entry
|
||||
return trampoline;
|
||||
} // generateMissingTrampoline16
|
||||
|
||||
static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int argc, char **argv, char **envp)
|
||||
static __attribute__((noreturn)) void runLxModule(LxModule *lxmod)
|
||||
{
|
||||
uint8 *stack = (uint8 *) ((size_t) lxmod->esp);
|
||||
|
||||
// ...and you pass it the pointer to argv0. This is (at least as far as the docs suggest) appended to the environment table.
|
||||
//fprintf(stderr, "jumping into LX land for exe '%s'...! eip=%p esp=%p\n", lxmod->name, (void *) lxmod->eip, stack); fflush(stderr);
|
||||
|
||||
GLoaderState->running = 1;
|
||||
GLoaderState.running = 1;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl %%esi,%%esp \n\t" // use the OS/2 process's stack.
|
||||
@@ -836,8 +834,8 @@ static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int arg
|
||||
"call endLxProcess \n\t" // never returns.
|
||||
// If we returned here, %eax has the exit code from the app.
|
||||
: // no outputs.
|
||||
: "a" (GLoaderState->pib.pib_pchcmd),
|
||||
"c" (GLoaderState->pib.pib_pchenv),
|
||||
: "a" (GLoaderState.pib.pib_pchcmd),
|
||||
"c" (GLoaderState.pib.pib_pchenv),
|
||||
"d" (lxmod), "S" (stack), "D" (lxmod->eip)
|
||||
: "memory"
|
||||
);
|
||||
@@ -852,8 +850,8 @@ static void runLxLibraryInitOrTerm(LxModule *lxmod, const int isTermination)
|
||||
uint8 *stack = NULL;
|
||||
|
||||
// force us over to OS/2 main module's stack if we aren't already on it.
|
||||
if (!GLoaderState->running)
|
||||
stack = (uint8 *) ((size_t) GLoaderState->main_module->esp);
|
||||
if (!GLoaderState.running)
|
||||
stack = (uint8 *) ((size_t) GLoaderState.main_module->esp);
|
||||
|
||||
//fprintf(stderr, "jumping into LX land to %s library '%s'...! eip=%p esp=%p\n", isTermination ? "terminate" : "initialize", lxmod->name, (void *) lxmod->eip, stack); fflush(stderr);
|
||||
|
||||
@@ -892,7 +890,7 @@ static void runLxLibraryInitOrTerm(LxModule *lxmod, const int isTermination)
|
||||
//fprintf(stderr, "...survived time in LX land!\n"); fflush(stderr);
|
||||
|
||||
// !!! FIXME: this entry point returns a result...do we abort if it reports error?
|
||||
// !!! FIXME: (actually, DosLoadModule() can report that failure. Abort if (GLoaderState->running == 0), though!)
|
||||
// !!! FIXME: (actually, DosLoadModule() can report that failure. Abort if (GLoaderState.running == 0), though!)
|
||||
} // runLxLibraryInitOrTerm
|
||||
|
||||
static void runLxLibraryInit(LxModule *lxmod)
|
||||
@@ -933,7 +931,7 @@ static void freeLxModule(LxModule *lxmod)
|
||||
if (lxmod->refcount > 0)
|
||||
return; // something is still using it.
|
||||
|
||||
if ((lxmod->initialized) && (lxmod != GLoaderState->main_module)) {
|
||||
if ((lxmod->initialized) && (lxmod != GLoaderState.main_module)) {
|
||||
if (!lxmod->nativelib) {
|
||||
runLxLibraryTerm(lxmod);
|
||||
} else {
|
||||
@@ -949,11 +947,11 @@ static void freeLxModule(LxModule *lxmod)
|
||||
if (lxmod->prev)
|
||||
lxmod->prev->next = lxmod->next;
|
||||
|
||||
if (lxmod == GLoaderState->loaded_modules)
|
||||
GLoaderState->loaded_modules = lxmod->next;
|
||||
if (lxmod == GLoaderState.loaded_modules)
|
||||
GLoaderState.loaded_modules = lxmod->next;
|
||||
|
||||
if (GLoaderState->main_module == lxmod) {
|
||||
GLoaderState->main_module = NULL;
|
||||
if (GLoaderState.main_module == lxmod) {
|
||||
GLoaderState.main_module = NULL;
|
||||
LxMmaps *lxmmap = &lxmod->mmaps[lxmod->lx.esp_object - 1];
|
||||
const uint32 stackbase = (uint32) ((size_t)lxmmap->addr);
|
||||
initOs2StackSegments(stackbase, lxmmap->size, 1);
|
||||
@@ -967,7 +965,7 @@ static void freeLxModule(LxModule *lxmod)
|
||||
|
||||
for (uint32 i = 0; i < lxmod->lx.module_num_objects; i++) {
|
||||
if (lxmod->mmaps[i].alias != 0xFFFF)
|
||||
freeSelector(lxmod->mmaps[i].alias);
|
||||
lxFreeSelector(lxmod->mmaps[i].alias);
|
||||
if (lxmod->mmaps[i].mapped)
|
||||
munmap(lxmod->mmaps[i].mapped, lxmod->mmaps[i].size);
|
||||
} // for
|
||||
@@ -1111,7 +1109,7 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
|
||||
finalsize = 4;
|
||||
break;
|
||||
case 0x6: // 16:32 pointer fixup
|
||||
finalval2 = GLoaderState->original_cs;
|
||||
finalval2 = GLoaderState.original_cs;
|
||||
finalsize = 6;
|
||||
allow_fixup_to_alias = 1;
|
||||
break;
|
||||
@@ -1365,7 +1363,7 @@ static void fixupLinearCodeSegmentReferences(uint8 *addr, size_t size)
|
||||
if (*(addr++) == 0xEA) {
|
||||
if ((addr[4] == 0x5B) && (addr[5] == 0x00)) {
|
||||
//printf("Patching out code segment 0x5B at %p\n", addr+4);
|
||||
memcpy(&addr[4], &GLoaderState->original_cs, 2);
|
||||
memcpy(&addr[4], &GLoaderState.original_cs, 2);
|
||||
size -= 6;
|
||||
addr += 6;
|
||||
} // if
|
||||
@@ -1394,10 +1392,10 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
|
||||
|
||||
const int isDLL = (module_type == 0x8000);
|
||||
|
||||
if (isDLL && !GLoaderState->main_module) {
|
||||
if (isDLL && !GLoaderState.main_module) {
|
||||
fprintf(stderr, "uhoh, need to load an .exe before a .dll!\n");
|
||||
goto loadlx_failed;
|
||||
} else if (!isDLL && GLoaderState->main_module) {
|
||||
} else if (!isDLL && GLoaderState.main_module) {
|
||||
fprintf(stderr, "uhoh, loading an .exe after already loading one!\n");
|
||||
goto loadlx_failed;
|
||||
} // if else if
|
||||
@@ -1434,8 +1432,8 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
|
||||
} // if
|
||||
|
||||
if (!isDLL) {
|
||||
GLoaderState->main_module = retval;
|
||||
GLoaderState->pib.pib_hmte = retval;
|
||||
GLoaderState.main_module = retval;
|
||||
GLoaderState.pib.pib_hmte = retval;
|
||||
} // else if
|
||||
|
||||
const char *modname = retval->name;
|
||||
@@ -1574,7 +1572,8 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
|
||||
|
||||
// This needs to be set up now, so it's available to any library
|
||||
// init code that runs in LX land.
|
||||
initOs2Tib(GLoaderState->main_tibspace, (void *) ((size_t) retval->esp), stacksize, 0);
|
||||
GLoaderState.initOs2Tib(GLoaderState.main_tibspace, (void *) ((size_t) retval->esp), stacksize, 0);
|
||||
GLoaderState.main_tib_selector = GLoaderState.setOs2Tib(GLoaderState.main_tibspace);
|
||||
initOs2StackSegments(stackbase, stacksize, 0);
|
||||
} // if
|
||||
|
||||
@@ -1587,7 +1586,7 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
|
||||
continue; // Object doesn't need a 16:16 alias, skip it.
|
||||
uint16 offset = 0;
|
||||
const int iscode = (obj->object_flags & 0x4) ? 1 : 0;
|
||||
if (!findSelector((uint32) (size_t) retval->mmaps[i].addr, &retval->mmaps[i].alias, &offset, iscode)) {
|
||||
if (!lxFindSelector((uint32) (size_t) retval->mmaps[i].addr, &retval->mmaps[i].alias, &offset, iscode)) {
|
||||
fprintf(stderr, "Ran out of LDT entries getting a 16:16 alias for '%s' object #%u!\n", modname, (uint) (i + 1));
|
||||
goto loadlx_failed;
|
||||
} // if
|
||||
@@ -1755,19 +1754,19 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
|
||||
retval->initialized = 1;
|
||||
} else {
|
||||
// call library init code...
|
||||
assert(GLoaderState->main_module != NULL);
|
||||
assert(GLoaderState->main_module != retval);
|
||||
assert(GLoaderState.main_module != NULL);
|
||||
assert(GLoaderState.main_module != retval);
|
||||
runLxLibraryInit(retval);
|
||||
|
||||
retval->initialized = 1;
|
||||
|
||||
// module is ready to use, put it in the loaded list.
|
||||
// !!! FIXME: mutex this
|
||||
if (GLoaderState->loaded_modules) {
|
||||
retval->next = GLoaderState->loaded_modules;
|
||||
GLoaderState->loaded_modules->prev = retval;
|
||||
if (GLoaderState.loaded_modules) {
|
||||
retval->next = GLoaderState.loaded_modules;
|
||||
GLoaderState.loaded_modules->prev = retval;
|
||||
} // if
|
||||
GLoaderState->loaded_modules = retval;
|
||||
GLoaderState.loaded_modules = retval;
|
||||
} // if
|
||||
|
||||
return retval;
|
||||
@@ -1840,7 +1839,7 @@ static LxModule *loadNativeModule(const char *fname, const char *modname)
|
||||
if (!fn)
|
||||
goto loadnative_failed;
|
||||
|
||||
exports = fn(GLoaderState, &num_exports);
|
||||
exports = fn(&num_exports);
|
||||
if (!exports)
|
||||
goto loadnative_failed;
|
||||
retval->refcount = 1;
|
||||
@@ -1865,7 +1864,7 @@ loadnative_failed:
|
||||
static LxModule *loadLxModuleByModuleNameInternal(const char *modname, const int dependency_tree_depth)
|
||||
{
|
||||
// !!! FIXME: mutex this
|
||||
for (LxModule *i = GLoaderState->loaded_modules; 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, (uint) i->refcount);
|
||||
@@ -1892,140 +1891,16 @@ static LxModule *loadLxModuleByModuleNameInternal(const char *modname, const int
|
||||
if (retval != NULL) {
|
||||
// module is ready to use, put it in the loaded list.
|
||||
// !!! FIXME: mutex this
|
||||
if (GLoaderState->loaded_modules) {
|
||||
retval->next = GLoaderState->loaded_modules;
|
||||
GLoaderState->loaded_modules->prev = retval;
|
||||
if (GLoaderState.loaded_modules) {
|
||||
retval->next = GLoaderState.loaded_modules;
|
||||
GLoaderState.loaded_modules->prev = retval;
|
||||
} // if
|
||||
GLoaderState->loaded_modules = retval;
|
||||
GLoaderState.loaded_modules = retval;
|
||||
} // if
|
||||
} // if
|
||||
return retval;
|
||||
} // loadLxModuleByModuleNameInternal
|
||||
|
||||
static void initPib(LxPIB *pib, const int argc, char **argv, char **envp)
|
||||
{
|
||||
// !!! FIXME: this is incomplete.
|
||||
memset(pib, '\0', sizeof (*pib));
|
||||
|
||||
// Eventually, the environment table looks like this (double-null to terminate list): var1=a\0var2=b\0var3=c\0\0
|
||||
// The command line looks like this: \0argv0\0argv1 argv2 argvN\0\0
|
||||
// Between env and cmd is the exe name: argv0\0
|
||||
|
||||
size_t len = 1;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
int needs_escape = 0;
|
||||
int num_backslashes = 0;
|
||||
for (const char *arg = argv[i]; *arg; arg++) {
|
||||
const char ch = *arg;
|
||||
if ((ch == ' ') || (ch == '\t'))
|
||||
needs_escape = 1;
|
||||
else if ((ch == '\\') || (ch == '\"'))
|
||||
num_backslashes++;
|
||||
len++;
|
||||
} // for
|
||||
|
||||
if (needs_escape) {
|
||||
len += 2 + num_backslashes;
|
||||
} // if
|
||||
|
||||
len++; // terminator
|
||||
} // for
|
||||
|
||||
len += strlen(argv[0]) + 1; // for the exe name.
|
||||
|
||||
const char *default_os2path = "PATH=C:\\home\\icculus\\Dropbox\\emx\\bin;C:\\WATCOM\\binp;C:\\home\\icculus"; // !!! FIXME: noooooope.
|
||||
for (int i = 0; envp[i]; i++) {
|
||||
const char *str = envp[i];
|
||||
if (strncmp(str, "PATH=", 5) == 0) {
|
||||
if (!GLoaderState->subprocess)
|
||||
str = default_os2path;
|
||||
} else if (strncmp(str, "IS_2INE=", 8) == 0) {
|
||||
continue;
|
||||
} // if
|
||||
len += strlen(str) + 1;
|
||||
} // for
|
||||
|
||||
len += 4; // null terminators.
|
||||
|
||||
char *env = (char *) malloc(len);
|
||||
if (!env) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
exit(1);
|
||||
} // if
|
||||
|
||||
const char *libpath = NULL;
|
||||
char *ptr = env;
|
||||
for (int i = 0; envp[i]; i++) {
|
||||
const char *str = envp[i];
|
||||
if (strncmp(str, "PATH=", 5) == 0) {
|
||||
if (!GLoaderState->subprocess)
|
||||
str = default_os2path;
|
||||
} else if (strncmp(str, "LIBPATH=", 8) == 0) {
|
||||
libpath = str + 8;
|
||||
} else if (strncmp(str, "IS_2INE=", 8) == 0) {
|
||||
continue;
|
||||
} // if
|
||||
|
||||
strcpy(ptr, str);
|
||||
ptr += strlen(str) + 1;
|
||||
}
|
||||
*(ptr++) = '\0';
|
||||
|
||||
// we keep a copy of LIBPATH for undocumented API
|
||||
// DosQueryHandleInfo(..., QHINF_LIBPATH, ...). I guess in case the app
|
||||
// has changed the environment var after start? Java uses this.
|
||||
if (libpath == NULL)
|
||||
libpath = "";
|
||||
|
||||
GLoaderState->libpath = strdup(libpath);
|
||||
GLoaderState->libpathlen = strlen(libpath) + 1;
|
||||
|
||||
// put the exe name between the environment and the command line.
|
||||
strcpy(ptr, argv[0]);
|
||||
ptr += strlen(argv[0]) + 1;
|
||||
|
||||
char *cmd = ptr;
|
||||
strcpy(ptr, argv[0]);
|
||||
ptr += strlen(argv[0]);
|
||||
*(ptr++) = '\0';
|
||||
for (int i = 1; i < argc; i++) {
|
||||
int needs_escape = 0;
|
||||
for (const char *arg = argv[i]; *arg; arg++) {
|
||||
const char ch = *arg;
|
||||
if ((ch == ' ') || (ch == '\t'))
|
||||
needs_escape = 1;
|
||||
} // for
|
||||
|
||||
if (needs_escape) {
|
||||
*(ptr++) = '"';
|
||||
for (const char *arg = argv[i]; *arg; arg++) {
|
||||
const char ch = *arg;
|
||||
if ((ch == '\\') || (ch == '\n'))
|
||||
*(ptr++) = '\\';
|
||||
*(ptr++) = ch;
|
||||
} // for
|
||||
*(ptr++) = '"';
|
||||
} else {
|
||||
for (const char *arg = argv[i]; *arg; arg++)
|
||||
*(ptr++) = *arg;
|
||||
} // if
|
||||
|
||||
if (i < (argc-1))
|
||||
*(ptr++) = ' ';
|
||||
} // for
|
||||
|
||||
*(ptr++) = '\0';
|
||||
|
||||
pib->pib_ulpid = (uint32) getpid();
|
||||
pib->pib_ulppid = (uint32) getppid();
|
||||
pib->pib_pchcmd = cmd;
|
||||
pib->pib_pchenv = env;
|
||||
//pib->pib_hmte is filled in later during loadLxModule()
|
||||
// !!! FIXME: uint32 pib_flstatus;
|
||||
// !!! FIXME: uint32 pib_ultype;
|
||||
} // initPib
|
||||
|
||||
|
||||
static LxModule *loadLxModuleByModuleName(const char *modname)
|
||||
{
|
||||
return loadLxModuleByModuleNameInternal(modname, 0);
|
||||
@@ -2046,7 +1921,7 @@ static LxModule *loadLxModuleByPathOrModuleName(const char *modname)
|
||||
} // if
|
||||
} else {
|
||||
uint32 err = 0;
|
||||
char *path = makeUnixPath(modname, &err);
|
||||
char *path = lxMakeUnixPath(modname, &err);
|
||||
if (!path)
|
||||
return NULL;
|
||||
retval = loadLxModuleByPath(path);
|
||||
@@ -2126,7 +2001,7 @@ static void segfault_catcher(int sig, siginfo_t *info, void *ctx)
|
||||
{
|
||||
ucontext_t *uctx = (ucontext_t *) ctx;
|
||||
const uint32 *addr = (const uint32 *) info->si_addr;
|
||||
const uint32 *tlspage = GLoaderState->tlspage;
|
||||
const uint32 *tlspage = GLoaderState.tlspage;
|
||||
|
||||
if (tlspage && (addr >= tlspage))
|
||||
{
|
||||
@@ -2171,52 +2046,46 @@ int main(int argc, char **argv, char **envp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
GLoaderState.ldt = (uint32 *) calloc(LX_MAX_LDT_SLOTS, sizeof (*GLoaderState.ldt));
|
||||
if (!GLoaderState.ldt) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// cleanup some defaults lib2ine set up, since we'll set it up a different way.
|
||||
GLoaderState.using_lx_loader = 1;
|
||||
GLoaderState.running = 0;
|
||||
GLoaderState.deinitOs2Tib(GLoaderState.main_tib_selector);
|
||||
GLoaderState.main_tib_selector = 0;
|
||||
|
||||
if (!installSignalHandlers())
|
||||
return 1;
|
||||
|
||||
if (getenv("TRACE_NATIVE"))
|
||||
GLoaderState->trace_native = 1;
|
||||
|
||||
if (getenv("TRACE_EVENTS"))
|
||||
GLoaderState->trace_events = 1;
|
||||
|
||||
unsigned int segment = 0;
|
||||
__asm__ __volatile__ ( "movw %%cs, %%ax \n\t" : "=a" (segment) );
|
||||
GLoaderState->original_cs = segment;
|
||||
GLoaderState.original_cs = segment;
|
||||
__asm__ __volatile__ ( "movw %%ds, %%ax \n\t" : "=a" (segment) );
|
||||
GLoaderState->original_ds = segment;
|
||||
GLoaderState.original_ds = segment;
|
||||
__asm__ __volatile__ ( "movw %%es, %%ax \n\t" : "=a" (segment) );
|
||||
GLoaderState->original_es = segment;
|
||||
GLoaderState.original_es = segment;
|
||||
__asm__ __volatile__ ( "movw %%ss, %%ax \n\t" : "=a" (segment) );
|
||||
GLoaderState->original_ss = segment;
|
||||
GLoaderState.original_ss = segment;
|
||||
|
||||
const char *envr = getenv("IS_2INE");
|
||||
GLoaderState->subprocess = (envr != NULL);
|
||||
GLoaderState->initOs2Tib = initOs2Tib;
|
||||
GLoaderState->deinitOs2Tib = deinitOs2Tib;
|
||||
GLoaderState->findSelector = findSelector;
|
||||
GLoaderState->freeSelector = freeSelector;
|
||||
GLoaderState->convert1616to32 = convert1616to32;
|
||||
GLoaderState->convert32to1616 = convert32to1616;
|
||||
GLoaderState->loadModule = loadLxModuleByPathOrModuleName;
|
||||
GLoaderState->locatePathCaseInsensitive = locatePathCaseInsensitive;
|
||||
GLoaderState->makeUnixPath = makeUnixPath;
|
||||
GLoaderState->makeOS2Path = makeOS2Path;
|
||||
GLoaderState->terminate = terminate;
|
||||
|
||||
const char *modulename = GLoaderState->subprocess ? envr : argv[1];
|
||||
|
||||
// standalone, drop argv[0]. As a subprocess, keep it.
|
||||
if (!GLoaderState->subprocess) {
|
||||
argc--;
|
||||
argv++;
|
||||
} // if
|
||||
|
||||
initPib(&GLoaderState->pib, argc, argv, envp);
|
||||
GLoaderState.setOs2Tib = lxSetOs2Tib;
|
||||
GLoaderState.getOs2Tib = lxGetOs2Tib;
|
||||
GLoaderState.deinitOs2Tib = lxDeinitOs2Tib;
|
||||
GLoaderState.findSelector = lxFindSelector;
|
||||
GLoaderState.freeSelector = lxFreeSelector;
|
||||
GLoaderState.convert1616to32 = lxConvert1616to32;
|
||||
GLoaderState.convert32to1616 = lxConvert32to1616;
|
||||
GLoaderState.loadModule = loadLxModuleByPathOrModuleName;
|
||||
GLoaderState.makeUnixPath = lxMakeUnixPath;
|
||||
GLoaderState.terminate = lxTerminate;
|
||||
|
||||
const char *modulename = GLoaderState.subprocess ? getenv("IS_2INE") : argv[1];
|
||||
LxModule *lxmod = loadLxModuleByPath(modulename);
|
||||
if (lxmod != NULL)
|
||||
runLxModule(lxmod, argc, argv, envp);
|
||||
runLxModule(lxmod);
|
||||
|
||||
return 1;
|
||||
} // main
|
||||
|
||||
+37
-58
@@ -127,33 +127,15 @@ static void timespecNowPlusMilliseconds(struct timespec *waittime, const ULONG u
|
||||
} // if
|
||||
} // timespecNowPlusMilliseconds
|
||||
|
||||
static PTIB2 getTib2(void)
|
||||
{
|
||||
// just read the FS register, since we have to stick it there anyhow...
|
||||
PTIB2 ptib2;
|
||||
__asm__ __volatile__ ( "movl %%fs:0xC, %0 \n\t" : "=r" (ptib2) );
|
||||
return ptib2;
|
||||
} // getTib2
|
||||
|
||||
static PTIB getTib(void)
|
||||
{
|
||||
// we store the TIB2 struct right after the TIB struct on the stack,
|
||||
// so get the TIB2's linear address from %fs:0xC, then step back
|
||||
// to the TIB's linear address.
|
||||
uint8 *ptib2 = (uint8 *) getTib2();
|
||||
return (PTIB) (ptib2 - sizeof (TIB));
|
||||
} // getTib
|
||||
|
||||
|
||||
APIRET DosGetInfoBlocks(PTIB *pptib, PPIB *pppib)
|
||||
{
|
||||
TRACE_NATIVE("DosGetInfoBlocks(%p, %p)", pptib, pppib);
|
||||
|
||||
if (pptib != NULL)
|
||||
*pptib = getTib();
|
||||
*pptib = (PTIB) LX_GETTIB();
|
||||
|
||||
if (pppib != NULL)
|
||||
*pppib = (PPIB) &GLoaderState->pib;
|
||||
*pppib = (PPIB) &GLoaderState.pib;
|
||||
|
||||
return 0;
|
||||
} // DosGetInfoBlocks
|
||||
@@ -255,7 +237,7 @@ APIRET DosScanEnv(PSZ name, PSZ *outval)
|
||||
{
|
||||
TRACE_NATIVE("DosScanEnv('%s', %p)", name, outval);
|
||||
|
||||
char *env = GLoaderState->pib.pib_pchenv;
|
||||
char *env = GLoaderState.pib.pib_pchenv;
|
||||
const size_t len = strlen(name);
|
||||
while (*env) {
|
||||
if ((strncmp(env, name, len) == 0) && (env[len] == '=')) {
|
||||
@@ -327,7 +309,7 @@ VOID DosExit(ULONG action, ULONG exitcode)
|
||||
// terminate the process.
|
||||
runDosExitList(TC_EXIT);
|
||||
|
||||
GLoaderState->terminate(exitcode);
|
||||
GLoaderState.terminate(exitcode);
|
||||
} // DosExit
|
||||
|
||||
APIRET DosExitList(ULONG ordercode, PFNEXITLIST fn)
|
||||
@@ -484,7 +466,7 @@ APIRET DosUnsetExceptionHandler(PEXCEPTIONREGISTRATIONRECORD rec)
|
||||
ULONG _DosFlatToSel(PVOID ptr)
|
||||
{
|
||||
TRACE_NATIVE("DosFlatToSel(%p)", ptr);
|
||||
return GLoaderState->convert32to1616(ptr);
|
||||
return GLoaderState.convert32to1616(ptr);
|
||||
} // _DosFlatToSel
|
||||
|
||||
// DosFlatToSel() passes its argument in %eax, so a little asm to bridge that...
|
||||
@@ -517,19 +499,19 @@ APIRET DosSetSignalExceptionFocus(BOOL32 flag, PULONG pulTimes)
|
||||
TRACE_NATIVE("DosSetSignalExceptionFocus(%u, %p)", (uint) flag, pulTimes);
|
||||
|
||||
if (flag == 0) {
|
||||
if (GLoaderState->main_module->signal_exception_focus_count == 0)
|
||||
if (GLoaderState.main_module->signal_exception_focus_count == 0)
|
||||
return ERROR_ALREADY_RESET;
|
||||
GLoaderState->main_module->signal_exception_focus_count--;
|
||||
GLoaderState.main_module->signal_exception_focus_count--;
|
||||
} else if (flag == 1) {
|
||||
if (GLoaderState->main_module->signal_exception_focus_count == 0xFFFFFFFF)
|
||||
if (GLoaderState.main_module->signal_exception_focus_count == 0xFFFFFFFF)
|
||||
return ERROR_NESTING_TOO_DEEP;
|
||||
GLoaderState->main_module->signal_exception_focus_count++;
|
||||
GLoaderState.main_module->signal_exception_focus_count++;
|
||||
} else {
|
||||
// !!! FIXME: does OS/2 do something if flag != 0 or 1?
|
||||
} // else
|
||||
|
||||
if (pulTimes)
|
||||
*pulTimes = GLoaderState->main_module->signal_exception_focus_count;
|
||||
*pulTimes = GLoaderState.main_module->signal_exception_focus_count;
|
||||
|
||||
// !!! FIXME: I guess enable/disable SIGINT handler here?
|
||||
|
||||
@@ -666,7 +648,7 @@ APIRET DosGetDateTime(PDATETIME pdt)
|
||||
|
||||
static char *makeUnixPath(const char *os2path, APIRET *err)
|
||||
{
|
||||
return GLoaderState->makeUnixPath(os2path, (uint32 *) err);
|
||||
return GLoaderState.makeUnixPath(os2path, (uint32 *) err);
|
||||
} // makeUnixPath
|
||||
|
||||
static APIRET doDosOpen(PSZ pszFileName, PHFILE pHf, PULONG pulAction, LONGLONG cbFile, ULONG ulAttribute, ULONG fsOpenFlags, ULONG fsOpenMode, PEAOP2 peaop2)
|
||||
@@ -983,7 +965,7 @@ APIRET DosEnterMustComplete(PULONG pulNesting)
|
||||
{
|
||||
TRACE_NATIVE("DosEnterMustComplete(%p)", pulNesting);
|
||||
|
||||
PTIB2 tib2 = getTib2();
|
||||
PTIB2 tib2 = (PTIB2) LX_GETTIB2();
|
||||
if (tib2->tib2_usMCCount == 0xFFFF) {
|
||||
return ERROR_NESTING_TOO_DEEP;
|
||||
} else if (tib2->tib2_usMCCount == 0) {
|
||||
@@ -1002,7 +984,7 @@ APIRET DosExitMustComplete(PULONG pulNesting)
|
||||
{
|
||||
TRACE_NATIVE("DosExitMustComplete(%p)", pulNesting);
|
||||
|
||||
PTIB2 tib2 = getTib2();
|
||||
PTIB2 tib2 = (PTIB2) LX_GETTIB2();
|
||||
if (tib2->tib2_usMCCount == 0) {
|
||||
return ERROR_ALREADY_RESET;
|
||||
} else if (tib2->tib2_usMCCount == 1) {
|
||||
@@ -1212,7 +1194,7 @@ APIRET DosQueryFileInfo(HFILE hf, ULONG ulInfoLevel, PVOID pInfo, ULONG cbInfoBu
|
||||
static void os2ThreadCleanup(void *arg)
|
||||
{
|
||||
Thread *thread = (Thread *) arg;
|
||||
GLoaderState->deinitOs2Tib(thread->selector);
|
||||
GLoaderState.deinitOs2Tib(thread->selector);
|
||||
grabLock(&GMutexDosCalls);
|
||||
thread->prev = NULL;
|
||||
thread->next = GDeadThreads;
|
||||
@@ -1223,7 +1205,8 @@ static void os2ThreadCleanup(void *arg)
|
||||
static void os2ThreadEntry2(uint8 *tibspace, Thread *thread)
|
||||
{
|
||||
void *esp = NULL; // close enough.
|
||||
thread->selector = GLoaderState->initOs2Tib(tibspace, &esp, thread->stacklen, (TID) thread);
|
||||
GLoaderState.initOs2Tib(tibspace, &esp, thread->stacklen, (TID) thread);
|
||||
thread->selector = GLoaderState.setOs2Tib(tibspace);
|
||||
pthread_cleanup_push(os2ThreadCleanup, thread);
|
||||
thread->fn(thread->fnarg);
|
||||
pthread_cleanup_pop(1);
|
||||
@@ -1954,7 +1937,7 @@ APIRET DosQueryModuleHandle(PSZ pszModname, PHMODULE phmod)
|
||||
TRACE_NATIVE("DosQueryModuleHandle('%s', %p)", pszModname, phmod);
|
||||
grabLock(&GMutexDosCalls);
|
||||
LxModule *lxmod;
|
||||
for (lxmod = GLoaderState->loaded_modules; lxmod; lxmod = lxmod->next) {
|
||||
for (lxmod = GLoaderState.loaded_modules; lxmod; lxmod = lxmod->next) {
|
||||
if (strcasecmp(lxmod->name, pszModname) == 0)
|
||||
break;
|
||||
} // for
|
||||
@@ -2378,7 +2361,7 @@ APIRET DosLoadModule(PSZ pszName, ULONG cbName, PSZ pszModname, PHMODULE phmod)
|
||||
*pszName = 0;
|
||||
|
||||
FIXME("there's no mutex on this global state at the moment!");
|
||||
LxModule *lxmod = GLoaderState->loadModule(pszModname);
|
||||
LxModule *lxmod = GLoaderState.loadModule(pszModname);
|
||||
if (!lxmod)
|
||||
return ERROR_BAD_FORMAT;
|
||||
|
||||
@@ -2553,8 +2536,8 @@ APIRET DosAllocThreadLocalMemory(ULONG cb, PULONG *p)
|
||||
// this is probably expensive to do with the mutex held, but honestly,
|
||||
// is there a lot of thread contention at the point where your app is
|
||||
// allocating TLS?
|
||||
if (GLoaderState->tlspage == NULL) {
|
||||
if ((GLoaderState->tlspage = initTLSPage()) == NULL) {
|
||||
if (GLoaderState.tlspage == NULL) {
|
||||
if ((GLoaderState.tlspage = initTLSPage()) == NULL) {
|
||||
ungrabLock(&GMutexDosCalls);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
} // if
|
||||
@@ -2562,17 +2545,17 @@ APIRET DosAllocThreadLocalMemory(ULONG cb, PULONG *p)
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 32; i++, mask <<= 1) {
|
||||
if (((GLoaderState->tlsmask ^ mask) & mask) == mask)
|
||||
if (((GLoaderState.tlsmask ^ mask) & mask) == mask)
|
||||
break;
|
||||
} // for
|
||||
|
||||
if (i == 32)
|
||||
retval = ERROR_NOT_ENOUGH_MEMORY; // there are only 32 slots, couldn't find anything contiguous.
|
||||
else {
|
||||
assert(GLoaderState->tlsallocs[i] == 0);
|
||||
GLoaderState->tlsallocs[i] = (uint8) cb;
|
||||
GLoaderState->tlsmask |= mask;
|
||||
*p = GLoaderState->tlspage + i;
|
||||
assert(GLoaderState.tlsallocs[i] == 0);
|
||||
GLoaderState.tlsallocs[i] = (uint8) cb;
|
||||
GLoaderState.tlsmask |= mask;
|
||||
*p = GLoaderState.tlspage + i;
|
||||
printf("allocated %u OS/2 TLS slot%s at %p\n", (uint) cb, (cb == 1) ? "" : "s", *p); fflush(stdout);
|
||||
} // else
|
||||
|
||||
@@ -2589,16 +2572,16 @@ APIRET DosFreeThreadLocalMemory(ULONG *p)
|
||||
|
||||
grabLock(&GMutexDosCalls);
|
||||
|
||||
if (GLoaderState->tlspage) {
|
||||
const uint32 slot = (uint32) (p - GLoaderState->tlspage);
|
||||
if (GLoaderState.tlspage) {
|
||||
const uint32 slot = (uint32) (p - GLoaderState.tlspage);
|
||||
if (slot < 32) {
|
||||
const uint8 slots = GLoaderState->tlsallocs[slot];
|
||||
const uint8 slots = GLoaderState.tlsallocs[slot];
|
||||
if (slots > 0) {
|
||||
const uint32 mask = ((uint32) (0xFF >> (8 - slots))) << slot;
|
||||
assert((GLoaderState->tlsmask & mask) == mask);
|
||||
GLoaderState->tlsmask &= ~mask;
|
||||
assert((GLoaderState.tlsmask & mask) == mask);
|
||||
GLoaderState.tlsmask &= ~mask;
|
||||
printf("freed %u OS/2 TLS slot%s at %p\n", (uint) slots, (slots == 1) ? "" : "s", p); fflush(stdout);
|
||||
GLoaderState->tlsallocs[slot] = 0;
|
||||
GLoaderState.tlsallocs[slot] = 0;
|
||||
retval = NO_ERROR;
|
||||
} // if
|
||||
} // if
|
||||
@@ -2640,13 +2623,13 @@ APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbB
|
||||
case QHINF_LIBPATHLENGTH:
|
||||
if (cbBuffer < sizeof (ULONG))
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
*((ULONG *) pvBuffer) = GLoaderState->libpathlen;
|
||||
*((ULONG *) pvBuffer) = GLoaderState.libpathlen;
|
||||
return NO_ERROR;
|
||||
|
||||
case QHINF_LIBPATH:
|
||||
if (cbBuffer < GLoaderState->libpathlen)
|
||||
if (cbBuffer < GLoaderState.libpathlen)
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
strcpy((char *) pvBuffer, GLoaderState->libpath);
|
||||
strcpy((char *) pvBuffer, GLoaderState.libpath);
|
||||
return NO_ERROR;
|
||||
|
||||
//case QHINF_FIXENTRY:
|
||||
@@ -2730,7 +2713,7 @@ APIRET DosQueryThreadContext(TID tid, ULONG level, PCONTEXTRECORD pcxt)
|
||||
ULONG _DosSelToFlat(void *ptr)
|
||||
{
|
||||
TRACE_NATIVE("DosSelToFlat(%p)", ptr);
|
||||
return (ULONG) GLoaderState->convert1616to32((uint32) ptr);
|
||||
return (ULONG) GLoaderState.convert1616to32((uint32) ptr);
|
||||
} // _DosSelToFlat
|
||||
|
||||
// DosSelToFlat() passes its argument in %eax, so a little asm to bridge that...
|
||||
@@ -2873,9 +2856,7 @@ APIRET DosSetFileSize(HFILE h, ULONG len)
|
||||
|
||||
LX_NATIVE_CONSTRUCTOR(doscalls)
|
||||
{
|
||||
if (GLoaderState) {
|
||||
GLoaderState->dosExit = DosExit;
|
||||
}
|
||||
GLoaderState.dosExit = DosExit;
|
||||
|
||||
if (pthread_mutex_init(&GMutexDosCalls, NULL) == -1) {
|
||||
fprintf(stderr, "pthread_mutex_init failed!\n");
|
||||
@@ -2917,9 +2898,7 @@ LX_NATIVE_CONSTRUCTOR(doscalls)
|
||||
|
||||
LX_NATIVE_DESTRUCTOR(doscalls)
|
||||
{
|
||||
if (GLoaderState) {
|
||||
GLoaderState->dosExit = NULL;
|
||||
}
|
||||
GLoaderState.dosExit = NULL;
|
||||
|
||||
ExitListItem *next = GExitList;
|
||||
GExitList = NULL;
|
||||
|
||||
+10
-12
@@ -28,35 +28,30 @@
|
||||
|
||||
#include "os2types.h"
|
||||
#include "os2errors.h"
|
||||
#include "../lx_loader.h"
|
||||
|
||||
// note that this is defined in _every_ module that includes this file!
|
||||
static LxLoaderState *GLoaderState = NULL;
|
||||
#include "../lib2ine.h"
|
||||
|
||||
#if 1
|
||||
#define TRACE_NATIVE(...) do { if (GLoaderState && GLoaderState->trace_native) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } } while (0)
|
||||
#define TRACE_NATIVE(...) do { if (GLoaderState.trace_native) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } } while (0)
|
||||
#else
|
||||
#define TRACE_NATIVE(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define TRACE_EVENT(...) do { if (GLoaderState && GLoaderState->trace_events) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } } while (0)
|
||||
#define TRACE_EVENT(...) do { if (GLoaderState.trace_events) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } } while (0)
|
||||
#else
|
||||
#define TRACE_EVENT(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
OS2EXPORT const LxExport * lxNativeModuleInit(LxLoaderState *lx_state, uint32 *lx_num_exports);
|
||||
OS2EXPORT const LxExport * lxNativeModuleInit(uint32 *lx_num_exports);
|
||||
OS2EXPORT void lxNativeModuleDeinit(void);
|
||||
|
||||
#define LX_NATIVE_MODULE_DEINIT(deinitcode) \
|
||||
void lxNativeModuleDeinit(void) { \
|
||||
deinitcode; \
|
||||
GLoaderState = NULL; \
|
||||
}
|
||||
|
||||
#define LX_NATIVE_MODULE_INIT(initcode) \
|
||||
const LxExport *lxNativeModuleInit(LxLoaderState *lx_state, uint32 *lx_num_exports) { \
|
||||
GLoaderState = lx_state; \
|
||||
const LxExport *lxNativeModuleInit(uint32 *lx_num_exports) { \
|
||||
initcode; \
|
||||
static const LxExport lx_native_exports[] = {
|
||||
|
||||
@@ -69,8 +64,11 @@ OS2EXPORT void lxNativeModuleDeinit(void);
|
||||
return lx_native_exports; \
|
||||
}
|
||||
|
||||
#define LX_NATIVE_CONSTRUCTOR(modname) void __attribute__((constructor)) lxNativeConstructor_##modname(void)
|
||||
#define LX_NATIVE_DESTRUCTOR(modname) void __attribute__((destructor)) lxNativeDestructor_##modname(void)
|
||||
// we store the TIB2 struct right after the TIB struct on the stack,
|
||||
// so get the TIB, then step forward to the TIB2.
|
||||
#define LX_GETTIB() ((LxTIB *) GLoaderState.getOs2Tib())
|
||||
#define LX_GETTIB2() ((LxTIB2 *) (LX_GETTIB() + 1))
|
||||
#define LX_GETPOSTTIB() ((LxPostTIB *) (LX_GETTIB2() + 1))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+11
-11
@@ -24,8 +24,8 @@
|
||||
#define LX_NATIVE_MODULE_16BIT_SUPPORT_END()
|
||||
|
||||
#define LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT() \
|
||||
if ((obj16.alias != 0xFFFF) && (GLoaderState)) { \
|
||||
GLoaderState->freeSelector(obj16.alias); \
|
||||
if (obj16.alias != 0xFFFF) { \
|
||||
GLoaderState.freeSelector(obj16.alias); \
|
||||
} \
|
||||
if (obj16.mapped != NULL) { \
|
||||
munmap(obj16.mapped, obj16.size); \
|
||||
@@ -59,7 +59,7 @@
|
||||
obj16.addr = mmapaddr; \
|
||||
\
|
||||
uint16 offset = 0; \
|
||||
if (!GLoaderState->findSelector((uint32) obj16.addr, &obj16.alias, &offset, 1)) { \
|
||||
if (!GLoaderState.findSelector((uint32) obj16.addr, &obj16.alias, &offset, 1)) { \
|
||||
fprintf(stderr, "couldn't find a selector for 16-bit entry points!\n"); \
|
||||
munmap(obj16.mapped, vsize); \
|
||||
obj16.mapped = obj16.addr = NULL; \
|
||||
@@ -135,7 +135,7 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling
|
||||
*(ptr++) = 0xEA; /* ...jmp dword 0x7788:0x33332222 */ \
|
||||
const uint32 jmp32addr = (uint32) (ptr + 6); \
|
||||
memcpy(ptr, &jmp32addr, 4); ptr += 4; \
|
||||
memcpy(ptr, &GLoaderState->original_cs, 2); ptr += 2; \
|
||||
memcpy(ptr, &GLoaderState.original_cs, 2); ptr += 2; \
|
||||
\
|
||||
/* USE32 */ \
|
||||
*(ptr++) = 0x66; /* mov bx,ss... */ \
|
||||
@@ -162,7 +162,7 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling
|
||||
*(ptr++) = 0xC8; /* ...mov ax,cx */ \
|
||||
*(ptr++) = 0x66; /* mov cx,0xabcd... */ \
|
||||
*(ptr++) = 0xB9; /* ...mov cx,0xabcd */ \
|
||||
memcpy(ptr, &GLoaderState->original_ss, 2); ptr += 2; \
|
||||
memcpy(ptr, &GLoaderState.original_ss, 2); ptr += 2; \
|
||||
*(ptr++) = 0x8E; /* mov ss,ecx... */ \
|
||||
*(ptr++) = 0xD1; /* ...mov ss,ecx */ \
|
||||
*(ptr++) = 0x89; /* mov esp,eax... */ \
|
||||
@@ -173,17 +173,17 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling
|
||||
*(ptr++) = 0x53; /* push ebx */ \
|
||||
*(ptr++) = 0x1E; /* push ds */ \
|
||||
*(ptr++) = 0x06; /* push es */ \
|
||||
if (GLoaderState->original_ss != GLoaderState->original_ds) { \
|
||||
if (GLoaderState.original_ss != GLoaderState.original_ds) { \
|
||||
*(ptr++) = 0x66; /* mov cx,0x8888... */ \
|
||||
*(ptr++) = 0xB9; /* ...mov cx,0x8888 */ \
|
||||
memcpy(ptr, &GLoaderState->original_ds, 2); ptr += 2; \
|
||||
memcpy(ptr, &GLoaderState.original_ds, 2); ptr += 2; \
|
||||
} \
|
||||
*(ptr++) = 0x8E; /* mov ds,ecx... */ \
|
||||
*(ptr++) = 0xD9; /* ...mov ds,ecx */ \
|
||||
if (GLoaderState->original_ds != GLoaderState->original_es) { \
|
||||
if (GLoaderState.original_ds != GLoaderState.original_es) { \
|
||||
*(ptr++) = 0x66; /* mov cx,0x9999... */ \
|
||||
*(ptr++) = 0xB9; /* ...mov cx,0x9999 */ \
|
||||
memcpy(ptr, &GLoaderState->original_es, 2); ptr += 2; \
|
||||
memcpy(ptr, &GLoaderState.original_es, 2); ptr += 2; \
|
||||
} \
|
||||
*(ptr++) = 0x8E; /* mov es,ecx... */ \
|
||||
*(ptr++) = 0xC1; /* ...mov es,ecx */ \
|
||||
@@ -224,7 +224,7 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling
|
||||
if (mprotect(obj16.mapped, vsize, PROT_READ | PROT_EXEC) == -1) { \
|
||||
fprintf(stderr, "mprotect() failed for 16-bit bridge code!\n"); \
|
||||
munmap(obj16.mapped, vsize); \
|
||||
GLoaderState->freeSelector(obj16.alias); \
|
||||
GLoaderState.freeSelector(obj16.alias); \
|
||||
obj16.mapped = obj16.addr = NULL; \
|
||||
obj16.size = 0; \
|
||||
obj16.alias = 0xFFFF; \
|
||||
@@ -236,7 +236,7 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling
|
||||
const typ var = *((typ *) args); args += sizeof (typ)
|
||||
|
||||
#define LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(typ, var) \
|
||||
typ var = (typ) GLoaderState->convert1616to32(*((uint32 *) args)); args += sizeof (uint32)
|
||||
typ var = (typ) GLoaderState.convert1616to32(*((uint32 *) args)); args += sizeof (uint32)
|
||||
|
||||
#define LX_NATIVE_EXPORT16(fn, ord) { ord, #fn, &fn##16, &obj16 }
|
||||
|
||||
|
||||
+3
-20
@@ -117,26 +117,9 @@ typedef struct
|
||||
|
||||
static Window desktop_window; // !!! FIXME: initialize and upkeep on this.
|
||||
|
||||
// !!! FIXME: duplication from doscalls.c
|
||||
static LxTIB2 *getTib2(void)
|
||||
{
|
||||
// just read the FS register, since we have to stick it there anyhow...
|
||||
LxTIB2 *ptib2;
|
||||
__asm__ __volatile__ ( "movl %%fs:0xC, %0 \n\t" : "=r" (ptib2) );
|
||||
return ptib2;
|
||||
} // getTib2
|
||||
|
||||
static inline LxPostTIB *getPostTib(void)
|
||||
{
|
||||
// we store the LxPostTIB struct right after the TIB2 struct on the stack,
|
||||
// so get the TIB2's linear address from %fs:0xC, then step over it
|
||||
// to the LxPostTIB's linear address.
|
||||
return (LxPostTIB *) (getTib2() + 1);
|
||||
} // getPostTib
|
||||
|
||||
static inline AnchorBlock *getAnchorBlockNoHAB(void)
|
||||
{
|
||||
return (AnchorBlock *) getPostTib()->anchor_block;
|
||||
return (AnchorBlock *) LX_GETPOSTTIB()->anchor_block;
|
||||
} // getAnchorBlockNoHAB
|
||||
|
||||
static AnchorBlock *getAnchorBlock(const HAB hab)
|
||||
@@ -381,7 +364,7 @@ HAB WinInitialize(ULONG flOptions)
|
||||
return NULLHANDLE; // reserved; must be zero.
|
||||
}
|
||||
|
||||
LxPostTIB *posttib = getPostTib();
|
||||
LxPostTIB *posttib = LX_GETPOSTTIB();
|
||||
if (posttib->anchor_block != NULL) {
|
||||
return NULLHANDLE; // fail if thread already has a HAB
|
||||
}
|
||||
@@ -546,7 +529,7 @@ BOOL WinTerminate(HAB hab)
|
||||
}
|
||||
|
||||
free(anchor);
|
||||
getPostTib()->anchor_block = NULL;
|
||||
LX_GETPOSTTIB()->anchor_block = NULL;
|
||||
|
||||
SDL_Quit(); // !!! FIXME: does this reference count?
|
||||
|
||||
|
||||
Reference in new issue
Block a user