PDA

View Full Version : Self-modifying code that works under Linux


Slice
09/07/2012, 12:38 PM
(this is not a release, more of a proof-of-concept)

tl;dr: demo code at the bottom

I recently noticed that reading AMX opcodes under Linux is completely different from Windows - on Windows you get the opcodes when you read them, but on Linux you get pointers to strange values I couldn't figure out what they were.. So I simply embraced them instead!

Here's some code that essentially reads the values of most opcodes and stores them into variables, ready to use.

So now, instead of doing this:#emit CONST.pri 119
#emit SREF.S.pri some_addr
Do this:
LoadOpcodes();

#emit LOAD.pri OP_FILL
#emit SREF.S.pri some_addr

Here's an example of a memset function that replaces two NOP instructions with FILL <param>.

stock raw_memset(address, cells, value) {
new param_adr;

LoadOpcodes();

// "cells" now actually holds the number of bytes
cells *= 4;

// This block reads the address of the first NOP, relative to DAT.
#emit LCTRL 6
#emit MOVE.alt
#emit LCTRL 0
#emit ADD
#emit MOVE.alt
#emit LCTRL 1
#emit SUB.alt
#emit ADD.C 120

// Store it
#emit STOR.S.pri param_adr

// Put the FILL opcode at [param_adr]
#emit LOAD.pri OP_FILL
#emit SREF.S.pri param_adr

// Put the parameter for FILL, which is the number of bytes
#emit LOAD.S.pri param_adr
#emit ADD.C 4
#emit STOR.S.pri param_adr
#emit LOAD.S.pri cells
#emit SREF.S.pri param_adr

#emit LOAD.S.alt address
#emit LOAD.S.pri value
#emit NOP
#emit NOP
}

Here's the code for LoadOpcodes():
enum E_OPCODE {
Opcode,
Name[11],
bool:HasParam
};

stock const g_Opcodes[114][E_OPCODE] = {
{ 1, "LOAD.pri", true}, { 2, "LOAD.alt", true}, { 3, "LOAD.S.pri", true},
{ 4, "LOAD.S.alt", true}, { 5, "LREF.pri", true}, { 6, "LREF.alt", true},
{ 7, "LREF.S.pri", true}, { 8, "LREF.S.alt", true}, { 9, "LOAD.I", false},
{ 10, "LODB.I", true}, { 11, "CONST.pri", true}, { 12, "CONST.alt", true},
{ 13, "ADDR.pri", true}, { 14, "ADDR.alt", true}, { 15, "STOR.pri", true},
{ 16, "STOR.alt", true}, { 17, "STOR.S.pri", true}, { 18, "STOR.S.alt", true},
{ 19, "SREF.pri", true}, { 20, "SREF.alt", true}, { 21, "SREF.S.pri", true},
{ 22, "SREF.S.alt", true}, { 23, "STOR.I", false}, { 24, "STRB.I", true},
{ 25, "LIDX", false}, { 26, "LIDX.B", true}, { 27, "IDXADDR", false},
{ 28, "IDXADDR.B", true}, { 29, "ALIGN.pri", true}, { 30, "ALIGN.alt", true},
{ 31, "LCTRL", true}, { 32, "SCTRL", true}, { 33, "MOVE.pri", false},
{ 34, "MOVE.alt", false}, { 35, "XCHG", false}, { 36, "PUSH.pri", false},
{ 37, "PUSH.alt", false}, { 38, "PUSH.R", true}, { 39, "PUSH.C", true},
{ 40, "PUSH", true}, { 41, "PUSH.S", true}, { 42, "POP.pri", false},
{ 43, "POP.alt", false}, { 44, "STACK", true}, { 45, "HEAP", true},
{ 46, "PROC", false}, { 47, "RET", false}, { 48, "RETN", false},
// { 49, "CALL", true},
{ 50, "CALL.pri", false},
// { 51, "JUMP", true}, { 52, "JREL", true}, { 53, "JZER", true},
// { 54, "JNZ", true}, { 55, "JEQ", true}, { 56, "JNEQ", true},
// { 57, "JLESS", true}, { 58, "JLEQ", true}, { 59, "JGRTR", true},
// { 60, "JGEQ", true}, { 61, "JSLESS", true}, { 62, "JSLEQ", true},
// { 63, "JSGRTR", true}, { 64, "JSGEQ", true},
{ 65, "SHL", false}, { 66, "SHR", false}, { 67, "SSHR", false},
{ 68, "SHL.C.pri", true}, { 69, "SHL.C.alt", true}, { 70, "SHR.C.pri", true},
{ 71, "SHR.C.alt", true}, { 72, "SMUL", false}, { 73, "SDIV", false},
{ 74, "SDIV.alt", false}, { 75, "UMUL", false}, { 76, "UDIV", false},
{ 77, "UDIV.alt", false}, { 78, "ADD", false}, { 79, "SUB", false},
{ 80, "SUB.alt", false}, { 81, "AND", false}, { 82, "OR", false},
{ 83, "XOR", false}, { 84, "NOT", false}, { 85, "NEG", false},
{ 86, "INVERT", false}, { 87, "ADD.C", true}, { 88, "SMUL.C", true},
{ 89, "ZERO.pri", false}, { 90, "ZERO.alt", false}, { 91, "ZERO", true},
{ 92, "ZERO.S", true}, { 93, "SIGN.pri", false}, { 94, "SIGN.alt", false},
{ 95, "EQ", false}, { 96, "NEQ", false}, { 97, "LESS", false},
{ 98, "LEQ", false}, { 99, "GRTR", false}, {100, "GEQ", false},
{101, "SLESS", false}, {102, "SLEQ", false}, {103, "SGRTR", false},
{104, "SGEQ", false}, {105, "EQ.C.pri", true}, {106, "EQ.C.alt", true},
{107, "INC.pri", false}, {108, "INC.alt", false}, {109, "INC", true},
{110, "INC.S", true}, {111, "INC.I", false}, {112, "DEC.pri", false},
{113, "DEC.alt", false}, {114, "DEC", true}, {115, "DEC.S", true},
{116, "DEC.I", false}, {117, "MOVS", true}, {118, "CMPS", true},
{119, "FILL", true}, {120, "HALT", true}, {121, "BOUNDS", true},
{122, "SYSREQ.pri", false}, {123, "SYSREQ.C", true}, {128, "JUMP.pri", false},
// {129, "SWITCH", true}, {130, "CASETBL", false},
{131, "SWAP.pri", false}, {132, "SWAP.alt", false}, {133, "PUSH.ADR", true},
{134, "NOP", false}, {137, "BREAK", false}
};

enum {
E_OP_LOAD_PRI, E_OP_LOAD_ALT, E_OP_LOAD_S_PRI,
E_OP_LOAD_S_ALT, E_OP_LREF_PRI, E_OP_LREF_ALT,
E_OP_LREF_S_PRI, E_OP_LREF_S_ALT, E_OP_LOAD_I,
E_OP_LODB_I, E_OP_CONST_PRI, E_OP_CONST_ALT,
E_OP_ADDR_PRI, E_OP_ADDR_ALT, E_OP_STOR_PRI,
E_OP_STOR_ALT, E_OP_STOR_S_PRI, E_OP_STOR_S_ALT,
E_OP_SREF_PRI, E_OP_SREF_ALT, E_OP_SREF_S_PRI,
E_OP_SREF_S_ALT, E_OP_STOR_I, E_OP_STRB_I,
E_OP_LIDX, E_OP_LIDX_B, E_OP_IDXADDR,
E_OP_IDXADDR_B, E_OP_ALIGN_PRI, E_OP_ALIGN_ALT,
E_OP_LCTRL, E_OP_SCTRL, E_OP_MOVE_PRI,
E_OP_MOVE_ALT, E_OP_XCHG, E_OP_PUSH_PRI,
E_OP_PUSH_ALT, E_OP_PUSH_R, E_OP_PUSH_C,
E_OP_PUSH, E_OP_PUSH_S, E_OP_POP_PRI,
E_OP_POP_ALT, E_OP_STACK, E_OP_HEAP,
E_OP_PROC, E_OP_RET, E_OP_RETN,
// E_OP_CALL,
E_OP_CALL_PRI,
// E_OP_JUMP, E_OP_JREL, E_OP_JZER,
// E_OP_JNZ, E_OP_JEQ, E_OP_JNEQ,
// E_OP_JLESS, E_OP_JLEQ, E_OP_JGRTR,
// E_OP_JGEQ, E_OP_JSLESS, E_OP_JSLEQ,
// E_OP_JSGRTR, E_OP_JSGEQ,
E_OP_SHL, E_OP_SHR, E_OP_SSHR,
E_OP_SHL_C_PRI, E_OP_SHL_C_ALT, E_OP_SHR_C_PRI,
E_OP_SHR_C_ALT, E_OP_SMUL, E_OP_SDIV,
E_OP_SDIV_ALT, E_OP_UMUL, E_OP_UDIV,
E_OP_UDIV_ALT, E_OP_ADD, E_OP_SUB,
E_OP_SUB_ALT, E_OP_AND, E_OP_OR,
E_OP_XOR, E_OP_NOT, E_OP_NEG,
E_OP_INVERT, E_OP_ADD_C, E_OP_SMUL_C,
E_OP_ZERO_PRI, E_OP_ZERO_ALT, E_OP_ZERO,
E_OP_ZERO_S, E_OP_SIGN_PRI, E_OP_SIGN_ALT,
E_OP_EQ, E_OP_NEQ, E_OP_LESS,
E_OP_LEQ, E_OP_GRTR, E_OP_GEQ,
E_OP_SLESS, E_OP_SLEQ, E_OP_SGRTR,
E_OP_SGEQ, E_OP_EQ_C_PRI, E_OP_EQ_C_ALT,
E_OP_INC_PRI, E_OP_INC_ALT, E_OP_INC,
E_OP_INC_S, E_OP_INC_I, E_OP_DEC_PRI,
E_OP_DEC_ALT, E_OP_DEC, E_OP_DEC_S,
E_OP_DEC_I, E_OP_MOVS, E_OP_CMPS,
E_OP_FILL, E_OP_HALT, E_OP_BOUNDS,
E_OP_SYSREQ_PRI, E_OP_SYSREQ_C, E_OP_JUMP_PRI,
// E_OP_SWITCH,
// E_OP_CASETBL,
E_OP_SWAP_PRI, E_OP_SWAP_ALT, E_OP_PUSH_ADR,
E_OP_NOP, E_OP_BREAK
};

stock
OP_LOAD_PRI, OP_LOAD_ALT, OP_LOAD_S_PRI,
OP_LOAD_S_ALT, OP_LREF_PRI, OP_LREF_ALT,
OP_LREF_S_PRI, OP_LREF_S_ALT, OP_LOAD_I,
OP_LODB_I, OP_CONST_PRI, OP_CONST_ALT,
OP_ADDR_PRI, OP_ADDR_ALT, OP_STOR_PRI,
OP_STOR_ALT, OP_STOR_S_PRI, OP_STOR_S_ALT,
OP_SREF_PRI, OP_SREF_ALT, OP_SREF_S_PRI,
OP_SREF_S_ALT, OP_STOR_I, OP_STRB_I,
OP_LIDX, OP_LIDX_B, OP_IDXADDR,
OP_IDXADDR_B, OP_ALIGN_PRI, OP_ALIGN_ALT,
OP_LCTRL, OP_SCTRL, OP_MOVE_PRI,
OP_MOVE_ALT, OP_XCHG, OP_PUSH_PRI,
OP_PUSH_ALT, OP_PUSH_R, OP_PUSH_C,
OP_PUSH, OP_PUSH_S, OP_POP_PRI,
OP_POP_ALT, OP_STACK, OP_HEAP,
OP_PROC, OP_RET, OP_RETN,
// OP_CALL,
OP_CALL_PRI,
// OP_JUMP, OP_JREL, OP_JZER,
// OP_JNZ, OP_JEQ, OP_JNEQ,
// OP_JLESS, OP_JLEQ, OP_JGRTR,
// OP_JGEQ, OP_JSLESS, OP_JSLEQ,
// OP_JSGRTR, OP_JSGEQ,
OP_SHL, OP_SHR, OP_SSHR,
OP_SHL_C_PRI, OP_SHL_C_ALT, OP_SHR_C_PRI,
OP_SHR_C_ALT, OP_SMUL, OP_SDIV,
OP_SDIV_ALT, OP_UMUL, OP_UDIV,
OP_UDIV_ALT, OP_ADD, OP_SUB,
OP_SUB_ALT, OP_AND, OP_OR,
OP_XOR, OP_NOT, OP_NEG,
OP_INVERT, OP_ADD_C, OP_SMUL_C,
OP_ZERO_PRI, OP_ZERO_ALT, OP_ZERO,
OP_ZERO_S, OP_SIGN_PRI, OP_SIGN_ALT,
OP_EQ, OP_NEQ, OP_LESS,
OP_LEQ, OP_GRTR, OP_GEQ,
OP_SLESS, OP_SLEQ, OP_SGRTR,
OP_SGEQ, OP_EQ_C_PRI, OP_EQ_C_ALT,
OP_INC_PRI, OP_INC_ALT, OP_INC,
OP_INC_S, OP_INC_I, OP_DEC_PRI,
OP_DEC_ALT, OP_DEC, OP_DEC_S,
OP_DEC_I, OP_MOVS, OP_CMPS,
OP_FILL, OP_HALT, OP_BOUNDS,
OP_SYSREQ_PRI, OP_SYSREQ_C, OP_JUMP_PRI,
// OP_SWITCH,
// OP_CASETBL,
OP_SWAP_PRI, OP_SWAP_ALT, OP_PUSH_ADR,
OP_NOP, OP_BREAK
;

stock LoadOpcodes() {
static bool:loaded = false;

// We only need to load them once
if (loaded)
return;
else
loaded = true;

new addr = _LoadOpcodes(), opcode_values[sizeof(g_Opcodes)];

for (new i = 0; i < sizeof(g_Opcodes); i++) {
new opcode, param;

#emit LREF.S.pri addr
#emit STOR.S.pri opcode

addr += 4;

if (g_Opcodes[i][HasParam]) {
#emit LREF.S.pri addr
#emit STOR.S.pri param

//printf("%04x%04x %04x%04x", opcode >>> 16, opcode & 0xFFFF, param >>> 16, param & 0xFFFF);

addr += 4;
} else {
//printf("%04x%04x", opcode >>> 16, opcode & 0xFFFF);
}

opcode_values[i] = opcode;
}

// bleh
OP_LOAD_PRI = opcode_values[E_OP_LOAD_PRI]; OP_LOAD_ALT = opcode_values[E_OP_LOAD_ALT]; OP_LOAD_S_PRI = opcode_values[E_OP_LOAD_S_PRI];
OP_LOAD_S_ALT = opcode_values[E_OP_LOAD_S_ALT]; OP_LREF_PRI = opcode_values[E_OP_LREF_PRI]; OP_LREF_ALT = opcode_values[E_OP_LREF_ALT];
OP_LREF_S_PRI = opcode_values[E_OP_LREF_S_PRI]; OP_LREF_S_ALT = opcode_values[E_OP_LREF_S_ALT]; OP_LOAD_I = opcode_values[E_OP_LOAD_I];
OP_LODB_I = opcode_values[E_OP_LODB_I]; OP_CONST_PRI = opcode_values[E_OP_CONST_PRI]; OP_CONST_ALT = opcode_values[E_OP_CONST_ALT];
OP_ADDR_PRI = opcode_values[E_OP_ADDR_PRI]; OP_ADDR_ALT = opcode_values[E_OP_ADDR_ALT]; OP_STOR_PRI = opcode_values[E_OP_STOR_PRI];
OP_STOR_ALT = opcode_values[E_OP_STOR_ALT]; OP_STOR_S_PRI = opcode_values[E_OP_STOR_S_PRI]; OP_STOR_S_ALT = opcode_values[E_OP_STOR_S_ALT];
OP_SREF_PRI = opcode_values[E_OP_SREF_PRI]; OP_SREF_ALT = opcode_values[E_OP_SREF_ALT]; OP_SREF_S_PRI = opcode_values[E_OP_SREF_S_PRI];
OP_SREF_S_ALT = opcode_values[E_OP_SREF_S_ALT]; OP_STOR_I = opcode_values[E_OP_STOR_I]; OP_STRB_I = opcode_values[E_OP_STRB_I];
OP_LIDX = opcode_values[E_OP_LIDX]; OP_LIDX_B = opcode_values[E_OP_LIDX_B]; OP_IDXADDR = opcode_values[E_OP_IDXADDR];
OP_IDXADDR_B = opcode_values[E_OP_IDXADDR_B]; OP_ALIGN_PRI = opcode_values[E_OP_ALIGN_PRI]; OP_ALIGN_ALT = opcode_values[E_OP_ALIGN_ALT];
OP_LCTRL = opcode_values[E_OP_LCTRL]; OP_SCTRL = opcode_values[E_OP_SCTRL]; OP_MOVE_PRI = opcode_values[E_OP_MOVE_PRI];
OP_MOVE_ALT = opcode_values[E_OP_MOVE_ALT]; OP_XCHG = opcode_values[E_OP_XCHG]; OP_PUSH_PRI = opcode_values[E_OP_PUSH_PRI];
OP_PUSH_ALT = opcode_values[E_OP_PUSH_ALT]; OP_PUSH_R = opcode_values[E_OP_PUSH_R]; OP_PUSH_C = opcode_values[E_OP_PUSH_C];
OP_PUSH = opcode_values[E_OP_PUSH]; OP_PUSH_S = opcode_values[E_OP_PUSH_S]; OP_POP_PRI = opcode_values[E_OP_POP_PRI];
OP_POP_ALT = opcode_values[E_OP_POP_ALT]; OP_STACK = opcode_values[E_OP_STACK]; OP_HEAP = opcode_values[E_OP_HEAP];
OP_PROC = opcode_values[E_OP_PROC]; OP_RET = opcode_values[E_OP_RET]; OP_RETN = opcode_values[E_OP_RETN];
// OP_CALL = opcode_values[E_OP_CALL];
OP_CALL_PRI = opcode_values[E_OP_CALL_PRI];
// OP_JUMP = opcode_values[E_OP_JUMP]; OP_JREL = opcode_values[E_OP_OP_JREL]; OP_JZER = opcode_values[E_OP_OP_JZER];
// OP_JNZ = opcode_values[E_OP_OP_JNZ]; OP_JEQ = opcode_values[E_OP_OP_JEQ]; OP_JNEQ = opcode_values[E_OP_OP_JNEQ];
// OP_JLESS = opcode_values[E_OP_OP_JLESS]; OP_JLEQ = opcode_values[E_OP_OP_JLEQ]; OP_JGRTR = opcode_values[E_OP_OP_JGRTR];
// OP_JGEQ = opcode_values[E_OP_OP_JGEQ]; OP_JSLESS = opcode_values[E_OP_OP_JSLESS]; OP_JSLEQ = opcode_values[E_OP_OP_JSLEQ];
// OP_JSGRTR = opcode_values[E_OP_OP_JSGRTR]; OP_JSGEQ = opcode_values[E_OP_OP_JSGEQ];
OP_SHL = opcode_values[E_OP_SHL]; OP_SHR = opcode_values[E_OP_SHR]; OP_SSHR = opcode_values[E_OP_SSHR];
OP_SHL_C_PRI = opcode_values[E_OP_SHL_C_PRI]; OP_SHL_C_ALT = opcode_values[E_OP_SHL_C_ALT]; OP_SHR_C_PRI = opcode_values[E_OP_SHR_C_PRI];
OP_SHR_C_ALT = opcode_values[E_OP_SHR_C_ALT]; OP_SMUL = opcode_values[E_OP_SMUL]; OP_SDIV = opcode_values[E_OP_SDIV];
OP_SDIV_ALT = opcode_values[E_OP_SDIV_ALT]; OP_UMUL = opcode_values[E_OP_UMUL]; OP_UDIV = opcode_values[E_OP_UDIV];
OP_UDIV_ALT = opcode_values[E_OP_UDIV_ALT]; OP_ADD = opcode_values[E_OP_ADD]; OP_SUB = opcode_values[E_OP_SUB];
OP_SUB_ALT = opcode_values[E_OP_SUB_ALT]; OP_AND = opcode_values[E_OP_AND]; OP_OR = opcode_values[E_OP_OR];
OP_XOR = opcode_values[E_OP_XOR]; OP_NOT = opcode_values[E_OP_NOT]; OP_NEG = opcode_values[E_OP_NEG];
OP_INVERT = opcode_values[E_OP_INVERT]; OP_ADD_C = opcode_values[E_OP_ADD_C]; OP_SMUL_C = opcode_values[E_OP_SMUL_C];
OP_ZERO_PRI = opcode_values[E_OP_ZERO_PRI]; OP_ZERO_ALT = opcode_values[E_OP_ZERO_ALT]; OP_ZERO = opcode_values[E_OP_ZERO];
OP_ZERO_S = opcode_values[E_OP_ZERO_S]; OP_SIGN_PRI = opcode_values[E_OP_SIGN_PRI]; OP_SIGN_ALT = opcode_values[E_OP_SIGN_ALT];
OP_EQ = opcode_values[E_OP_EQ]; OP_NEQ = opcode_values[E_OP_NEQ]; OP_LESS = opcode_values[E_OP_LESS];
OP_LEQ = opcode_values[E_OP_LEQ]; OP_GRTR = opcode_values[E_OP_GRTR]; OP_GEQ = opcode_values[E_OP_GEQ];
OP_SLESS = opcode_values[E_OP_SLESS]; OP_SLEQ = opcode_values[E_OP_SLEQ]; OP_SGRTR = opcode_values[E_OP_SGRTR];
OP_SGEQ = opcode_values[E_OP_SGEQ]; OP_EQ_C_PRI = opcode_values[E_OP_EQ_C_PRI]; OP_EQ_C_ALT = opcode_values[E_OP_EQ_C_ALT];
OP_INC_PRI = opcode_values[E_OP_INC_PRI]; OP_INC_ALT = opcode_values[E_OP_INC_ALT]; OP_INC = opcode_values[E_OP_INC];
OP_INC_S = opcode_values[E_OP_INC_S]; OP_INC_I = opcode_values[E_OP_INC_I]; OP_DEC_PRI = opcode_values[E_OP_DEC_PRI];
OP_DEC_ALT = opcode_values[E_OP_DEC_ALT]; OP_DEC = opcode_values[E_OP_DEC]; OP_DEC_S = opcode_values[E_OP_DEC_S];
OP_DEC_I = opcode_values[E_OP_DEC_I]; OP_MOVS = opcode_values[E_OP_MOVS]; OP_CMPS = opcode_values[E_OP_CMPS];
OP_FILL = opcode_values[E_OP_FILL]; OP_HALT = opcode_values[E_OP_HALT]; OP_BOUNDS = opcode_values[E_OP_BOUNDS];
OP_SYSREQ_PRI = opcode_values[E_OP_SYSREQ_PRI]; OP_SYSREQ_C = opcode_values[E_OP_SYSREQ_C]; OP_JUMP_PRI = opcode_values[E_OP_JUMP_PRI];
// OP_SWITCH = opcode_values[E_OP_SWITCH];
// OP_CASETBL = opcode_values[E_OP_OP_CASETBL];
OP_SWAP_PRI = opcode_values[E_OP_SWAP_PRI]; OP_SWAP_ALT = opcode_values[E_OP_SWAP_ALT]; OP_PUSH_ADR = opcode_values[E_OP_PUSH_ADR];
OP_NOP = opcode_values[E_OP_NOP]; OP_BREAK = opcode_values[E_OP_BREAK];
}

stock _LoadOpcodes() {
// Return the address of "LOAD.pri" below
#emit LCTRL 6
#emit MOVE.alt
#emit LCTRL 0
#emit ADD
#emit MOVE.alt
#emit LCTRL 1
#emit SUB.alt
#emit ADD.C 44
#emit RETN

// The values of the parameters are insignificant, but they must to be there.
#emit LOAD.pri 1 // 1
#emit LOAD.alt 2 // 2
#emit LOAD.S.pri 3 // 3
#emit LOAD.S.alt 4 // 4
#emit LREF.pri 5 // 5
#emit LREF.alt 6 // 6
#emit LREF.S.pri 7 // 7
#emit LREF.S.alt 8 // 8
#emit LOAD.I // 9
#emit LODB.I 10 // 10
#emit CONST.pri 11 // 11
#emit CONST.alt 12 // 12
#emit ADDR.pri 13 // 13
#emit ADDR.alt 14 // 14
#emit STOR.pri 15 // 15
#emit STOR.alt 16 // 16
#emit STOR.S.pri 17 // 17
#emit STOR.S.alt 18 // 18
#emit SREF.pri 19 // 19
#emit SREF.alt 20 // 20
#emit SREF.S.pri 21 // 21
#emit SREF.S.alt 22 // 22
#emit STOR.I // 23
#emit STRB.I 24 // 24
#emit LIDX // 25
#emit LIDX.B 26 // 26
#emit IDXADDR // 27
#emit IDXADDR.B 28 // 28
#emit ALIGN.pri 29 // 29
#emit ALIGN.alt 30 // 30
#emit LCTRL 31 // 31
#emit SCTRL 32 // 32
#emit MOVE.pri // 33
#emit MOVE.alt // 34
#emit XCHG // 35
#emit PUSH.pri // 36
#emit PUSH.alt // 37
#emit PUSH.R 38 // 38
#emit PUSH.C 39 // 39
#emit PUSH 40 // 40
#emit PUSH.S 41 // 41
#emit POP.pri // 42
#emit POP.alt // 43
#emit STACK 44 // 44
#emit HEAP 45 // 45
#emit PROC // 46
#emit RET // 47
#emit RETN // 48
// #emit CALL 49 // 49
#emit CALL.pri // 50
// #emit JUMP 51 // 51
// #emit JREL 52 // 52
// #emit JZER 53 // 53
// #emit JNZ 54 // 54
// #emit JEQ 55 // 55
// #emit JNEQ 56 // 56
// #emit JLESS 57 // 57
// #emit JLEQ 58 // 58
// #emit JGRTR 59 // 59
// #emit JGEQ 60 // 60
// #emit JSLESS 61 // 61
// #emit JSLEQ 62 // 62
// #emit JSGRTR 63 // 63
// #emit JSGEQ 64 // 64
#emit SHL // 65
#emit SHR // 66
#emit SSHR // 67
#emit SHL.C.pri 68 // 68
#emit SHL.C.alt 69 // 69
#emit SHR.C.pri 70 // 70
#emit SHR.C.alt 71 // 71
#emit SMUL // 72
#emit SDIV // 73
#emit SDIV.alt // 74
#emit UMUL // 75
#emit UDIV // 76
#emit UDIV.alt // 77
#emit ADD // 78
#emit SUB // 79
#emit SUB.alt // 80
#emit AND // 81
#emit OR // 82
#emit XOR // 83
#emit NOT // 84
#emit NEG // 85
#emit INVERT // 86
#emit ADD.C 87 // 87
#emit SMUL.C 88 // 88
#emit ZERO.pri // 89
#emit ZERO.alt // 90
#emit ZERO 91 // 91
#emit ZERO.S 92 // 92
#emit SIGN.pri // 93
#emit SIGN.alt // 94
#emit EQ // 95
#emit NEQ // 96
#emit LESS // 97
#emit LEQ // 98
#emit GRTR // 99
#emit GEQ // 100
#emit SLESS // 101
#emit SLEQ // 102
#emit SGRTR // 103
#emit SGEQ // 104
#emit EQ.C.pri 105 // 105
#emit EQ.C.alt 106 // 106
#emit INC.pri // 107
#emit INC.alt // 108
#emit INC 109 // 109
#emit INC.S 110 // 110
#emit INC.I // 111
#emit DEC.pri // 112
#emit DEC.alt // 113
#emit DEC 114 // 114
#emit DEC.S 115 // 115
#emit DEC.I // 116
#emit MOVS 117 // 117
#emit CMPS 118 // 118
#emit FILL 119 // 119
#emit HALT 120 // 120
#emit BOUNDS 121 // 121
#emit SYSREQ.pri // 122
#emit SYSREQ.C 123 // 123
#emit JUMP.pri // 128
// #emit SWITCH 129 // 129
// #emit CASETBL // 130
#emit SWAP.pri // 131
#emit SWAP.alt // 132
#emit PUSH.ADR 133 // 133
#emit NOP // 134
#emit BREAK // 137

return 0;
}


Copy & paste this code into PAWN Playground (http://slice-vps.nl/ppg/) for a demo (I'm unable to save it due to a length limitation).
#include <a_samp>

stock
OP_LOAD_PRI, OP_LOAD_ALT, OP_LOAD_S_PRI,
OP_LOAD_S_ALT, OP_LREF_PRI, OP_LREF_ALT,
OP_LREF_S_PRI, OP_LREF_S_ALT, OP_LOAD_I,
OP_LODB_I, OP_CONST_PRI, OP_CONST_ALT,
OP_ADDR_PRI, OP_ADDR_ALT, OP_STOR_PRI,
OP_STOR_ALT, OP_STOR_S_PRI, OP_STOR_S_ALT,
OP_SREF_PRI, OP_SREF_ALT, OP_SREF_S_PRI,
OP_SREF_S_ALT, OP_STOR_I, OP_STRB_I,
OP_LIDX, OP_LIDX_B, OP_IDXADDR,
OP_IDXADDR_B, OP_ALIGN_PRI, OP_ALIGN_ALT,
OP_LCTRL, OP_SCTRL, OP_MOVE_PRI,
OP_MOVE_ALT, OP_XCHG, OP_PUSH_PRI,
OP_PUSH_ALT, OP_PUSH_R, OP_PUSH_C,
OP_PUSH, OP_PUSH_S, OP_POP_PRI,
OP_POP_ALT, OP_STACK, OP_HEAP,
OP_PROC, OP_RET, OP_RETN,
// OP_CALL,
OP_CALL_PRI,
// OP_JUMP, OP_JREL, OP_JZER,
// OP_JNZ, OP_JEQ, OP_JNEQ,
// OP_JLESS, OP_JLEQ, OP_JGRTR,
// OP_JGEQ, OP_JSLESS, OP_JSLEQ,
// OP_JSGRTR, OP_JSGEQ,
OP_SHL, OP_SHR, OP_SSHR,
OP_SHL_C_PRI, OP_SHL_C_ALT, OP_SHR_C_PRI,
OP_SHR_C_ALT, OP_SMUL, OP_SDIV,
OP_SDIV_ALT, OP_UMUL, OP_UDIV,
OP_UDIV_ALT, OP_ADD, OP_SUB,
OP_SUB_ALT, OP_AND, OP_OR,
OP_XOR, OP_NOT, OP_NEG,
OP_INVERT, OP_ADD_C, OP_SMUL_C,
OP_ZERO_PRI, OP_ZERO_ALT, OP_ZERO,
OP_ZERO_S, OP_SIGN_PRI, OP_SIGN_ALT,
OP_EQ, OP_NEQ, OP_LESS,
OP_LEQ, OP_GRTR, OP_GEQ,
OP_SLESS, OP_SLEQ, OP_SGRTR,
OP_SGEQ, OP_EQ_C_PRI, OP_EQ_C_ALT,
OP_INC_PRI, OP_INC_ALT, OP_INC,
OP_INC_S, OP_INC_I, OP_DEC_PRI,
OP_DEC_ALT, OP_DEC, OP_DEC_S,
OP_DEC_I, OP_MOVS, OP_CMPS,
OP_FILL, OP_HALT, OP_BOUNDS,
OP_SYSREQ_PRI, OP_SYSREQ_C, OP_JUMP_PRI,
// OP_SWITCH,
// OP_CASETBL,
OP_SWAP_PRI, OP_SWAP_ALT, OP_PUSH_ADR,
OP_NOP, OP_BREAK
;

main() {
new test[20] = {4, ...};

memset(test[5], 10, 1234);

for (new i = 0; i < sizeof(test); i++) {
printf("test[%d] = %d", i, test[i]);
}

#if defined quit
quit();
#endif
}

stock memset(variable[], cells, value) {
new address;

#emit LOAD.S.pri variable
#emit STOR.S.pri address

raw_memset(address, cells, value);
}

stock raw_memset(address, cells, value) {
new param_adr;

LoadOpcodes();

// "cells" now actually holds the number of bytes
cells *= 4;

// This block reads the address of the first NOP, relative to DAT.
#emit LCTRL 6
#emit MOVE.alt
#emit LCTRL 0
#emit ADD
#emit MOVE.alt
#emit LCTRL 1
#emit SUB.alt
#emit ADD.C 120

// Store it
#emit STOR.S.pri param_adr

// Put the FILL opcode at [param_adr]
#emit LOAD.pri OP_FILL
#emit SREF.S.pri param_adr

// Put the parameter for FILL, which is the number of bytes
#emit LOAD.S.pri param_adr
#emit ADD.C 4
#emit STOR.S.pri param_adr
#emit LOAD.S.pri cells
#emit SREF.S.pri param_adr

#emit LOAD.S.alt address
#emit LOAD.S.pri value
#emit NOP
#emit NOP
}











enum E_OPCODE {
Opcode,
Name[11],
bool:HasParam
};

stock const g_Opcodes[114][E_OPCODE] = {
{ 1, "LOAD.pri", true}, { 2, "LOAD.alt", true}, { 3, "LOAD.S.pri", true},
{ 4, "LOAD.S.alt", true}, { 5, "LREF.pri", true}, { 6, "LREF.alt", true},
{ 7, "LREF.S.pri", true}, { 8, "LREF.S.alt", true}, { 9, "LOAD.I", false},
{ 10, "LODB.I", true}, { 11, "CONST.pri", true}, { 12, "CONST.alt", true},
{ 13, "ADDR.pri", true}, { 14, "ADDR.alt", true}, { 15, "STOR.pri", true},
{ 16, "STOR.alt", true}, { 17, "STOR.S.pri", true}, { 18, "STOR.S.alt", true},
{ 19, "SREF.pri", true}, { 20, "SREF.alt", true}, { 21, "SREF.S.pri", true},
{ 22, "SREF.S.alt", true}, { 23, "STOR.I", false}, { 24, "STRB.I", true},
{ 25, "LIDX", false}, { 26, "LIDX.B", true}, { 27, "IDXADDR", false},
{ 28, "IDXADDR.B", true}, { 29, "ALIGN.pri", true}, { 30, "ALIGN.alt", true},
{ 31, "LCTRL", true}, { 32, "SCTRL", true}, { 33, "MOVE.pri", false},
{ 34, "MOVE.alt", false}, { 35, "XCHG", false}, { 36, "PUSH.pri", false},
{ 37, "PUSH.alt", false}, { 38, "PUSH.R", true}, { 39, "PUSH.C", true},
{ 40, "PUSH", true}, { 41, "PUSH.S", true}, { 42, "POP.pri", false},
{ 43, "POP.alt", false}, { 44, "STACK", true}, { 45, "HEAP", true},
{ 46, "PROC", false}, { 47, "RET", false}, { 48, "RETN", false},
// { 49, "CALL", true},
{ 50, "CALL.pri", false},
// { 51, "JUMP", true}, { 52, "JREL", true}, { 53, "JZER", true},
// { 54, "JNZ", true}, { 55, "JEQ", true}, { 56, "JNEQ", true},
// { 57, "JLESS", true}, { 58, "JLEQ", true}, { 59, "JGRTR", true},
// { 60, "JGEQ", true}, { 61, "JSLESS", true}, { 62, "JSLEQ", true},
// { 63, "JSGRTR", true}, { 64, "JSGEQ", true},
{ 65, "SHL", false}, { 66, "SHR", false}, { 67, "SSHR", false},
{ 68, "SHL.C.pri", true}, { 69, "SHL.C.alt", true}, { 70, "SHR.C.pri", true},
{ 71, "SHR.C.alt", true}, { 72, "SMUL", false}, { 73, "SDIV", false},
{ 74, "SDIV.alt", false}, { 75, "UMUL", false}, { 76, "UDIV", false},
{ 77, "UDIV.alt", false}, { 78, "ADD", false}, { 79, "SUB", false},
{ 80, "SUB.alt", false}, { 81, "AND", false}, { 82, "OR", false},
{ 83, "XOR", false}, { 84, "NOT", false}, { 85, "NEG", false},
{ 86, "INVERT", false}, { 87, "ADD.C", true}, { 88, "SMUL.C", true},
{ 89, "ZERO.pri", false}, { 90, "ZERO.alt", false}, { 91, "ZERO", true},
{ 92, "ZERO.S", true}, { 93, "SIGN.pri", false}, { 94, "SIGN.alt", false},
{ 95, "EQ", false}, { 96, "NEQ", false}, { 97, "LESS", false},
{ 98, "LEQ", false}, { 99, "GRTR", false}, {100, "GEQ", false},
{101, "SLESS", false}, {102, "SLEQ", false}, {103, "SGRTR", false},
{104, "SGEQ", false}, {105, "EQ.C.pri", true}, {106, "EQ.C.alt", true},
{107, "INC.pri", false}, {108, "INC.alt", false}, {109, "INC", true},
{110, "INC.S", true}, {111, "INC.I", false}, {112, "DEC.pri", false},
{113, "DEC.alt", false}, {114, "DEC", true}, {115, "DEC.S", true},
{116, "DEC.I", false}, {117, "MOVS", true}, {118, "CMPS", true},
{119, "FILL", true}, {120, "HALT", true}, {121, "BOUNDS", true},
{122, "SYSREQ.pri", false}, {123, "SYSREQ.C", true}, {128, "JUMP.pri", false},
// {129, "SWITCH", true}, {130, "CASETBL", false},
{131, "SWAP.pri", false}, {132, "SWAP.alt", false}, {133, "PUSH.ADR", true},
{134, "NOP", false}, {137, "BREAK", false}
};

enum {
E_OP_LOAD_PRI, E_OP_LOAD_ALT, E_OP_LOAD_S_PRI,
E_OP_LOAD_S_ALT, E_OP_LREF_PRI, E_OP_LREF_ALT,
E_OP_LREF_S_PRI, E_OP_LREF_S_ALT, E_OP_LOAD_I,
E_OP_LODB_I, E_OP_CONST_PRI, E_OP_CONST_ALT,
E_OP_ADDR_PRI, E_OP_ADDR_ALT, E_OP_STOR_PRI,
E_OP_STOR_ALT, E_OP_STOR_S_PRI, E_OP_STOR_S_ALT,
E_OP_SREF_PRI, E_OP_SREF_ALT, E_OP_SREF_S_PRI,
E_OP_SREF_S_ALT, E_OP_STOR_I, E_OP_STRB_I,
E_OP_LIDX, E_OP_LIDX_B, E_OP_IDXADDR,
E_OP_IDXADDR_B, E_OP_ALIGN_PRI, E_OP_ALIGN_ALT,
E_OP_LCTRL, E_OP_SCTRL, E_OP_MOVE_PRI,
E_OP_MOVE_ALT, E_OP_XCHG, E_OP_PUSH_PRI,
E_OP_PUSH_ALT, E_OP_PUSH_R, E_OP_PUSH_C,
E_OP_PUSH, E_OP_PUSH_S, E_OP_POP_PRI,
E_OP_POP_ALT, E_OP_STACK, E_OP_HEAP,
E_OP_PROC, E_OP_RET, E_OP_RETN,
// E_OP_CALL,
E_OP_CALL_PRI,
// E_OP_JUMP, E_OP_JREL, E_OP_JZER,
// E_OP_JNZ, E_OP_JEQ, E_OP_JNEQ,
// E_OP_JLESS, E_OP_JLEQ, E_OP_JGRTR,
// E_OP_JGEQ, E_OP_JSLESS, E_OP_JSLEQ,
// E_OP_JSGRTR, E_OP_JSGEQ,
E_OP_SHL, E_OP_SHR, E_OP_SSHR,
E_OP_SHL_C_PRI, E_OP_SHL_C_ALT, E_OP_SHR_C_PRI,
E_OP_SHR_C_ALT, E_OP_SMUL, E_OP_SDIV,
E_OP_SDIV_ALT, E_OP_UMUL, E_OP_UDIV,
E_OP_UDIV_ALT, E_OP_ADD, E_OP_SUB,
E_OP_SUB_ALT, E_OP_AND, E_OP_OR,
E_OP_XOR, E_OP_NOT, E_OP_NEG,
E_OP_INVERT, E_OP_ADD_C, E_OP_SMUL_C,
E_OP_ZERO_PRI, E_OP_ZERO_ALT, E_OP_ZERO,
E_OP_ZERO_S, E_OP_SIGN_PRI, E_OP_SIGN_ALT,
E_OP_EQ, E_OP_NEQ, E_OP_LESS,
E_OP_LEQ, E_OP_GRTR, E_OP_GEQ,
E_OP_SLESS, E_OP_SLEQ, E_OP_SGRTR,
E_OP_SGEQ, E_OP_EQ_C_PRI, E_OP_EQ_C_ALT,
E_OP_INC_PRI, E_OP_INC_ALT, E_OP_INC,
E_OP_INC_S, E_OP_INC_I, E_OP_DEC_PRI,
E_OP_DEC_ALT, E_OP_DEC, E_OP_DEC_S,
E_OP_DEC_I, E_OP_MOVS, E_OP_CMPS,
E_OP_FILL, E_OP_HALT, E_OP_BOUNDS,
E_OP_SYSREQ_PRI, E_OP_SYSREQ_C, E_OP_JUMP_PRI,
// E_OP_SWITCH,
// E_OP_CASETBL,
E_OP_SWAP_PRI, E_OP_SWAP_ALT, E_OP_PUSH_ADR,
E_OP_NOP, E_OP_BREAK
};

stock LoadOpcodes() {
static bool:loaded = false;

// We only need to load them once
if (loaded)
return;
else
loaded = true;

new addr = _LoadOpcodes(), opcode_values[sizeof(g_Opcodes)];

for (new i = 0; i < sizeof(g_Opcodes); i++) {
new opcode, param;

#emit LREF.S.pri addr
#emit STOR.S.pri opcode

addr += 4;

if (g_Opcodes[i][HasParam]) {
#emit LREF.S.pri addr
#emit STOR.S.pri param

//printf("%04x%04x %04x%04x", opcode >>> 16, opcode & 0xFFFF, param >>> 16, param & 0xFFFF);

addr += 4;
} else {
//printf("%04x%04x", opcode >>> 16, opcode & 0xFFFF);
}

opcode_values[i] = opcode;
}

// bleh
OP_LOAD_PRI = opcode_values[E_OP_LOAD_PRI]; OP_LOAD_ALT = opcode_values[E_OP_LOAD_ALT]; OP_LOAD_S_PRI = opcode_values[E_OP_LOAD_S_PRI];
OP_LOAD_S_ALT = opcode_values[E_OP_LOAD_S_ALT]; OP_LREF_PRI = opcode_values[E_OP_LREF_PRI]; OP_LREF_ALT = opcode_values[E_OP_LREF_ALT];
OP_LREF_S_PRI = opcode_values[E_OP_LREF_S_PRI]; OP_LREF_S_ALT = opcode_values[E_OP_LREF_S_ALT]; OP_LOAD_I = opcode_values[E_OP_LOAD_I];
OP_LODB_I = opcode_values[E_OP_LODB_I]; OP_CONST_PRI = opcode_values[E_OP_CONST_PRI]; OP_CONST_ALT = opcode_values[E_OP_CONST_ALT];
OP_ADDR_PRI = opcode_values[E_OP_ADDR_PRI]; OP_ADDR_ALT = opcode_values[E_OP_ADDR_ALT]; OP_STOR_PRI = opcode_values[E_OP_STOR_PRI];
OP_STOR_ALT = opcode_values[E_OP_STOR_ALT]; OP_STOR_S_PRI = opcode_values[E_OP_STOR_S_PRI]; OP_STOR_S_ALT = opcode_values[E_OP_STOR_S_ALT];
OP_SREF_PRI = opcode_values[E_OP_SREF_PRI]; OP_SREF_ALT = opcode_values[E_OP_SREF_ALT]; OP_SREF_S_PRI = opcode_values[E_OP_SREF_S_PRI];
OP_SREF_S_ALT = opcode_values[E_OP_SREF_S_ALT]; OP_STOR_I = opcode_values[E_OP_STOR_I]; OP_STRB_I = opcode_values[E_OP_STRB_I];
OP_LIDX = opcode_values[E_OP_LIDX]; OP_LIDX_B = opcode_values[E_OP_LIDX_B]; OP_IDXADDR = opcode_values[E_OP_IDXADDR];
OP_IDXADDR_B = opcode_values[E_OP_IDXADDR_B]; OP_ALIGN_PRI = opcode_values[E_OP_ALIGN_PRI]; OP_ALIGN_ALT = opcode_values[E_OP_ALIGN_ALT];
OP_LCTRL = opcode_values[E_OP_LCTRL]; OP_SCTRL = opcode_values[E_OP_SCTRL]; OP_MOVE_PRI = opcode_values[E_OP_MOVE_PRI];
OP_MOVE_ALT = opcode_values[E_OP_MOVE_ALT]; OP_XCHG = opcode_values[E_OP_XCHG]; OP_PUSH_PRI = opcode_values[E_OP_PUSH_PRI];
OP_PUSH_ALT = opcode_values[E_OP_PUSH_ALT]; OP_PUSH_R = opcode_values[E_OP_PUSH_R]; OP_PUSH_C = opcode_values[E_OP_PUSH_C];
OP_PUSH = opcode_values[E_OP_PUSH]; OP_PUSH_S = opcode_values[E_OP_PUSH_S]; OP_POP_PRI = opcode_values[E_OP_POP_PRI];
OP_POP_ALT = opcode_values[E_OP_POP_ALT]; OP_STACK = opcode_values[E_OP_STACK]; OP_HEAP = opcode_values[E_OP_HEAP];
OP_PROC = opcode_values[E_OP_PROC]; OP_RET = opcode_values[E_OP_RET]; OP_RETN = opcode_values[E_OP_RETN];
// OP_CALL = opcode_values[E_OP_CALL];
OP_CALL_PRI = opcode_values[E_OP_CALL_PRI];
// OP_JUMP = opcode_values[E_OP_JUMP]; OP_JREL = opcode_values[E_OP_OP_JREL]; OP_JZER = opcode_values[E_OP_OP_JZER];
// OP_JNZ = opcode_values[E_OP_OP_JNZ]; OP_JEQ = opcode_values[E_OP_OP_JEQ]; OP_JNEQ = opcode_values[E_OP_OP_JNEQ];
// OP_JLESS = opcode_values[E_OP_OP_JLESS]; OP_JLEQ = opcode_values[E_OP_OP_JLEQ]; OP_JGRTR = opcode_values[E_OP_OP_JGRTR];
// OP_JGEQ = opcode_values[E_OP_OP_JGEQ]; OP_JSLESS = opcode_values[E_OP_OP_JSLESS]; OP_JSLEQ = opcode_values[E_OP_OP_JSLEQ];
// OP_JSGRTR = opcode_values[E_OP_OP_JSGRTR]; OP_JSGEQ = opcode_values[E_OP_OP_JSGEQ];
OP_SHL = opcode_values[E_OP_SHL]; OP_SHR = opcode_values[E_OP_SHR]; OP_SSHR = opcode_values[E_OP_SSHR];
OP_SHL_C_PRI = opcode_values[E_OP_SHL_C_PRI]; OP_SHL_C_ALT = opcode_values[E_OP_SHL_C_ALT]; OP_SHR_C_PRI = opcode_values[E_OP_SHR_C_PRI];
OP_SHR_C_ALT = opcode_values[E_OP_SHR_C_ALT]; OP_SMUL = opcode_values[E_OP_SMUL]; OP_SDIV = opcode_values[E_OP_SDIV];
OP_SDIV_ALT = opcode_values[E_OP_SDIV_ALT]; OP_UMUL = opcode_values[E_OP_UMUL]; OP_UDIV = opcode_values[E_OP_UDIV];
OP_UDIV_ALT = opcode_values[E_OP_UDIV_ALT]; OP_ADD = opcode_values[E_OP_ADD]; OP_SUB = opcode_values[E_OP_SUB];
OP_SUB_ALT = opcode_values[E_OP_SUB_ALT]; OP_AND = opcode_values[E_OP_AND]; OP_OR = opcode_values[E_OP_OR];
OP_XOR = opcode_values[E_OP_XOR]; OP_NOT = opcode_values[E_OP_NOT]; OP_NEG = opcode_values[E_OP_NEG];
OP_INVERT = opcode_values[E_OP_INVERT]; OP_ADD_C = opcode_values[E_OP_ADD_C]; OP_SMUL_C = opcode_values[E_OP_SMUL_C];
OP_ZERO_PRI = opcode_values[E_OP_ZERO_PRI]; OP_ZERO_ALT = opcode_values[E_OP_ZERO_ALT]; OP_ZERO = opcode_values[E_OP_ZERO];
OP_ZERO_S = opcode_values[E_OP_ZERO_S]; OP_SIGN_PRI = opcode_values[E_OP_SIGN_PRI]; OP_SIGN_ALT = opcode_values[E_OP_SIGN_ALT];
OP_EQ = opcode_values[E_OP_EQ]; OP_NEQ = opcode_values[E_OP_NEQ]; OP_LESS = opcode_values[E_OP_LESS];
OP_LEQ = opcode_values[E_OP_LEQ]; OP_GRTR = opcode_values[E_OP_GRTR]; OP_GEQ = opcode_values[E_OP_GEQ];
OP_SLESS = opcode_values[E_OP_SLESS]; OP_SLEQ = opcode_values[E_OP_SLEQ]; OP_SGRTR = opcode_values[E_OP_SGRTR];
OP_SGEQ = opcode_values[E_OP_SGEQ]; OP_EQ_C_PRI = opcode_values[E_OP_EQ_C_PRI]; OP_EQ_C_ALT = opcode_values[E_OP_EQ_C_ALT];
OP_INC_PRI = opcode_values[E_OP_INC_PRI]; OP_INC_ALT = opcode_values[E_OP_INC_ALT]; OP_INC = opcode_values[E_OP_INC];
OP_INC_S = opcode_values[E_OP_INC_S]; OP_INC_I = opcode_values[E_OP_INC_I]; OP_DEC_PRI = opcode_values[E_OP_DEC_PRI];
OP_DEC_ALT = opcode_values[E_OP_DEC_ALT]; OP_DEC = opcode_values[E_OP_DEC]; OP_DEC_S = opcode_values[E_OP_DEC_S];
OP_DEC_I = opcode_values[E_OP_DEC_I]; OP_MOVS = opcode_values[E_OP_MOVS]; OP_CMPS = opcode_values[E_OP_CMPS];
OP_FILL = opcode_values[E_OP_FILL]; OP_HALT = opcode_values[E_OP_HALT]; OP_BOUNDS = opcode_values[E_OP_BOUNDS];
OP_SYSREQ_PRI = opcode_values[E_OP_SYSREQ_PRI]; OP_SYSREQ_C = opcode_values[E_OP_SYSREQ_C]; OP_JUMP_PRI = opcode_values[E_OP_JUMP_PRI];
// OP_SWITCH = opcode_values[E_OP_SWITCH];
// OP_CASETBL = opcode_values[E_OP_OP_CASETBL];
OP_SWAP_PRI = opcode_values[E_OP_SWAP_PRI]; OP_SWAP_ALT = opcode_values[E_OP_SWAP_ALT]; OP_PUSH_ADR = opcode_values[E_OP_PUSH_ADR];
OP_NOP = opcode_values[E_OP_NOP]; OP_BREAK = opcode_values[E_OP_BREAK];
}

stock _LoadOpcodes() {
// Return the address of "LOAD.pri" below
#emit LCTRL 6
#emit MOVE.alt
#emit LCTRL 0
#emit ADD
#emit MOVE.alt
#emit LCTRL 1
#emit SUB.alt
#emit ADD.C 44
#emit RETN

// The values of the parameters are insignificant, but they must to be there.
#emit LOAD.pri 1 // 1
#emit LOAD.alt 2 // 2
#emit LOAD.S.pri 3 // 3
#emit LOAD.S.alt 4 // 4
#emit LREF.pri 5 // 5
#emit LREF.alt 6 // 6
#emit LREF.S.pri 7 // 7
#emit LREF.S.alt 8 // 8
#emit LOAD.I // 9
#emit LODB.I 10 // 10
#emit CONST.pri 11 // 11
#emit CONST.alt 12 // 12
#emit ADDR.pri 13 // 13
#emit ADDR.alt 14 // 14
#emit STOR.pri 15 // 15
#emit STOR.alt 16 // 16
#emit STOR.S.pri 17 // 17
#emit STOR.S.alt 18 // 18
#emit SREF.pri 19 // 19
#emit SREF.alt 20 // 20
#emit SREF.S.pri 21 // 21
#emit SREF.S.alt 22 // 22
#emit STOR.I // 23
#emit STRB.I 24 // 24
#emit LIDX // 25
#emit LIDX.B 26 // 26
#emit IDXADDR // 27
#emit IDXADDR.B 28 // 28
#emit ALIGN.pri 29 // 29
#emit ALIGN.alt 30 // 30
#emit LCTRL 31 // 31
#emit SCTRL 32 // 32
#emit MOVE.pri // 33
#emit MOVE.alt // 34
#emit XCHG // 35
#emit PUSH.pri // 36
#emit PUSH.alt // 37
#emit PUSH.R 38 // 38
#emit PUSH.C 39 // 39
#emit PUSH 40 // 40
#emit PUSH.S 41 // 41
#emit POP.pri // 42
#emit POP.alt // 43
#emit STACK 44 // 44
#emit HEAP 45 // 45
#emit PROC // 46
#emit RET // 47
#emit RETN // 48
// #emit CALL 49 // 49
#emit CALL.pri // 50
// #emit JUMP 51 // 51
// #emit JREL 52 // 52
// #emit JZER 53 // 53
// #emit JNZ 54 // 54
// #emit JEQ 55 // 55
// #emit JNEQ 56 // 56
// #emit JLESS 57 // 57
// #emit JLEQ 58 // 58
// #emit JGRTR 59 // 59
// #emit JGEQ 60 // 60
// #emit JSLESS 61 // 61
// #emit JSLEQ 62 // 62
// #emit JSGRTR 63 // 63
// #emit JSGEQ 64 // 64
#emit SHL // 65
#emit SHR // 66
#emit SSHR // 67
#emit SHL.C.pri 68 // 68
#emit SHL.C.alt 69 // 69
#emit SHR.C.pri 70 // 70
#emit SHR.C.alt 71 // 71
#emit SMUL // 72
#emit SDIV // 73
#emit SDIV.alt // 74
#emit UMUL // 75
#emit UDIV // 76
#emit UDIV.alt // 77
#emit ADD // 78
#emit SUB // 79
#emit SUB.alt // 80
#emit AND // 81
#emit OR // 82
#emit XOR // 83
#emit NOT // 84
#emit NEG // 85
#emit INVERT // 86
#emit ADD.C 87 // 87
#emit SMUL.C 88 // 88
#emit ZERO.pri // 89
#emit ZERO.alt // 90
#emit ZERO 91 // 91
#emit ZERO.S 92 // 92
#emit SIGN.pri // 93
#emit SIGN.alt // 94
#emit EQ // 95
#emit NEQ // 96
#emit LESS // 97
#emit LEQ // 98
#emit GRTR // 99
#emit GEQ // 100
#emit SLESS // 101
#emit SLEQ // 102
#emit SGRTR // 103
#emit SGEQ // 104
#emit EQ.C.pri 105 // 105
#emit EQ.C.alt 106 // 106
#emit INC.pri // 107
#emit INC.alt // 108
#emit INC 109 // 109
#emit INC.S 110 // 110
#emit INC.I // 111
#emit DEC.pri // 112
#emit DEC.alt // 113
#emit DEC 114 // 114
#emit DEC.S 115 // 115
#emit DEC.I // 116
#emit MOVS 117 // 117
#emit CMPS 118 // 118
#emit FILL 119 // 119
#emit HALT 120 // 120
#emit BOUNDS 121 // 121
#emit SYSREQ.pri // 122
#emit SYSREQ.C 123 // 123
#emit JUMP.pri // 128
// #emit SWITCH 129 // 129
// #emit CASETBL // 130
#emit SWAP.pri // 131
#emit SWAP.alt // 132
#emit PUSH.ADR 133 // 133
#emit NOP // 134
#emit BREAK // 137

return 0;
}

Y_Less
09/07/2012, 12:59 PM
Nice. I will have to try this on my new include. I never would have considered just embracing the problem. How consistent are the values in your tests for one mode run?

Slice
09/07/2012, 01:12 PM
It seems to have to do with the number of unique opcodes used, or at least I suspect so.

The values on Linux are absolute pointers, though it gets even more mysterious here.. I collected a few values that the opcode values pointed to, reversed the byte order, and came up with this:
Look at ALIGN.alt/ALIGN.pri! While their pointers were different, they pointed to the same values (perhaps some sort of struct with the same info in the beginning, who knows).

(the lines that are grouped are next to each other in amx.h).

/*
Values for opcodes:

ADD - 0x8B55C089 - 0b10001011010101011100000010001001
ADD.C - 0x8B168D46 - 0b10001011000101101000110101000110
ADDR.alt - 0x8B55C08D - 0b10001011010101011100000010001101
ADDR.pri - 0x8B4DC08D - 0b10001011010011011100000010001101
ALIGN.alt - 0x8B0683C6 - 0b10001011000001101000001111000110
ALIGN.pri - 0x8B0683C6 - 0b10001011000001101000001111000110

JZER - 0x8B45E485 - 0b10001011010001011110010010000101
LCTRL - 0x833E068D - 0b10000011001111100000011010001101

MOVE.alt - 0x8B4DE489 - 0b10001011010011011110010010001001
MOVE.pri - 0x8B55C089 - 0b10001011010101011100000010001001
MOVS - 0x8B45E48B - 0b10001011010001011110010010001011

NEG - 0x8B4DC089 - 0b10001011010011011100000010001001
NEQ - 0x8B4DBC31 - 0b10001011010011011011110000110001
NOP - 0x8B7DC089 - 0b10001011011111011100000010001001

PUSH.alt - 0x8B45BC8D - 0b10001011010001011011110010001101
PUSH.pri - 0x8B45E48D - 0b10001011010001011110010010001101
*/

pujan
09/07/2012, 02:33 PM
Are you suggesting polymorphism?

Y_Less
09/07/2012, 02:43 PM
This is just code to make it work on Linux. There are already two releases with self-modifying code, amazingly both from less than a day before this topic was made:

http://forum.sa-mp.com/showthread.php?t=357881
http://forum.sa-mp.com/showthread.php?p=1974747#post1974747

So polymorphic code is possible (but I don't think it works with the JIT plugin unless there is some way to force recompilation), but not overly easy unless currently (of course, all these things get easier over time as more is done on them).

JoBullet
09/07/2012, 04:47 PM
It perhaps has to do with that trickery of opcode_list. One should inspect amx sources to be sure of (or to get to know) the reason of this behaviour.

Slice
09/07/2012, 05:24 PM
I think the values read are addresses to labels in amx.c. That's why many of them look similar, they all start with GETPARAM(offs) and some other stuff.

Edit:
/* GNU C version uses the "labels as values" extension to create
* fast "indirect threaded" interpreter. The Intel C/C++ compiler
* supports this too.
*/

JoBullet
10/07/2012, 12:09 PM
Well, you do not actually need to care about values you get(pointer values could change across releases).
By the way, here are excerpts from amx.c so you can see that your values are pointers to opcode labels(token threading technique <wiki (http://en.wikipedia.org/wiki/Threaded_code#Token_threading)>):

#if (defined __GNUC__ || defined __ICC || defined ASM32 || defined JIT) && !defined AMX_TOKENTHREADING
/* relocate opcode (only works if the size of an opcode is at least
* as big as the size of a pointer (jump address); so basically we
* rely on the opcode and a pointer being 32-bit
*/
*(cell *)(code+(int)cip) = opcode_list[op];
#endif


static const void * const amx_opcodelist[] = {
&&op_none, &&op_load_pri, &&op_load_alt, &&op_load_s_pri,
&&op_load_s_alt,&&op_lref_pri, &&op_lref_alt, &&op_lref_s_pri,
&&op_lref_s_alt,&&op_load_i, &&op_lodb_i, &&op_const_pri,
&&op_const_alt, &&op_addr_pri, &&op_addr_alt, &&op_stor_pri,
&&op_stor_alt, &&op_stor_s_pri,&&op_stor_s_alt,&&op_sref_pri,
&&op_sref_alt, &&op_sref_s_pri,&&op_sref_s_alt,&&op_stor_i,
&&op_strb_i, &&op_lidx, &&op_lidx_b, &&op_idxaddr,
&&op_idxaddr_b, &&op_align_pri, &&op_align_alt, &&op_lctrl,
&&op_sctrl, &&op_move_pri, &&op_move_alt, &&op_xchg,
&&op_push_pri, &&op_push_alt, &&op_push_r, &&op_push_c,
&&op_push, &&op_push_s, &&op_pop_pri, &&op_pop_alt,
&&op_stack, &&op_heap, &&op_proc, &&op_ret,
&&op_retn, &&op_call, &&op_call_pri, &&op_jump,
&&op_jrel, &&op_jzer, &&op_jnz, &&op_jeq,
&&op_jneq, &&op_jless, &&op_jleq, &&op_jgrtr,
&&op_jgeq, &&op_jsless, &&op_jsleq, &&op_jsgrtr,
&&op_jsgeq, &&op_shl, &&op_shr, &&op_sshr,
&&op_shl_c_pri, &&op_shl_c_alt, &&op_shr_c_pri, &&op_shr_c_alt,
&&op_smul, &&op_sdiv, &&op_sdiv_alt, &&op_umul,
&&op_udiv, &&op_udiv_alt, &&op_add, &&op_sub,
&&op_sub_alt, &&op_and, &&op_or, &&op_xor,
&&op_not, &&op_neg, &&op_invert, &&op_add_c,
&&op_smul_c, &&op_zero_pri, &&op_zero_alt, &&op_zero,
&&op_zero_s, &&op_sign_pri, &&op_sign_alt, &&op_eq,
&&op_neq, &&op_less, &&op_leq, &&op_grtr,
&&op_geq, &&op_sless, &&op_sleq, &&op_sgrtr,
&&op_sgeq, &&op_eq_c_pri, &&op_eq_c_alt, &&op_inc_pri,
&&op_inc_alt, &&op_inc, &&op_inc_s, &&op_inc_i,
&&op_dec_pri, &&op_dec_alt, &&op_dec, &&op_dec_s,
&&op_dec_i, &&op_movs, &&op_cmps, &&op_fill,
&&op_halt, &&op_bounds, &&op_sysreq_pri,&&op_sysreq_c,
&&op_file, &&op_line, &&op_symbol, &&op_srange,
&&op_jump_pri, &&op_switch, &&op_casetbl, &&op_swap_pri,
&&op_swap_alt, &&op_push_adr, &&op_nop, &&op_sysreq_n,
&&op_symtag, &&op_break, &&op_push2_c, &&op_push2,
&&op_push2_s, &&op_push2_adr, &&op_push3_c, &&op_push3,
&&op_push3_s, &&op_push3_adr, &&op_push4_c, &&op_push4,
&&op_push4_s, &&op_push4_adr, &&op_push5_c, &&op_push5,
&&op_push5_s, &&op_push5_adr, &&op_load_both, &&op_load_s_both,
&&op_const, &&op_const_s,
#if !defined AMX_NO_PACKED_OPC
&&op_load_p_pri, &&op_load_p_alt, &&op_load_p_s_pri,&&op_load_p_s_alt,
&&op_lref_p_pri, &&op_lref_p_alt, &&op_lref_p_s_pri,&&op_lref_p_s_alt,
&&op_lodb_p_i, &&op_const_p_pri,&&op_const_p_alt, &&op_addr_p_pri,
&&op_addr_p_alt, &&op_stor_p_pri, &&op_stor_p_alt, &&op_stor_p_s_pri,
&&op_stor_p_s_alt,&&op_sref_p_pri, &&op_sref_p_alt, &&op_sref_p_s_pri,
&&op_sref_p_s_alt,&&op_strb_p_i, &&op_lidx_p_b, &&op_idxaddr_p_b,
&&op_align_p_pri, &&op_align_p_alt,&&op_push_p_c, &&op_push_p,
&&op_push_p_s, &&op_stack_p, &&op_heap_p, &&op_shl_p_c_pri,
&&op_shl_p_c_alt, &&op_shr_p_c_pri,&&op_shr_p_c_alt, &&op_add_p_c,
&&op_smul_p_c, &&op_zero_p, &&op_zero_p_s, &&op_eq_p_c_pri,
&&op_eq_p_c_alt, &&op_inc_p, &&op_inc_p_s, &&op_dec_p,
&&op_dec_p_s, &&op_movs_p, &&op_cmps_p, &&op_fill_p,
&&op_halt_p, &&op_bounds_p, &&op_push_p_adr,
#endif
&&op_sysreq_d, &&op_sysreq_nd };

Note 1: && is special GNUC construction to get a label's address.
Note 2: that opcode_list is actually amx_opcodelist.
This is kind of proof that your code should work(if there's no error in your implementation, though I did not see any.)

Slice
10/07/2012, 12:38 PM
The only little issue that remains is you can't emit SYSREQ.D with #emit because it requires 2 params (only opcodes with 1 param works in #emit due to a bug).
I suppose searching for like 5 pointers in a row would get us the location of amx_opcodelist, which then would get us the pointer for op_sysreq_d.

JoBullet
10/07/2012, 12:42 PM
You could perhaps get "op_const_s"(the opcode before op_sysreq_d, note that AMX_NO_PACKED_OPC is undefined, thus not accounted for) opcode pointer and increment it by 4 (because we can assert that amx_opcodelist structure won't change and AMX_NO_PACKED_OPC was not defined at time of compiling compiler)
thus getting us address of op_sysreq_d.

Slice
10/07/2012, 12:49 PM
The problem is all those opcodes above op_sysreq_d require more than 1 params, which can't be emitted with the original PAWN compiler.

Edit: Oh, you mean like that.. Of course!

Edit2: The values read from COD are pointers directly to the labels, so that won't work. :(

JoBullet
10/07/2012, 01:26 PM
Seems like SYSREQ.d was replaced with SYSREQ.n

{135, "sysreq.n", sIN_CSEG, parm2 }, /* version 9 (replaces SYSREQ.d from earlier version) */

and SYSREQ.n can be compiled(with 1 param though but we do not care about that because we add additional one manually).

Slice
10/07/2012, 01:53 PM
That doesn't work as it seems to silently fail when loading the AMX.

http://slice-vps.nl/ppg/#gist=58965657788cc6b3acd7

JoBullet
10/07/2012, 02:50 PM
Then only alternative i can think of is looking up in IDA to see raw difference between labels, i.e. (op_sysreq_d - op_const_s) and using that when you want to get op_sysreq_d label(i.e. place op_const_s at some offset where you want op_sysreq_d and increment its value by pointer difference, which should be constant across releases)

Slice
10/07/2012, 02:59 PM
What I don't like about that, though, is if opcodes were to change (they have in the past). Maybe not even changed, but different compiler optimizations could change the size as well.

Xentiarox
11/07/2012, 12:19 AM
tl;dr but this is going to be scary, probably you even can create maliscious code with that that almost nobody understands and put it into an 'usefull' include! :o