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