- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经编写了一些代码来了解调用堆栈。我已经使用一些内联程序集完成了此操作,用于在堆栈上传递参数。我用 gcc 4.1.2(在 CentOS5.4 上)编译它并且运行良好,然后我用 gcc 4.8.4(在 Ubuntu14.04.3 上)编译它并运行程序但它总是崩溃。
我发现变量的引用方式存在差异。 gcc 4.1.2(CentOS5.4)中局部变量使用EBP寄存器寻址,gcc 4.8.4(Ubuntu14.04.3)中局部变量使用ESP寄存器寻址。这似乎是它崩溃的原因。
我的问题是,如何控制 gcc 使用 EBP 还是 ESP?还有,它们有什么区别?
这是 C 代码:
double fun(double d) {
return d;
}
int main(void) {
double a = 1.6;
double (*myfun)() = fun;
asm volatile("subl $8, %esp\n"
"fstpl (%esp)\n");
myfun();
asm volatile("addl $8, %esp\n");
return 0;
}
这是 gcc 4.1.2 中的程序集,它可以工作
int main(void) {
**......**
double a = 1.6;
0x080483bf <+17>: fldl 0x80484d0
0x080483c5 <+23>: fstpl -0x18(%ebp)
double (*myfun) () = fun;
0x080483c8 <+26>: movl $0x8048384,-0xc(%ebp)
asm volatile("subl $8, %esp\n"
"fstpl (%esp)\n");
0x080483cf <+33>: sub $0x8,%esp
0x080483d2 <+36>: fstpl (%esp)
myfun();
0x080483d5 <+39>: mov -0xc(%ebp),%eax
0x080483d8 <+42>: call *%eax
0x080483da <+44>: fstp %st(0)
asm volatile("addl $8, %esp\n");
0x080483dc <+46>: add $0x8,%esp
**......**
这是 gcc 4.8.4 中的程序集。这就是崩溃的原因:
int main(void) {
**......**
double a = 1.6;
0x0804840d <+9>: fldl 0x80484d0
0x08048413 <+15>: fstpl 0x8(%esp)
double (*myfun)() = fun;
0x08048417 <+19>: movl $0x80483ed,0x4(%esp)
asm volatile("subl $8,%esp\n"
"fstpl (%esp)\n");
0x0804841f <+27>: sub $0x8,%esp
0x08048422 <+30>: fstpl (%esp)
myfun();
0x08048425 <+33>: mov 0x4(%esp),%eax
0x08048429 <+37>: call *%eax
0x0804842b <+39>: fstp %st(0)
asm volatile("addl $8,%esp\n");
0x0804842d <+41>: add $0x8,%esp
**......**
最佳答案
使用 esp
之间没有真正的区别和 ebp
, 除了 esp
更改为 push
, pop
, call
, ret
,这有时会让人很难知道某个局部变量或参数在堆栈中的位置。这就是为什么 ebp
加载 esp
, 以便有一个稳定的引用点来引用函数参数和局部变量。
对于这样的函数:
int foo( int arg ) {
int a, b, c, d;
....
}
通常生成以下程序集:
# using Intel syntax, where `mov eax, ebx` puts the value in `ebx` into `eax`
.intel_syntax noprefix
foo:
push ebp # preserve
mov ebp, esp # remember stack
sub esp, 16 # allocate local variables a, b, c, d
...
mov esp, ebp # de-allocate the 16 bytes
pop ebp # restore ebp
ret
调用此方法 ( foo(0)
) 会生成如下内容:
pushd 0 # the value for arg; esp becomes esp-4
call foo
add esp, 4 # free the 4 bytes of the argument 'arg'.
紧接着 call
指令已执行,就在 foo
的第一条指令之前方法被执行,[esp]
将保存返回地址,[esp+4]
0
arg
的值.
在方法中foo
, 如果我们想加载 arg
进入eax
(在 ...
处)我们可以使用:
mov eax, [ebp + 4 + 4]
因为[ebp + 0]
保留 ebp
的先前值(来自 push ebp
),和 [ebp + 4]
(esp
的原始值),保存返回地址。
但我们也可以使用 esp
引用参数:
mov eax, [esp + 16 + 4 + 4]
我们添加16
因为 sub esp, 16
, 然后 4
因为 push ebp
, 和另一个 4
跳过返回地址,到达 arg
.
同样可以通过两种方式访问四个局部变量:
mov eax, [ebp - 4]
mov eax, [ebp - 8]
mov eax, [ebp - 12]
mov eax, [ebp - 16]
或
mov eax, [esp + 12]
mov eax, [esp + 8]
mov eax, [esp + 4]
mov eax, [esp + 0]
但是,每当esp
更改,这些说明也必须更改。所以,最后,是否esp
并不重要。或 ebp
用来。使用 esp
可能更有效因为你不必 push ebp; mov ebp, esp; ... mov esp, ebp; pop ebp
.
据我所知,无法保证您的内联汇编能够正常工作:Ubunty 上的 gcc 4.8.4 优化了 ebp
的使用。并用 esp
引用所有内容.它不知道你的内联汇编修改了 esp
, 所以当它试图调用 myfun()
,它从 [esp + 4]
中获取它, 但它应该从 [esp + 4 + 8]
中获取它.
这里有一个变通方法:不要在使用进行堆栈操作的内联汇编的函数中使用局部变量(或参数)。绕过类型转换问题double fun(double)
至 double fn()
直接在汇编中调用函数:
void my_call() {
asm volatile("subl $8, %esp\n"
"fstpl (%esp)\n"
"call fun\n"
"addl $8, %esp\n");
}
int main(void) {
my_call();
return 0;
}
您还可以放置 my_call
在单独的 .s
中运行(或 .S
)文件:
.text
.global my_call
my_call:
subl $8, %esp
fstpl (%esp)
call fun
addl $8, %esp
ret
在 C 中:
extern double my_call();
你也可以传递 fun
作为论据:
extern double my_call( double (*myfun)() );
...
my_call( fun );
和
.text
.global my_call
my_call:
sub $8, %esp
fstp (%esp)
call *12(%esp)
add $8, %esp
ret
关于c - 基于ebp的寻址和esp寻址之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34001600/
回车和有什么区别 push ebp mov ebp, esp sub esp, imm 说明?有性能差异吗?如果是这样,哪个更快,为什么编译器总是使用后者? 与离开和类似 mov esp, eb
我有以下 NASM 汇编程序,运行时间约为 9.5 秒: section .text global _start _start: mov eax, 0 mov ebx, 8 loop:
根据互联网上的许多教程,据说您可以找到以下结构的命令行参数: 然而,在花一些时间测试我为 NASM 编写的汇编代码后,我发现 ESP 的值是一些数字,例如: -144807325 实际参数计数存储在更
1. 设备烧录的程序rainmaker自带gpio示例 2. swaggerapis登录账户 3. 调用Rainmaker封装好的py
文章结构: 项目概述 成品预览 项目框架 硬件资料,代码 项目槽点 -项目
我是一个学习汇编的初学者,在函数调用之前保留 ESP 寄存器时,通过加法或减法来实现是否重要?很难解释,请考虑以下内容 mov esi, esp sub esp, 12 // on 32bit OS
我反汇编了一个小程序,该程序询问用户的姓名,然后输出“Hello + [user's_name]” 这是反汇编的输出: 主要功能: 打招呼功能: 我注意到,对于 main() 函数,ESP 寄存器递减
我正在从事 Visual Studio 项目项目 A(在编译时生成静态库) 有课 using namespace mynamespace; class projectAclass { virtua
从上图中可以看出,函数setAttribute 时发生了错误。从它的调用返回。 有谁知道如何解决图中显示的这个错误?我知道这是调用约定之间的错误,但是如何找出 setAttribute 的调用约定是什
我用 QT 制作了一个 .dll 文件并将其加载到我的应用程序中。当它即将从一个函数返回时,我收到: The value of ESP was not properly saved across a
我找不到答案。从我读到的 %ebp 有 32 位,将 %esp 移动到 %ebp 你仍然有 32 位,然后减去 70 到 32,我不明白其余的。我对此很陌生,所以我不是很精通。请给出详细的解释。谢谢!
我有一个从 c 程序调用的简单汇编函数,我必须使用需要内存操作数的指令( FIDIV )。 将值移动到 [esp - 2] 是否安全并在下一条指令中使用它,或者以这种方式使用堆栈永远不会安全? 我知道
以下陈述有什么区别? mov %eax,%esp mov %eax,(%esp) 我正在努力散布一个二元炸弹,但在处理一些 mov 时遇到了问题。和 leal在程序集的早期命令。 最佳答案 这会将 %
我使用 duinotech XC-3800 在 ESP32 芯片上使用 ESP IDF 测试运行裸机代码,并在图像大小方面获得以下结果。 ESP32 的分析二进制大小 文件夹结构 温度/ 主要的/ C
我正在 OS X(32 位)上执行系统调用,如下所示: push 123 mov eax, 1 sub esp, 4 int 0x80 而且我不太明白 sub esp, 4 间隙。 我在某处读到,BS
当我在 gdb 中反汇编 main() 时,它会重新调整此结果: 0x0804854c : push ebp 0x0804854d : mov ebp,esp 0x0804
我目前正在学习英特尔处理器的汇编。既然堆栈“向下增长”,为什么我们必须添加才能访问特定元素 [ebp + 8] ;; This will access the first param 我知道我们必须跳
我试图了解如何将堆栈与程序集一起使用,在我尝试时,我在 SO 中的一个问题中遇到了以下代码,即: push ecx mov eax, 4 mov ebx, 1 mov ecx, result m
我有这个 C 代码部分: #include void main() { int n, array[1000], c, d, t, e; char step; puts("Enter a number
我不太明白为什么 gcc 在调用函数之前要先将 esp 减去 12。 pushl %ebp movl %esp,%ebp sub $12,%esp socke
我是一名优秀的程序员,十分优秀!