我正在编写一个加密程序,并且核心(一个宽的乘法例程)是用x86-64汇编编写的,两者都是为了速度而且因为它广泛使用adc那些不容易从C中访问的指令.我不想内联这个函数,因为它很大,并且在内循环中被调用了好几次.
理想情况下,我还想为此函数定义一个自定义调用约定,因为它在内部使用所有寄存器(除外rsp),不破坏其参数,并在寄存器中返回.现在,它适应了C调用约定,但当然这使它变慢(大约10%).
为了避免这种情况,我可以调用它,asm("call %Pn" : ... : my_function... : "cc", all the registers);但有没有办法告诉GCC调用指令与堆栈混淆?否则GCC会将所有这些寄存器放在红色区域中,而顶部的寄存器将被破坏.我可以使用-mno-red-zone编译整个模块,但是我更喜欢告诉GCC,比方说,红色区域的前8个字节将被破坏,以便它不会放任何东西.
来自维基百科:
在计算中,红色区域是函数堆栈帧中超出返回地址的固定大小区域,该区域不被该函数保留.被调用函数可以使用红色区域来存储局部变量,而无需修改堆栈指针的额外开销.中断/异常/信号处理程序不会修改此内存区域.System V使用的x86-64 ABI要求一个128字节的红色区域,它直接在返回地址之后开始并包含函数的参数.OpenRISC工具链假设一个128字节的红色区域.
超出%rsp指向的位置的128字节区域被认为是保留的,不应被信号或中断处理程序修改.因此,函数可以将此区域用于函数调用不需要的临时数据.特别是,叶子函数可以将这个区域用于它们的整个堆栈帧,而不是调整序言和尾声中的堆栈指针.这个区域被称为红区.
鉴于这两个引号,堆叠的返回地址上方或堆叠的返回地址下方的红色区域 是?
由于这个红色区域是相对的RSP,它是否向下push移动并且每个区域向上移动pop?
强烈建议在创建64位内核(对于x86_64平台)时,指示编译器不要使用用户空间ABI所执行的128字节红区.(对于GCC,编译器标志是-mno-red-zone).
如果启用了内核,则内核不会是中断安全的.
但那是为什么呢?
我希望能够%rbp在内联asm中使用基指针寄存器().这样的玩具示例是这样的:
void Foo(int &x)
{
asm volatile ("pushq %%rbp;" // 'prologue'
"movq %%rsp, %%rbp;" // 'prologue'
"subq $12, %%rsp;" // make room
"movl $5, -12(%%rbp);" // some asm instruction
"movq %%rbp, %%rsp;" // 'epilogue'
"popq %%rbp;" // 'epilogue'
: : : );
x = 5;
}
int main()
{
int x;
Foo(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望,因为我使用通常的序幕/结尾函数调用方法来推送和弹出旧的%rbp,这样就可以了.但是,当我尝试在内x联asm之后访问时,它会出现故障.
GCC生成的汇编代码(略微剥离)是:
_Foo:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
# INLINEASM
pushq %rbp; // prologue
movq %rsp, …Run Code Online (Sandbox Code Playgroud) 这就是我通过阅读一些内存分段文档所理解的:当调用一个函数时,有一些指令(称为函数序言)将帧指针保存在堆栈上,将堆栈指针的值复制到基本指针中并保存一些局部变量的内存.
这是我尝试使用GDB调试的一个简单代码:
void test_function(int a, int b, int c, int d) {
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_function(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)
调试此代码的目的是了解调用函数时堆栈中发生的情况:因此我必须在执行程序的各个步骤(在调用函数之前和执行期间)检查内存.虽然我设法通过检查基指针来查看返回地址和保存的帧指针之类的东西,但我真的无法理解在反汇编代码之后我要写的内容.
拆解:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400509 <+0>: push rbp
0x000000000040050a <+1>: mov rbp,rsp
0x000000000040050d <+4>: mov ecx,0x4
0x0000000000400512 <+9>: mov edx,0x3
0x0000000000400517 <+14>: mov esi,0x2
0x000000000040051c <+19>: mov edi,0x1
0x0000000000400521 <+24>: call 0x4004ec <test_function>
0x0000000000400526 <+29>: pop rbp
0x0000000000400527 <+30>: ret
End …Run Code Online (Sandbox Code Playgroud)