我想在我的 Apple Silicon Macbook 中编写一个原生协程。由于原生协程需要
jmp_buf
中的 setjmp.h
,我试图找出 jmp_buf
中存储了哪些寄存器。
当我跳进
setjmp.h
中的/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/setjmp.h
文件时,我刚刚找到了代码,但看起来有点奇怪。
代码是:
/*
* _JBLEN is the number of ints required to save the following:
* r21-r29, sp, fp, lr == 12 registers, 8 bytes each. d8-d15
* are another 8 registers, each 8 bytes long. (aapcs64 specifies
* that only 64-bit versions of FP registers need to be saved).
* Finally, two 8-byte fields for signal handling purposes.
*/
#define _JBLEN ((14 + 8 + 2) * 2)
typedef int jmp_buf[_JBLEN];
typedef int sigjmp_buf[_JBLEN + 1];
#else
# error Undefined platform for setjmp
#endif
_JBLEN
似乎定义了14 + 8个寄存器,但注释说是12 + 8。正如其他帖子所说,在arm64 arch中,x19-x28是被调用者保存的寄存器,应该保存,x29(fp)、x30(lr)、x31(sp)、pc也应该保存。在这种情况下,14 个寄存器似乎是有意义的。是评论错误还是我的计算错误?
我希望有人能帮我弄清楚jmp_buf中到底保存了哪些寄存器,如果MacOSX sdk的注释有误,我希望有人能帮忙纠正。
该评论显然是错误的,因为它漏掉了
x19
和 x20
,并且提到了 x29
和 fp
,它们是同一个。
以下是 ABI 声明的被调用者保存的内容:
x19
至 x30
(包括 x29
= fp
和 x0
= lr
)q8
到q15
的低64位,即d8
-d15
sp
保存
pc
没有意义,因为你知道当前正在从哪里执行。所以你真的需要13 + 8
。
现在,Apple 的源转储确实包含
setjmp
的实现,但该源转储是一个谎言,因为生产中使用的 实际 实现使用指针身份验证,并且到目前为止是闭源的。我可以把它的反汇编交给你,但我认为这是一个坏主意。 jmp_buf
被声明为不透明 blob 的全部原因是因为它的布局是私有的,并且允许更改 setjmp
和 longjmp
的实现。
如果您需要修改
jmp_buf
的能力,那么您最好编写自己的汇编例程来溢出/重新加载被调用者保存的寄存器。