我的代码中有这个代码段
void jmp_esp()
{
__asm__("jmp *%esp");
}
Run Code Online (Sandbox Code Playgroud)
用gcc编译时
gcc aslr.c -o aslr -ggdb -fno-stack-protector -z execstack
Run Code Online (Sandbox Code Playgroud)
我收到这个错误.
aslr.c: Assembler messages:
aslr.c:6: Error: operand type mismatch for `jmp'
Run Code Online (Sandbox Code Playgroud)
尽管汇编指令有效,为什么这行无法编译?
我读过有关DEP(数据执行预防)的文章.可能是这个功能正在创建这个编译错误?如果是的话,如何禁用它?
对于有C启动代码的微控制器和嵌入式系统来说,C启动代码的功能之一就是初始化堆栈指针。
这个初始栈指针地址和C启动代码一般是芯片厂商定义和提供的吗?
还是由我们作为固件/软件开发人员手动修改或创建 C 启动代码并指定堆栈指针?这部分让我感到困惑。
#include <stdio.h>
void main() {
{
int x;
printf("%p\n", &x);
}
{
int x;
printf("%p\n", &x);
}
}
Run Code Online (Sandbox Code Playgroud)
我认为运行此命令将输出相同的内容两次。当它声明第一个变量时,它会递增堆栈指针,但会离开作用域,因此会递减它,然后第二次重复该过程,因此int x两次都将占用堆栈上的相同内存位置。
但是事实并非如此。堆栈指针不会递减,int x在两种情况下都将占用堆栈中的不同位置。实际上,int x即使范围已消失,第一个仍然可以访问。
#include <stdio.h>
void main() {
{
int x = 10;
printf("%p\n", &x);
}
{
int x = 25;
printf("%p\n", &x);
}
{
int x = 71;
printf("%p\n", &x);
int *p = &x;
printf("%i %i %i\n", *(p + 2), *(p + 1), *p);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么是这样?我有什么误会?
我正在尝试制作一个适用于两种架构的引导加载程序:x86 和 PDP-11。主操作系统是为 PDP-11 兼容机器编写的,但从 x86 启动也应该可以工作,启动模拟器。
AFAIK,如果最后两个字节是, x86 加载第一个磁盘扇区0x7c00并跳转到那里。相反,如果第一个命令是且最后两个字节是 ,则 PDP-11 兼容机将第一个扇区加载到(八进制)并执行它。然而,由于一些硬件细节的原因,加载的数据实际上是颠倒的——例如,x86 读取的数据,另一台机器读取的数据。在这种情况下,这在某种程度上是一个功能,因为如果我制作最后两个字节,它们将适用于两台机器。0x55 0xaa0o20000NOP0xaa 0x550x120xed0x55 0xaa
总之,PDP-11兼容机需要前两个字节包含NOP命令,即0o000240,或0x00a0。数据被反转,因此 x86 实际上会读取0xff5f。
0x5f是 x86 中的真实命令。不幸的是,它是pop di. AFAIK,sp和ss值都没有指定,所以这个命令读取谁知道什么。
我的问题是:
0x0000:0x0000or 0xffff:0xffff?ss:sp指向读取不安全的内存映射硬件寄存器?如果是的话,如果我读了它们,会发生什么更糟糕的事情?我不想意外损坏笔记本电脑。ss:sp指向不可用的内存,即可能pop di触发总线错误?如果是,BIOS 将如何从中恢复,即它将重新启动、显示消息或执行其他操作?有人告诉我,如果我用作rsp通用寄存器,操作系统可能会将寄存器转储到它在中断时指向的位置,从而导致出现问题的行为。
这是真的吗?如果不是,那么如果我不需要堆栈,我可以将其rsp用作通用寄存器吗?
编辑:在用户空间中运行。
我知道call并且ret会修改espand that的值push并且pop有许多变体,但是还有其他指令会影响堆栈指针吗?
在一些教程中,据说堆栈指针指向堆栈的顶部元素:
+-------------+
| stack |
+-------------+
| top element | <-- esp
+-------------+
Run Code Online (Sandbox Code Playgroud)
在其他情况下,据说它指向它的后面,因此指向堆栈增长时可以写入的第一个内存地址。
+-------------+
| stack |
+-------------+
| top element |
+-------------+ <-- esp
Run Code Online (Sandbox Code Playgroud)
在这个德国维基百科网站 https://de.wikipedia.org/wiki/Register_(Computer)#Stapelregister上 ,据说两个版本都存在,并且取决于 CPU 架构。
我的问题是,它在 x86-CPU 上表现如何?它也取决于操作系统吗?
对于某些功能,我需要切换堆栈以使原始堆栈保持不变。为此,我编写了两个宏,如下所示。
#define SAVE_STACK() __asm__ __volatile__ ( "mov %%rsp, %0; mov %1, %%rsp" : \
"=m" (saved_sp) : "m" (temp_sp) );
#define RESTORE_STACK() __asm__ __volatile__ ( "mov %0, %%rsp" : \
"=m" (saved_sp) );
Run Code Online (Sandbox Code Playgroud)
这里temp_sp和saved_sp是线程局部变量。temp_sp指向我们使用的临时堆栈。对于一个我希望不修改其原始堆栈的函数,我将 SAVE_STACK 放在开头,将 RESTORE_STACK 放在底部。例如,像这样。
int some_func(int param1, int param2)
{
int a, b, r;
SAVE_STACK();
// Function Body here
.....................
RESTORE_STACK();
return r;
}
Run Code Online (Sandbox Code Playgroud)
现在我的问题是这种方法是否可行。在 x86(64 位)上,局部变量和参数是通过rbp寄存器访问的,并且rsp在函数序言中相应地被减去,直到在函数尾声中才被触及,在函数结尾中将其添加到原始值。因此,我认为这里没有问题。
我不确定在存在上下文切换和信号的情况下这是否正确。(在 Linux 上)。另外,我不确定如果函数是内联的,或者是否应用尾部调用优化(使用jmp而不是call ),这是否正确。您发现这种方法有任何问题或副作用吗?
我有两个寄存器 w1 和 w2,我想将它们存储在堆栈上。我想将完整的单词w1和w2的一半存储到堆栈中。这是我的实现:
STR w1, [sp, #-8]!
STRH w2, [sp, #-8]!
Run Code Online (Sandbox Code Playgroud)
编译时,第一条指令运行良好,但第二条指令引发总线错误。我知道这是一些对齐问题,但我无法正确理解为什么会发生这种情况?
我正在针对 ARMv8(64 位)架构进行编译。
我正在学习x86汇编,使用下面的代码进行测试,我在gdb控制台中看到指向堆栈顶部的rsp寄存器从0x7FFFFFFFDFD0开始,如果我理解正确的话,在代码中我没有使用push或pop修改 rsp,因此 0x7FFFFFFFDFD0 它是默认值,这意味着我们在堆栈中具有相同的字节数,但我使用堆栈大小为 8mb 的 Linux
section .text
global _start
_start:
mov rcx, 2
add rcx, 8
mov rax, 0x1
mov rbx, 0xff
int 0x80
Run Code Online (Sandbox Code Playgroud)