相关疑难解决方法(0)

内联装配破坏了红色区域

我正在编写一个加密程序,并且核心(一个宽的乘法例程)是用x86-64汇编编写的,两者都是为了速度而且因为它广泛使用adc那些不容易从C中访问的指令.我不想内联这个函数,因为它很大,并且在内循环中被调用了好几次.

理想情况下,我还想为此函数定义一个自定义调用约定,因为它在内部使用所有寄存器(除外rsp),不破坏其参数,并在寄存器中返回.现在,它适应了C调用约定,但当然这使它变慢(大约10%).

为了避免这种情况,我可以调用它,asm("call %Pn" : ... : my_function... : "cc", all the registers);但有没有办法告诉GCC调用指令与堆栈混淆?否则GCC会将所有这些寄存器放在红色区域中,而顶部的寄存器将被破坏.我可以使用-mno-red-zone编译整个模块,但是我更喜欢告诉GCC,比方说,红色区域的前8个字节将被破坏,以便它不会放任何东西.

c x86 gcc inline-assembly red-zone

20
推荐指数
2
解决办法
1716
查看次数

x86-64上的红色区域究竟在哪里?

来自维基百科:

在计算中,红色区域是函数堆栈帧中超出返回地址的固定大小区域,该区域不被该函数保留.被调用函数可以使用红色区域来存储局部变量,而无需修改堆栈指针的额外开销.中断/异常/信号处理程序不会修改此内存区域.System V使用的x86-64 ABI要求一个128字节的红色区域,它直接在返回地址之后开始并包含函数的参数.OpenRISC工具链假设一个128字节的红色区域.

System V x86-64 ABI:

超出%rsp指向的位置的128字节区域被认为是保留的,不应被信号或中断处理程序修改.因此,函数可以将此区域用于函数调用不需要的临时数据.特别是,叶子函数可以将这个区域用于它们的整个堆栈帧,而不是调整序言和尾声中的堆栈指针.这个区域被称为红区.

  • 鉴于这两个引号,堆叠的返回地址上方或堆叠的返回地址下方红色区域 是?

  • 由于这个红色区域是相对的RSP,它是否向下push移动并且每个区域向上移动pop

assembly x86-64 abi calling-convention red-zone

20
推荐指数
2
解决办法
2331
查看次数

为什么内核代码不能使用Red Zone

强烈建议在创建64位内核(对于x86_64平台)时,指示编译器不要使用用户空间ABI所执行的128字节红区.(对于GCC,编译器标志是-mno-red-zone).

如果启用了内核,则内核不会是中断安全的.

但那是为什么呢?

x86-64 abi red-zone

18
推荐指数
3
解决办法
2874
查看次数

在C++内联asm中使用基指针寄存器

我希望能够%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)

c++ x86 assembly red-zone

13
推荐指数
1
解决办法
4119
查看次数

为什么在这个函数序言中没有"sub rsp"指令,为什么函数参数存储在负rbp偏移量?

这就是我通过阅读一些内存分段文档所理解的:当调用一个函数时,有一些指令(称为函数序言)将帧指针保存在堆栈上,将堆栈指针的值复制到基本指针中并保存一些局部变量的内存.

这是我尝试使用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)

c assembly stack x86-64 red-zone

5
推荐指数
1
解决办法
1311
查看次数

标签 统计

red-zone ×5

assembly ×3

x86-64 ×3

abi ×2

c ×2

x86 ×2

c++ ×1

calling-convention ×1

gcc ×1

inline-assembly ×1

stack ×1