简介setjmp是C语言解决exception的标准方案 函数间跳转我们常用的函数是goto
我们要知道,要实现这种类型的跳转,和操作系统中任务切换的上下文(context)切换有点类似,我们只需要恢复Label标签处函数上下文即可。函数的上下文包括以下内容: 函数栈帧,主要是栈帧指针BP和栈顶指针SP 这样,在执行GOTO Label这条语句,我们恢复Label处的上下文,即完成跳转到Label处的功能。 Linux 会把进程的上下文保存在 task_struct 结构体中,切换时直接恢复。 源代码分析函数原型
具体实现我们以下面的例子分析在linux x86_64下的setjmp 与longjmp的具体实现: 运行结果: setjmp首先,jmp_buf 的结构在bss段中 这段代码就就是在x86-64体系下存在jmp_buf的内容,其中,我们可见有一个简单的亦或与循环移位的加密: 其中fs:0x30是每次会变化,但在一次运行的过程中是不变的,我们不妨称之为cookie,称整个加密过程为encrypt,用python描述如下: setjmp的作用就是将当前的程序状态存储到这个jmp_buf结构中,部分关键内容进行加密 jmp_buf根据汇编中的内容,我们可以知道jmp_buf中保存的内容,整个jmp_buf的结构描述如下,虽然jmp_buf开辟空间不小,但在x64下只用到了一下空间:
longjmplongjmp的源代码glibc/sysdeps/x86_64/__longjmp.S 可见在longjmp中主要是有一个简单的解密过程,用python描述如下: 之后从rdi,也就是jmp_buf中把相应的内容恢复,这样就实现了类似context的切换过程 整个过程中,理解setjmp最关键的是对整个jmp_buf结构的把握 使用setjmp和longjmp要注意以下几点: 1、setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp函数,之后再调用longjmp函数,以恢复到先前被保存的context setjmp异常处理setjmp有一个重要的功能:exception 的抛出和捕获。 结果: 参考资料http://en./wiki/Longjmp |
|
来自: astrotycoon > 《C》