强烈建议在创建64位内核(对于x86_64平台)时,指示编译器不要使用用户空间ABI所执行的128字节红区.(对于GCC,编译器标志是-mno-red-zone).
如果启用了内核,则内核不会是中断安全的.
但那是为什么呢?
考虑以下简单程序:
int main(int argc, char **argv)
{
char buffer[256];
buffer[0] = 0x41;
buffer[128] = 0x41;
buffer[255] = 0x41;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在x86-64机器上使用GCC 4.7.0编译.用GDB反汇编main()给出:
0x00000000004004cc <+0>: push rbp
0x00000000004004cd <+1>: mov rbp,rsp
0x00000000004004d0 <+4>: sub rsp,0x98
0x00000000004004d7 <+11>: mov DWORD PTR [rbp-0x104],edi
0x00000000004004dd <+17>: mov QWORD PTR [rbp-0x110],rsi
0x00000000004004e4 <+24>: mov BYTE PTR [rbp-0x100],0x41
0x00000000004004eb <+31>: mov BYTE PTR [rbp-0x80],0x41
0x00000000004004ef <+35>: mov BYTE PTR [rbp-0x1],0x41
0x00000000004004f3 <+39>: mov eax,0x0
0x00000000004004f8 <+44>: leave
0x00000000004004f9 <+45>: ret
Run Code Online (Sandbox Code Playgroud)
当缓冲区为256字节时,为什么sub rsp只有0x98 = 152d?当我将数据移入缓冲区[0]时,它似乎只是使用分配的堆栈帧之外的数据并使用rbp来引用,那么甚至sub rsp的点是什么,0x98? …
对于 RISC-V,堆栈指针是否指向压入堆栈的最后一个数据,或者堆栈的下一个空闲地址位置?
当堆栈指针在程序的最开始处初始化时(例如crt.S)(即堆栈为空),堆栈指针是否应该初始化为指向第一个字将被压入的内存位置或之前的地址?(例如,假设堆栈的第一个元素将在 4092 处压入。那么,堆栈指针是从 4096 还是 4092 开始?)
指向其定义位置的指针将不胜感激。
我有以下疑惑:
正如我们所知,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) 为了更好地理解汇编,我使用 g++ 编译了一个简单的 C++ 程序,然后使用 gdbgui 逐步执行。我制作了一个堆栈状态的图形,并在程序中的几个连续点进行了注册,以帮助自己更好地了解正在发生的事情。似乎程序在执行期间多次在堆栈指针之外的内存中写入/读取。这让我很惊讶。我的印象是程序永远不应该写超出堆栈指针的范围。我理解它是如何工作的,相对寻址基于基指针,但我希望程序以某种方式调整堆栈指针以包含它计划使用的内存。这种超出堆栈的写入方法是编译器的常用技术吗?
C++:
#include <iostream>
int square(int i) {
i = i * i;
return i;
}
int main() {
int i = square(2);
}
Run Code Online (Sandbox Code Playgroud)
在 Ubuntu 19.10 上编译:
g++ -o square_2 square_2.cpp
Run Code Online (Sandbox Code Playgroud)
g++ 版本:
g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.2.1-9ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib …Run Code Online (Sandbox Code Playgroud) 这是一个简单的函数
#include <stdio.h>
int foo() {
int a = 3;
int b = 4;
int c = 5;
return a * b * c;
}
int main() {
int a = foo();
}
Run Code Online (Sandbox Code Playgroud)
foo() 的程序集看起来像
foo:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 3
mov DWORD PTR [rbp-8], 4
mov DWORD PTR [rbp-12], 5
mov eax, DWORD PTR [rbp-4]
imul eax, DWORD PTR [rbp-8]
imul eax, DWORD PTR [rbp-12]
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
从 中可以看出rbp - N,内部堆栈框架正在被修改。那么,为什么没有 …
以下代码
int main() {
int arr[120];
return arr[0];
}
Run Code Online (Sandbox Code Playgroud)
编译成这样:
sub rsp, 360
mov eax, DWORD PTR [rsp-480]
add rsp, 360
ret
Run Code Online (Sandbox Code Playgroud)
知道整数是 4 个字节,数组的大小为 120,数组应该占用 480 个字节,但从 ESP 中只减去了 360 个字节......这是为什么?
在过去的几天里,我一直在为一种试图获得 EFLAGS 状态的奇怪行为而苦苦挣扎。为此,我编写了以下代码:
#include <stdio.h>
int flags_state()
{
int flags = 0;
__asm__ __volatile__("pushfq");
__asm__ __volatile__("pop %%rax": "=a"(flags));
return flags;
}
int main()
{
printf("Returning EFLAGS state: 0x%x\n", flags_state());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当它运行时,我得到:
./flags
Returning EFLAGS state: 0x246
Run Code Online (Sandbox Code Playgroud)
当我打印两次标志时,它变得更奇怪了
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x206
Run Code Online (Sandbox Code Playgroud)
当我尝试打印 6 次时它发生了变化
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Run Code Online (Sandbox Code Playgroud)
最后是最奇怪的(至少对我来说),当我打印 8 次时
Returning EFLAGS state: …Run Code Online (Sandbox Code Playgroud) assembly ×6
x86-64 ×6
red-zone ×4
abi ×2
gcc ×2
c++ ×1
disassembly ×1
eflags ×1
riscv ×1
stack ×1
stack-frame ×1
stack-memory ×1
x86 ×1