c++ - 裸函数中的 Asm 插入
问题描述
我有 ubuntu 16.04、x86_64 arch、4.15.0-39-generic 内核版本。海合会 8.1.0
我试图将这个函数(从第一篇文章https://groups.google.com/forum/#!topic/comp.lang.c++.moderated/qHDCU73cEFc)从英特尔方言重写为 AT&T。而我没有成功。
namespace atomic {
__declspec(naked)
static void*
ldptr_acq(void* volatile*) {
_asm {
MOV EAX, [ESP + 4]
MOV EAX, [EAX]
RET
}
}
__declspec(naked)
static void*
stptr_rel(void* volatile*, void* const) {
_asm {
MOV ECX, [ESP + 4]
MOV EAX, [ESP + 8]
MOV [ECX], EAX
RET
}
}
}
然后我写了一个简单的程序,来获取相同的指针,我在里面传递。我安装了支持裸属性的 GCC 8.1 版(https://gcc.gnu.org/gcc-8/changes.html“x86端口现在支持裸函数属性”)用于功能。据我记得,这个属性告诉编译器不要创建函数的序言和结语,我可以自己从堆栈中取出参数并返回它们。代码:(不要使用段错误)
#include <cstdio>
#include <cstdlib>
__attribute__ ((naked))
int *get_num(int*) {
__asm__ (
"movl 4(%esp), %eax\n\t"
"movl (%eax), %eax\n\t"
"ret"
);
}
int main() {
int *i =(int*) malloc(sizeof(int));
*i = 5;
int *j = get_num(i);
printf("%d\n", *j);
free(i);
return 0;
}
然后我尝试使用 64 位寄存器:(不要使用 segfault)
__asm__ (
"movq 4(%rsp), %rax\n\t"
"movq (%rax), %rax\n\t"
"ret"
);
只有在我从 rdi 寄存器中取出值之后 - 这一切都奏效了。
__asm__ (
"movq %rdi, %rax\n\t"
"ret"
);
为什么我无法通过堆栈寄存器进行传输?我可能犯了一个错误。请告诉我我的失败在哪里?
解决方案
因为 x86-64 System V 调用约定在寄存器中传递 args,而不是在堆栈上,这与旧的低效 i386 System V 调用约定不同。
如果您在 asm 中编写整个函数,就像使用naked
函数或独立.S
文件一样,您总是必须编写符合调用约定的 asm。
GNU C 扩展 asm 允许您使用操作数来指定 asm 语句的输入,编译器将生成指令来实现这一点。(不过,在您了解 asm 以及编译器如何将 C 转换为启用优化的 asm 之前,我不建议您使用它。)
另请注意,movq %rdi, %rax
实现long *foo(long*p){return p;}
not return *p
。也许您mov (%rdi), %rax
的意思是取消引用指针 arg?
顺便说一句,您绝对不需要也不应该为此使用内联汇编。 https://gcc.gnu.org/wiki/DontUseInlineAsm,请参阅https://stackoverflow.com/tags/inline-assembly/info
在 GNU C 中,您可以将指针强制转换为volatile uint64_t*
. 或者,您可以使用__atomic_load_n (ptr, __ATOMIC_ACQUIRE)
基本上从该 asm 中获取所有内容,而无需函数调用的开销或调用站点的优化器的任何成本,即所有调用破坏的寄存器都被破坏。
您可以在任何对象上使用它们:https ://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html 与 C++11 不同,您只能在std::atomic<T>
.
推荐阅读
- angular - 在 FormArray 中将焦点设置为动态创建的 FormControl
- c# - ConfirmEmailAsync() 无论如何都会得到无效的令牌
- html - 当我尝试在网页上嵌入处理草图时,为什么会出现空白屏幕?
- twitter-bootstrap - 将 div 与 Bootstrap 列中的相邻 div 对齐
- vue.js - 我可以在 vuejs 上使用 highchart 插件创建日历热图吗
- python - 使用 MinMaxScaler 缩放熊猫数据框中的特定列
- dictionary - 更改地图上的质心大小/不透明度
- ansible - 在 Ansible 中,如何在 git-bash shell 中运行 shell 脚本?
- css - 如何解决我的 React 中的 CSS 问题?
- c# - 如何使用 UIAutomation 在 .NET 4.8 WinForms 应用程序中获取所有 ComboBox ListItem 值?