There are various versions of CALL
s with different opcodes so you can't just check for 0xE8
. The full list can be found in Intel manual, call procedure section:
Opcode Instruction Description
E8 cw CALL rel16 Call near, relative, displacement relative to next instruction
E8 cd CALL rel32 Call near, relative, displacement relative to next instruction
32-bit displacement sign extended to 64-bits in 64-bit mode.
FF /2 CALL r/m16 Call near, absolute indirect, address given in r/m16.
FF /2 CALL r/m32 Call near, absolute indirect, address given in r/m32.
FF /2 CALL r/m64 Call near, absolute indirect, address given in r/m64.
9A cd CALL ptr16:16 Call far, absolute, address given in operand.
9A cp CALL ptr16:32 Call far, absolute, address given in operand.
FF /3 CALL m16:16 Call far, absolute indirect address given in m16:16.
In 32-bit mode: if selector points to a gate, then
RIP = 32-bit zero extended displacement taken from gate; else
RIP = zero extended 16-bit offset from far pointer
referenced in the instruction.
FF /3 CALL m16:32 In 64-bit mode: If selector points to a gate, then
RIP = 64-bit displacement taken from gate; else
RIP = zero extended 32-bit offset from far pointer
referenced in the instruction.
REX.W FF /3 CALL m16:64 In 64-bit mode: If selector points to a gate, then
RIP = 64-bit displacement taken from gate; else
RIP = 64-bit offset from far pointer
referenced in the instruction.
The same to RET
Opcode* Instruction Description
C3 RET Near return to calling procedure.
CB RET Far return to calling procedure.
C2 iw RET imm16 Near return to calling procedure and pop imm16 bytes from stack.
CA iw RET imm16 Far return to calling procedure and pop imm16 bytes from stack.
Note that the lines containing the same opcodes above are just for different modes (16/32/64-bit)