标签: red-zone

内联装配破坏了红色区域

我正在编写一个加密程序,并且核心(一个宽的乘法例程)是用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
查看次数

从Java VM无效访问堆栈红区

我试图弄清楚在Java中可能导致此错误的原因:

Invalid access of stack red zone 0x115ee0ed0 rip=0x114973900
Run Code Online (Sandbox Code Playgroud)

有没有人遇到过这个错误信息?它实际上是在杀死JVM,一切都停在那里.

我目前正在使用这个版本的Java :(在OS X 10.6上)

java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03-219)
Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02-90, mixed mode)
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是关于如何避免再次发生这种情况的某种解释和提示.

提前致谢!

java jvm jvm-hotspot red-zone

15
推荐指数
2
解决办法
5751
查看次数

在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
查看次数

为什么在分配没有后续函数调用的大数组时,GCC会将错误的值减去堆栈指针?

真奇怪的gcc怪癖.看一下这个:

main() { int a[100]; a[0]=1; }
Run Code Online (Sandbox Code Playgroud)

产生这个组件:

   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 18 01 00 00    sub    $0x118,%rsp
   b:   c7 85 70 fe ff ff 01    movl   $0x1,-0x190(%rbp)
  12:   00 00 00 
  15:   c9                      leaveq 
  16:   c3                      retq
Run Code Online (Sandbox Code Playgroud)

堆栈的顶部显然是400,因为它是一个100*4阵列.因此,当它写入第一个条目时,它会执行rbp - 400(行'b').好.但是为什么它从堆栈(第4行)指针中减去280?那不指向数组的中间吗?

如果我们之后添加一个函数调用,gcc会做正确的事情:

b() {}
main() { int a[100]; a[0]=1; b(); }
Run Code Online (Sandbox Code Playgroud)

产生这个组件:

0000000000000000 <b>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   c9                      leaveq 
   5:   c3                      retq …
Run Code Online (Sandbox Code Playgroud)

x86 assembly stack gcc red-zone

12
推荐指数
2
解决办法
1495
查看次数

我如何告诉 gcc 我的内联汇编破坏了堆栈的一部分?

考虑这样的内联汇编:

uint64_t flags;
asm ("pushf\n\tpop %0" : "=rm"(flags) : : /* ??? */);
Run Code Online (Sandbox Code Playgroud)

尽管可能存在某种内在函数来获取 RFLAGS 的内容,但我如何向编译器表明我的内联汇编破坏了堆栈顶部的一个四字内存?

c gcc x86-64 inline-assembly red-zone

7
推荐指数
1
解决办法
529
查看次数

当我们有一个红区时,为什么我们需要堆栈分配?

我有以下疑惑:

正如我们所知,System V x86-64 ABI为我们提供了堆栈帧中固定大小的区域(128字节),即所谓的redzone.因此,结果我们不需要使用,例如,sub rsp, 12.只是做mov [rsp-12], X,这就是全部.

但我无法理解这一点.为什么这有关系?sub rsp, 12没有redzone 是否有必要?毕竟,堆栈大小在开始时是有限的,为什么sub rsp, 12重要?我知道这使得我们可以跟随堆栈的顶部但是让我们忽略它.

我知道一些指令使用了什么rsp价值(比如ret)但在那一刻并不关心它.

问题的症结在于:我们没有红区,我们已经完成了:

function:
    mov [rsp-16], rcx
    mov [rsp-32], rcx
    mov [rsp-128], rcx
    mov [rsp-1024], rcx
    ret
Run Code Online (Sandbox Code Playgroud)

它有区别吗?

function:
    sub rsp, 1024
    mov [rsp-16], rcx
    mov [rsp-32], rcx
    mov [rsp-128], rcx
    mov [rsp-1024], rcx
    add rsp, 1024
    ret
Run Code Online (Sandbox Code Playgroud)

x86 assembly x86-64 abi red-zone

6
推荐指数
1
解决办法
1073
查看次数

我可以从堆栈中间弹出吗?

在x86汇编语言中:

我假设我有一个正常的功能序言,请阅读

push ebp
mov  ebp,esp
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过访问内存目标操作数来读取或写入寄存器,假设我想要第一个参数。我会做

mov eax,[ebp +8]
Run Code Online (Sandbox Code Playgroud)

从堆栈中获取一个整数参数。

那为什么我不直接使用stackpointer呢?

add  esp,8              ; point ESP at the data we want
pop  eax
sub  esp,12             ; restore ESP to its original position
Run Code Online (Sandbox Code Playgroud)

这会导致错误吗?在任何情况下都使用吗?

我当然知道第一个操作的大小较小,因为它只是一个操作码,mov而不是三个,但这不是问题的重点。

(编者注:mov eax, [ebp+8]。在x86机器代码的3字节的指令 add/ subESP,imm8指定为3个字节的每个,pop eax是1个字节。
mov eax, [esp+8]是一个4字节的指令:不像在16位寻址模式,ESP可以是一个基址寄存器。但是它确实需要一个SIB字节来对其进行编码。
这些都是现代CPU上的单联指令,不包括额外的堆栈同步联指令。)

为什么这样做是错误的做法?

x86 assembly callstack abi red-zone

6
推荐指数
1
解决办法
825
查看次数

为什么在这个函数序言中没有"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
查看次数