汇编指令 call、ret、jump 的区别

call、ret、jump 指令介绍

  • call 用于调用子程序,在调用前会保存返回地址(x86 架构下,段内跳转时只保存 EIP;段间跳转还会保存 CS)。ret 会返回到 call 指令的下一行,也就是跳转前已保存的返回地址。通常在函数调用时,callret 都是成对出现的。

  • jmp 会直接进行跳转,不会保存返回地址,jmp 之后的指令如果跟了 ret,那就直接退出到上一个 call 指令对应的下一行。

call 和 ret 使用方法

call 和 ret 指令用来调用子程序和从子程序返回:

  • call 的使用方法:call 子程序入口处地址,该地址可以是标号,也可以存放在寄存器和内存中。

  • ret 的使用方法:直接在子程序中使用 ret 指令即可,可以没有参数,执行该指令会直接返回至调用子程序的位置处。

之前遇到的一个 bug

函数 A 调用函数 B,然后在函数 B 里进行协程切换,进入到协程上下文(此时还没有结束函数调用)。在新的协程上下文中,使用 ret $27,gcc 编译能够跳转到 $27 指定的地址处,clang 编译则会忽略 $27 的值,clang 编译器规定 ret 指令编译成 ret $ra,从而导致报错。