Merge pull request #34 from akkartik/survey
SubX in SubX: computing addresses for labels
This commit is contained in:
commit
c4aa819a5d
|
@ -273,6 +273,7 @@ int main(int argc, char* argv[]) {
|
|||
search(Current_search_pattern, opposite(Current_search_direction));
|
||||
}
|
||||
}
|
||||
tb_clear();
|
||||
tb_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -203,6 +203,7 @@ inline uint8_t* mem_addr_u8(uint32_t addr) {
|
|||
if (result == NULL) {
|
||||
if (Trace_file) Trace_file.flush();
|
||||
raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end();
|
||||
exit(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -293,7 +294,6 @@ void run_one_instruction() {
|
|||
// End Two-Byte Opcodes Starting With 0f
|
||||
default:
|
||||
cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -305,13 +305,11 @@ void run_one_instruction() {
|
|||
// End Three-Byte Opcodes Starting With f2 0f
|
||||
default:
|
||||
cerr << "unrecognized third opcode after f2 0f: " << HEXBYTE << NUM(op3) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "unrecognized second opcode after f2: " << HEXBYTE << NUM(op2) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -323,19 +321,16 @@ void run_one_instruction() {
|
|||
// End Three-Byte Opcodes Starting With f3 0f
|
||||
default:
|
||||
cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1103,7 +1103,6 @@ case 0xff: {
|
|||
}
|
||||
default:
|
||||
cerr << "unrecognized subop for ff: " << HEXBYTE << NUM(subop) << '\n';
|
||||
DUMP("");
|
||||
exit(1);
|
||||
// End Op ff Subops
|
||||
}
|
||||
|
|
|
@ -874,7 +874,7 @@ void test_add_r32_to_mem_at_r32_plus_disp8() {
|
|||
}
|
||||
|
||||
:(before "End Mod Special-cases(addr)")
|
||||
case 1: // indirect + disp8 addressing
|
||||
case 1: { // indirect + disp8 addressing
|
||||
switch (rm) {
|
||||
default:
|
||||
addr = Reg[rm].u;
|
||||
|
@ -882,11 +882,16 @@ case 1: // indirect + disp8 addressing
|
|||
break;
|
||||
// End Mod 1 Special-cases(addr)
|
||||
}
|
||||
int8_t displacement = static_cast<int8_t>(next());
|
||||
if (addr > 0) {
|
||||
addr += static_cast<int8_t>(next());
|
||||
addr += displacement;
|
||||
trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding disp8)" << end();
|
||||
}
|
||||
else {
|
||||
trace(Callstack_depth+1, "run") << "null address; skipping displacement" << end();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
:(code)
|
||||
void test_add_r32_to_mem_at_r32_plus_negative_disp8() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
put_new(Name, "eb", "jump disp8 bytes away (jmp)");
|
||||
|
||||
:(code)
|
||||
void test_jump_rel8() {
|
||||
void test_jump_disp8() {
|
||||
run(
|
||||
"== code 0x1\n"
|
||||
// op ModR/M SIB displacement immediate
|
||||
|
@ -23,7 +23,7 @@ void test_jump_rel8() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0xeb: { // jump rel8
|
||||
case 0xeb: { // jump disp8
|
||||
int8_t offset = static_cast<int>(next());
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
EIP += offset;
|
||||
|
@ -36,7 +36,7 @@ case 0xeb: { // jump rel8
|
|||
put_new(Name, "74", "jump disp8 bytes away if equal, if ZF is set (jcc/jz/je)");
|
||||
|
||||
:(code)
|
||||
void test_je_rel8_success() {
|
||||
void test_je_disp8_success() {
|
||||
ZF = true;
|
||||
run(
|
||||
"== code 0x1\n"
|
||||
|
@ -54,7 +54,7 @@ void test_je_rel8_success() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0x74: { // jump rel8 if ZF
|
||||
case 0x74: { // jump disp8 if ZF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -64,7 +64,7 @@ case 0x74: { // jump rel8 if ZF
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_je_rel8_fail() {
|
||||
void test_je_disp8_fail() {
|
||||
ZF = false;
|
||||
run(
|
||||
"== code 0x1\n"
|
||||
|
@ -87,7 +87,7 @@ void test_je_rel8_fail() {
|
|||
put_new(Name, "75", "jump disp8 bytes away if not equal, if ZF is not set (jcc/jnz/jne)");
|
||||
|
||||
:(code)
|
||||
void test_jne_rel8_success() {
|
||||
void test_jne_disp8_success() {
|
||||
ZF = false;
|
||||
run(
|
||||
"== code 0x1\n"
|
||||
|
@ -105,7 +105,7 @@ void test_jne_rel8_success() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0x75: { // jump rel8 unless ZF
|
||||
case 0x75: { // jump disp8 unless ZF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (!ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -115,7 +115,7 @@ case 0x75: { // jump rel8 unless ZF
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_jne_rel8_fail() {
|
||||
void test_jne_disp8_fail() {
|
||||
ZF = true;
|
||||
run(
|
||||
"== code 0x1\n"
|
||||
|
@ -139,7 +139,7 @@ put_new(Name, "7f", "jump disp8 bytes away if greater (signed), if ZF is unset a
|
|||
put_new(Name, "77", "jump disp8 bytes away if greater (unsigned), if ZF is unset and CF is unset (jcc/ja/jnbe)");
|
||||
|
||||
:(code)
|
||||
void test_jg_rel8_success() {
|
||||
void test_jg_disp8_success() {
|
||||
ZF = false;
|
||||
SF = false;
|
||||
OF = false;
|
||||
|
@ -159,7 +159,7 @@ void test_jg_rel8_success() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0x7f: { // jump rel8 if SF == OF and !ZF
|
||||
case 0x7f: { // jump disp8 if SF == OF and !ZF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (SF == OF && !ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -167,7 +167,7 @@ case 0x7f: { // jump rel8 if SF == OF and !ZF
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 0x77: { // jump rel8 if !CF and !ZF
|
||||
case 0x77: { // jump disp8 if !CF and !ZF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (!CF && !ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -177,7 +177,7 @@ case 0x77: { // jump rel8 if !CF and !ZF
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_jg_rel8_fail() {
|
||||
void test_jg_disp8_fail() {
|
||||
ZF = false;
|
||||
SF = true;
|
||||
OF = false;
|
||||
|
@ -203,7 +203,7 @@ put_new(Name, "7d", "jump disp8 bytes away if greater or equal (signed), if SF =
|
|||
put_new(Name, "73", "jump disp8 bytes away if greater or equal (unsigned), if CF is unset (jcc/jae/jnb)");
|
||||
|
||||
:(code)
|
||||
void test_jge_rel8_success() {
|
||||
void test_jge_disp8_success() {
|
||||
SF = false;
|
||||
OF = false;
|
||||
run(
|
||||
|
@ -222,7 +222,7 @@ void test_jge_rel8_success() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0x7d: { // jump rel8 if SF == OF
|
||||
case 0x7d: { // jump disp8 if SF == OF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (SF == OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -230,7 +230,7 @@ case 0x7d: { // jump rel8 if SF == OF
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 0x73: { // jump rel8 if !CF
|
||||
case 0x73: { // jump disp8 if !CF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (!CF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -240,7 +240,7 @@ case 0x73: { // jump rel8 if !CF
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_jge_rel8_fail() {
|
||||
void test_jge_disp8_fail() {
|
||||
SF = true;
|
||||
OF = false;
|
||||
run(
|
||||
|
@ -265,7 +265,7 @@ put_new(Name, "7c", "jump disp8 bytes away if lesser (signed), if SF != OF (jcc/
|
|||
put_new(Name, "72", "jump disp8 bytes away if lesser (unsigned), if CF is set (jcc/jb/jnae)");
|
||||
|
||||
:(code)
|
||||
void test_jl_rel8_success() {
|
||||
void test_jl_disp8_success() {
|
||||
ZF = false;
|
||||
SF = true;
|
||||
OF = false;
|
||||
|
@ -285,7 +285,7 @@ void test_jl_rel8_success() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0x7c: { // jump rel8 if SF != OF
|
||||
case 0x7c: { // jump disp8 if SF != OF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (SF != OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -293,7 +293,7 @@ case 0x7c: { // jump rel8 if SF != OF
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 0x72: { // jump rel8 if CF
|
||||
case 0x72: { // jump disp8 if CF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (CF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -303,7 +303,7 @@ case 0x72: { // jump rel8 if CF
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_jl_rel8_fail() {
|
||||
void test_jl_disp8_fail() {
|
||||
ZF = false;
|
||||
SF = false;
|
||||
OF = false;
|
||||
|
@ -329,7 +329,7 @@ put_new(Name, "7e", "jump disp8 bytes away if lesser or equal (signed), if ZF is
|
|||
put_new(Name, "76", "jump disp8 bytes away if lesser or equal (unsigned), if ZF is set or CF is set (jcc/jbe/jna)");
|
||||
|
||||
:(code)
|
||||
void test_jle_rel8_equal() {
|
||||
void test_jle_disp8_equal() {
|
||||
ZF = true;
|
||||
SF = false;
|
||||
OF = false;
|
||||
|
@ -349,7 +349,7 @@ void test_jle_rel8_equal() {
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_jle_rel8_lesser() {
|
||||
void test_jle_disp8_lesser() {
|
||||
ZF = false;
|
||||
SF = true;
|
||||
OF = false;
|
||||
|
@ -369,7 +369,7 @@ void test_jle_rel8_lesser() {
|
|||
}
|
||||
|
||||
:(before "End Single-Byte Opcodes")
|
||||
case 0x7e: { // jump rel8 if ZF or SF != OF
|
||||
case 0x7e: { // jump disp8 if ZF or SF != OF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (ZF || SF != OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -377,7 +377,7 @@ case 0x7e: { // jump rel8 if ZF or SF != OF
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 0x76: { // jump rel8 if ZF or CF
|
||||
case 0x76: { // jump disp8 if ZF or CF
|
||||
const int8_t offset = static_cast<int>(next());
|
||||
if (ZF || CF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
|
@ -387,7 +387,7 @@ case 0x76: { // jump rel8 if ZF or CF
|
|||
}
|
||||
|
||||
:(code)
|
||||
void test_jle_rel8_greater() {
|
||||
void test_jle_disp8_greater() {
|
||||
ZF = false;
|
||||
SF = false;
|
||||
OF = false;
|
||||
|
|
|
@ -57,7 +57,7 @@ void test_je_disp32_success() {
|
|||
case 0x84: { // jump disp32 if ZF
|
||||
const int32_t offset = next32();
|
||||
if (ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
|
@ -108,7 +108,7 @@ void test_jne_disp32_success() {
|
|||
case 0x85: { // jump disp32 unless ZF
|
||||
const int32_t offset = next32();
|
||||
if (!ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
|
@ -135,7 +135,8 @@ void test_jne_disp32_fail() {
|
|||
//:: jump if greater
|
||||
|
||||
:(before "End Initialize Op Names")
|
||||
put_new(Name_0f, "8f", "jump disp32 bytes away if greater, if ZF is unset and SF == OF (jcc/jg/jnle)");
|
||||
put_new(Name_0f, "8f", "jump disp32 bytes away if greater (signed), if ZF is unset and SF == OF (jcc/jg/jnle)");
|
||||
put_new(Name_0f, "87", "jump disp32 bytes away if greater (unsigned), if ZF is unset and CF is unset (jcc/ja/jnbe)");
|
||||
|
||||
:(code)
|
||||
void test_jg_disp32_success() {
|
||||
|
@ -161,7 +162,15 @@ void test_jg_disp32_success() {
|
|||
case 0x8f: { // jump disp32 if !SF and !ZF
|
||||
const int32_t offset = next32();
|
||||
if (!ZF && SF == OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x87: { // jump disp32 if !CF and !ZF
|
||||
const int32_t offset = next();
|
||||
if (!CF && !ZF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
|
@ -190,7 +199,8 @@ void test_jg_disp32_fail() {
|
|||
//:: jump if greater or equal
|
||||
|
||||
:(before "End Initialize Op Names")
|
||||
put_new(Name_0f, "8d", "jump disp32 bytes away if greater or equal, if SF == OF (jcc/jge/jnl)");
|
||||
put_new(Name_0f, "8d", "jump disp32 bytes away if greater or equal (signed), if SF == OF (jcc/jge/jnl)");
|
||||
put_new(Name_0f, "83", "jump disp32 bytes away if greater or equal (unsigned), if CF is unset (jcc/jae/jnb)");
|
||||
|
||||
:(code)
|
||||
void test_jge_disp32_success() {
|
||||
|
@ -215,7 +225,15 @@ void test_jge_disp32_success() {
|
|||
case 0x8d: { // jump disp32 if !SF
|
||||
const int32_t offset = next32();
|
||||
if (SF == OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x83: { // jump disp32 if !CF
|
||||
const int32_t offset = next32();
|
||||
if (!CF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
|
@ -243,7 +261,8 @@ void test_jge_disp32_fail() {
|
|||
//:: jump if lesser
|
||||
|
||||
:(before "End Initialize Op Names")
|
||||
put_new(Name_0f, "8c", "jump disp32 bytes away if lesser, if SF != OF (jcc/jl/jnge)");
|
||||
put_new(Name_0f, "8c", "jump disp32 bytes away if lesser (signed), if SF != OF (jcc/jl/jnge)");
|
||||
put_new(Name_0f, "82", "jump disp32 bytes away if lesser (unsigned), if CF is set (jcc/jb/jnae)");
|
||||
|
||||
:(code)
|
||||
void test_jl_disp32_success() {
|
||||
|
@ -269,7 +288,15 @@ void test_jl_disp32_success() {
|
|||
case 0x8c: { // jump disp32 if SF and !ZF
|
||||
const int32_t offset = next32();
|
||||
if (SF != OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x72: { // jump disp32 if CF
|
||||
const int32_t offset = next32();
|
||||
if (CF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
|
@ -298,7 +325,8 @@ void test_jl_disp32_fail() {
|
|||
//:: jump if lesser or equal
|
||||
|
||||
:(before "End Initialize Op Names")
|
||||
put_new(Name_0f, "8e", "jump disp32 bytes away if lesser or equal, if ZF is set or SF != OF (jcc/jle/jng)");
|
||||
put_new(Name_0f, "8e", "jump disp32 bytes away if lesser or equal (signed), if ZF is set or SF != OF (jcc/jle/jng)");
|
||||
put_new(Name_0f, "86", "jump disp8 bytes away if lesser or equal (unsigned), if ZF is set or CF is set (jcc/jbe/jna)");
|
||||
|
||||
:(code)
|
||||
void test_jle_disp32_equal() {
|
||||
|
@ -344,7 +372,15 @@ void test_jle_disp32_lesser() {
|
|||
case 0x8e: { // jump disp32 if SF or ZF
|
||||
const int32_t offset = next32();
|
||||
if (ZF || SF != OF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x86: { // jump disp32 if ZF or CF
|
||||
const int32_t offset = next32();
|
||||
if (ZF || CF) {
|
||||
trace(Callstack_depth+1, "run") << "jump " << offset << end();
|
||||
EIP += offset;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -162,7 +162,7 @@ case 0xc6: { // copy imm8 to r/m8
|
|||
const uint8_t modrm = next();
|
||||
const uint8_t src = next();
|
||||
trace(Callstack_depth+1, "run") << "copy imm8 to r8/m8-at-r32" << end();
|
||||
trace(Callstack_depth+1, "run") << "imm8 is 0x" << HEXWORD << src << end();
|
||||
trace(Callstack_depth+1, "run") << "imm8 is 0x" << HEXWORD << NUM(src) << end();
|
||||
const uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits
|
||||
if (subop != 0) {
|
||||
cerr << "unrecognized subop for opcode c6: " << NUM(subop) << " (only 0/copy currently implemented)\n";
|
||||
|
|
|
@ -225,12 +225,11 @@ void init_permitted_operands() {
|
|||
put(Permitted_operands, "87", 0x01);
|
||||
// copy address (lea)
|
||||
put(Permitted_operands, "8d", 0x01);
|
||||
// pop
|
||||
put(Permitted_operands, "8f", 0x01);
|
||||
|
||||
//// Class N: op, ModR/M and subop (not r32)
|
||||
// imm32 imm8 disp32 |disp16 disp8 subop modrm
|
||||
// 0 0 0 |0 0 1 1
|
||||
put(Permitted_operands, "8f", 0x03); // pop
|
||||
put(Permitted_operands, "d3", 0x03); // shift
|
||||
put(Permitted_operands, "f7", 0x03); // test/not/mul/div
|
||||
put(Permitted_operands, "ff", 0x03); // jump/push/call
|
||||
|
@ -627,8 +626,12 @@ map</*op*/string, /*bitvector*/uint8_t> Permitted_operands_0f;
|
|||
//// Class D: just op and disp32
|
||||
// imm32 imm8 disp32 |disp16 disp8 subop modrm
|
||||
// 0 0 1 |0 0 0 0
|
||||
put_new(Permitted_operands_0f, "82", 0x10);
|
||||
put_new(Permitted_operands_0f, "83", 0x10);
|
||||
put_new(Permitted_operands_0f, "84", 0x10);
|
||||
put_new(Permitted_operands_0f, "85", 0x10);
|
||||
put_new(Permitted_operands_0f, "86", 0x10);
|
||||
put_new(Permitted_operands_0f, "87", 0x10);
|
||||
put_new(Permitted_operands_0f, "8c", 0x10);
|
||||
put_new(Permitted_operands_0f, "8d", 0x10);
|
||||
put_new(Permitted_operands_0f, "8e", 0x10);
|
||||
|
|
|
@ -74,9 +74,9 @@ Watch_points.clear();
|
|||
:(code)
|
||||
void dump_watch_points() {
|
||||
if (Watch_points.empty()) return;
|
||||
dbg << "watch points:" << end();
|
||||
trace(Callstack_depth, "dbg") << "watch points:" << end();
|
||||
for (map<string, uint32_t>::iterator p = Watch_points.begin(); p != Watch_points.end(); ++p)
|
||||
dbg << " " << p->first << ": " << HEXWORD << p->second << " -> " << HEXWORD << read_mem_u32(p->second) << end();
|
||||
trace(Callstack_depth, "dbg") << " " << p->first << ": " << HEXWORD << p->second << " -> " << HEXWORD << read_mem_u32(p->second) << end();
|
||||
}
|
||||
|
||||
:(before "End Globals")
|
||||
|
@ -91,6 +91,20 @@ if (!Watch_this_effective_address.empty()) {
|
|||
put(Watch_points, Watch_this_effective_address, addr);
|
||||
}
|
||||
|
||||
//: Special label that dumps regions of memory.
|
||||
//: Not a general mechanism; by the time you get here you're willing to hack
|
||||
//: on the emulator.
|
||||
:(after "Run One Instruction")
|
||||
if (contains_key(Symbol_name, EIP) && get(Symbol_name, EIP) == "$dump-stream-at-EAX")
|
||||
dump_stream_at(Reg[EAX].u);
|
||||
:(code)
|
||||
void dump_stream_at(uint32_t stream_start) {
|
||||
int32_t stream_length = read_mem_i32(stream_start + 8);
|
||||
dbg << "stream length: " << std::dec << stream_length << end();
|
||||
for (int i = 0; i < stream_length + 12; ++i)
|
||||
dbg << "0x" << HEXWORD << (stream_start+i) << ": " << HEXBYTE << NUM(read_mem_u8(stream_start+i)) << end();
|
||||
}
|
||||
|
||||
//: helpers
|
||||
|
||||
:(code)
|
||||
|
|
|
@ -15,22 +15,20 @@ Entry: # run all tests
|
|||
|
||||
string-equal?: # s : (address string), benchmark : (address string) -> EAX : boolean
|
||||
# pseudocode:
|
||||
# lens = s->length
|
||||
# if (lens != benchmark->length) return false
|
||||
# i = 0
|
||||
# if (s->length != benchmark->length) return false
|
||||
# currs = s->data
|
||||
# currb = benchmark->data
|
||||
# while i < s->length
|
||||
# maxs = s->data + s->length
|
||||
# while currs < maxs
|
||||
# c1 = *currs
|
||||
# c2 = *currb
|
||||
# if (c1 != c2) return false
|
||||
# ++i, ++currs, ++currb
|
||||
# ++currs, ++currb
|
||||
# return true
|
||||
#
|
||||
# registers:
|
||||
# i: ECX
|
||||
# lens: EDX
|
||||
# currs: ESI
|
||||
# maxs: ECX
|
||||
# currb: EDI
|
||||
# c1: EAX
|
||||
# c2: EBX
|
||||
|
@ -41,40 +39,38 @@ string-equal?: # s : (address string), benchmark : (address string) -> EAX : bo
|
|||
# . save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# EDI = benchmark
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI
|
||||
# lens/EDX = s->length
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
|
||||
# ECX = s->length
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX
|
||||
$string-equal?:lengths:
|
||||
# if (lens != benchmark->length) return false
|
||||
39/compare 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # compare *EDI and EDX
|
||||
# if (ECX != benchmark->length) return false
|
||||
39/compare 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # compare *EDI and ECX
|
||||
75/jump-if-not-equal $string-equal?:false/disp8
|
||||
# currs/ESI = s->data
|
||||
81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI
|
||||
# maxs/ECX = s->data + s->length
|
||||
01/add 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # add ESI to ECX
|
||||
# currb/EDI = benchmark->data
|
||||
81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 4/imm32 # add to EDI
|
||||
# i/ECX = c1/EAX = c2/EBX = 0
|
||||
31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX
|
||||
# c1/EAX = c2/EDX = 0
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
||||
31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX
|
||||
$string-equal?:loop:
|
||||
# if (i >= lens) return true
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $string-equal?:true/disp8
|
||||
# if (currs >= maxs) return true
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX
|
||||
73/jump-if-greater-or-equal-unsigned $string-equal?:true/disp8
|
||||
# c1 = *currs
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL
|
||||
# c2 = *currb
|
||||
8a/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at *EDI to BL
|
||||
8a/copy-byte 0/mod/indirect 7/rm32/EDI . . . 2/r32/DL . . # copy byte at *EDI to DL
|
||||
# if (c1 != c2) return false
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX and EDX
|
||||
75/jump-if-not-equal $string-equal?:false/disp8
|
||||
# ++i
|
||||
41/increment-ECX
|
||||
# ++currs
|
||||
46/increment-ESI
|
||||
# ++currb
|
||||
|
@ -89,7 +85,6 @@ $string-equal?:end:
|
|||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# . epilog
|
||||
|
@ -179,4 +174,57 @@ test-compare-inequal-strings-equal-lengths:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
# helper for later tests
|
||||
check-string-equal: # s : (address string), expected : (address string), msg : (address string)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
# EAX = string-equal?(s, expected)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call string-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$check-string-equal:end:
|
||||
# . restore registers
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# test the helper
|
||||
test-check-string-equal:
|
||||
# check-string-equal?("Abc", "Abc")
|
||||
# . . push args
|
||||
68/push "Abc"/imm32
|
||||
68/push "Abc"/imm32
|
||||
# . . call
|
||||
e8/call check-string-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-check-string-equal"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
|
@ -37,7 +37,7 @@ clear-stream: # f : (address stream) -> <void>
|
|||
$clear-stream:loop:
|
||||
# if (EAX >= ECX) break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $clear-stream:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $clear-stream:end/disp8
|
||||
# *EAX = 0
|
||||
c6 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm8 # copy byte to *EAX
|
||||
# ++EAX
|
||||
|
|
|
@ -4,19 +4,13 @@
|
|||
# write : int # index at which writes go
|
||||
# read : int # index that we've read until
|
||||
# data : (array byte) # prefixed by length as usual
|
||||
# In a real trace the data will be in a special segment set aside for the purpose.
|
||||
# Usually the trace stream will be in a separate segment set aside for the purpose.
|
||||
#
|
||||
# primitives for operating on traces:
|
||||
# - initialize-trace-stream (update global variable)
|
||||
# - trace: stream, string
|
||||
# - die: stream (exit(1) if using real trace)
|
||||
# - check-trace-contains: stream, string/line, string/message (scans only from stream's read pointer, prints message to stderr on failure, updates stream's read pointer)
|
||||
# - scan-to-next-line: stream (advance read pointer past next newline)
|
||||
#
|
||||
# Traces are very fundamental, so many of the helpers we create here won't be
|
||||
# used elsewhere; we'll switch to more bounds-checked variants. But here we get
|
||||
# bounds-checking for free; we allocate a completely disjoint segment for trace
|
||||
# data, and overflowing it will generate a page fault.
|
||||
# primitives for operating on traces (arguments in quotes):
|
||||
# - initialize-trace-stream: populates Trace-stream with a new segment of the given 'size'
|
||||
# - trace: adds a 'line' to Trace-stream
|
||||
# - check-trace-contains: scans from Trace-stream's start for a matching 'line', prints a 'message' to stderr on failure
|
||||
# - check-trace-scans-to: scans from Trace-stream's read pointer for a matching 'line', prints a 'message' to stderr on failure
|
||||
|
||||
== data
|
||||
|
||||
|
@ -24,6 +18,10 @@
|
|||
Trace-stream:
|
||||
0/imm32
|
||||
|
||||
Trace-segment:
|
||||
0/imm32/curr
|
||||
0/imm32/limit
|
||||
|
||||
# Fake trace-stream for tests.
|
||||
# Also illustrates the layout of the real trace-stream (segment).
|
||||
_test-trace-stream:
|
||||
|
@ -43,23 +41,45 @@ _test-trace-stream:
|
|||
|
||||
# Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream.
|
||||
# The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a)
|
||||
initialize-trace-stream:
|
||||
# EAX = new-segment(0x1000)
|
||||
initialize-trace-stream: # n : int -> <void>
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
# ECX = n
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
# Trace-segment = new-segment(n)
|
||||
# . . push args
|
||||
68/push 0x1000/imm32/N
|
||||
68/push Trace-segment/imm32
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# copy EAX to *Trace-stream
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# copy Trace-segment->curr to *Trace-stream
|
||||
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-segment/disp32 # copy *Trace-segment to EAX
|
||||
# watch point to catch Trace-stream leaks
|
||||
#? $watch-1:
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# Trace-stream->length = 0x1000/N - 12
|
||||
c7 0/subop/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 0xff4/imm32 # copy 0xff4 to *(EAX+8)
|
||||
# Trace-stream->length = n - 12
|
||||
# . ECX -= 12
|
||||
81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 0xc/imm32 # subtract from ECX
|
||||
# . Trace-stream->length = ECX
|
||||
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy ECX to *(EAX+8)
|
||||
$initialize-trace-stream:end:
|
||||
# . restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# Append a string to the given trace stream.
|
||||
# Silently give up if it's already full. Or truncate the string if there isn't enough room.
|
||||
trace: # t : (address trace-stream), line : string
|
||||
trace: # line : (address string)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -70,10 +90,10 @@ trace: # t : (address trace-stream), line : string
|
|||
53/push-EBX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# EDI = t
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# EDI = *Trace-stream
|
||||
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 7/r32/EDI Trace-stream/disp32 # copy *Trace-stream to EDI
|
||||
# ESI = line
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# ECX = t->write
|
||||
8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX
|
||||
# EDX = t->length
|
||||
|
@ -126,15 +146,707 @@ $trace:end:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
clear-trace-stream: # t : (address trace-stream)
|
||||
test-trace-single:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# trace("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream->data, 41/A 62/b 0a/newline 00, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-single"/imm32
|
||||
68/push 0x0a6241/imm32/Ab-newline
|
||||
# . . push *_test-trace-stream->data
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-trace-appends:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# trace("C")
|
||||
# . . push args
|
||||
68/push "C"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace("D")
|
||||
# . . push args
|
||||
68/push "D"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream->data, 43/C 0a/newline 44/D 0a/newline, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-appends"/imm32
|
||||
68/push 0x0a440a43/imm32/C-newline-D-newline
|
||||
# . . push *_test-trace-stream->data
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-trace-empty-line:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# trace("")
|
||||
# . . push args
|
||||
68/push ""/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream->data, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-empty-line"/imm32
|
||||
68/push 0/imm32
|
||||
# . . push *_test-trace-stream->data
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# end
|
||||
c3/return
|
||||
|
||||
check-trace-contains: # line : (address string), msg : (address string)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# rewind-stream(*Trace-stream)
|
||||
# . . push args
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# . . call
|
||||
e8/call rewind-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-trace-scans-to(line, msg)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call check-trace-scans-to/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
$check-trace-contains:end:
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
check-trace-scans-to: # line : (address string), msg : (address string)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
# EAX = trace-scan(line)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call trace-scan/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$check-trace-scans-to:end:
|
||||
# . restore registers
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# Start scanning from Trace-stream->read for 'line'. If found, update Trace-stream->read and return true.
|
||||
trace-scan: # line : (address string) -> result/EAX : boolean
|
||||
# pseudocode:
|
||||
# push Trace-stream->read
|
||||
# while true:
|
||||
# if Trace-stream->read >= Trace-stream->write
|
||||
# break
|
||||
# if next-line-matches?(Trace-stream, line)
|
||||
# skip-next-line(Trace-stream)
|
||||
# dump saved copy of Trace-stream->read
|
||||
# return true
|
||||
# skip-next-line(Trace-stream)
|
||||
# pop saved copy of Trace-stream->read
|
||||
# return false
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
51/push-ECX
|
||||
56/push-ESI
|
||||
# ESI = *Trace-stream
|
||||
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 6/r32/ESI Trace-stream/disp32 # copy *Trace-stream to ESI
|
||||
# ECX = Trace-stream->write
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . # copy *ESI to ECX
|
||||
# push Trace-stream->read
|
||||
ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4)
|
||||
$trace-scan:loop:
|
||||
# if (Trace-stream->read >= Trace-stream->write) return false
|
||||
39/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4)
|
||||
7d/jump-if-greater-or-equal $trace-scan:false/disp8
|
||||
# EAX = next-line-matches?(Trace-stream, line)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
56/push-ESI
|
||||
# . . call
|
||||
e8/call next-line-matches?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# if (EAX == 0) continue
|
||||
3d/compare-EAX-and 0/imm32
|
||||
74/jump-if-equal $trace-scan:continue/disp8
|
||||
$trace-scan:true:
|
||||
# skip-next-line(Trace-stream)
|
||||
# . . push args
|
||||
56/push-ESI
|
||||
# . . call
|
||||
e8/call skip-next-line/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# dump saved copy of Trace-stream->read
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# return true
|
||||
b8/copy-to-EAX 1/imm32/true
|
||||
eb/jump $trace-scan:end/disp8
|
||||
$trace-scan:continue:
|
||||
# skip-next-line(Trace-stream)
|
||||
# . . push args
|
||||
56/push-ESI
|
||||
# . . call
|
||||
e8/call skip-next-line/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
eb/jump $trace-scan:loop/disp8
|
||||
$trace-scan:false:
|
||||
# restore saved copy of Trace-stream->read
|
||||
8f 0/subop/pop 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # pop to *(ESI+4)
|
||||
# return false
|
||||
b8/copy-to-EAX 0/imm32/false
|
||||
$trace-scan:end:
|
||||
# . restore registers
|
||||
59/pop-to-ECX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-trace-scan-first:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# setup
|
||||
# . *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# . clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . trace("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# EAX = trace-scan("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace-scan/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-scan-first"/imm32
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
test-trace-scan-skips-lines-until-found:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# setup
|
||||
# . *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# . clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . trace("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# . trace("cd")
|
||||
# . . push args
|
||||
68/push "cd"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# EAX = trace-scan("cd")
|
||||
# . . push args
|
||||
68/push "cd"/imm32
|
||||
# . . call
|
||||
e8/call trace-scan/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-scan-skips-lines-until-found"/imm32
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
test-trace-second-scan-starts-where-first-left-off:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# setup
|
||||
# . *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# . clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . trace("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# . EAX = trace-scan("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace-scan/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# second scan fails
|
||||
# . EAX = trace-scan("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace-scan/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-second-scan-starts-where-first-left-off"/imm32
|
||||
68/push 0/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
test-trace-scan-failure-leaves-read-index-untouched:
|
||||
# push *Trace-stream
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
||||
# setup
|
||||
# . *Trace-stream = _test-trace-stream
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# . clear-trace-stream()
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . trace("Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# . check-ints-equal(_test-trace-stream->read, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-second-scan-starts-where-first-left-off/precondition-failure"/imm32
|
||||
68/push 0/imm32
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# perform a failing scan
|
||||
# . EAX = trace-scan("Ax")
|
||||
# . . push args
|
||||
68/push "Ax"/imm32
|
||||
# . . call
|
||||
e8/call trace-scan/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# no change in read index
|
||||
# . check-ints-equal(_test-trace-stream->read, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-second-scan-starts-where-first-left-off"/imm32
|
||||
68/push 0/imm32
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# pop into *Trace-stream
|
||||
8f 0/subop/pop 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # pop into *Trace-stream
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
next-line-matches?: # t : (address stream), line : (address string) -> result/EAX : boolean
|
||||
# pseudocode:
|
||||
# while true:
|
||||
# if (currl >= maxl) break
|
||||
# if (currt >= maxt) return false
|
||||
# if (*currt != *currl) return false
|
||||
# ++currt
|
||||
# ++currl
|
||||
# return *currt == '\n'
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# EDX = line
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX
|
||||
# currl/ESI = line->data
|
||||
# . ESI = line/EDX->data
|
||||
8d/copy-address 1/mod/*+disp8 2/rm32/EDX . . . 6/r32/ESI 4/disp8 . # copy EDX+4 to ESI
|
||||
# maxl/ECX = line->data + line->size
|
||||
# . EAX = line/EDX->size
|
||||
8b/copy 0/mod/indirect 2/rm32/EDX . . 0/r32/EAX . . # copy *EDX to EAX
|
||||
# . maxl/ECX = line->data/ESI + line->size/EAX
|
||||
8d/copy-address 0/mod/indirect 4/rm32/sib 6/base/ESI 0/index/EAX . 1/r32/ECX . . # copy EDX+EAX to ECX
|
||||
# EDI = t
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# EBX = t->data
|
||||
8d/copy-address 1/mod/*+disp8 7/rm32/EDI . . . 3/r32/EBX 0xc/disp8 . # copy EDI+12 to EBX
|
||||
# maxt/EDX = t->data + t->write
|
||||
# . EAX = t->write
|
||||
8b/copy 0/mod/indirect 7/rm32/EDI . . 0/r32/EAX . . # copy *EDI to EAX
|
||||
# . maxt/EDX = t->data/EBX + t->write/EAX
|
||||
8d/copy-address 0/mod/indirect 4/rm32/sib 3/base/EBX 0/index/EAX . 2/r32/EDX . . # copy EBX+EAX to EDX
|
||||
# currt/EDI = t->data + t->read
|
||||
# . EAX = t/EDI->read
|
||||
8b/copy 1/mod/*+disp8 7/rm32/EDI . . 0/r32/EAX 4/disp8 . # copy *(EDI+4) to EAX
|
||||
# . currt/EDI = t->data/EBX + t->read/EAX
|
||||
8d/copy-address 0/mod/indirect 4/rm32/sib 3/base/EBX 0/index/EAX . 7/r32/EDI . . # copy EBX+EAX to EDI
|
||||
$next-line-matches?:loop:
|
||||
# if (currl/ESI >= maxl/ECX) break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI and ECX
|
||||
73/jump-if-greater-or-equal-unsigned $next-line-matches?:break/disp8
|
||||
# if (currt/EDI >= maxt/EDX) return false
|
||||
# . EAX = false
|
||||
b8/copy-to-EAX 0/imm32/false
|
||||
39/compare 3/mod/direct 7/rm32/EDI . . . 2/r32/EDX . . # compare EDI and EDX
|
||||
73/jump-if-greater-or-equal-unsigned $next-line-matches?:end/disp8
|
||||
# if (*currt/EDI != *currl/ESI) return false
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
31/xor 3/mod/direct 3/rm32/EAX . . . 3/r32/EAX . . # clear EBX
|
||||
# . EAX = (char) *currt/EDI
|
||||
8a/copy-byte 0/mod/indirect 7/rm32/EDI . . 0/r32/EAX . . # copy *EDI to EAX
|
||||
# . EBX = (char) *currl/ESI
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . 3/r32/EBX . . # copy *ESI to EBX
|
||||
# . EAX >= EBX
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX
|
||||
# . EAX = false
|
||||
b8/copy-to-EAX 0/imm32/false
|
||||
75/jump-if-not-equal $next-line-matches?:end/disp8
|
||||
# ++currt/EDI
|
||||
47/increment-EDI
|
||||
# ++currl/ESI
|
||||
46/increment-ESI
|
||||
eb/jump $next-line-matches?:loop/disp8
|
||||
$next-line-matches?:break:
|
||||
# return *currt == '\n'
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
# . EAX = (char) *currt
|
||||
8a/copy-byte 0/mod/indirect 7/rm32/EDI . . 0/r32/EAX . . # copy *EDI to EAX
|
||||
3d/compare-EAX-and 0xa/imm32/newline
|
||||
# . EAX = false
|
||||
b8/copy-to-EAX 1/imm32/true
|
||||
74/jump-if-equal $next-line-matches?:end/disp8
|
||||
b8/copy-to-EAX 0/imm32/true
|
||||
$next-line-matches?:end:
|
||||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-line-matches?-no-match-1:
|
||||
# next line of "ABABA" does not match "blah blah"
|
||||
# . EAX = next-line-matches?(_test-stream-line-ABABA, "blah blah")
|
||||
# . . push args
|
||||
68/push "blah blah"/imm32
|
||||
68/push _test-stream-line-ABABA/imm32
|
||||
# . . call
|
||||
e8/call next-line-matches?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . check-ints-equal(EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-line-matches?-no-match-1"/imm32
|
||||
68/push 0/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-next-line-matches?-no-match-2:
|
||||
# next line of "ABABA" does not match ""
|
||||
# . EAX = next-line-matches?(_test-stream-line-ABABA, "")
|
||||
# . . push args
|
||||
68/push ""/imm32
|
||||
68/push _test-stream-line-ABABA/imm32
|
||||
# . . call
|
||||
e8/call next-line-matches?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . check-ints-equal(EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-line-matches?-no-match-2"/imm32
|
||||
68/push 0/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-next-line-matches?-no-match-3:
|
||||
# next line of "ABABA" does not match "AA"
|
||||
# . EAX = next-line-matches?(_test-stream-line-ABABA, "AA")
|
||||
# . . push args
|
||||
68/push "AA"/imm32
|
||||
68/push _test-stream-line-ABABA/imm32
|
||||
# . . call
|
||||
e8/call next-line-matches?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . check-ints-equal(EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-line-matches?-no-match-3"/imm32
|
||||
68/push 0/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-next-line-matches?-match:
|
||||
# next line of "ABABA" matches "ABABA"
|
||||
# . EAX = next-line-matches?(_test-stream-line-ABABA, "ABABA")
|
||||
# . . push args
|
||||
68/push "ABABA"/imm32
|
||||
68/push _test-stream-line-ABABA/imm32
|
||||
# . . call
|
||||
e8/call next-line-matches?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-line-matches?-match"/imm32
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
# move t->read to _after_ next newline
|
||||
skip-next-line: # t : (address stream)
|
||||
# pseudocode:
|
||||
# max = t->data + t->write
|
||||
# i = t->read
|
||||
# curr = t->data + t->read
|
||||
# while true
|
||||
# if (curr >= max) break
|
||||
# ++i
|
||||
# if (*curr == '\n') break
|
||||
# ++curr
|
||||
# t->read = i
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
# EAX = t
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
# ECX = t
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
# EDX = t/ECX->data
|
||||
8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 0xc/disp8 . # copy ECX+12 to EDX
|
||||
# EAX = t/ECX->write
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
# max/EBX = t->data/EDX + t->write/EAX
|
||||
8d/copy-address 0/mod/indirect 4/rm32/sib 2/base/EDX 0/index/EAX . 3/r32/EBX . . # copy EDX+EAX to EBX
|
||||
# EAX = t/ECX->read
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EDX
|
||||
# curr/ECX = t->data/EDX + t->read/EAX
|
||||
8d/copy-address 0/mod/indirect 4/rm32/sib 2/base/EDX 0/index/EAX . 1/r32/ECX . . # copy EDX+EAX to ECX
|
||||
# i/EDX = EAX
|
||||
8b/copy 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # copy EAX to EDX
|
||||
$skip-next-line:loop:
|
||||
# if (curr/ECX >= max/EBX) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX and EBX
|
||||
73/jump-if-greater-or-equal-unsigned $skip-next-line:end/disp8
|
||||
# ++i/EDX
|
||||
42/increment-EDX
|
||||
# if (*curr/ECX == '\n') break
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
3d/compare-EAX-and 0a/imm32/newline
|
||||
74/jump-if-equal $skip-next-line:end/disp8
|
||||
# ++curr/ECX
|
||||
41/increment-ECX
|
||||
# loop
|
||||
eb/jump $skip-next-line:loop/disp8
|
||||
$skip-next-line:end:
|
||||
# ECX = t
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
# t/ECX->read = i/EDX
|
||||
89/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy EDX to *(ECX+4)
|
||||
# . restore registers
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-skip-next-line-empty:
|
||||
# skipping next line in empty stream leaves read pointer at 0
|
||||
# . skip-next-line(_test-stream-empty)
|
||||
# . . push args
|
||||
68/push _test-stream-empty/imm32
|
||||
# . . call
|
||||
e8/call skip-next-line/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# . check-ints-equal(_test-stream-empty->read, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-skip-next-line-empty"/imm32
|
||||
68/push 0/imm32
|
||||
b8/copy-to-EAX _test-stream-empty/imm32
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 4/disp8 . # copy *(EAX+4) to EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-skip-next-line-filled:
|
||||
# skipping next line increments read pointer by length of line + 1 (for newline)
|
||||
# . skip-next-line(_test-stream-filled)
|
||||
# . . push args
|
||||
68/push _test-stream-filled/imm32
|
||||
# . . call
|
||||
e8/call skip-next-line/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# . check-ints-equal(_test-stream-filled->read, 5, msg)
|
||||
# . . push args
|
||||
68/push "F - test-skip-next-line-filled"/imm32
|
||||
68/push 5/imm32
|
||||
b8/copy-to-EAX _test-stream-filled/imm32
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 4/disp8 . # copy *(EAX+4) to EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
clear-trace-stream:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
# EAX = *Trace-stream
|
||||
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX
|
||||
# ECX = t->length
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
|
||||
# ECX = &t->data[t->length]
|
||||
|
@ -148,7 +860,7 @@ clear-trace-stream: # t : (address trace-stream)
|
|||
$clear-trace-stream:loop:
|
||||
# if (EAX >= ECX) break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $clear-trace-stream:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $clear-trace-stream:end/disp8
|
||||
# *EAX = 0
|
||||
c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# EAX += 4
|
||||
|
@ -163,106 +875,6 @@ $clear-trace-stream:end:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# - tests
|
||||
|
||||
test-trace-single:
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# . . push args
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "Ab")
|
||||
# . . push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream->data, 41/A 62/b 0a/newline 00, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-single"/imm32
|
||||
68/push 0x0a6241/imm32/Ab-newline
|
||||
# . . push *_test-trace-stream->data
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-trace-appends:
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# . . push args
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "C")
|
||||
# . . push args
|
||||
68/push "C"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "D")
|
||||
# . . push args
|
||||
68/push "D"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream->data, 43/C 0a/newline 44/D 0a/newline, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-appends"/imm32
|
||||
68/push 0x0a440a43/imm32/C-newline-D-newline
|
||||
# . . push *_test-trace-stream->data
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-trace-empty-line:
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# . . push args
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-trace-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "")
|
||||
# . . push args
|
||||
68/push ""/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# . . call
|
||||
e8/call trace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream->data, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-trace-empty-line"/imm32
|
||||
68/push 0/imm32
|
||||
# . . push *_test-trace-stream->data
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
# - helpers
|
||||
|
||||
# 3-argument variant of _append
|
||||
|
@ -321,10 +933,10 @@ _append-4: # out : address, outend : address, in : address, inend : address ->
|
|||
$_append-4:loop:
|
||||
# if (in >= inend) break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX
|
||||
7d/jump-if-greater-or-equal $_append-4:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $_append-4:end/disp8
|
||||
# if (out >= outend) abort # just to catch test failures fast
|
||||
39/compare 3/mod/direct 7/rm32/EDI . . . 2/r32/EDX . . # compare EDI with EDX
|
||||
7d/jump-if-greater-or-equal $_append-4:abort/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $_append-4:abort/disp8
|
||||
# *out = *in
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 3/r32/BL . . # copy byte at *ESI to BL
|
||||
88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at BL to *EDI
|
||||
|
@ -362,4 +974,36 @@ $_append-4:abort:
|
|||
cd/syscall 0x80/imm8
|
||||
# never gets here
|
||||
|
||||
== data
|
||||
|
||||
_test-stream-line-ABABA:
|
||||
# write
|
||||
8/imm32
|
||||
# read
|
||||
0/imm32
|
||||
# length
|
||||
8/imm32
|
||||
# data
|
||||
41 42 41 42 41 0A 00 00 # 8 bytes
|
||||
|
||||
_test-stream-empty:
|
||||
# write
|
||||
0/imm32
|
||||
# read
|
||||
0/imm32
|
||||
# length
|
||||
8/imm32
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
|
||||
_test-stream-filled:
|
||||
# write
|
||||
8/imm32
|
||||
# read
|
||||
0/imm32
|
||||
# length
|
||||
8/imm32
|
||||
# data
|
||||
41 41 41 41 0A 41 41 41 # 8 bytes
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
|
@ -5,13 +5,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-next-stream-line-equal-stops-at-newline/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
# compare all the data in a stream (ignoring the read pointer)
|
||||
stream-data-equal?: # f : (address stream), s : (address string) -> EAX : boolean
|
||||
# . prolog
|
||||
|
@ -26,7 +19,7 @@ stream-data-equal?: # f : (address stream), s : (address string) -> EAX : boole
|
|||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# EAX = f->write
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
||||
# max/EDX = f->data + f->write
|
||||
# maxf/EDX = f->data + f->write
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 2/r32/EDX 0xc/disp8 . # copy ESI+EAX+12 to EDX
|
||||
# currf/ESI = f->data
|
||||
81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 0xc/imm32 # add to ESI
|
||||
|
@ -42,9 +35,9 @@ $stream-data-equal?:compare-lengths:
|
|||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX
|
||||
$stream-data-equal?:loop:
|
||||
# if (curr >= max) return true
|
||||
# if (currf >= maxf) return true
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 2/r32/EDX . . # compare ESI with EDX
|
||||
7d/jump-if-greater-or-equal $stream-data-equal?:true/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $stream-data-equal?:true/disp8
|
||||
# AL = *currs
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL
|
||||
# CL = *curr
|
||||
|
|
|
@ -37,13 +37,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-stop-skips-returns-on-exit/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
# Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to
|
||||
# the stack.
|
||||
# Ugly that we need to know the size of args, but so it goes.
|
||||
|
|
|
@ -165,10 +165,10 @@ _buffer-4: # out : address, outend : address, in : address, inend : address ->
|
|||
$_buffer-4:loop:
|
||||
# if (in >= inend) break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX
|
||||
7d/jump-if-greater-or-equal $_buffer-4:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $_buffer-4:end/disp8
|
||||
# if (out >= outend) break # for now silently ignore filled up buffer
|
||||
39/compare 3/mod/direct 7/rm32/EDI . . . 2/r32/EDX . . # compare EDI with EDX
|
||||
7d/jump-if-greater-or-equal $_buffer-4:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $_buffer-4:end/disp8
|
||||
# *out = *in
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 3/r32/BL . . # copy byte at *ESI to BL
|
||||
88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at BL to *EDI
|
||||
|
|
|
@ -31,14 +31,6 @@ Stdin:
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-read-byte-buffered-multiple/disp32
|
||||
#? e8/call test-read-byte-buffered-refills-buffer/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
# return next byte value in EAX, with top 3 bytes cleared.
|
||||
# On reaching end of file, return 0xffffffff (Eof).
|
||||
read-byte-buffered: # f : (address buffered-file) -> byte-or-Eof/EAX
|
||||
|
|
205
subx/065hex.subx
205
subx/065hex.subx
|
@ -23,7 +23,7 @@ is-hex-int?: # in : (address slice) -> EAX : boolean
|
|||
# if s is empty return false
|
||||
b8/copy-to-EAX 0/imm32/false
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $is-hex-int?:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $is-hex-int?:end/disp8
|
||||
# skip past leading '-'
|
||||
# . if (*curr == '-') ++curr
|
||||
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
||||
|
@ -44,7 +44,7 @@ $is-hex-int?:initial-0:
|
|||
$is-hex-int?:initial-0x:
|
||||
# . if (curr >= in->end) return true
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $is-hex-int?:true/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $is-hex-int?:true/disp8
|
||||
# . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
|
||||
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 3/r32/BL . . # copy byte at *ECX to BL
|
||||
|
@ -55,7 +55,7 @@ $is-hex-int?:initial-0x:
|
|||
$is-hex-int?:loop:
|
||||
# if (curr >= in->end) return true
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $is-hex-int?:true/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $is-hex-int?:true/disp8
|
||||
# EAX = is-hex-digit?(*curr)
|
||||
# . . push args
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL
|
||||
|
@ -88,9 +88,14 @@ test-is-hex-int:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "34"
|
||||
68/push _test-slice-hex-int-end/imm32
|
||||
68/push _test-slice-hex-int/imm32
|
||||
# (EAX..ECX) = "34"
|
||||
b8/copy-to-EAX "34"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -117,9 +122,14 @@ test-is-hex-int-handles-letters:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "34a"
|
||||
68/push _test-slice-hex-int-letters-end/imm32
|
||||
68/push _test-slice-hex-int-letters/imm32
|
||||
# (EAX..ECX) = "34a"
|
||||
b8/copy-to-EAX "34a"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -146,9 +156,14 @@ test-is-hex-int-with-trailing-char:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "34q"
|
||||
68/push _test-slice-digits-and-char-end/imm32
|
||||
68/push _test-slice-digits-and-char/imm32
|
||||
# (EAX..ECX) = "34q"
|
||||
b8/copy-to-EAX "34q"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -175,9 +190,14 @@ test-is-hex-int-with-leading-char:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "q34"
|
||||
68/push _test-slice-char-and-digits-end/imm32
|
||||
68/push _test-slice-char-and-digits/imm32
|
||||
# (EAX..ECX) = "q34"
|
||||
b8/copy-to-EAX "q34"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -205,8 +225,8 @@ test-is-hex-int-empty:
|
|||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = ""
|
||||
68/push _test-slice-empty-end/imm32
|
||||
68/push _test-slice-empty/imm32
|
||||
68/push 0/imm32
|
||||
68/push 0/imm32
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -233,9 +253,14 @@ test-is-hex-int-handles-0x-prefix:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "0x3a"
|
||||
68/push _test-slice-hex-int-with-0x-prefix-end/imm32
|
||||
68/push _test-slice-hex-int-with-0x-prefix/imm32
|
||||
# (EAX..ECX) = "0x3a"
|
||||
b8/copy-to-EAX "0x3a"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -262,9 +287,14 @@ test-is-hex-int-handles-negative:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "-34a"
|
||||
68/push _test-slice-hex-int-letters-end/imm32
|
||||
68/push _test-slice-hex-int-letters-negative/imm32
|
||||
# (EAX..ECX) = "-34a"
|
||||
b8/copy-to-EAX "-34a"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -291,9 +321,14 @@ test-is-hex-int-handles-negative-0x-prefix:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "-0x3a"
|
||||
68/push _test-slice-hex-int-with-0x-prefix-end/imm32
|
||||
68/push _test-slice-hex-int-with-0x-prefix-negative/imm32
|
||||
# (EAX..ECX) = "-0x3a"
|
||||
b8/copy-to-EAX "-0x3a"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = is-hex-int?(slice)
|
||||
# . . push args
|
||||
|
@ -356,7 +391,7 @@ $parse-hex-int:initial-0:
|
|||
$parse-hex-int:initial-0x:
|
||||
# . if (curr >= in->end) return result
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $parse-hex-int:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $parse-hex-int:end/disp8
|
||||
# . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL
|
||||
|
@ -367,7 +402,7 @@ $parse-hex-int:initial-0x:
|
|||
$parse-hex-int:loop:
|
||||
# if (curr >= in->end) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $parse-hex-int:negate/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $parse-hex-int:negate/disp8
|
||||
# EAX = from-hex-char(*curr)
|
||||
# . . copy arg to EAX
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL
|
||||
|
@ -400,9 +435,14 @@ test-parse-hex-int-single-digit:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "a"
|
||||
68/push _test-slice-hex-int-single-letter-end/imm32
|
||||
68/push _test-slice-hex-int-single-letter/imm32
|
||||
# (EAX..ECX) = "a"
|
||||
b8/copy-to-EAX "a"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
|
@ -429,9 +469,14 @@ test-parse-hex-int-multi-digit:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "34a"
|
||||
68/push _test-slice-hex-int-letters-end/imm32
|
||||
68/push _test-slice-hex-int-letters/imm32
|
||||
# (EAX..ECX) = "34a"
|
||||
b8/copy-to-EAX "34a"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
|
@ -458,9 +503,14 @@ test-parse-hex-int-0x-prefix:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "0x34"
|
||||
68/push _test-slice-hex-int-with-0x-prefix-end/imm32
|
||||
68/push _test-slice-hex-int-with-0x-prefix/imm32
|
||||
# (EAX..ECX) = "0x34"
|
||||
b8/copy-to-EAX "0x34"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
|
@ -487,9 +537,14 @@ test-parse-hex-int-zero:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "0"
|
||||
68/push _test-slice-hex-int-zero-end/imm32
|
||||
68/push _test-slice-hex-int-zero/imm32
|
||||
# (EAX..ECX) = "0"
|
||||
b8/copy-to-EAX "0"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
|
@ -516,9 +571,14 @@ test-parse-hex-int-0-prefix:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "03"
|
||||
68/push _test-slice-hex-int-with-0-prefix-end/imm32
|
||||
68/push _test-slice-hex-int-with-0-prefix/imm32
|
||||
# (EAX..ECX) = "03"
|
||||
b8/copy-to-EAX "03"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
|
@ -545,9 +605,14 @@ test-parse-hex-int-negative:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX = "-03"
|
||||
68/push _test-slice-hex-int-negative-with-0-prefix-end/imm32
|
||||
68/push _test-slice-hex-int-negative-with-0-prefix/imm32
|
||||
# (EAX..ECX) = "-03"
|
||||
b8/copy-to-EAX "-03"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
|
@ -729,7 +794,7 @@ test-hex-above-f:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
from-hex-char: # in/EAX : byte -> out/EAX : num
|
||||
from-hex-char: # in/EAX : byte -> out/EAX : nibble
|
||||
# no error checking; accepts argument in EAX
|
||||
# if (EAX <= '9') return EAX - '0'
|
||||
3d/compare-EAX-with 0x39/imm32/9
|
||||
|
@ -753,50 +818,4 @@ $to-hex-char:else:
|
|||
05/add-to-EAX 0x57/imm32/a-10
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-slice-empty:
|
||||
# nothing
|
||||
_test-slice-empty-end:
|
||||
|
||||
_test-slice-hex-int:
|
||||
33/3 34/4
|
||||
_test-slice-hex-int-end:
|
||||
|
||||
_test-slice-hex-int-letters-negative:
|
||||
2d/-
|
||||
_test-slice-hex-int-letters:
|
||||
33/3 34/4 61/a
|
||||
_test-slice-hex-int-letters-end:
|
||||
|
||||
_test-slice-hex-int-single-letter:
|
||||
61/a
|
||||
_test-slice-hex-int-single-letter-end:
|
||||
|
||||
_test-slice-char-and-digits:
|
||||
71/q 33/3 34/4
|
||||
_test-slice-char-and-digits-end:
|
||||
|
||||
_test-slice-digits-and-char:
|
||||
33/3 34/4 71/q
|
||||
_test-slice-digits-and-char-end:
|
||||
|
||||
_test-slice-hex-int-with-0x-prefix-negative:
|
||||
2d/-
|
||||
_test-slice-hex-int-with-0x-prefix:
|
||||
30/0 78/x 33/3 34/4
|
||||
_test-slice-hex-int-with-0x-prefix-end:
|
||||
|
||||
_test-slice-hex-int-zero:
|
||||
30/0
|
||||
_test-slice-hex-int-zero-end:
|
||||
|
||||
_test-slice-hex-int-with-0-prefix:
|
||||
30/0 33/3
|
||||
_test-slice-hex-int-with-0-prefix-end:
|
||||
|
||||
_test-slice-hex-int-negative-with-0-prefix:
|
||||
2d/- 30/0 33/3
|
||||
_test-slice-hex-int-negative-with-0-prefix-end:
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
|
@ -5,14 +5,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-write-buffered/disp32
|
||||
#? e8/call test-write-buffered-with-intermediate-flush/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
write-buffered: # f : (address buffered-file), msg : (address array byte) -> <void>
|
||||
# pseudocode:
|
||||
# in = msg->data
|
||||
|
@ -60,7 +52,7 @@ write-buffered: # f : (address buffered-file), msg : (address array byte) -> <v
|
|||
$write-buffered:loop:
|
||||
# if (in >= inend) break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX
|
||||
7d/jump-if-greater-or-equal $write-buffered:loop-end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $write-buffered:loop-end/disp8
|
||||
# if (f->write >= f->length) flush and clear f's stream
|
||||
39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX with EDX
|
||||
7c/jump-if-lesser $write-buffered:to-stream/disp8
|
||||
|
|
|
@ -5,13 +5,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-print-int32/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
append-byte-hex: # f : (address stream), n : int -> <void>
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
|
@ -259,6 +252,23 @@ test-print-int32:
|
|||
# . end
|
||||
c3/return
|
||||
|
||||
# TODO: append to string
|
||||
check-ints-equal2: # (a : int, b : int, msg : (address array byte))
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
print-int32-buffered: # f : (address buffered-file), n : int -> <void>
|
||||
# pseudocode:
|
||||
# write-buffered(f, "0x")
|
||||
|
|
|
@ -3,13 +3,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-read-line-buffered/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
# read bytes from 'f' until (and including) a newline and store them into 's'
|
||||
# 's' fails to grow if and only if no data found
|
||||
# just abort if 's' is too small
|
||||
|
|
|
@ -6,13 +6,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-slice-to-string/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
slice-empty?: # s : (address slice) -> EAX : boolean
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
|
@ -154,7 +147,7 @@ $slice-equal?:nonnull-string:
|
|||
$slice-equal?:loop:
|
||||
# if (currs >= maxs) return true
|
||||
39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI
|
||||
7d/jump-if-greater-or-equal $slice-equal?:true/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $slice-equal?:true/disp8
|
||||
# AL = *currp
|
||||
8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at *EBX to AL
|
||||
# CL = *currs
|
||||
|
@ -188,9 +181,14 @@ test-slice-equal:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "Abc")
|
||||
# . . push args
|
||||
|
@ -219,9 +217,14 @@ test-slice-equal-false:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-4/imm32/end
|
||||
68/push _test-slice-data-1/imm32/start
|
||||
# (EAX..ECX) = "bcd"
|
||||
b8/copy-to-EAX "bcd"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "Abc")
|
||||
# . . push args
|
||||
|
@ -250,9 +253,14 @@ test-slice-equal-too-long:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-4/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abcd"
|
||||
b8/copy-to-EAX "Abcd"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "Abc")
|
||||
# . . push args
|
||||
|
@ -281,9 +289,14 @@ test-slice-equal-too-short:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-1/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "A"
|
||||
b8/copy-to-EAX "A"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "Abc")
|
||||
# . . push args
|
||||
|
@ -313,8 +326,8 @@ test-slice-equal-empty:
|
|||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-0/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "Abc")
|
||||
# . . push args
|
||||
|
@ -343,9 +356,14 @@ test-slice-equal-with-empty:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-2/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Ab"
|
||||
b8/copy-to-EAX "Ab"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "")
|
||||
# . . push args
|
||||
|
@ -375,8 +393,8 @@ test-slice-equal-empty-with-empty:
|
|||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-0/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, "")
|
||||
# . . push args
|
||||
|
@ -405,9 +423,14 @@ test-slice-equal-with-null:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-2/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Ab"
|
||||
b8/copy-to-EAX "Ab"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-equal?(ECX, 0)
|
||||
# . . push args
|
||||
|
@ -523,9 +546,14 @@ test-slice-starts-with-single-character:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-starts-with?(ECX, "A")
|
||||
# . . push args
|
||||
|
@ -554,9 +582,14 @@ test-slice-starts-with-empty-string:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-starts-with?(ECX, "")
|
||||
# . . push args
|
||||
|
@ -585,9 +618,14 @@ test-slice-starts-with-multiple-characters:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-starts-with?(ECX, "Ab")
|
||||
# . . push args
|
||||
|
@ -616,9 +654,14 @@ test-slice-starts-with-entire-string:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-starts-with?(ECX, "Abc")
|
||||
# . . push args
|
||||
|
@ -647,9 +690,14 @@ test-slice-starts-with-fails:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-starts-with?(ECX, "Abd")
|
||||
# . . push args
|
||||
|
@ -678,9 +726,14 @@ test-slice-starts-with-fails-2:
|
|||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var slice/ECX
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-starts-with?(ECX, "Ac")
|
||||
# . . push args
|
||||
|
@ -704,6 +757,124 @@ test-slice-starts-with-fails-2:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# write a slice to a stream
|
||||
# abort if the stream doesn't have enough space
|
||||
write-slice: # out : (address stream), s : (address slice)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# curr/ECX = s->start
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX
|
||||
# max/ESI = s->end
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI
|
||||
# EDI = out
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# EDX = out->length
|
||||
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX
|
||||
# EBX = out->write
|
||||
8b/copy 0/mod/indirect 7/rm32/EDI . . . 3/r32/EBX . . # copy *EDI to EBX
|
||||
$write-slice:loop:
|
||||
# if (curr >= max) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # compare ECX with ESI
|
||||
73/jump-if-greater-or-equal-unsigned $write-slice:loop-end/disp8
|
||||
# if (out->write >= out->length) abort
|
||||
39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX with EDX
|
||||
7d/jump-if-greater-or-equal $write-slice:abort/disp8
|
||||
# out->data[out->write] = *in
|
||||
# . AL = *in
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL
|
||||
# . out->data[out->write] = AL
|
||||
88/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/EDI 3/index/EBX . 0/r32/AL 0xc/disp8 . # copy AL to *(EDI+EBX+12)
|
||||
# ++out->write
|
||||
43/increment-EBX
|
||||
# ++in
|
||||
41/increment-ECX
|
||||
eb/jump $write-slice:loop/disp8
|
||||
$write-slice:loop-end:
|
||||
# persist out->write
|
||||
89/copy 0/mod/indirect 7/rm32/EDI . . . 3/r32/EBX . . # copy EBX to *EDI
|
||||
$write-slice:end:
|
||||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
$write-slice:abort:
|
||||
# . _write(2/stderr, error)
|
||||
# . . push args
|
||||
68/push "write-slice: out of space"/imm32
|
||||
68/push 2/imm32/stderr
|
||||
# . . call
|
||||
e8/call _write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . syscall(exit, 1)
|
||||
bb/copy-to-EBX 1/imm32
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
# never gets here
|
||||
|
||||
test-write-slice:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# setup
|
||||
# . clear-stream(_test-stream)
|
||||
# . . push args
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# write-slice(_test-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call write-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-stream-equal(_test-stream, "Abc", msg)
|
||||
# . . push args
|
||||
68/push "F - test-write-slice"/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call check-stream-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# write a slice to a buffered-file
|
||||
write-slice-buffered: # out : (address buffered-file), s : (address slice)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
|
@ -730,7 +901,7 @@ write-slice-buffered: # out : (address buffered-file), s : (address slice)
|
|||
$write-slice-buffered:loop:
|
||||
# if (curr >= max) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # compare ECX with ESI
|
||||
7d/jump-if-greater-or-equal $write-slice-buffered:loop-end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $write-slice-buffered:loop-end/disp8
|
||||
# if (out->write >= out->length) flush and clear out's stream
|
||||
39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX with EDX
|
||||
7c/jump-if-lesser $write-slice-buffered:to-stream/disp8
|
||||
|
@ -802,9 +973,14 @@ test-write-slice-buffered:
|
|||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = "Abc"
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# write-slice-buffered(_test-buffered-file, slice)
|
||||
# . . push args
|
||||
|
@ -929,9 +1105,14 @@ test-slice-to-string:
|
|||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# var slice/ECX = "Abc"
|
||||
68/push _test-slice-data-3/imm32/end
|
||||
68/push _test-slice-data-0/imm32/start
|
||||
# (EAX..ECX) = "Abc"
|
||||
b8/copy-to-EAX "Abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = slice-to-string(heap, slice)
|
||||
# . . push args
|
||||
|
@ -989,16 +1170,4 @@ test-slice-to-string:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-slice-data-0:
|
||||
41/A
|
||||
_test-slice-data-1:
|
||||
62/b
|
||||
_test-slice-data-2:
|
||||
63/c
|
||||
_test-slice-data-3:
|
||||
64/d
|
||||
_test-slice-data-4:
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
# Some tokenization primitives.
|
||||
|
||||
== code
|
||||
# instruction effective address register displacement immediate
|
||||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-next-token-from-slice/disp32
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
# extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
|
||||
# on reaching end of file, return an empty interval
|
||||
next-token: # in : (address stream), delimiter : byte, out : (address slice)
|
||||
|
@ -698,7 +693,7 @@ skip-chars-matching-in-slice: # curr : (address byte), end : (address byte), de
|
|||
$skip-chars-matching-in-slice:loop:
|
||||
# if (curr >= end) break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $skip-chars-matching-in-slice:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $skip-chars-matching-in-slice:end/disp8
|
||||
# if (*curr != delimiter) break
|
||||
8a/copy-byte 0/mod/indirect 0/rm32/EAX . . . 3/r32/BL . . # copy byte at *EAX to BL
|
||||
39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX and EDX
|
||||
|
@ -724,7 +719,7 @@ test-skip-chars-matching-in-slice:
|
|||
05/add-to-EAX 4/imm32
|
||||
# EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
|
||||
# . . push args
|
||||
68/push 0x20/imm32
|
||||
68/push 0x20/imm32/space
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
|
@ -753,7 +748,7 @@ test-skip-chars-matching-in-slice-none:
|
|||
05/add-to-EAX 4/imm32
|
||||
# EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
|
||||
# . . push args
|
||||
68/push 0x20/imm32
|
||||
68/push 0x20/imm32/space
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
|
@ -794,7 +789,7 @@ skip-chars-not-matching-in-slice: # curr : (address byte), end : (address byte)
|
|||
$skip-chars-not-matching-in-slice:loop:
|
||||
# if (curr >= end) break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $skip-chars-not-matching-in-slice:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $skip-chars-not-matching-in-slice:end/disp8
|
||||
# if (*curr == delimiter) break
|
||||
8a/copy-byte 0/mod/indirect 0/rm32/EAX . . . 3/r32/BL . . # copy byte at *EAX to BL
|
||||
39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX and EDX
|
||||
|
@ -820,7 +815,7 @@ test-skip-chars-not-matching-in-slice:
|
|||
05/add-to-EAX 4/imm32
|
||||
# EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
|
||||
# . . push args
|
||||
68/push 0x20/imm32
|
||||
68/push 0x20/imm32/space
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
|
@ -849,7 +844,7 @@ test-skip-chars-not-matching-in-slice-none:
|
|||
05/add-to-EAX 4/imm32
|
||||
# EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
|
||||
# . . push args
|
||||
68/push 0x20/imm32
|
||||
68/push 0x20/imm32/space
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
|
@ -878,7 +873,7 @@ test-skip-chars-not-matching-in-slice-all:
|
|||
05/add-to-EAX 4/imm32
|
||||
# EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
|
||||
# . . push args
|
||||
68/push 0x20/imm32
|
||||
68/push 0x20/imm32/space
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
|
|
|
@ -5,14 +5,6 @@
|
|||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
#? Entry: # run a single test, while debugging
|
||||
#? e8/call test-print-int32-decimal-negative/disp32
|
||||
#?
|
||||
#? # syscall(exit, Num-test-failures)
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? b8/copy-to-EAX 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
print-int32-decimal: # out : (address stream), n : int32
|
||||
# works by generating characters from lowest to highest and pushing them
|
||||
# to the stack, before popping them one by one into the stream
|
||||
|
@ -97,7 +89,7 @@ $print-int32-decimal:write-loop:
|
|||
74/jump-if-equal $print-int32-decimal:write-break/disp8
|
||||
# if (curr >= max) abort
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX with EBX
|
||||
7d/jump-if-greater-or-equal $print-int32-decimal:abort/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $print-int32-decimal:abort/disp8
|
||||
$print-int32-decimal:write-char:
|
||||
# *curr = AL
|
||||
88/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy AL to byte at *ECX
|
||||
|
|
|
@ -0,0 +1,629 @@
|
|||
# Comparing arrays of numbers.
|
||||
|
||||
== code
|
||||
# instruction effective address register displacement immediate
|
||||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
Entry:
|
||||
# initialize heap
|
||||
# . Heap = new-segment(64KB)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
68/push 0x10000/imm32/64KB
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
$array-equal-main:end:
|
||||
# syscall(exit, Num-test-failures)
|
||||
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
array-equal?: # a : (address array int), b : (address array int) -> EAX : boolean
|
||||
# pseudocode:
|
||||
# lena = a->length
|
||||
# if (lena != b->length) return false
|
||||
# i = 0
|
||||
# curra = a->data
|
||||
# currb = b->data
|
||||
# while i < lena
|
||||
# i1 = *curra
|
||||
# i2 = *currb
|
||||
# if (c1 != c2) return false
|
||||
# i+=4, curra+=4, currb+=4
|
||||
# return true
|
||||
#
|
||||
# registers:
|
||||
# i: ECX
|
||||
# lena: EDX
|
||||
# curra: ESI
|
||||
# currb: EDI
|
||||
# i1: EAX
|
||||
# i2: EBX
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = a
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# EDI = b
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI
|
||||
# lena/EDX = a->length
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
|
||||
$array-equal?:lengths:
|
||||
# if (lena != b->length) return false
|
||||
39/compare 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # compare *EDI and EDX
|
||||
75/jump-if-not-equal $array-equal?:false/disp8
|
||||
# curra/ESI = a->data
|
||||
81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI
|
||||
# currb/EDI = b->data
|
||||
81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 4/imm32 # add to EDI
|
||||
# i/ECX = i1/EAX = i2/EBX = 0
|
||||
31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX
|
||||
$array-equal?:loop:
|
||||
# if (i >= lena) return true
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $array-equal?:true/disp8
|
||||
# i1 = *curra
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
||||
# i2 = *currb
|
||||
8b/copy 0/mod/indirect 7/rm32/EDI . . . 3/r32/EBX . . # copy *EDI to EBX
|
||||
# if (i1 != i2) return false
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX
|
||||
75/jump-if-not-equal $array-equal?:false/disp8
|
||||
# i += 4
|
||||
81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX
|
||||
# currs += 4
|
||||
81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI
|
||||
# currb += 4
|
||||
81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 4/imm32 # add to EDI
|
||||
eb/jump $array-equal?:loop/disp8
|
||||
$array-equal?:true:
|
||||
b8/copy-to-EAX 1/imm32
|
||||
eb/jump $array-equal?:end/disp8
|
||||
$array-equal?:false:
|
||||
b8/copy-to-EAX 0/imm32
|
||||
$array-equal?:end:
|
||||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-compare-empty-with-empty-array:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = []
|
||||
68/push 0/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# var EDX = []
|
||||
68/push 0/imm32/size
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
# EAX = array-equal?(ECX, EDX)
|
||||
# . . push args
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compare-empty-with-empty-array"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-compare-empty-with-non-empty-array: # also checks length-mismatch code path
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = [1]
|
||||
68/push 1/imm32
|
||||
68/push 4/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# var EDX = []
|
||||
68/push 0/imm32/size
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
# EAX = array-equal?(ECX, EDX)
|
||||
# . . push args
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compare-empty-with-non-empty-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-compare-equal-arrays:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = [1, 2, 3]
|
||||
68/push 3/imm32
|
||||
68/push 2/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# var EDX = [1, 2, 3]
|
||||
68/push 3/imm32
|
||||
68/push 2/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
# EAX = array-equal?(ECX, EDX)
|
||||
# . . push args
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compare-equal-arrays"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-compare-inequal-arrays-equal-lengths:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = [1, 4, 3]
|
||||
68/push 3/imm32
|
||||
68/push 4/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# var EDX = [1, 2, 3]
|
||||
68/push 3/imm32
|
||||
68/push 2/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
# EAX = array-equal?(ECX, EDX)
|
||||
# . . push args
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compare-inequal-arrays-equal-lengths"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
parse-array-of-ints: # ad : (address allocation-descriptor), s : (address string) -> result/EAX : (address array int)
|
||||
# pseudocode
|
||||
# end = s->data + s->length
|
||||
# curr = s->data
|
||||
# size = 0
|
||||
# while true
|
||||
# if (curr >= end) break
|
||||
# curr = skip-chars-matching-in-slice(curr, end, ' ')
|
||||
# if (curr >= end) break
|
||||
# curr = skip-chars-not-matching-in-slice(curr, end, ' ')
|
||||
# ++size
|
||||
# result = allocate(ad, (size+1)*4)
|
||||
# result->size = (size+1)*4
|
||||
# var slice = {s->data, 0}
|
||||
# out = result->data
|
||||
# while true
|
||||
# if (slice->start >= end) break
|
||||
# slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
|
||||
# if (slice->start >= end) break
|
||||
# slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
|
||||
# *out = parse-hex-int(slice)
|
||||
# out += 4
|
||||
# slice->start = slice->end
|
||||
# return result
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# curr/ECX = s->data
|
||||
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ESI+4 to ECX
|
||||
# end/EDX = s->data + s->length
|
||||
# . EDX = s->length
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
|
||||
# . EDX += curr
|
||||
01/add 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # add ECX to EDX
|
||||
# size/EBX = 0
|
||||
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
||||
$parse-array-of-ints:loop1:
|
||||
# if (curr >= end) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:break1/disp8
|
||||
# curr = skip-chars-matching-in-slice(curr, end, ' ')
|
||||
# . EAX = skip-chars-matching-in-slice(curr, end, ' ')
|
||||
# . . push args
|
||||
68/push 0x20/imm32/space
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call skip-chars-matching-in-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . ECX = EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX
|
||||
# if (curr >= end) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:break1/disp8
|
||||
# curr = skip-chars-not-matching-in-slice(curr, end, ' ')
|
||||
# . EAX = skip-chars-not-matching-in-slice(curr, end, ' ')
|
||||
# . . push args
|
||||
68/push 0x20/imm32/space
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call skip-chars-not-matching-in-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . ECX = EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX
|
||||
# size += 4
|
||||
81 0/subop/add 3/mod/direct 3/rm32/EBX . . . . . 4/imm32 # add to EBX
|
||||
eb/jump $parse-array-of-ints:loop1/disp8
|
||||
$parse-array-of-ints:break1:
|
||||
# result/EDI = allocate(ad, size+4)
|
||||
# . EAX = allocate(ad, size+4)
|
||||
# . . push args
|
||||
89/copy 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # copy EBX to EAX
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call allocate/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . EDI = EAX
|
||||
89/copy 3/mod/direct 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to EDI
|
||||
# result->size = size
|
||||
89/copy 0/mod/indirect 0/rm32/EAX . . . 3/r32/EBX . . # copy EBX to *EAX
|
||||
$parse-array-of-ints:pass2:
|
||||
# var slice/ECX = {s->data, 0}
|
||||
# . push 0
|
||||
68/push 0/imm32/end
|
||||
# . push s->data
|
||||
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ESI+4 to ECX
|
||||
51/push-ECX
|
||||
# . bookmark
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# out/EBX = result->data
|
||||
8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 4/disp8 . # copy EAX+4 to EBX
|
||||
$parse-array-of-ints:loop2:
|
||||
# if (slice->start >= end) break
|
||||
39/compare 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # compare *ECX with EDX
|
||||
73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:end/disp8
|
||||
# slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
|
||||
# . EAX = skip-chars-matching-in-slice(slice->start, end, ' ')
|
||||
# . . push args
|
||||
68/push 0x20/imm32/space
|
||||
52/push-EDX
|
||||
ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX
|
||||
# . . call
|
||||
e8/call skip-chars-matching-in-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . slice->start = EAX
|
||||
89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX
|
||||
# if (slice->start >= end) break
|
||||
39/compare 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # compare *ECX with EDX
|
||||
73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:end/disp8
|
||||
# slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
|
||||
# . EAX = skip-chars-not-matching-in-slice(curr, end, ' ')
|
||||
# . . push args
|
||||
68/push 0x20/imm32/space
|
||||
52/push-EDX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call skip-chars-not-matching-in-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . slice->end = EAX
|
||||
89/copy 1/mod/direct 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ECX+4)
|
||||
# *out = parse-hex-int(slice)
|
||||
# . EAX = parse-hex-int(slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call parse-hex-int/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# *out = EAX
|
||||
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
|
||||
# out += 4
|
||||
81 0/subop/add 3/mod/direct 3/rm32/EBX . . . . . 4/imm32 # add to EBX
|
||||
# slice->start = slice->end
|
||||
8b/copy 1/mod/direct 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX
|
||||
81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX
|
||||
eb/jump $parse-array-of-ints:loop2/disp8
|
||||
$parse-array-of-ints:end:
|
||||
# return EDI
|
||||
89/copy 3/mod/direct 0/rm32/EAX . . . 7/r32/EDI . . # copy EDI to EAX
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-parse-array-of-ints:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = [1, 2, 3]
|
||||
68/push 3/imm32
|
||||
68/push 2/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-array-of-ints(Heap, "1 2 3")
|
||||
# . . push args
|
||||
68/push "1 2 3"/imm32
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call parse-array-of-ints/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# EAX = array-equal?(ECX, EAX)
|
||||
# . . push args
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-parse-array-of-ints"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-parse-array-of-ints-empty:
|
||||
# - empty string = empty array
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# EAX = parse-array-of-ints(Heap, "")
|
||||
# . . push args
|
||||
68/push ""/imm32
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call parse-array-of-ints/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-parse-array-of-ints-empty"/imm32
|
||||
68/push 0/imm32/size
|
||||
ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-parse-array-of-ints-just-whitespace:
|
||||
# - just whitespace = empty array
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# EAX = parse-array-of-ints(Heap, " ")
|
||||
# . . push args
|
||||
68/push " "/imm32
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call parse-array-of-ints/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*EAX, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-parse-array-of-ints-empty"/imm32
|
||||
68/push 0/imm32/size
|
||||
ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-parse-array-of-ints-extra-whitespace:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = [1, 2, 3]
|
||||
68/push 3/imm32
|
||||
68/push 2/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EAX = parse-array-of-ints(Heap, " 1 2 3 ")
|
||||
# . . push args
|
||||
68/push " 1 2 3 "/imm32
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call parse-array-of-ints/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# EAX = array-equal?(ECX, EAX)
|
||||
# . . push args
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-parse-array-of-ints-extra-whitespace"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# helper for later tests
|
||||
# compare an array with a string representation of an array literal
|
||||
check-array-equal: # a : (address array int), expected : (address string), msg : (address string)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
# var b/ECX = parse-array-of-ints(Heap, expected)
|
||||
# . EAX = parse-array-of-ints(Heap, expected)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call parse-array-of-ints/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . b = EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX
|
||||
# EAX = array-equal?(a, b)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call array-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$check-array-equal:end:
|
||||
# . restore registers
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-check-array-equal:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var ECX = [1, 2, 3]
|
||||
68/push 3/imm32
|
||||
68/push 2/imm32
|
||||
68/push 1/imm32
|
||||
68/push 0xc/imm32/size
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# check-array-equal(ECX, "1 2 3", "msg")
|
||||
# . . push args
|
||||
68/push "F - test-check-array-equal"/imm32
|
||||
68/push "1 2 3"/imm32
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call check-array-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
Heap:
|
||||
# curr
|
||||
0/imm32
|
||||
# limit
|
||||
0/imm32
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
|
@ -0,0 +1,84 @@
|
|||
# Fill a region of memory with zeroes.
|
||||
|
||||
== code
|
||||
# instruction effective address register displacement immediate
|
||||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
zero-out: # start : address, len : int
|
||||
# pseudocode:
|
||||
# curr/ESI = start
|
||||
# i/ECX = 0
|
||||
# while true
|
||||
# if (i >= len) break
|
||||
# *curr = 0
|
||||
# ++curr
|
||||
# ++i
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
56/push-ESI
|
||||
# curr/ESI = start
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# i/ECX = 0
|
||||
31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX
|
||||
# EDX = len
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX
|
||||
$zero-out:loop:
|
||||
# if (i >= len) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $zero-out:end/disp8
|
||||
# *curr = 0
|
||||
c6 0/subop/copy 0/mod/direct 6/rm32/ESI . . . . . 0/imm8 # copy byte to *ESI
|
||||
# ++curr
|
||||
46/increment-ESI
|
||||
# ++i
|
||||
41/increment-ECX
|
||||
eb/jump $zero-out:loop/disp8
|
||||
$zero-out:end:
|
||||
# . restore registers
|
||||
5e/pop-to-ESI
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-zero-out:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# region/ECX = 34, 35, 36, 37
|
||||
68/push 0x37363534/imm32
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# zero-out(ECX, 3)
|
||||
# . . push args
|
||||
68/push 3/imm32/len
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call zero-out/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# first 3 bytes cleared, fourth left alone
|
||||
# . check-ints-equal(*ECX, 0x37000000, msg)
|
||||
# . . push args
|
||||
68/push "F - test-zero-out"/imm32
|
||||
68/push 0x37000000/imm32
|
||||
ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
|
@ -627,18 +627,26 @@ allocated memory for it.)_
|
|||
#### writing to disk
|
||||
* `write`: string -> file
|
||||
- Can also be used to cat a string into a stream.
|
||||
- Will abort the entire program if there isn't enough room.
|
||||
- Will abort the entire program if destination is a stream and doesn't have
|
||||
enough room.
|
||||
* `write-stream`: stream -> file
|
||||
- Can also be used to cat one stream into another.
|
||||
- Will abort the entire program if there isn't enough room.
|
||||
- Will abort the entire program if destination is a stream and doesn't have
|
||||
enough room.
|
||||
* `write-slice`: slice -> stream
|
||||
- Will abort the entire program if there isn't enough room in the
|
||||
destination stream.
|
||||
* `append-byte`: int -> stream
|
||||
- Will abort the entire program if there isn't enough room.
|
||||
- Will abort the entire program if there isn't enough room in the
|
||||
destination stream.
|
||||
* `append-byte-hex`: int -> stream
|
||||
- textual representation in hex, no '0x' prefix
|
||||
- Will abort the entire program if there isn't enough room.
|
||||
- Will abort the entire program if there isn't enough room in the
|
||||
destination stream.
|
||||
* `print-int32`: int -> stream
|
||||
- textual representation in hex, including '0x' prefix
|
||||
- Will abort the entire program if there isn't enough room.
|
||||
- Will abort the entire program if there isn't enough room in the
|
||||
destination stream.
|
||||
* `write-buffered`: string -> buffered-file
|
||||
* `write-slice-buffered`: slice -> buffered-file
|
||||
* `flush`: buffered-file
|
||||
|
|
BIN
subx/apps/assort
BIN
subx/apps/assort
Binary file not shown.
|
@ -34,11 +34,6 @@ Entry:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
# for debugging: run a single test
|
||||
#? e8/call test-convert/disp32
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? eb/jump $main:end/disp8
|
||||
|
||||
# run tests if necessary, convert stdin if not
|
||||
# . prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -86,8 +81,8 @@ $main:end:
|
|||
cd/syscall 0x80/imm8
|
||||
|
||||
# data structure:
|
||||
# row: pair of (address array byte) and (address stream byte)
|
||||
# table: (address stream row)
|
||||
# table: (address stream {string, (address stream byte)}) (8 bytes per row)
|
||||
# inefficient; uses sequential search for looking up segments by name
|
||||
|
||||
convert: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
# pseudocode:
|
||||
|
@ -439,7 +434,8 @@ test-convert:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
read-segments: # in : (address buffered-file), table : (address stream row)
|
||||
# beware: leaks memory (one name per segment read)
|
||||
read-segments: # in : (address buffered-file), table : (address stream {string, (address stream byte)})
|
||||
# pseudocode:
|
||||
# var curr-segment = null
|
||||
# var line = new-stream(512, 1)
|
||||
|
@ -454,13 +450,14 @@ read-segments: # in : (address buffered-file), table : (address stream row)
|
|||
# continue
|
||||
# if slice-equal?(word-slice, "==")
|
||||
# var segment-name = next-word(line)
|
||||
# curr-segment = get-or-insert-segment(table, segment-name, Segment-size)
|
||||
# if curr-segment->write == 0
|
||||
# rewind-stream(line)
|
||||
# write-stream(curr-segment, line)
|
||||
# else
|
||||
# rewind-stream(line)
|
||||
# write-stream(curr-segment, line) # abort if curr-segment overflows
|
||||
# segment-slot = leaky-get-or-insert-slice(table, segment-name, row-size=8)
|
||||
# curr-segment = *segment-slot
|
||||
# if curr-segment != 0
|
||||
# continue
|
||||
# curr-segment = new-stream(Segment-size)
|
||||
# *segment-slot = curr-segment
|
||||
# rewind-stream(line)
|
||||
# write-stream(curr-segment, line) # abort if curr-segment overflows
|
||||
#
|
||||
# word-slice and segment-name are both slices with disjoint lifetimes, so
|
||||
# we'll use the same address for them.
|
||||
|
@ -489,7 +486,7 @@ read-segments: # in : (address buffered-file), table : (address stream row)
|
|||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# var word-slice/EDX = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/curr
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
$read-segments:loop:
|
||||
# clear-stream(line)
|
||||
|
@ -610,10 +607,7 @@ $read-segments:check-for-segment-header:
|
|||
#? # . . discard args
|
||||
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
#? # }}}
|
||||
# if slice-equal?(word-slice, "==")
|
||||
# segment-name = next-word(line)
|
||||
# curr-segment = get-or-insert(table, segment-name)
|
||||
# if (curr-segment->write > 0) continue
|
||||
# if !slice-equal?(word-slice, "==") goto next check
|
||||
# . EAX = slice-equal?(word-slice, "==")
|
||||
# . . push args
|
||||
68/push "=="/imm32
|
||||
|
@ -625,7 +619,7 @@ $read-segments:check-for-segment-header:
|
|||
# . if (EAX == 0) goto check3
|
||||
3d/compare-EAX-and 0/imm32
|
||||
0f 84/jump-if-equal $read-segments:regular-line/disp32
|
||||
# . next-word(line, segment-name)
|
||||
# segment-name = next-word(line)
|
||||
# . . push args
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
|
@ -675,21 +669,38 @@ $read-segments:check-for-segment-header:
|
|||
#? # . . discard args
|
||||
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
#? # }}}
|
||||
# . EAX = get-or-insert-segment(table, segment-name, Segment-size)
|
||||
# segment-slot/EAX = leaky-get-or-insert-slice(table, segment-name, row-size=8)
|
||||
# . . push args
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size
|
||||
68/push 8/imm32/row-size
|
||||
52/push-EDX
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
# . . call
|
||||
e8/call get-or-insert-segment/disp32
|
||||
e8/call leaky-get-or-insert-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# curr-segment = *segment-slot
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 3/r32/EBX . . # copy *EAX to EBX
|
||||
# if (curr-segment != 0) continue
|
||||
81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX
|
||||
0f 85/jump-if-not-equal $read-segments:loop/disp32
|
||||
# curr-segment = new-stream(Heap, Segment-size, 1)
|
||||
# . save segment-slot
|
||||
50/push-EAX
|
||||
# . EAX = new-stream(Heap, Segment-size, 1)
|
||||
# . . push args
|
||||
68/push 1/imm32
|
||||
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call new-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . curr-segment = EAX
|
||||
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
|
||||
# . if (curr-segment->write > 0) continue
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX
|
||||
3d/compare-EAX-and 0/imm32
|
||||
0f 8f/jump-if-greater $read-segments:loop/disp32
|
||||
# . restore segment-slot
|
||||
58/pop-to-EAX
|
||||
# *segment-slot = curr-segment
|
||||
89/copy 0/mod/indirect 0/rm32/EAX . . . 3/r32/EBX . . # copy EBX to *EAX
|
||||
# fall through
|
||||
$read-segments:regular-line:
|
||||
# rewind-stream(line)
|
||||
|
@ -724,7 +735,7 @@ $read-segments:end:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
write-segments: # out : (address buffered-file), table : (address stream row)
|
||||
write-segments: # out : (address buffered-file), table : (address stream {string, (address stream byte)})
|
||||
# pseudocode:
|
||||
# var curr = table->data
|
||||
# var max = table->data + table->write
|
||||
|
@ -752,7 +763,7 @@ write-segments: # out : (address buffered-file), table : (address stream row)
|
|||
$write-segments:loop:
|
||||
# if (curr >= max) break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 2/r32/EDX . . # compare ESI with EDX
|
||||
7d/jump-if-greater-or-equal $write-segments:break/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $write-segments:break/disp8
|
||||
# stream/EAX = table[i].stream
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
||||
# write-stream-data(out, stream)
|
||||
|
@ -785,534 +796,9 @@ $write-segments:end:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
## helpers
|
||||
|
||||
# TODO: pass in an allocation descriptor
|
||||
get-or-insert-segment: # table : (address stream row), s : (address slice), n : int -> EAX : (address stream)
|
||||
# pseudocode:
|
||||
# curr = table->data
|
||||
# max = &table->data[table->write]
|
||||
# while curr < max
|
||||
# if slice-equal?(s, *curr)
|
||||
# return *(curr+4)
|
||||
# curr += 8
|
||||
# if table->write < table->length
|
||||
# *max = slice-to-string(Heap, s)
|
||||
# result = new-stream(Heap, n, 1)
|
||||
# *(max+4) = result
|
||||
# table->write += 8
|
||||
# return result
|
||||
# return 0
|
||||
#
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
56/push-ESI
|
||||
# ESI = table
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# curr/ECX = table->data
|
||||
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX
|
||||
# max/EDX = table->data + table->write
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
|
||||
8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX
|
||||
$get-or-insert-segment:search-loop:
|
||||
# if (curr >= max) break
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $get-or-insert-segment:not-found/disp8
|
||||
# if (slice-equal?(s, *curr)) return *(curr+4)
|
||||
# . EAX = slice-equal?(s, *curr)
|
||||
# . . push args
|
||||
ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
# . . call
|
||||
e8/call slice-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . if (EAX != 0) return EAX = *(curr+4)
|
||||
3d/compare-EAX-and 0/imm32
|
||||
74/jump-if-equal $get-or-insert-segment:mismatch/disp8
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
eb/jump $get-or-insert-segment:end/disp8
|
||||
$get-or-insert-segment:mismatch:
|
||||
# curr += 8
|
||||
81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 8/imm32 # add to ECX
|
||||
# loop
|
||||
eb/jump $get-or-insert-segment:search-loop/disp8
|
||||
$get-or-insert-segment:not-found:
|
||||
# result/EAX = 0
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
# if (table->write >= table->length) abort
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX
|
||||
3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8)
|
||||
7d/jump-if-greater-or-equal $get-or-insert-segment:abort/disp8
|
||||
# *max = slice-to-string(Heap, s)
|
||||
# . EAX = slice-to-string(Heap, s)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call slice-to-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . *max = EAX
|
||||
89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX
|
||||
# result/EAX = new-stream(Heap, n, 1)
|
||||
# . . push args
|
||||
68/push 1/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
||||
68/push Heap/imm32
|
||||
# . . call
|
||||
e8/call new-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# *(max+4) = result
|
||||
89/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDX+4)
|
||||
# table->write += 8
|
||||
81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 8/imm32 # add to *ESI
|
||||
$get-or-insert-segment:end:
|
||||
# . restore registers
|
||||
5e/pop-to-ESI
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
$get-or-insert-segment:abort:
|
||||
# . _write(2/stderr, error)
|
||||
# . . push args
|
||||
68/push "get-or-insert-segment: too many segments\n"/imm32
|
||||
68/push 2/imm32/stderr
|
||||
# . . call
|
||||
e8/call _write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . syscall(exit, 1)
|
||||
bb/copy-to-EBX 1/imm32
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
# never gets here
|
||||
|
||||
test-get-or-insert-segment:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# var table/ECX : (address stream byte) = stream(2 * 8)
|
||||
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP
|
||||
68/push 0x10/imm32/length
|
||||
68/push 0/imm32/read
|
||||
68/push 0/imm32/write
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# EDX : (address slice) = "code"
|
||||
68/push _test-code-segment-end/imm32/end
|
||||
68/push _test-code-segment/imm32/start
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
$test-get-or-insert-segment:first-call:
|
||||
# - start with an empty table, insert one segment, verify that it was inserted
|
||||
# segment/EAX = get-or-insert-segment(table, "code" slice, 10)
|
||||
# . . push args
|
||||
68/push 0xa/imm32/segment-length
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call get-or-insert-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# save segment
|
||||
50/push-EAX
|
||||
# if (segment != 0) goto next check
|
||||
3d/compare-EAX-and 0/imm32
|
||||
75/jump-if-not-equal $test-get-or-insert-segment:check1/disp8
|
||||
# fail test
|
||||
# . _write(2/stderr, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/0\n"/imm32
|
||||
68/push 2/imm32/stderr
|
||||
# . . call
|
||||
e8/call _write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# . increment Num-test-failures
|
||||
ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Num-test-failures/disp32 # increment *Num-test-failures
|
||||
e9/jump $test-get-or-insert-segment:end/disp32
|
||||
$test-get-or-insert-segment:check1:
|
||||
# check-ints-equal(segment->length, 10, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/1"/imm32
|
||||
68/push 0xa/imm32/segment-length
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$test-get-or-insert-segment:check2:
|
||||
# check-ints-equal(table->write, rowsize = 8, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/2"/imm32
|
||||
68/push 8/imm32/row-size
|
||||
ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# EAX = string-equal?(*table->data, "code")
|
||||
# . . push args
|
||||
68/push "code"/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12)
|
||||
# . . call
|
||||
e8/call string-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/3"/imm32
|
||||
68/push 1/imm32
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$test-get-or-insert-segment:check3:
|
||||
# stream/EAX = *(table->data+4)
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 0x10/disp8 . # copy *(ECX+16) to EAX
|
||||
# check-ints-equal(stream->length, 10, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/4"/imm32
|
||||
68/push 0xa/imm32/segment-size
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$test-get-or-insert-segment:second-call:
|
||||
# - insert the same segment name again, verify that it was reused
|
||||
# segment2/EAX = get-or-insert-segment(table, "code" slice, 8)
|
||||
# . . push args
|
||||
68/push 8/imm32/segment-length
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call get-or-insert-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# restore old segment1
|
||||
5a/pop-to-EDX
|
||||
# check-ints-equal(segment2/EAX, segment1/EDX, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/5"/imm32
|
||||
52/push-EDX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# no change to table size
|
||||
# . check-ints-equal(table->write, rowsize = 8, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/6"/imm32
|
||||
68/push 8/imm32/row-size
|
||||
ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$test-get-or-insert-segment:third-call:
|
||||
# - insert a new segment name, verify that it was inserted
|
||||
# EDX : (address slice) = "data"
|
||||
c7 0/subop/copy 0/mod/indirect 2/rm32/EDX . . . . . _test-data-segment/imm32 # copy to *EDX
|
||||
c7 0/subop/copy 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 _test-data-segment-end/imm32 # copy to *(EDX+4)
|
||||
# segment2/EAX = get-or-insert-segment(table, "data" slice, 8)
|
||||
# . . push args
|
||||
68/push 8/imm32/segment-length
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call get-or-insert-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# table gets a new row
|
||||
# . check-ints-equal(table->write, 2 rows = 16, msg)
|
||||
# . . push args
|
||||
68/push "F - test-get-or-insert-segment/7"/imm32
|
||||
68/push 0x10/imm32/two-rows
|
||||
ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
$test-get-or-insert-segment:end:
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# (re)compute the bounds of the next word in the line
|
||||
# return empty string on reaching end of file
|
||||
next-word: # line : (address stream byte), out : (address slice)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# . save registers
|
||||
50/push-EAX
|
||||
51/push-ECX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = line
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# EDI = out
|
||||
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI
|
||||
# skip-chars-matching(line, ' ')
|
||||
# . . push args
|
||||
68/push 0x20/imm32/space
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call skip-chars-matching/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
$next-word:check0:
|
||||
# if (line->read >= line->write) clear out and return
|
||||
# . EAX = line->read
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
||||
# . if (EAX < line->write) goto next check
|
||||
3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI
|
||||
7c/jump-if-lesser $next-word:check-for-comment/disp8
|
||||
# . return out = {0, 0}
|
||||
c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI
|
||||
c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4)
|
||||
eb/jump $next-word:end/disp8
|
||||
$next-word:check-for-comment:
|
||||
# out->start = &line->data[line->read]
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX
|
||||
89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI
|
||||
# if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return
|
||||
# . EAX = line->data[line->read]
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL
|
||||
# . compare
|
||||
3d/compare-EAX-and 0x23/imm32/pound
|
||||
75/jump-if-not-equal $next-word:regular-word/disp8
|
||||
$next-word:comment:
|
||||
# . out->end = &line->data[line->write]
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
|
||||
89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4)
|
||||
# . line->read = line->write
|
||||
89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4)
|
||||
# . return
|
||||
eb/jump $next-word:end/disp8
|
||||
$next-word:regular-word:
|
||||
# otherwise skip-chars-not-matching-whitespace(line) # including trailing newline
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
# . . call
|
||||
e8/call skip-chars-not-matching-whitespace/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# out->end = &line->data[line->read]
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX
|
||||
89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4)
|
||||
$next-word:end:
|
||||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# setup
|
||||
# . clear-stream(_test-stream)
|
||||
# . . push args
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# write(_test-stream, " ab")
|
||||
# . . push args
|
||||
68/push " ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# next-word(_test-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(slice->start - _test-stream->data, 2, msg)
|
||||
# . check-ints-equal(slice->start - _test-stream, 14, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word: start"/imm32
|
||||
68/push 0xe/imm32
|
||||
# . . push slice->start - _test-stream
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# check-ints-equal(slice->end - _test-stream->data, 4, msg)
|
||||
# . check-ints-equal(slice->end - _test-stream, 16, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word: end"/imm32
|
||||
68/push 0x10/imm32
|
||||
# . . push slice->end - _test-stream
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word-returns-whole-comment:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# setup
|
||||
# . clear-stream(_test-stream)
|
||||
# . . push args
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# write(_test-stream, " # a")
|
||||
# . . push args
|
||||
68/push " # a"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# next-word(_test-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(slice->start - _test-stream->data, 2, msg)
|
||||
# . check-ints-equal(slice->start - _test-stream, 14, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment: start"/imm32
|
||||
68/push 0xe/imm32
|
||||
# . . push slice->start - _test-stream
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# check-ints-equal(slice->end - _test-stream->data, 5, msg)
|
||||
# . check-ints-equal(slice->end - _test-stream, 17, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment: end"/imm32
|
||||
68/push 0x11/imm32
|
||||
# . . push slice->end - _test-stream
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word-returns-empty-string-on-eof:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# setup
|
||||
# . clear-stream(_test-stream)
|
||||
# . . push args
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# write nothing to _test-stream
|
||||
# next-word(_test-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(slice->end - slice->start, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-empty-string-on-eof"/imm32
|
||||
68/push 0/imm32
|
||||
# . . push slice->end - slice->start
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX
|
||||
50/push-EAX
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-code-segment:
|
||||
63/c 6f/o 64/d 65/e
|
||||
_test-code-segment-end:
|
||||
|
||||
_test-data-segment:
|
||||
64/d 61/a 74/t 61/a
|
||||
_test-data-segment-end:
|
||||
|
||||
Segment-size:
|
||||
0x1000/imm32/4KB
|
||||
|
||||
Heap:
|
||||
# curr
|
||||
0/imm32
|
||||
# limit
|
||||
0/imm32
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
Binary file not shown.
|
@ -31,10 +31,15 @@
|
|||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
Entry: # run tests if necessary, call 'compile' if not
|
||||
|
||||
#? # for debugging: run a single test; don't bother setting status code
|
||||
#? e8/call test-get-num-aborts-on-non-digit-in-Look/disp32
|
||||
#? eb/jump $main:end/disp8
|
||||
# initialize heap
|
||||
# . Heap = new-segment(64KB)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
68/push 0x10000/imm32/64KB
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
# . prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
|
Binary file not shown.
|
@ -31,10 +31,15 @@
|
|||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
Entry: # run tests if necessary, call 'compile' if not
|
||||
|
||||
#? # for debugging: run a single test; don't bother setting status code
|
||||
#? e8/call test-get-num-reads-single-digit/disp32
|
||||
#? eb/jump $main:end/disp8
|
||||
# initialize heap
|
||||
# . Heap = new-segment(64KB)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
68/push 0x10000/imm32/64KB
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
# . prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
|
Binary file not shown.
|
@ -30,11 +30,6 @@ Entry:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
# for debugging: run a single test
|
||||
#? e8/call test-string-length-at-start-of-slice-escaped/disp32
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? eb/jump $main:end/disp8
|
||||
|
||||
# run tests if necessary, convert stdin if not
|
||||
# . prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -95,7 +90,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> <void
|
|||
# read-line-buffered(in, line)
|
||||
# if (line->write == 0) break # end of file
|
||||
# while true
|
||||
# var word-slice = next-word(line)
|
||||
# var word-slice = next-word-or-string(line)
|
||||
# if slice-empty?(word-slice) # end of line
|
||||
# break
|
||||
# if slice-starts-with?(word-slice, "#") # comment
|
||||
|
@ -127,7 +122,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> <void
|
|||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# var word-slice/EDX = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/curr
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
||||
# new-data-segment/EDI = new-stream(Heap, Segment-size, 1)
|
||||
# . EAX = new-stream(Heap, Segment-size, 1)
|
||||
|
@ -170,12 +165,12 @@ $convert:check0:
|
|||
81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX
|
||||
0f 84/jump-if-equal $convert:break/disp32
|
||||
$convert:word-loop:
|
||||
# next-word(line, word-slice)
|
||||
# next-word-or-string(line, word-slice)
|
||||
# . . push args
|
||||
52/push-EDX
|
||||
51/push-ECX
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
$convert:check1:
|
||||
|
@ -913,7 +908,7 @@ $emit-string-literal-data:loop-init:
|
|||
$emit-string-literal-data:loop:
|
||||
# if (curr >= max) break
|
||||
39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI
|
||||
7d/jump-if-greater-or-equal $emit-string-literal-data:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp8
|
||||
# CL = *curr
|
||||
8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL
|
||||
# if (ECX == '"') break
|
||||
|
@ -926,7 +921,7 @@ $emit-string-literal-data:loop:
|
|||
42/increment-EDX
|
||||
# . if (curr >= max) break
|
||||
39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI
|
||||
7d/jump-if-greater-or-equal $emit-string-literal-data:end/disp8
|
||||
73/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp8
|
||||
# . CL = *curr
|
||||
8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL
|
||||
$emit-string-literal-data:emit:
|
||||
|
@ -1037,7 +1032,7 @@ test-emit-string-literal-data:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = '"abc"/d'
|
||||
68/push _test-slice-abc-metadata-end/imm32
|
||||
68/push _test-slice-abc-limit/imm32
|
||||
68/push _test-slice-abc/imm32
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-string-literal-data(_test-output-stream, slice)
|
||||
|
@ -1101,8 +1096,8 @@ test-emit-string-literal-data-empty:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = '""'
|
||||
68/push _test-slice-empty-string-literal-end/imm32
|
||||
68/push _test-slice-empty-string-literal/imm32
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-string-literal-data(_test-output-stream, slice)
|
||||
# . . push args
|
||||
|
@ -1166,7 +1161,7 @@ test-emit-string-literal-data-no-metadata-for-non-alphanumerics:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = '"a b"'
|
||||
68/push _test-slice-a-space-b-end/imm32
|
||||
68/push _test-slice-a-space-b-limit/imm32
|
||||
68/push _test-slice-a-space-b/imm32
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-string-literal-data(_test-output-stream, slice)
|
||||
|
@ -1230,7 +1225,7 @@ test-emit-string-literal-data-handles-escape-sequences:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = '"a\"b"'
|
||||
68/push _test-slice-a-dquote-b-end/imm32
|
||||
68/push _test-slice-a-dquote-b-limit/imm32
|
||||
68/push _test-slice-a-dquote-b/imm32
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-string-literal-data(_test-output-stream, slice)
|
||||
|
@ -1295,7 +1290,7 @@ emit-metadata: # out : (address buffered-file), word : (address slice)
|
|||
# if *curr == '/'
|
||||
# break
|
||||
# ++curr
|
||||
# slice->curr = curr
|
||||
# slice->start = curr
|
||||
# write-slice-buffered(out, slice)
|
||||
#
|
||||
# . prolog
|
||||
|
@ -1349,7 +1344,7 @@ $emit-metadata:skip-datum-loop:
|
|||
41/increment-ECX
|
||||
eb/jump $emit-metadata:skip-datum-loop/disp8
|
||||
$emit-metadata:emit:
|
||||
# slice->curr = ECX
|
||||
# slice->start = ECX
|
||||
89/copy 0/mod/indirect 3/rm32/EBX . . . 1/r32/ECX . . # copy ECX to *EBX
|
||||
# write-slice-buffered(out, slice)
|
||||
# . . push args
|
||||
|
@ -1394,9 +1389,14 @@ test-emit-metadata:
|
|||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = "abc/def"
|
||||
68/push _test-slice-word-end/imm32
|
||||
68/push _test-slice-word/imm32/start
|
||||
# (EAX..ECX) = "abc/def"
|
||||
b8/copy-to-EAX "abc/def"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-metadata(_test-output-buffered-file, slice)
|
||||
# . . push args
|
||||
|
@ -1448,9 +1448,14 @@ test-emit-metadata-none:
|
|||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = "abc"
|
||||
68/push _test-slice-word-datum-end/imm32
|
||||
68/push _test-slice-word/imm32/start
|
||||
# (EAX..ECX) = "abc"
|
||||
b8/copy-to-EAX "abc"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-metadata(_test-output-buffered-file, slice)
|
||||
# . . push args
|
||||
|
@ -1502,9 +1507,14 @@ test-emit-metadata-multiple:
|
|||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = "abc/def/ghi"
|
||||
68/push _test-slice-word-end2/imm32
|
||||
68/push _test-slice-word/imm32/start
|
||||
# (EAX..ECX) = "abc/def/ghi"
|
||||
b8/copy-to-EAX "abc/def/ghi"/imm32
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
|
||||
05/add-to-EAX 4/imm32
|
||||
# var slice/ECX = {EAX, ECX}
|
||||
51/push-ECX
|
||||
50/push-EAX
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-metadata(_test-output-buffered-file, slice)
|
||||
# . . push args
|
||||
|
@ -1618,7 +1628,7 @@ test-emit-metadata-in-string-literal:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# var slice/ECX = "\"abc/def\"/ghi"
|
||||
68/push _test-slice-literal-string-with-metadata-end/imm32
|
||||
68/push _test-slice-literal-string-with-limit/imm32
|
||||
68/push _test-slice-literal-string/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# emit-metadata(_test-output-buffered-file, slice)
|
||||
|
@ -1678,7 +1688,7 @@ test-emit-metadata-in-string-literal:
|
|||
|
||||
# (re)compute the bounds of the next word in the line
|
||||
# return empty string on reaching end of file
|
||||
next-word: # line : (address stream byte), out : (address slice)
|
||||
next-word-or-string: # line : (address stream byte), out : (address slice)
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -1699,18 +1709,18 @@ next-word: # line : (address stream byte), out : (address slice)
|
|||
e8/call skip-chars-matching/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
$next-word:check0:
|
||||
$next-word-or-string:check0:
|
||||
# if (line->read >= line->write) clear out and return
|
||||
# . EAX = line->read
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
||||
# . if (EAX < line->write) goto next check
|
||||
3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI
|
||||
7c/jump-if-lesser $next-word:check-for-comment/disp8
|
||||
7c/jump-if-lesser $next-word-or-string:check-for-comment/disp8
|
||||
# . return out = {0, 0}
|
||||
c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI
|
||||
c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4)
|
||||
eb/jump $next-word:end/disp8
|
||||
$next-word:check-for-comment:
|
||||
eb/jump $next-word-or-string:end/disp8
|
||||
$next-word-or-string:check-for-comment:
|
||||
# out->start = &line->data[line->read]
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX
|
||||
|
@ -1721,8 +1731,8 @@ $next-word:check-for-comment:
|
|||
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL
|
||||
# . compare
|
||||
3d/compare-EAX-and 0x23/imm32/pound
|
||||
75/jump-if-not-equal $next-word:check-for-string-literal/disp8
|
||||
$next-word:comment:
|
||||
75/jump-if-not-equal $next-word-or-string:check-for-string-literal/disp8
|
||||
$next-word-or-string:comment:
|
||||
# out->end = &line->data[line->write]
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
|
||||
|
@ -1731,16 +1741,16 @@ $next-word:comment:
|
|||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
||||
89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4)
|
||||
# return
|
||||
eb/jump $next-word:end/disp8
|
||||
$next-word:check-for-string-literal:
|
||||
eb/jump $next-word-or-string:end/disp8
|
||||
$next-word-or-string:check-for-string-literal:
|
||||
# if line->data[line->read] == '"'
|
||||
# . EAX = line->data[line->read]
|
||||
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
||||
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL
|
||||
# . compare
|
||||
3d/compare-EAX-and 0x22/imm32/dquote
|
||||
75/jump-if-not-equal $next-word:regular-word/disp8
|
||||
$next-word:string-literal:
|
||||
75/jump-if-not-equal $next-word-or-string:regular-word/disp8
|
||||
$next-word-or-string:string-literal:
|
||||
# skip-string(line)
|
||||
# . . push args
|
||||
56/push-ESI
|
||||
|
@ -1749,7 +1759,7 @@ $next-word:string-literal:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# fall through
|
||||
$next-word:regular-word:
|
||||
$next-word-or-string:regular-word:
|
||||
# skip-chars-not-matching-whitespace(line) # including trailing newline
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
||||
|
@ -1761,7 +1771,7 @@ $next-word:regular-word:
|
|||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX
|
||||
89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4)
|
||||
$next-word:end:
|
||||
$next-word-or-string:end:
|
||||
# . restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
|
@ -1772,7 +1782,7 @@ $next-word:end:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word:
|
||||
test-next-word-or-string:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -1796,17 +1806,17 @@ test-next-word:
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# next-word(_test-input-stream, slice)
|
||||
# next-word-or-string(_test-input-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-input-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(_test-input-stream->read, 4, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word/updates-stream-read-correctly"/imm32
|
||||
68/push "F - test-next-word-or-string/updates-stream-read-correctly"/imm32
|
||||
68/push 4/imm32
|
||||
b8/copy-to-EAX _test-input-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
|
||||
|
@ -1817,7 +1827,7 @@ test-next-word:
|
|||
# check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
|
||||
# . check-ints-equal(slice->start - _test-input-stream, 14, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word: start"/imm32
|
||||
68/push "F - test-next-word-or-string: start"/imm32
|
||||
68/push 0xe/imm32
|
||||
# . . push slice->start - _test-input-stream
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
|
@ -1830,7 +1840,7 @@ test-next-word:
|
|||
# check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
|
||||
# . check-ints-equal(slice->end - _test-input-stream, 16, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word: end"/imm32
|
||||
68/push "F - test-next-word-or-string: end"/imm32
|
||||
68/push 0x10/imm32
|
||||
# . . push slice->end - _test-input-stream
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
|
@ -1845,7 +1855,7 @@ test-next-word:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word-returns-whole-comment:
|
||||
test-next-word-or-string-returns-whole-comment:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -1869,17 +1879,17 @@ test-next-word-returns-whole-comment:
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# next-word(_test-input-stream, slice)
|
||||
# next-word-or-string(_test-input-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-input-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(_test-input-stream->read, 5, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment/updates-stream-read-correctly"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32
|
||||
68/push 5/imm32
|
||||
b8/copy-to-EAX _test-input-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
|
||||
|
@ -1890,7 +1900,7 @@ test-next-word-returns-whole-comment:
|
|||
# check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
|
||||
# . check-ints-equal(slice->start - _test-input-stream, 14, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment: start"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-whole-comment: start"/imm32
|
||||
68/push 0xe/imm32
|
||||
# . . push slice->start - _test-input-stream
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
|
@ -1903,7 +1913,7 @@ test-next-word-returns-whole-comment:
|
|||
# check-ints-equal(slice->end - _test-input-stream->data, 5, msg)
|
||||
# . check-ints-equal(slice->end - _test-input-stream, 17, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment: end"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-whole-comment: end"/imm32
|
||||
68/push 0x11/imm32
|
||||
# . . push slice->end - _test-input-stream
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
|
@ -1918,7 +1928,7 @@ test-next-word-returns-whole-comment:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word-returns-empty-string-on-eof:
|
||||
test-next-word-or-string-returns-empty-string-on-eof:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -1935,17 +1945,17 @@ test-next-word-returns-empty-string-on-eof:
|
|||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
||||
# write nothing to _test-input-stream
|
||||
# next-word(_test-input-stream, slice)
|
||||
# next-word-or-string(_test-input-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-input-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(slice->end - slice->start, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-empty-string-on-eof"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-empty-string-on-eof"/imm32
|
||||
68/push 0/imm32
|
||||
# . . push slice->end - slice->start
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
|
@ -1960,7 +1970,7 @@ test-next-word-returns-empty-string-on-eof:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word-returns-whole-string:
|
||||
test-next-word-or-string-returns-whole-string:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -1984,18 +1994,18 @@ test-next-word-returns-whole-string:
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# next-word(_test-input-stream, slice)
|
||||
# next-word-or-string(_test-input-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-input-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
|
||||
# . check-ints-equal(slice->start - _test-input-stream, 13, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-string: start"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-whole-string: start"/imm32
|
||||
68/push 0xd/imm32
|
||||
# . . push slice->start - _test-input-stream
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
|
@ -2008,7 +2018,7 @@ test-next-word-returns-whole-string:
|
|||
# check-ints-equal(slice->end - _test-input-stream->data, 12, msg)
|
||||
# . check-ints-equal(slice->end - _test-input-stream, 24, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-string: end"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-whole-string: end"/imm32
|
||||
68/push 0x18/imm32
|
||||
# . . push slice->end - _test-input-stream
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
|
@ -2023,7 +2033,7 @@ test-next-word-returns-whole-string:
|
|||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-next-word-returns-string-with-escapes:
|
||||
test-next-word-or-string-returns-string-with-escapes:
|
||||
# . prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
@ -2047,18 +2057,18 @@ test-next-word-returns-string-with-escapes:
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# next-word(_test-input-stream, slice)
|
||||
# next-word-or-string(_test-input-stream, slice)
|
||||
# . . push args
|
||||
51/push-ECX
|
||||
68/push _test-input-stream/imm32
|
||||
# . . call
|
||||
e8/call next-word/disp32
|
||||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
|
||||
# . check-ints-equal(slice->start - _test-input-stream, 13, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-string-with-escapes: start"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32
|
||||
68/push 0xd/imm32
|
||||
# . . push slice->start - _test-input-stream
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
||||
|
@ -2071,7 +2081,7 @@ test-next-word-returns-string-with-escapes:
|
|||
# check-ints-equal(slice->end - _test-input-stream->data, 9, msg)
|
||||
# . check-ints-equal(slice->end - _test-input-stream, 21, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-string-with-escapes: end"/imm32
|
||||
68/push "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32
|
||||
68/push 0x15/imm32
|
||||
# . . push slice->end - _test-input-stream
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
||||
|
@ -2634,12 +2644,6 @@ Segment-size:
|
|||
Next-string-literal: # tracks the next auto-generated variable name
|
||||
1/imm32
|
||||
|
||||
Heap:
|
||||
# curr
|
||||
0/imm32
|
||||
# limit
|
||||
0/imm32
|
||||
|
||||
# length-prefixed string containing just a single space
|
||||
Space:
|
||||
# size
|
||||
|
@ -2656,30 +2660,16 @@ Slash:
|
|||
|
||||
_test-slice-abc:
|
||||
22/dquote 61/a 62/b 63/c 22/dquote # "abc"
|
||||
_test-slice-abc-end:
|
||||
2f/slash 64/d
|
||||
_test-slice-abc-metadata-end:
|
||||
|
||||
_test-slice-empty-string-literal:
|
||||
22/dquote 22/dquote # ""
|
||||
_test-slice-empty-string-literal-end:
|
||||
_test-slice-abc-limit:
|
||||
|
||||
_test-slice-a-space-b:
|
||||
22/dquote 61/a 20/space 62/b 22/dquote # "a b"
|
||||
_test-slice-a-space-b-end:
|
||||
_test-slice-a-space-b-limit:
|
||||
|
||||
_test-slice-a-dquote-b:
|
||||
22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b"
|
||||
_test-slice-a-dquote-b-end:
|
||||
|
||||
# abc/def/ghi
|
||||
_test-slice-word:
|
||||
61/a 62/b 63/c # abc
|
||||
_test-slice-word-datum-end:
|
||||
2f/slash 64/d 65/e 66/f # /def
|
||||
_test-slice-word-end:
|
||||
2f/slash 67/g 68/h 69/i # /ghi
|
||||
_test-slice-word-end2:
|
||||
_test-slice-a-dquote-b-limit:
|
||||
|
||||
# "abc/def"/ghi
|
||||
_test-slice-literal-string:
|
||||
|
@ -2687,8 +2677,7 @@ _test-slice-literal-string:
|
|||
61/a 62/b 63/c # abc
|
||||
2f/slash 64/d 65/e 66/f # /def
|
||||
22/dquote
|
||||
_test-slice-literal-string-end:
|
||||
2f/slash 67/g 68/h 69/i # /ghi
|
||||
_test-slice-literal-string-with-metadata-end:
|
||||
_test-slice-literal-string-with-limit:
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
Binary file not shown.
|
@ -19,10 +19,15 @@
|
|||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
Entry: # run tests if necessary, compute `factorial(5)` if not
|
||||
|
||||
#? # for debugging: run a single test; don't bother setting status code
|
||||
#? e8/call test-get-num-reads-single-digit/disp32
|
||||
#? eb/jump $main:end/disp8
|
||||
# initialize heap
|
||||
# . Heap = new-segment(64KB)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
68/push 0x10000/imm32/64KB
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
# . prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
|
BIN
subx/apps/handle
BIN
subx/apps/handle
Binary file not shown.
BIN
subx/apps/hex
BIN
subx/apps/hex
Binary file not shown.
|
@ -18,11 +18,15 @@
|
|||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
Entry: # run tests if necessary, convert stdin if not
|
||||
|
||||
#? # for debugging: run a single test
|
||||
#? e8/call test-convert-next-octet-aborts-on-single-hex-byte/disp32
|
||||
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
#? eb/jump $main:end/disp8
|
||||
# initialize heap
|
||||
# . Heap = new-segment(64KB)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
68/push 0x10000/imm32/64KB
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
|
||||
# . prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
|
|
BIN
subx/apps/pack
BIN
subx/apps/pack
Binary file not shown.
1499
subx/apps/pack.subx
1499
subx/apps/pack.subx
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
28
subx/dgen
28
subx/dgen
|
@ -1,28 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Little helper to quickly build SubX programs in 'debug mode' from the commandline.
|
||||
# Only works for programs in some standard places the repo knows about.
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: $0 <file root without subdirectory or .subx extension>"
|
||||
echo
|
||||
echo "Naming convention: Files starting with 'ex' will be assumed to live in examples/ and be self-contained."
|
||||
echo "Other files will be assumed to live in apps/ and need the standard library."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build in debug mode since the common case at the moment is building small
|
||||
# files. To override, calling scripts should do their own builds to ensure
|
||||
# subx_bin is up to date.
|
||||
export CFLAGS=-g
|
||||
|
||||
case $1 in
|
||||
ex*)
|
||||
./subx --debug translate examples/$1.subx -o examples/`echo $1 |sed 's/\..*//'`
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
./subx --debug translate *.subx apps/$1.subx -o apps/`echo $1 |sed 's/\..*//'`
|
||||
exit $?
|
||||
;;
|
||||
esac
|
22
subx/drun
22
subx/drun
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env zsh
|
||||
# Run commonly-used SubX programs using the SubX VM in 'debug mode'.
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: $0 <binary name without directory> <args>"
|
||||
echo
|
||||
echo "Naming convention: Binaries starting with 'ex' will be assumed to live in examples/"
|
||||
echo "Other binaries will be assumed to live in apps/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
ex*)
|
||||
./subx --debug --trace run examples/$*
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
./subx --debug --trace run apps/$*
|
||||
exit $?
|
||||
;;
|
||||
esac
|
28
subx/gen
28
subx/gen
|
@ -1,28 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Little helper to quickly build SubX programs from the commandline.
|
||||
# Only works for programs in some standard places the repo knows about.
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: $0 <file root without subdirectory or .subx extension>"
|
||||
echo
|
||||
echo "Naming convention: Files starting with 'ex' will be assumed to live in examples/ and be self-contained."
|
||||
echo "Other files will be assumed to live in apps/ and need the standard library."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build in debug mode since the common case at the moment is building small
|
||||
# files. To override, calling scripts should do their own builds to ensure
|
||||
# subx_bin is up to date.
|
||||
export CFLAGS=-g
|
||||
|
||||
case $1 in
|
||||
ex*)
|
||||
./subx translate examples/$1.subx -o examples/`echo $1 |sed 's/\..*//'`
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
./subx translate *.subx apps/$1.subx -o apps/`echo $1 |sed 's/\..*//'`
|
||||
exit $?
|
||||
;;
|
||||
esac
|
22
subx/run
22
subx/run
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env zsh
|
||||
# Run commonly-used SubX programs using the SubX VM.
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: $0 <binary name without directory> <args>"
|
||||
echo
|
||||
echo "Naming convention: Binaries starting with 'ex' will be assumed to live in examples/"
|
||||
echo "Other binaries will be assumed to live in apps/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
ex*)
|
||||
./subx run examples/$*
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
./subx run apps/$*
|
||||
exit $?
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env zsh
|
||||
# Either run the test with the given name, or rerun the most recently run test.
|
||||
# Intended to be called from within Vim. Check out the vimrc.vim file.
|
||||
|
||||
if [[ $2 == 'test-'* ]]
|
||||
then
|
||||
TEST_NAME=$2 envsubst '$TEST_NAME' < run_one_test.subx > /tmp/run_one_test.subx
|
||||
FILES=$(ls [0-9]*.subx apps/subx-common.subx $1 |sort |uniq)
|
||||
echo $FILES > /tmp/last_run_files
|
||||
elif [[ -e /tmp/last_run_files ]]
|
||||
then
|
||||
FILES=`cat /tmp/last_run_files`
|
||||
else
|
||||
echo "no test found"
|
||||
exit 0 # don't open trace
|
||||
fi
|
||||
|
||||
set -e
|
||||
# turn newlines into spaces
|
||||
CFLAGS=$CFLAGS ./subx --debug translate $(echo $FILES) /tmp/run_one_test.subx -o /tmp/a.elf
|
||||
|
||||
./subx --debug --trace run /tmp/a.elf
|
|
@ -0,0 +1,30 @@
|
|||
# run a single test
|
||||
|
||||
== code
|
||||
# instruction effective address register displacement immediate
|
||||
# . op subop mod rm32 base index scale r32
|
||||
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
||||
|
||||
Entry:
|
||||
# Heap = new-segment(64KB)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
68/push 0x10000/imm32/64KB
|
||||
# . . call
|
||||
e8/call new-segment/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# initialize-trace-stream(256KB)
|
||||
# . . push args
|
||||
68/push 0x40000/imm32/256KB
|
||||
# . . call
|
||||
e8/call initialize-trace-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# for debugging: run a single test
|
||||
e8/call $TEST_NAME/disp32
|
||||
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
|
@ -184,6 +184,16 @@ test `uname` = 'Linux' && {
|
|||
echo
|
||||
}
|
||||
|
||||
echo survey
|
||||
./subx translate 0*.subx apps/subx-common.subx apps/survey.subx -o apps/survey
|
||||
[ "$1" != record ] && git diff --exit-code apps/survey
|
||||
./subx run apps/survey test
|
||||
echo
|
||||
test `uname` = 'Linux' && {
|
||||
apps/survey test
|
||||
echo
|
||||
}
|
||||
|
||||
echo pack
|
||||
./subx translate 0*.subx apps/subx-common.subx apps/pack.subx -o apps/pack
|
||||
[ "$1" != record ] && git diff --exit-code apps/pack
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../vimrc.vim
|
|
@ -0,0 +1,95 @@
|
|||
" Highlighting literate directives in C++ sources.
|
||||
function! HighlightTangledFile()
|
||||
" Tangled comments only make sense in the sources and are stripped out of
|
||||
" the generated .cc file. They're highlighted same as regular comments.
|
||||
syntax match tangledComment /\/\/:.*/ | highlight link tangledComment Comment
|
||||
syntax match tangledSalientComment /\/\/::.*/ | highlight link tangledSalientComment SalientComment
|
||||
set comments-=://
|
||||
set comments-=n://
|
||||
set comments+=n://:,n://
|
||||
|
||||
" Inside tangle scenarios.
|
||||
syntax region tangleDirective start=+:(+ skip=+".*"+ end=+)+
|
||||
highlight link tangleDirective Delimiter
|
||||
syntax match traceContains /^+.*/
|
||||
highlight traceContains ctermfg=22
|
||||
syntax match traceAbsent /^-.*/
|
||||
highlight traceAbsent ctermfg=darkred
|
||||
syntax match tangleScenarioSetup /^\s*% .*/ | highlight link tangleScenarioSetup SpecialChar
|
||||
highlight Special ctermfg=160
|
||||
|
||||
syntax match subxString %"[^"]*"% | highlight link subxString Constant
|
||||
" match globals but not registers like 'EAX'
|
||||
syntax match subxGlobal %\<[A-Z][a-z0-9_-]*\>% | highlight link subxGlobal SpecialChar
|
||||
endfunction
|
||||
augroup LocalVimrc
|
||||
autocmd BufRead,BufNewFile *.cc call HighlightTangledFile()
|
||||
autocmd BufRead,BufNewFile *.subx set ft=subx
|
||||
augroup END
|
||||
|
||||
" Scenarios considered:
|
||||
" opening or starting vim with a new or existing file without an extension (should interpret as C++)
|
||||
" opening or starting vim with a new or existing file with a .mu extension
|
||||
" starting vim or opening a buffer without a file name (ok to do nothing)
|
||||
" opening a second file in a new or existing window (shouldn't mess up existing highlighting)
|
||||
" reloading an existing file (shouldn't mess up existing highlighting)
|
||||
|
||||
" assumes CWD is subx/
|
||||
command! -nargs=1 E call EditSubx("edit", <f-args>)
|
||||
if exists("&splitvertical")
|
||||
command! -nargs=1 S call EditSubx("vert split", <f-args>)
|
||||
command! -nargs=1 H call EditSubx("hor split", <f-args>)
|
||||
else
|
||||
command! -nargs=1 S call EditSubx("vert split", <f-args>)
|
||||
command! -nargs=1 H call EditSubx("split", <f-args>)
|
||||
endif
|
||||
|
||||
function! EditSubx(cmd, arg)
|
||||
exec "silent! " . a:cmd . " " . SubxPath(a:arg)
|
||||
endfunction
|
||||
|
||||
function! SubxPath(arg)
|
||||
if a:arg =~ "^ex"
|
||||
return "examples/" . a:arg . ".subx"
|
||||
else
|
||||
return "apps/" . a:arg . ".subx"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" we often want to crib lines of machine code from other files
|
||||
function! GrepSubX(regex)
|
||||
" https://github.com/mtth/scratch.vim
|
||||
Scratch!
|
||||
silent exec "r !grep -h '".a:regex."' *.subx */*.subx"
|
||||
endfunction
|
||||
command! -nargs=1 G call GrepSubX(<q-args>)
|
||||
|
||||
if exists("&splitvertical")
|
||||
command! -nargs=0 P hor split opcodes
|
||||
else
|
||||
command! -nargs=0 P split opcodes
|
||||
endif
|
||||
|
||||
" useful for inspecting just the control flow in a trace
|
||||
" see https://github.com/akkartik/mu/blob/master/subx/Readme.md#a-few-hints-for-debugging
|
||||
" the '-a' is because traces can sometimes contain unprintable characters that bother grep
|
||||
command! -nargs=0 L exec "%!grep -a label |grep -v clear-stream:loop"
|
||||
|
||||
" run test cursor around cursor
|
||||
" if test fails, open trace in split window
|
||||
" if test passes, just show output and wait for <CR>
|
||||
" don't move cursor in original window
|
||||
" this solution is unfortunate, but seems forced:
|
||||
" can't put initial cursor movement inside function because we rely on <C-r><C-w> to grab word at cursor
|
||||
" can't put final cursor movement out of function because that disables the wait for <CR> prompt; function must be final operation of map
|
||||
" can't avoid the function because that disables the wait for <CR> prompt
|
||||
" known issue:
|
||||
" cursor on '#' causes error
|
||||
noremap <Leader>t {j0:call RunTestMoveCursorAndMaybeOpenTrace("<C-r><C-w>")<CR>
|
||||
function RunTestMoveCursorAndMaybeOpenTrace(arg)
|
||||
exec "!run_one_test.sh ".expand("%")." ".a:arg
|
||||
exec "normal \<C-o>"
|
||||
if v:shell_error
|
||||
noautocmd vertical split last_run
|
||||
endif
|
||||
endfunction
|
47
vimrc.vim
47
vimrc.vim
|
@ -16,16 +16,10 @@ function! HighlightTangledFile()
|
|||
syntax match traceAbsent /^-.*/
|
||||
highlight traceAbsent ctermfg=darkred
|
||||
syntax match tangleScenarioSetup /^\s*% .*/ | highlight link tangleScenarioSetup SpecialChar
|
||||
|
||||
highlight Special ctermfg=160
|
||||
|
||||
syntax match subxString %"[^"]*"% | highlight link subxString Constant
|
||||
" match globals but not registers like 'EAX'
|
||||
syntax match subxGlobal %\<[A-Z][a-z0-9_-]*\>% | highlight link subxGlobal SpecialChar
|
||||
endfunction
|
||||
augroup LocalVimrc
|
||||
autocmd BufRead,BufNewFile *.cc call HighlightTangledFile()
|
||||
autocmd BufRead,BufNewFile *.subx set ft=subx
|
||||
autocmd BufRead,BufNewFile *.mu set ft=mu
|
||||
augroup END
|
||||
|
||||
|
@ -35,44 +29,3 @@ augroup END
|
|||
" starting vim or opening a buffer without a file name (ok to do nothing)
|
||||
" opening a second file in a new or existing window (shouldn't mess up existing highlighting)
|
||||
" reloading an existing file (shouldn't mess up existing highlighting)
|
||||
|
||||
" assumes CWD is subx/
|
||||
command! -nargs=1 E call EditSubx("edit", <f-args>)
|
||||
if exists("&splitvertical")
|
||||
command! -nargs=1 S call EditSubx("vert split", <f-args>)
|
||||
command! -nargs=1 H call EditSubx("hor split", <f-args>)
|
||||
else
|
||||
command! -nargs=1 S call EditSubx("vert split", <f-args>)
|
||||
command! -nargs=1 H call EditSubx("split", <f-args>)
|
||||
endif
|
||||
|
||||
function! EditSubx(cmd, arg)
|
||||
exec "silent! " . a:cmd . " " . SubxPath(a:arg)
|
||||
endfunction
|
||||
|
||||
function! SubxPath(arg)
|
||||
if a:arg =~ "^ex"
|
||||
return "examples/" . a:arg . ".subx"
|
||||
else
|
||||
return "apps/" . a:arg . ".subx"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" we often want to crib lines of machine code from other files
|
||||
function! GrepSubX(regex)
|
||||
" https://github.com/mtth/scratch.vim
|
||||
Scratch!
|
||||
silent exec "r !grep -h '".a:regex."' *.subx */*.subx"
|
||||
endfunction
|
||||
command! -nargs=1 G call GrepSubX(<q-args>)
|
||||
|
||||
if exists("&splitvertical")
|
||||
command! -nargs=0 P hor split opcodes
|
||||
else
|
||||
command! -nargs=0 P split opcodes
|
||||
endif
|
||||
|
||||
" useful for inspecting just the control flow in a trace
|
||||
" see https://github.com/akkartik/mu/blob/master/subx/Readme.md#a-few-hints-for-debugging
|
||||
" the '-a' is because traces can sometimes contain unprintable characters that bother grep
|
||||
command! -nargs=0 L exec "%!grep -a label |grep -v clear-stream:loop"
|
||||
|
|
Loading…
Reference in New Issue