summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DevDocs/code-style.txt2
-rwxr-xr-xcompile2
-rw-r--r--compile.bat2
-rw-r--r--src/ac.c2
-rw-r--r--src/alias.c2
-rw-r--r--src/bind.c4
-rw-r--r--src/chatrate.c2
-rw-r--r--src/chunklets/README-x8656
-rw-r--r--src/chunklets/x86.c (renamed from src/x86.c)28
-rw-r--r--src/chunklets/x86.h (renamed from src/x86.h)32
-rw-r--r--src/con_.c2
-rw-r--r--src/democustom.c2
-rw-r--r--src/demorec.c2
-rw-r--r--src/engineapi.c2
-rw-r--r--src/ent.c2
-rw-r--r--src/fastfwd.c5
-rw-r--r--src/fov.c2
-rw-r--r--src/gameserver.c2
-rw-r--r--src/hook.c2
-rw-r--r--src/hud.c2
-rw-r--r--src/inputhud.c2
-rw-r--r--src/kvsys.c2
-rw-r--r--src/l4d1democompat.c2
-rw-r--r--src/l4daddon.c2
-rw-r--r--src/l4dreset.c4
-rw-r--r--src/l4dwarp.c2
-rw-r--r--src/portalcolours.c1
-rw-r--r--src/portalisg.c2
-rw-r--r--src/sst.c1
-rw-r--r--src/x86util.h2
-rw-r--r--src/xhair.c1
-rw-r--r--test/hook.test.c2
-rw-r--r--test/x86.test.c5
33 files changed, 119 insertions, 64 deletions
diff --git a/DevDocs/code-style.txt b/DevDocs/code-style.txt
index d008a5c..cdbc666 100644
--- a/DevDocs/code-style.txt
+++ b/DevDocs/code-style.txt
@@ -169,7 +169,7 @@ In no particular order:
Bad example:
call_function("parameter 1 takes up some space", param_2 + 5, another_var,
- x);
+ x);
Good example:
call_function("parameter 1 takes up some space", param_2 + 5,
diff --git a/compile b/compile
index 5345cd3..6e36880 100755
--- a/compile
+++ b/compile
@@ -58,6 +58,7 @@ src="\
chatrate.c
chunklets/fastspin.c
chunklets/msg.c
+ chunklets/x86.c
clientcon.c
con_.c
crypto.c
@@ -86,7 +87,6 @@ src="\
portalcolours.c
sst.c
trace.c
- x86.c
xhair.c"
if [ "$dbg" = 1 ]; then src="$src \
dbg.c
diff --git a/compile.bat b/compile.bat
index e1e2a32..0affd05 100644
--- a/compile.bat
+++ b/compile.bat
@@ -68,6 +68,7 @@ setlocal DisableDelayedExpansion
:+ chatrate.c
:+ chunklets/fastspin.c
:+ chunklets/msg.c
+:+ chunklets/x86.c
:+ crypto.c
:+ democustom.c
:+ demorec.c
@@ -98,7 +99,6 @@ setlocal DisableDelayedExpansion
:+ rinput.c
:+ sst.c
:+ trace.c
-:+ x86.c
:+ xhair.c
:: just tack these on, whatever (repeated condition because of expansion memes)
if "%dbg%"=="1" set src=%src% src/dbg.c
diff --git a/src/ac.c b/src/ac.c
index 00edaed..e762083 100644
--- a/src/ac.c
+++ b/src/ac.c
@@ -27,6 +27,7 @@
#include "bind.h"
#include "chunklets/fastspin.h"
#include "chunklets/msg.h"
+#include "chunklets/x86.h"
#include "con_.h"
#include "crypto.h"
#include "democustom.h"
@@ -45,7 +46,6 @@
#include "ppmagic.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE()
diff --git a/src/alias.c b/src/alias.c
index 697e97c..add8add 100644
--- a/src/alias.c
+++ b/src/alias.c
@@ -17,13 +17,13 @@
#include <string.h>
#include "alias.h"
+#include "chunklets/x86.h"
#include "con_.h"
#include "errmsg.h"
#include "extmalloc.h"
#include "feature.h"
#include "gametype.h"
#include "mem.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("alias management")
diff --git a/src/bind.c b/src/bind.c
index 7fafdb1..3a7cb34 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -14,15 +14,13 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "chunklets/x86.h"
#include "con_.h"
-#include "dbg.h"
#include "errmsg.h"
#include "feature.h"
-#include "hook.h"
#include "intdefs.h"
#include "langext.h"
#include "mem.h"
-#include "x86.h"
#include "x86util.h"
FEATURE()
diff --git a/src/chatrate.c b/src/chatrate.c
index 06c16e9..daa275a 100644
--- a/src/chatrate.c
+++ b/src/chatrate.c
@@ -14,6 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "chunklets/x86.h"
#include "con_.h"
#include "errmsg.h"
#include "feature.h"
@@ -21,7 +22,6 @@
#include "intdefs.h"
#include "langext.h"
#include "os.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("chat rate limit removal")
diff --git a/src/chunklets/README-x86 b/src/chunklets/README-x86
new file mode 100644
index 0000000..cbfcb5d
--- /dev/null
+++ b/src/chunklets/README-x86
@@ -0,0 +1,56 @@
+x86.{c,h}: opcode-based x86 instruction analysis (NOT a disassembler)
+
+Currently only handles opcodes found in basic 32-bit userspace functions;
+there’s no kernel-mode instructions, no SSE 3+, no AVX, no REX (64-bit), no
+EVEX, yadda yadda.
+
+Subject to extension later if there’s ever a use for it.
+
+== Compiling ==
+
+ gcc -c -O2 [-flto] x86.c
+ clang -c -O2 [-flto] x86.c
+ tcc -c x86.c
+ cl.exe /c /O2 x86.c
+
+In most cases you can just drop the .c file straight into your codebase/build
+system. LTO is advised to avoid dead code and enable more efficient calls
+including potential inlining.
+
+== Compiler compatibility ==
+
+- Any reasonable GCC
+- Any reasonable Clang
+- Any reasonable MSVC
+- TinyCC
+- Probably almost all others; this is very portable code
+
+Note that GCC and Clang will generally give the best-performing output.
+
+Once the .c file is built, the public header can be consumed by virtually any C
+or C++ compiler, as well as probably most half-decent FFIs.
+
+Note that the .c source file is probably C++-compatible at the moment, but this
+is not guaranteed, so it's best to compile it as a C source. The header will
+work fine from either language.
+
+== API usage ==
+
+See documentation comments in x86.h for a basic idea. Some *pro tips*:
+
+== OS compatibility ==
+
+- All.
+- Seriously, this library doesn’t even use libc.
+
+== Architecture compatibility ==
+
+- All, so long as char is 8 bits.
+
+== Copyright ==
+
+The source file and header both fall under the ISC licence — read the notices in
+both of the files for specifics.
+
+Thanks, and have fun!
+- Michael Smith <mikesmiffy128@gmail.com>
diff --git a/src/x86.c b/src/chunklets/x86.c
index b017a70..012cbb0 100644
--- a/src/x86.c
+++ b/src/chunklets/x86.c
@@ -14,39 +14,35 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include "intdefs.h"
+// _Static_assert needs MSVC >= 2019, and this check is irrelevant on Windows
+#ifndef _MSC_VER
+_Static_assert((unsigned char)-1 == 255, "this code requires 8-bit chars");
+#endif
+
#include "x86.h"
-static int mrmsib(const uchar *p, int addrlen) {
- // I won't lie: I thought I almost understood this, but after bill walked me
- // through correcting a bunch of wrong cases I now realise that I don't
- // really understand it at all. If it helps, I used this as a reference:
- // https://github.com/Nomade040/length-disassembler/blob/e8b34546/ldisasm.cpp#L14
- // But it's confusingly-written enough that the code I wrote before didn't
- // work, so with any luck nobody will need to refer to it again and this is
- // actually correct now. Fingers crossed.
+static int mrmsib(const unsigned char *p, int addrlen) {
if (addrlen == 4 || *p & 0xC0) {
int sib = addrlen == 4 && *p < 0xC0 && (*p & 7) == 4;
switch (*p & 0xC0) {
- // disp8
- case 0x40: return 2 + sib;
- // disp16/32
- case 0:
+ case 0x40: // disp8
+ return 2 + sib;
+ case 0: // disp16/32
if ((*p & 7) != 5) {
// disp8/32 via SIB
if (sib && (p[1] & 7) == 5) return *p & 0x40 ? 3 : 6;
return 1 + sib;
}
- case 0x80: return 1 + addrlen + sib;
+ case 0x80:
+ return 1 + addrlen + sib;
}
}
if (addrlen == 2 && (*p & 0xC7) == 0x06) return 3;
return 1; // note: include the mrm itself in the byte count
}
-int x86_len(const void *insn_) {
+int x86_len(const unsigned char *insn) {
#define CASES(name, _) case name:
- const uchar *insn = insn_;
int pfxlen = 0, addrlen = 4, operandlen = 4;
p: switch (*insn) {
diff --git a/src/x86.h b/src/chunklets/x86.h
index 92e4ccb..e47d4ed 100644
--- a/src/x86.h
+++ b/src/chunklets/x86.h
@@ -14,21 +14,23 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef INC_X86_H
-#define INC_X86_H
-
-/*
- * Opcode-based X86 instruction analysis. In other words, *NOT* a disassembler.
- * Only cares about the instructions we expect to see in basic 32-bit userspace
- * functions; there's no kernel-mode instructions, no SSE 3+, no AVX, no REX,
- * EVEX, yadda yadda.
- */
+#ifndef INC_CHUNKLETS_X86_H
+#define INC_CHUNKLETS_X86_H
// XXX: no BOUND (0x62): ambiguous with EVEX prefix - can't be arsed!
// XXX: no LES (0xC4) or DES (0xC5) either for similar reasons. better to report
// an unknown instruction than to potentially misinterpret an AVX thing.
// these are all legacy instructions that won't really be used much anyway.
+/*
+ * Below, we define groups of instruction opcode bytes based on their
+ * variable-length characteristics. This is used to drive the actual parsing of
+ * the instructions by x86_len(). The instructions are also put into a large
+ * enum defining their byte values. This allows pattern-matching on instruction
+ * bytes, useful for searching for certain instructions, or patterns thereof,
+ * for reverse-engineering or modding purposes.
+ */
+
/* Instruction prefixes: segments */
#define X86_SEG_PREFIXES(X) \
X(X86_PFX_ES, 0x26) \
@@ -554,13 +556,21 @@ enum {
};
#undef _X86_ENUM
+#ifdef __cplusplus
+extern "C"
+#endif
/*
* Returns the length of an instruction, or -1 if it's a "known unknown" or
* invalid instruction. Doesn't handle unknown unknowns: may explode or hang on
* arbitrary untrusted data. Also doesn't handle, among other things, 3DNow!,
- * SSE3+, MMX, AVX, and such. Aims to be small and fast, not comprehensive.
+ * SSE3+, MMX, AVX, and such. Doesn't cover 64-bit nor kernel-only stuff either
+ * Aims to be small and fast, not comprehensive.
+ *
+ * The main purpose of this function to assist in hooking functions or searching
+ * for certain instruction patterns in existing known and trusted binaries. It
+ * is once again not suitable for use with arbitrary unknown data.
*/
-int x86_len(const void *insn);
+int x86_len(const unsigned char *insn);
/* Constructs a ModRM byte, assuming the parameters are all in range. */
#define X86_MODRM(mod, reg, rm) (unsigned char)((mod) << 6 | (reg) << 3 | rm)
diff --git a/src/con_.c b/src/con_.c
index 8359482..90cc0fd 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "abi.h"
+#include "chunklets/x86.h"
#include "con_.h"
#include "engineapi.h" // for factories and rgba - XXX: is this a bit circular?
#include "errmsg.h"
@@ -33,7 +34,6 @@
#include "os.h"
#include "vcall.h"
#include "version.h"
-#include "x86.h"
#include "x86util.h"
/******************************************************************************\
diff --git a/src/democustom.c b/src/democustom.c
index cae58a8..05c1d41 100644
--- a/src/democustom.c
+++ b/src/democustom.c
@@ -17,6 +17,7 @@
#include <string.h>
#include "bitbuf.h"
+#include "chunklets/x86.h"
#include "demorec.h"
#include "engineapi.h"
#include "feature.h"
@@ -25,7 +26,6 @@
#include "langext.h"
#include "mem.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE()
diff --git a/src/demorec.c b/src/demorec.c
index a763176..0511d46 100644
--- a/src/demorec.c
+++ b/src/demorec.c
@@ -17,6 +17,7 @@
#include <string.h>
+#include "chunklets/x86.h"
#include "con_.h"
#include "demorec.h"
#include "engineapi.h"
@@ -32,7 +33,6 @@
#include "os.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("improved demo recording")
diff --git a/src/engineapi.c b/src/engineapi.c
index 1893e0c..980ee99 100644
--- a/src/engineapi.c
+++ b/src/engineapi.c
@@ -28,9 +28,7 @@
#include "intdefs.h"
#include "langext.h"
#include "mem.h" // "
-#include "os.h"
#include "vcall.h"
-#include "x86.h"
u32 _gametype_tag = 0; // declared in gametype.h but seems sensible enough here
diff --git a/src/ent.c b/src/ent.c
index e4ae4c8..137aa75 100644
--- a/src/ent.c
+++ b/src/ent.c
@@ -15,6 +15,7 @@
*/
#include "accessor.h"
+#include "chunklets/x86.h"
#include "con_.h"
#include "dictmaptree.h"
#include "engineapi.h"
@@ -25,7 +26,6 @@
#include "langext.h"
#include "mem.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE()
diff --git a/src/fastfwd.c b/src/fastfwd.c
index 1b7588d..78f2d47 100644
--- a/src/fastfwd.c
+++ b/src/fastfwd.c
@@ -19,7 +19,7 @@
#include <stdlib.h>
-#include "con_.h"
+#include "chunklets/x86.h"
#include "engineapi.h"
#include "errmsg.h"
#include "gamedata.h"
@@ -29,10 +29,7 @@
#include "intdefs.h"
#include "langext.h"
#include "mem.h"
-#include "os.h"
-#include "ppmagic.h"
#include "sst.h"
-#include "x86.h"
#include "x86util.h"
FEATURE()
diff --git a/src/fov.c b/src/fov.c
index 8bfa2ab..b7a278c 100644
--- a/src/fov.c
+++ b/src/fov.c
@@ -18,6 +18,7 @@
// TODO(linux): theoretically, probably ifdef out the cvar-replacement stuff; we
// expect any game that's been ported to linux to already have fov_desired
+#include "chunklets/x86.h"
#include "con_.h"
#include "engineapi.h"
#include "errmsg.h"
@@ -31,7 +32,6 @@
#include "mem.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("extended FOV range")
diff --git a/src/gameserver.c b/src/gameserver.c
index 5cd8b0c..4315afe 100644
--- a/src/gameserver.c
+++ b/src/gameserver.c
@@ -14,6 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "chunklets/x86.h"
#include "con_.h"
#include "errmsg.h"
#include "feature.h"
@@ -21,7 +22,6 @@
#include "intdefs.h"
#include "langext.h"
#include "mem.h"
-#include "x86.h"
#include "vcall.h"
#include "x86util.h"
diff --git a/src/hook.c b/src/hook.c
index 5f964ad..0355c18 100644
--- a/src/hook.c
+++ b/src/hook.c
@@ -17,12 +17,12 @@
#include <string.h>
+#include "chunklets/x86.h"
#include "hook.h"
#include "intdefs.h"
#include "langext.h"
#include "mem.h"
#include "os.h"
-#include "x86.h"
// Warning: half-arsed hacky implementation (because that's all we really need)
// Almost certainly breaks in some weird cases. Oh well! Most of the time,
diff --git a/src/hud.c b/src/hud.c
index 5a666ea..0c5eea6 100644
--- a/src/hud.c
+++ b/src/hud.c
@@ -15,6 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "chunklets/x86.h"
#include "engineapi.h"
#include "errmsg.h"
#include "event.h"
@@ -28,7 +29,6 @@
#include "os.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE()
diff --git a/src/inputhud.c b/src/inputhud.c
index 6cff487..ef7f9ac 100644
--- a/src/inputhud.c
+++ b/src/inputhud.c
@@ -18,6 +18,7 @@
#include <math.h>
+#include "chunklets/x86.h"
#include "con_.h"
#include "engineapi.h"
#include "event.h"
@@ -32,7 +33,6 @@
#include "langext.h"
#include "mem.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("button input HUD")
diff --git a/src/kvsys.c b/src/kvsys.c
index 9c0f75c..25a6672 100644
--- a/src/kvsys.c
+++ b/src/kvsys.c
@@ -16,6 +16,7 @@
*/
#include "abi.h"
+#include "chunklets/x86.h"
#include "extmalloc.h"
#include "errmsg.h"
#include "feature.h"
@@ -25,7 +26,6 @@
#include "langext.h"
#include "os.h"
#include "vcall.h"
-#include "x86.h"
FEATURE()
diff --git a/src/l4d1democompat.c b/src/l4d1democompat.c
index 3c9b604..4280d53 100644
--- a/src/l4d1democompat.c
+++ b/src/l4d1democompat.c
@@ -17,6 +17,7 @@
*/
#include "accessor.h"
+#include "chunklets/x86.h"
#include "con_.h"
#include "errmsg.h"
#include "feature.h"
@@ -26,7 +27,6 @@
#include "mem.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("Left 4 Dead 1 demo file backwards compatibility")
diff --git a/src/l4daddon.c b/src/l4daddon.c
index 0f5fbe7..5336199 100644
--- a/src/l4daddon.c
+++ b/src/l4daddon.c
@@ -18,6 +18,7 @@
#include <string.h>
+#include "chunklets/x86.h"
#include "con_.h"
#include "engineapi.h"
#include "errmsg.h"
@@ -31,7 +32,6 @@
#include "ppmagic.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("Left 4 Dead 2 addon bugfixes")
diff --git a/src/l4dreset.c b/src/l4dreset.c
index 725c763..dd59c60 100644
--- a/src/l4dreset.c
+++ b/src/l4dreset.c
@@ -20,6 +20,7 @@
#include "abi.h"
#include "accessor.h"
+#include "chunklets/x86.h"
#include "con_.h"
#include "engineapi.h"
#include "ent.h"
@@ -32,12 +33,11 @@
#include "gametype.h"
#include "hook.h"
#include "intdefs.h"
-#include "langext.h"
#include "l4dmm.h"
+#include "langext.h"
#include "mem.h"
#include "sst.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
#ifdef _WIN32
diff --git a/src/l4dwarp.c b/src/l4dwarp.c
index 8db87c9..7ddb4cc 100644
--- a/src/l4dwarp.c
+++ b/src/l4dwarp.c
@@ -19,6 +19,7 @@
#include <math.h>
#include "accessor.h"
+#include "chunklets/x86.h"
#include "clientcon.h"
#include "con_.h"
#include "engineapi.h"
@@ -31,7 +32,6 @@
#include "mem.h"
#include "trace.h"
#include "vcall.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("Left 4 Dead warp testing")
diff --git a/src/portalcolours.c b/src/portalcolours.c
index 24224c1..e6e0354 100644
--- a/src/portalcolours.c
+++ b/src/portalcolours.c
@@ -26,7 +26,6 @@
#include "intdefs.h"
#include "langext.h"
#include "mem.h"
-#include "os.h"
#include "ppmagic.h"
#include "sst.h"
#include "vcall.h"
diff --git a/src/portalisg.c b/src/portalisg.c
index bdc007f..d7851eb 100644
--- a/src/portalisg.c
+++ b/src/portalisg.c
@@ -14,6 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "chunklets/x86.h"
#include "con_.h"
#include "engineapi.h"
#include "errmsg.h"
@@ -22,7 +23,6 @@
#include "intdefs.h"
#include "langext.h"
#include "mem.h"
-#include "x86.h"
#include "x86util.h"
FEATURE("Portal \"ISG\" state reset (experimental)")
diff --git a/src/sst.c b/src/sst.c
index e6737bb..64ebfa4 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -37,7 +37,6 @@
#include "hook.h"
#include "intdefs.h"
#include "langext.h"
-#include "mem.h" // for shuntvars() in generated code
#include "os.h"
#include "sst.h"
#include "vcall.h"
diff --git a/src/x86util.h b/src/x86util.h
index 33a3a08..433fbbf 100644
--- a/src/x86util.h
+++ b/src/x86util.h
@@ -17,9 +17,9 @@
#ifndef INC_X86UTIL_H
#define INC_X86UTIL_H
+#include "chunklets/x86.h"
#include "errmsg.h"
#include "langext.h"
-#include "x86.h"
// XXX: don't know where else to put this, or how else to design this, so this
// is very much a plonk-it-here-for-now scenario (and has been for years!)
diff --git a/src/xhair.c b/src/xhair.c
index 9d1ee34..9754f1e 100644
--- a/src/xhair.c
+++ b/src/xhair.c
@@ -20,7 +20,6 @@
#include "gamedata.h"
#include "hexcolour.h"
#include "hud.h"
-#include "intdefs.h"
#include "vcall.h"
FEATURE("custom crosshair drawing")
diff --git a/test/hook.test.c b/test/hook.test.c
index 625fdbf..6a9a7b4 100644
--- a/test/hook.test.c
+++ b/test/hook.test.c
@@ -4,7 +4,7 @@
#ifdef _WIN32
-#include "../src/x86.c"
+#include "../src/chunklets/x86.c"
#include "../src/hook.c"
#include "../src/os.c"
diff --git a/test/x86.test.c b/test/x86.test.c
index bf6e6e8..370a697 100644
--- a/test/x86.test.c
+++ b/test/x86.test.c
@@ -2,7 +2,10 @@
{.desc = "x86 opcode parsing"};
-#include "../src/x86.c"
+// TODO: should chunklets tests be moved or something? guess if/when that stuff
+// gets its own repo it would just go in there, right?
+
+#include "../src/chunklets/x86.c"
#include "../src/intdefs.h"
#include "../src/ppmagic.h"