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