https://github.com/akkartik/mu/blob/master/subx/019functions.cc

      1 //:: call
      2
      3 :(before "End Initialize Op Names")
      4 put_new(Name, "e8", "call disp32 (call)");
      5
      6 :(code)
      7 void test_call_disp32() {
      8   Reg[ESP].u = 0x64;
      9   run(
     10       "== 0x1\n"  // code segment
     11       // op     ModR/M  SIB   displacement  immediate
     12       "  e8                                 a0 00 00 00 \n"  // call function offset at 0x000000a0
     13       // next EIP is 6
     14   );
     15   CHECK_TRACE_CONTENTS(
     16       "run: call imm32 0x000000a0\n"
     17       "run: decrementing ESP to 0x00000060\n"
     18       "run: pushing value 0x00000006\n"
     19       "run: jumping to 0x000000a6\n"
     20   );
     21 }
     22
     23 :(before "End Single-Byte Opcodes")
     24 case 0xe8: {  // call disp32 relative to next EIP
     25   const int32_t offset = next32();
     26   ++Callstack_depth;
     27   trace(Callstack_depth+1, "run") << "call imm32 0x" << HEXWORD << offset << end();
     28 //?   cerr << "push: EIP: " << EIP << " => " << Reg[ESP].u << '\n';
     29   push(EIP);
     30   EIP += offset;
     31   trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end();
     32   break;
     33 }
     34
     35 //:
     36
     37 :(code)
     38 void test_call_r32() {
     39   Reg[ESP].u = 0x64;
     40   Reg[EBX].u = 0x000000a0;
     41   run(
     42       "== 0x1\n"  // code segment
     43       // op     ModR/M  SIB   displacement  immediate
     44       "  ff     d3                                      \n"  // call function offset at EBX
     45       // next EIP is 3
     46   );
     47   CHECK_TRACE_CONTENTS(
     48       "run: call to r/m32\n"
     49       "run: r/m32 is EBX\n"
     50       "run: decrementing ESP to 0x00000060\n"
     51       "run: pushing value 0x00000003\n"
     52       "run: jumping to 0x000000a3\n"
     53   );
     54 }
     55
     56 :(before "End Op ff Subops")
     57 case 2: {  // call function pointer at r/m32
     58   trace(Callstack_depth+1, "run") << "call to r/m32" << end();
     59   const int32_t* offset = effective_address(modrm);
     60   push(EIP);
     61   EIP += *offset;
     62   trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end();
     63   ++Callstack_depth;
     64   break;
     65 }
     66
     67 :(code)
     68 void test_call_mem_at_r32() {
     69   Reg[ESP].u = 0x64;
     70   Reg[EBX].u = 0x2000;
     71   run(
     72       "== 0x1\n"  // code segment
     73       // op     ModR/M  SIB   displacement  immediate
     74       "  ff     13                                      \n"  // call function offset at *EBX
     75       // next EIP is 3
     76       "== 0x2000\n"  // data segment
     77       "a0 00 00 00\n"  // 0x000000a0
     78   );
     79   CHECK_TRACE_CONTENTS(
     80       "run: call to r/m32\n"
     81       "run: effective address is 0x00002000 (EBX)\n"
     82       "run: decrementing ESP to 0x00000060\n"
     83       "run: pushing value 0x00000003\n"
     84       "run: jumping to 0x000000a3\n"
     85   );
     86 }
     87
     88 //:: ret
     89
     90 :(before "End Initialize Op Names")
     91 put_new(Name, "c3", "return from most recent unfinished call (ret)");
     92
     93 :(code)
     94 void test_ret() {
     95   Reg[ESP].u = 0x2000;
     96   run(
     97       "== 0x1\n"  // code segment
     98       // op     ModR/M  SIB   displacement  immediate
     99       "  c3                                           \n"  // return
    100       "== 0x2000\n"  // data segment
    101       "10 00 00 00\n"  // 0x00000010
    102   );
    103   CHECK_TRACE_CONTENTS(
    104       "run: return\n"
    105       "run: popping value 0x00000010\n"
    106       "run: jumping to 0x00000010\n"
    107   );
    108 }
    109
    110 :(before "End Single-Byte Opcodes")
    111 case 0xc3: {  // return from a call
    112   trace(Callstack_depth+1, "run") << "return" << end();
    113   --Callstack_depth;
    114   EIP = pop();
    115   trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end();
    116   break;
    117 }