From 4ed68f73dae9e7621d7d7512b5feb686e9440bb2 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 6 Jan 2022 23:39:21 +0000 Subject: Tidy up stubs, make vstdlib a stub, build on Linux Important note: it doesn't WORK on Linux, and there's tons of warnings and stuff, but it's easier to work on when all the compiler output and whatnot is there. --- README | 10 ++++++---- TODO/linux | 3 +++ compile | 8 +++++--- compile.bat | 5 +++-- src/con_.c | 6 ++++-- src/con_.h | 2 +- src/demorec.c | 9 ++++++--- src/gameinfo.c | 9 ++++----- src/os.h | 1 + src/sst.c | 33 ++++++++++----------------------- src/stubs/stub.h | 13 +++++++++++++ src/stubs/tier0.c | 9 +++++++++ src/stubs/vstdlib.c | 7 +++++++ src/tier0stub.c | 19 ------------------- 14 files changed, 72 insertions(+), 62 deletions(-) create mode 100644 src/stubs/stub.h create mode 100644 src/stubs/tier0.c create mode 100644 src/stubs/vstdlib.c delete mode 100644 src/tier0stub.c diff --git a/README b/README index 188b0ad..5760b2d 100644 --- a/README +++ b/README @@ -1,6 +1,7 @@ Hey! This README is for those looking to work on the code. For actual plugin -documentation, you'll want to look at the website, which doesn't exist yet, -or ask for help in the relevant speedrunning Discord, which does exist yet. +documentation, you'll want to look at the website, which currently exists in a +semi-temporary state at https://mikes.software.sst - or or ask for help in a +relevant speedrunning community. NOTE: Please read and understand LICENCE before redistributing this software! @@ -20,8 +21,9 @@ Linux: installed. - Run ./compile (in lieu of a better build tool, to be figured out later). -* NOTE: Linux builds currently fail; there's a bunch of code that needs to be - written. See also TODO/linux. +* NOTE: Linux builds currently produce a binary that most definitely does not + work, along with a whole host of warnings; there's a bunch of code that needs + to be written. See also TODO/linux. == How and where to install == diff --git a/TODO/linux b/TODO/linux index d89baca..d664626 100644 --- a/TODO/linux +++ b/TODO/linux @@ -4,3 +4,6 @@ Early prototype code was written with both Linux and Windows in mind, but since then most of the development happens to have happened on Windows, which has left some gaps. We want to eventually add back support for Linux once all the important Windows stuff is out of the way. + +As of writing the code does sort of compile on Linux, but decidedly does not +actually work. diff --git a/compile b/compile index 26aa925..f3af608 100755 --- a/compile +++ b/compile @@ -21,7 +21,8 @@ cc() { } ld() { - clang -m32 -shared -O2 -flto -fpic -s -fuse-ld=lld -L.build -ldl -o sst.so$objs + clang -m32 -shared -O2 -flto -fpic -s -fuse-ld=lld -L.build -ldl -ltier0 \ + -lvstdlib -o sst.so$objs } src="\ @@ -45,7 +46,8 @@ clang -O2 -fuse-ld=lld $warnings -D_FILE_OFFSET_BITS=64 -o .build/mkgamedata \ .build/codegen `for s in $src; do echo "src/$s"; done` .build/mkgamedata gamedata/gamelib.kv gamedata/engine.kv for s in $src; do cc "$s"; done -clang -m32 -shared -fpic -fuse-ld=lld -O0 -w -o .build/libtier0.so src/tier0stub.c +clang -m32 -shared -fpic -fuse-ld=lld -O0 -w -o .build/libtier0.so src/stubs/tier0.c +clang -m32 -shared -fpic -fuse-ld=lld -O0 -w -o .build/libvstdlib.so src/stubs/vstdlib.c ld clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/bitbuf.test test/bitbuf.test.c @@ -53,7 +55,7 @@ clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/bitbuf.test test/bitbu # skipping this test on linux for now, since inline hooks aren't compiled in #clang -m32 -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/hook.test test/hook.test.c #.build/hook.test -clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/kv test/kv.test.c +clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/kv.test test/kv.test.c .build/kv.test # vi: sw=4 tw=4 noet tw=80 cc=80 diff --git a/compile.bat b/compile.bat index 60b4973..3db7d1a 100644 --- a/compile.bat +++ b/compile.bat @@ -34,7 +34,8 @@ clang -E -xc src/dll.rc>.build\dll.pp.rc || exit /b llvm-rc /FO .build\dll.res .build\dll.pp.rc || exit /b :: might as well remove the temp file afterwards del .build\dll.pp.rc -clang -m32 -shared -fuse-ld=lld -O0 -w -o .build/tier0.dll src/tier0stub.c +clang -m32 -shared -fuse-ld=lld -O0 -w -o .build/tier0.dll src/stubs/tier0.c +clang -m32 -shared -fuse-ld=lld -O0 -w -o .build/vstdlib.dll src/stubs/vstdlib.c call :cc src/autojump.c || exit /b call :cc src/con_.c || exit /b call :cc src/demorec.c || exit /b @@ -48,7 +49,7 @@ call :cc src/kv.c || exit /b call :cc src/sst.c || exit /b call :cc src/udis86.c || exit /b clang -m32 -shared -O2 -flto -fuse-ld=lld -Wl,/implib:.build/sst.lib,/Brepro ^ --L.build -ladvapi32 -ltier0 -lshlwapi -o sst.dll%objs% .build/dll.res || exit /b +-L.build -ladvapi32 -lshlwapi -ltier0 -lvstdlib -o sst.dll%objs% .build/dll.res || exit /b :: get rid of another useless file (can we just not create this???) del .build\sst.lib diff --git a/src/con_.c b/src/con_.c index 1c9d4a7..be3f20c 100644 --- a/src/con_.c +++ b/src/con_.c @@ -16,6 +16,7 @@ */ #include +#include // should be implied by stdlib but glibc is dumb (offsetof) #include #include @@ -294,7 +295,7 @@ static void VCALLCONV Create_var(void *thisoff, const char *name, void *_con_vtab_cmd[14 + NVDTOR] = { (void *)&dtor, #ifndef _WIN32 - (void *)&dtor2, + (void *)&dtor, #endif (void *)&IsCommand_cmd, (void *)&IsFlagSet_cmd, @@ -312,10 +313,11 @@ void *_con_realvtab_var[20] = { &varrtti, #else // this, among many other things, will be totally different on linux +#warning FIX THIS TOO! #endif (void *)&dtor, #ifndef _WIN32 - (void *)&dtor2, + (void *)&dtor, #endif (void *)&IsCommand_var, (void *)&IsFlagSet_var, diff --git a/src/con_.h b/src/con_.h index bfc8c47..653bdad 100644 --- a/src/con_.h +++ b/src/con_.h @@ -127,7 +127,7 @@ struct con_cmd { // ConCommand in engine // con_var will be a bit different on linux; see offset_to_top etc. #ifdef __linux__ -#error FIXME: redo multi-vtable crap for itanium ABI! +#warning FIXME: redo multi-vtable crap for itanium ABI! #endif struct con_var { // ConVar in engine diff --git a/src/demorec.c b/src/demorec.c index 76e7f00..1a988ed 100644 --- a/src/demorec.c +++ b/src/demorec.c @@ -161,7 +161,8 @@ static inline void *find_demorecorder(struct con_cmd *cmd_stop) { } } #else -#error TODO(linux): implement linux equivalent (cdecl!) +#warning TODO(linux): implement linux equivalent (cdecl!) + return 0; #endif } return 0; @@ -203,7 +204,8 @@ static inline bool find_recmembers(void *stop_recording_func) { return false; } #else // linux is probably different here idk -#error TODO(linux): implement linux equivalent +#warning TODO(linux): implement linux equivalent + return false; #endif } return false; @@ -228,7 +230,8 @@ static bool find_WriteMessages(void) { #ifdef _WIN32 {0x56, 0x57, 0x8B, 0xF1, 0x8D, 0xBE, 0x8C, 0x06, 0x00, 0x00, 0x57, 0xE8}; #else -#error This is possibly different on Linux too, have a look! +#warning This is possibly different on Linux too, have a look! +{-1, -1, -1, -1, -1, -1}; #endif if (!memcmp(insns, bytes, sizeof(bytes))) { ssize off = mem_loadoffset(insns + sizeof(bytes)); diff --git a/src/gameinfo.c b/src/gameinfo.c index 32f5051..de5fafc 100644 --- a/src/gameinfo.c +++ b/src/gameinfo.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #ifdef _WIN32 @@ -49,9 +48,9 @@ const os_char *gameinfo_serverlib = _gameinfo_serverlib; // magical argc/argv grabber so we don't have to go through procfs #ifdef __linux__ -static const char *prog_argv; +static const char *const *prog_argv; static int storeargs(int argc, char *argv[]) { - prog_argv = argv; + prog_argv = (const char *const *)argv; return 0; } __attribute__((used, section(".init_array"))) @@ -116,7 +115,7 @@ static inline void do_gamelib_search(const char *p, uint len, bool isgamebin) { api_needs_null_term[len] = L'\0'; if (!PathIsRelativeA(api_needs_null_term)) #else - if (*p == "/") // so much easier :') + if (*p == '/') // so much easier :') #endif { // the mod path is absolute, so we're not sticking anything else in @@ -313,7 +312,7 @@ bool gameinfo_init(void) { // also do the executable name check just for portal2_linux if (!strcmp(exename, "portal2_linux")) modname = "portal2"; // ah, the sane, straightforward world of unix command line arguments :) - for (char **pp = prog_argv + 1; *pp; ++pp) { + for (const char *const *pp = prog_argv + 1; *pp; ++pp) { if (!strcmp(*pp, "-game")) { if (!*++pp) break; modname = *pp; diff --git a/src/os.h b/src/os.h index 654e754..d231e67 100644 --- a/src/os.h +++ b/src/os.h @@ -25,6 +25,7 @@ * between Windows and not-Windows under the rug. */ +#include #include #ifdef _WIN32 #define NOMINMAX diff --git a/src/sst.c b/src/sst.c index 94e1661..9cf21c2 100644 --- a/src/sst.c +++ b/src/sst.c @@ -84,6 +84,9 @@ static const char *VCALLCONV GetStringForSymbol_hook(void *this, int s) { return ret; } +// vstdlib symbol, only currently used in l4d2 but exists everywhere so oh well +IMPORT void *KeyValuesSystem(void); + static bool do_load(ifacefactory enginef, ifacefactory serverf) { factory_engine = enginef; factory_server = serverf; #ifndef __linux__ @@ -133,31 +136,15 @@ nc: gamedata_init(); // NOTE: this is technically redundant for early versions but I CBA writing // a version check; it's easier to just do this unilaterally. if (GAMETYPE_MATCHES(L4D2)) { -#ifdef _WIN32 - // XXX: not sure if vstdlib should be done dynamically like this or just - // another stub like tier0? - void *vstdlib = GetModuleHandleW(L"vstdlib.dll"); - if (!vstdlib) { - con_warn("sst: warning: couldn't get vstdlib, won't be able to " - "prevent nag message\n"); + void *kvs = KeyValuesSystem(); + kvsvt = *(void ***)kvs; + if (!os_mprot(kvsvt + 4, sizeof(void *), PAGE_READWRITE)) { + con_warn("sst: warning: couldn't unprotect KeyValuesSystem " + "vtable; won't be able to prevent nag message\n"); goto e; } - void *(*KeyValuesSystem)(void) = (void *(*)(void))os_dlsym(vstdlib, - "KeyValuesSystem"); - if (KeyValuesSystem) { - void *kvs = KeyValuesSystem(); - kvsvt = *(void ***)kvs; - if (!os_mprot(kvsvt + 4, sizeof(void *), PAGE_READWRITE)) { - con_warn("sst: warning: couldn't unprotect KeyValuesSystem " - "vtable; won't be able to prevent nag message\n"); - goto e; - } - orig_GetStringForSymbol = (GetStringForSymbol_func)hook_vtable( - kvsvt, 4, (void *)GetStringForSymbol_hook); - } -#else -#warning TODO(linux) suitably abstract this stuff to Linux! -#endif + orig_GetStringForSymbol = (GetStringForSymbol_func)hook_vtable(kvsvt, + 4, (void *)GetStringForSymbol_hook); } e: con_colourmsg(RGBA(64, 255, 64, 255), diff --git a/src/stubs/stub.h b/src/stubs/stub.h new file mode 100644 index 0000000..75d377c --- /dev/null +++ b/src/stubs/stub.h @@ -0,0 +1,13 @@ +// We produce dummy libraries for vstdlib and tier0 to allow linking without +// dlsym faff. These macros are because Windows needs additional care because +// it's dumb. + +#ifdef _WIN32 +#define F(name) __declspec(dllexport) void name(void) {} +#define V(name) __declspec(dllexport) void *name; +#else +#define F(name) void *name; +#define V(name) void *name; +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/stubs/tier0.c b/src/stubs/tier0.c new file mode 100644 index 0000000..2c9c578 --- /dev/null +++ b/src/stubs/tier0.c @@ -0,0 +1,9 @@ +/* This file is dedicated to the public domain. */ + +#include "stub.h" + +F(Msg) +F(Warning) +V(g_pMemAlloc) + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/stubs/vstdlib.c b/src/stubs/vstdlib.c new file mode 100644 index 0000000..d3a63b0 --- /dev/null +++ b/src/stubs/vstdlib.c @@ -0,0 +1,7 @@ +/* This file is dedicated to the public domain. */ + +#include "stub.h" + +F(KeyValuesSystem) + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/tier0stub.c b/src/tier0stub.c deleted file mode 100644 index a043bea..0000000 --- a/src/tier0stub.c +++ /dev/null @@ -1,19 +0,0 @@ -/* This file is dedicated to the public domain. */ - -// Produce a dummy tier0.dll/libtier0.so to allow linking without dlsym faff. -// Windows needs additional care because it's dumb. - -#ifdef _WIN32 -#define F(name) __declspec(dllexport) void name(void) {} -#define V(name) __declspec(dllexport) void *name; -#else -#define F(name) void *name; -#define V(name) void *name; -#endif - -F(Msg); -F(Warning); -// F(Error); // unused in plugin -V(g_pMemAlloc); - -// vi: sw=4 ts=4 noet tw=80 cc=80 -- cgit v1.2.3