首页 > 编程语言 >C++学习------csetjmp头文件的源码学习

C++学习------csetjmp头文件的源码学习

时间:2022-12-03 15:31:33浏览次数:63  
标签:__ csetjmp 头文件 rdi jmp mov setjmp 源码 buf

引言

csetjmp是C++对setjmp.h头文件的封装,通过这个头文件提供的工具允许程序员通过提供执行跳转的方法来绕过正常的函数调用和返回规程,从而保留调用环境。其中定义了一些函数和宏定义来完成这项工作。

setjmp.h

代码参考:​​www.aospxref.com/android-13.…​

变量定义sigjmp_buf和jmp_buf

根据不同平台定义了不同的数组别名sigjmp_buf和jmp_buf,其中保存的元素都是long,sigjmp_buf中的元素多1个。

45  #if defined(__aarch64__)
46 #define _JBLEN 32
47 #elif defined(__arm__)
48 #define _JBLEN 64
49 #elif defined(__i386__)
50 #define _JBLEN 10
51 #elif defined(__x86_64__)
52 #define _JBLEN 11
53 #endif
54
55 typedef long sigjmp_buf[_JBLEN + 1];
56 typedef long jmp_buf[_JBLEN];

宏函数定义setjmp

68  #define setjmp(__env) setjmp(__env)

这里实际上调用的还是函数实现的setjmp

函数定义

定义了setjmp和longjmp函数,sigsetjmp和siglongjmp函数

62  int _setjmp(jmp_buf __env) __returns_twice;
63 __noreturn void _longjmp(jmp_buf __env, int __value);
64
65 int setjmp(jmp_buf __env) __returns_twice;
66 __noreturn void longjmp(jmp_buf __env, int __value);
67
68 #define setjmp(__env) setjmp(__env)
69
70 int sigsetjmp(sigjmp_buf __env, int __save_signal_mask);
71 __noreturn void siglongjmp(sigjmp_buf __env, int __value);

setjmp函数---保存函数调用环境

代码参考:​​www.aospxref.com/android-13.…​​ 可以看到setjmp函数入参为jmp_buf数组首地址,观察汇编代码,该入参存储在rdi中,依次将rbx,rbp,r12,r13,r14,r15,rsp+8,(%rsp)位置上的值都保存到该数组中,即保存函数调用环境。 setjmp第一次返回0,第二次(即被longjmp加载函数调用环境之后)返回值由longjmp的第二个输入参数决定。

1 /* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
2 .global __setjmp
3 .global _setjmp
4 .global setjmp
5 .type __setjmp,@function
6 .type _setjmp,@function
7 .type setjmp,@function
8 __setjmp:
9 _setjmp:
10 setjmp:
11 mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */
12 mov %rbp,8(%rdi)
13 mov %r12,16(%rdi)
14 mov %r13,24(%rdi)
15 mov %r14,32(%rdi)
16 mov %r15,40(%rdi)
17 lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */
18 mov %rdx,48(%rdi)
19 mov (%rsp),%rdx /* save return addr ptr for new rip */
20 mov %rdx,56(%rdi)
21 xor %eax,%eax /* always return 0 */
22 ret

longjump---加载函数调用环境

代码参考:​​www.aospxref.com/android-13.…​​ 可以看到,依次还原输入的jmp_buf,然后跳转到之前保存的rsp地址中;注意,这里还对输入参数int __value做了处理,保存在esi中,如果不等于0,则eax=__value,如果等于0则eax = 1.

1 /* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
2 .global _longjmp
3 .global longjmp
4 .type _longjmp,@function
5 .type longjmp,@function
6 _longjmp:
7 longjmp:
8 xor %eax,%eax
9 cmp $1,%esi /* CF = val ? 0 : 1 */
10 adc %esi,%eax /* eax = val + !val */
11 mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */
12 mov 8(%rdi),%rbp
13 mov 16(%rdi),%r12
14 mov 24(%rdi),%r13
15 mov 32(%rdi),%r14
16 mov 40(%rdi),%r15
17 mov 48(%rdi),%rsp
18 jmp *56(%rdi) /* goto saved address without altering rsp */

有点类似于goto语句,又重新跳回某处执行,不过这里是将之前某处的指令执行现场保存下来,然后再加载执行。

sigsetjmp

代码参考:​​www.aospxref.com/android-13.…​​ 入参是:​​int sigsetjmp(sigjmp_buf __env, int __save_signal_mask)​​分别存储在rdi和esi中 通过__save_signal_mask判断,如果等于0,就跳转到标号1的位置;否则就保存信息到sigjmp_buf数组中

1 .global sigsetjmp
2 .global __sigsetjmp
3 .type sigsetjmp,@function
4 .type __sigsetjmp,@function
5 sigsetjmp:
6 __sigsetjmp:
7 test %esi,%esi
8 jz 1f
9
10 popq 64(%rdi)
11 mov %rbx,72+8(%rdi)
12 mov %rdi,%rbx
13
14 call setjmp@PLT
15
16 pushq 64(%rbx)
17 mov %rbx,%rdi
18 mov %eax,%esi
19 mov 72+8(%rbx),%rbx
20
21 .hidden __sigsetjmp_tail
22 jmp __sigsetjmp_tail
23
24 1: jmp setjmp@PLT

siglongjmp

代码参考:​​www.aospxref.com/android-13.…​​ 借助longjmp进行实现

1  #include <setjmp.h>
2 #include <signal.h>
3 #include "syscall.h"
4 #include "pthread_impl.h"
5
6 _Noreturn void siglongjmp(sigjmp_buf buf, int ret)
7 {
8 longjmp(buf, ret);
9 }

标签:__,csetjmp,头文件,rdi,jmp,mov,setjmp,源码,buf
From: https://blog.51cto.com/u_15830688/5908557

相关文章

  • 如何禁止F12 or右键查看源码
    方法1.引入jquery.min.js1.<scripttype="text/javascript"src="http://code.jquery.com/jquery-1.4.1.min.js"></script>2.插入一段js脚本<scripttype="text/ja......
  • 问题解决系列:从源码讲解为什么是 'JZ0SL_ Unsupported SQL type 1111'
    一、问题场景正在做代码改造,使用​​mybatis​​​+​​sybase​​进行数据库操作,运行过程中,提示以下报错:java.io.IOException:JZ0SL:UnsupportedSQLtype1111.本篇博客......
  • 将makefile中的宏传递给源码
    前言:今天遇到一个问题,在makefile中定义个宏,宏为一个字符串,希望将该字符串传递给代码。但是一直传递不过去,最后才找到原因,这里小结一下。直接上代码,makefile如下:1C_F......
  • 头文件<numeric>
    累加函数accumulate(first,last,val,op);first和last表示序列(可以是数组、vector、array等)的首尾指针/迭代器,val表示操作的初始值,op表示运算符,进行累加、累减......
  • idea查看源码快捷键
    查看当前类的层次结构⭐⭐⭐⭐⭐ Ctrl+H查看类结构⭐⭐⭐⭐ Alt+7快速检索类⭐⭐⭐⭐⭐ Ctrl+N(Win)查看方法/类的实现类⭐⭐⭐⭐ Ctrl+Alt+B(Win)......
  • redis字符串的底层源码以及应用实例
    内部编码int8个字节的长整型embstr小于等于39个字节的字符串raw大于39个字节的字符串string底层使用的sds自定义的字符串,因为c语言中string默认为\0为结尾,而redi......
  • C++学习------cmath头文件的源码学习08
    函数族定义---四舍五入与余数函数ceil---返回不小于x的最小整数doubleceil(doublex);代码示例:printf("ceilof2.3is%.1f\n",ceil(2.3));printf("ceilof3.8......
  • shiro源码第一天:登陆验证部分
    登陆验证部分:​​1.单点登陆系统中不同系统密码验证方式不一样​​1.单点登陆系统中不同系统密码验证方式不一样问题:当使用shiro作为鉴权框架时,首先用到的应该就是登陆认证......
  • EasyExcel 实践与源码梳理
    目录​​1.写在最前​​​​1.1EasyExcel版本​​​​1.2初探源码​​​​2.表头实体类MyUser​​​​3.最简单的导出Excel文件​​​​4.源码demo:​​​​4.1读Exc......
  • 学习Spring源码问题总结
    记录一下学习源码遇到的问题:​​1.编译时报错:Failedtoapplyplugin[id'com.gradle.build-scan']​​​​2.报错Groovy:compilermismatchprojectlevelis:2.4Works......