【发布时间】:2017-10-09 05:20:14
【问题描述】:
我现在正在使用堆栈式协同程序进行网络编程。但是我受到了返回堆栈缓冲区无效的惩罚(见 http://www.agner.org/optimize/microarchitecture.pdf p.36),在上下文切换期间(因为我们手动更改了SP寄存器)
经过汇编语言测试,我发现jmp 指令优于ret。但是,我还有一些函数可以间接调用用 C++ 语言(由 GCC 编译)编写的上下文切换函数。我们如何在 GCC 汇编结果中使用 jmp 而不是 ret 强制这些函数返回?
一些常见但并不完美的方法:
- 使用内联汇编并手动将SP寄存器设置为
__builtin_frame_address+2*sizeof(void*)和jmp为返回地址,在ret之前?
这是一个不安全的解决方案。在 C++ 中,局部变量或正确值在 ret 指令之前被破坏。如果我们jmp,我们将省略这些说明。更糟糕的是,即使我们在C语言中,被调用者保存的寄存器也需要在ret指令之前恢复,我们也会省略这些指令。
那么我们可以做些什么强制 GCC 使用 jmp 而不是 ret 来避免上面列出的问题?
【问题讨论】:
-
总结一下:你正在与 CPU 作斗争(返回堆栈缓冲区无效),你正在与 C 和 C++ 语言作斗争(汇编中的协同程序,直接修改寄存器)和 你正在与 GCC 作战。 (试图改变生成的代码)。在这一点上,退后一步,重新考虑使用这些协同程序的决定可能是明智的。这将是一个痛苦的维护,并且随着新 CPU 的发布,您的手动优化可能会成为一种悲观。
-
您必须编辑 GCC 的源代码并创建自己的编译器版本,该编译器使用
pop %ecxjmp *%ecx之类的东西而不是 RET 指令。 -
@RossRidge 我只是使用 gcc -S 和 sed&awk shell 替换 ret、retq、rep ret、repz ret 和 gcc *.S 来获得结果。
-
没有 C/C++ 语言。使用 C 或 C++。你说
Some common but not perfect methods,但只列出了一种方法!
标签: c++ gcc assembly x86 inline-assembly