x86汇编代码解释
Explanation of assembly code in x86
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char *argv[]){
char a[5];
char b[10];
strcpy(a,"nop");
gets(b);
printf("Hello there %s. Value in a is %s.\n",b,a);
exit(0);
}
汇编输出的前几行显示:
push %ebp
mov %esp,%ebp
sub [=11=]x28,%esp
mov [=11=]x80c5b08,%edx
lea -0xd(%ebp),%eax
mov (%edx),%edx
mov %edx,(%eax)
lea -0x17(%ebp),%eax
mov %eax,(%esp)
call 0x8049c60 <gets>
有几个原因让我很困惑。首先,如果char *argv[]
占8个字节,int argc
占4个,a
占8个,b
为什么要占40个字节sub [=12=]x28,%esp
] 占12 -> 8+4+8+12 = 32?
我也在努力查看 strcpy 发生的位置以及两个内存地址 [=17=]x80c5b08
和 0x8049c60
的原因。
局部变量后可能会有一些填充
因为 gets()
的参数需要有(32 位对齐的)空间
以及通过call指令保存的PC寄存器。
注意:ebp
寄存器必须指向下一个可用的堆栈地址
在本地堆栈帧之后。
注意:永远不要使用 gets()
函数,
有几个原因。请改用 fgets()
。
strcpy()
被编译器替换为宏调用。
该宏产生了以下内容:
mov [=10=]x80c5b08,%edx
lea -0xd(%ebp),%eax
mov (%edx),%edx
I'm also struggling to see where strcpy()
happens and what accounts for the two memory addresses [=18=]x80c5b08 and 0x8049c60"
0x80c5b08 是要复制到变量中的文字地址。
0x8049c60是gets()
函数的链接地址。
好吧,我会尽力而为,但我的组件有点生锈。首先,让我们从您正在查看的内容开始。使用 AT&T 语法,与 Intel 语法 (operation register data
) 相比,您基本上必须向后读取地址操作 (operation data register
),这是某些人更喜欢阅读 Intel 的部分原因。
从概述的角度来看,汇编调用并不太难理解。如果您查看前两个命令,第一个命令将先前的 base pointer
地址压入堆栈以保存它。 (当该程序退出时,先前的基指针地址将被恢复,这就是调用例程中的执行将恢复的位置)。第二行将该程序的 base pointer
地址移动到 current stack pointer
地址(堆栈顶部)以开始执行您的程序。这两行都被称为 assembly prolog
.
push %ebp
mov %esp,%ebp
stack pointer
的下一行subtracts 40 bytes (28 hex)
(堆栈向下增长)为局部变量a
和b
创建space,其中"nop" 数据和 gets
的结果将被复制。我不确定它试图实现什么样的精确对齐,但是 a
的存储空间是 5 个字节,b
是 10.
sub [=11=]x28,%esp
下一行将指针地址 0x80c5b08
移动到通用 dx
寄存器(edx
用于 80386 32 位寄存器)。在汇编中,您将要操作的数据的地址放入 CPU 寄存器之一,然后再对其进行操作。这里看起来是将 "nop" 的内存地址放在 edx
.
中
mov [=12=]x80c5b08,%edx
下一次调用lea
加载有效地址将内存地址(偏移处)base pointer - 14
(0xd hex)字节复制到eax
注册。 a
的起始地址,以便可以将字符串 "nop" 复制到那里。
lea -0xd(%ebp),%eax
以下对 mov
的调用将 edx
指向的数据复制到 eax
中指定的内存位置。复制 "nop" 到 a
.
mov (%edx),%edx
mov %edx,(%eax)
下一个lea
将base pointer - 23
(0x17十六进制)b
的内存地址加载到eax
中,mov
将地址放在堆栈上在调用 gets
填充该位置的内存之前。
lea -0x17(%ebp),%eax
mov %eax,(%esp)
call 0x8049c60 <gets>
之后,有指令在调用printf
之前加载a
和b
的内存地址以及字符串静态部分的地址。希望这会有所帮助。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char *argv[]){
char a[5];
char b[10];
strcpy(a,"nop");
gets(b);
printf("Hello there %s. Value in a is %s.\n",b,a);
exit(0);
}
汇编输出的前几行显示:
push %ebp
mov %esp,%ebp
sub [=11=]x28,%esp
mov [=11=]x80c5b08,%edx
lea -0xd(%ebp),%eax
mov (%edx),%edx
mov %edx,(%eax)
lea -0x17(%ebp),%eax
mov %eax,(%esp)
call 0x8049c60 <gets>
有几个原因让我很困惑。首先,如果char *argv[]
占8个字节,int argc
占4个,a
占8个,b
为什么要占40个字节sub [=12=]x28,%esp
] 占12 -> 8+4+8+12 = 32?
我也在努力查看 strcpy 发生的位置以及两个内存地址 [=17=]x80c5b08
和 0x8049c60
的原因。
局部变量后可能会有一些填充
因为 gets()
的参数需要有(32 位对齐的)空间
以及通过call指令保存的PC寄存器。
注意:ebp
寄存器必须指向下一个可用的堆栈地址
在本地堆栈帧之后。
注意:永远不要使用 gets()
函数,
有几个原因。请改用 fgets()
。
strcpy()
被编译器替换为宏调用。
该宏产生了以下内容:
mov [=10=]x80c5b08,%edx
lea -0xd(%ebp),%eax
mov (%edx),%edx
I'm also struggling to see where
strcpy()
happens and what accounts for the two memory addresses [=18=]x80c5b08 and 0x8049c60"
0x80c5b08 是要复制到变量中的文字地址。
0x8049c60是gets()
函数的链接地址。
好吧,我会尽力而为,但我的组件有点生锈。首先,让我们从您正在查看的内容开始。使用 AT&T 语法,与 Intel 语法 (operation register data
) 相比,您基本上必须向后读取地址操作 (operation data register
),这是某些人更喜欢阅读 Intel 的部分原因。
从概述的角度来看,汇编调用并不太难理解。如果您查看前两个命令,第一个命令将先前的 base pointer
地址压入堆栈以保存它。 (当该程序退出时,先前的基指针地址将被恢复,这就是调用例程中的执行将恢复的位置)。第二行将该程序的 base pointer
地址移动到 current stack pointer
地址(堆栈顶部)以开始执行您的程序。这两行都被称为 assembly prolog
.
push %ebp
mov %esp,%ebp
stack pointer
的下一行subtracts 40 bytes (28 hex)
(堆栈向下增长)为局部变量a
和b
创建space,其中"nop" 数据和 gets
的结果将被复制。我不确定它试图实现什么样的精确对齐,但是 a
的存储空间是 5 个字节,b
是 10.
sub [=11=]x28,%esp
下一行将指针地址 0x80c5b08
移动到通用 dx
寄存器(edx
用于 80386 32 位寄存器)。在汇编中,您将要操作的数据的地址放入 CPU 寄存器之一,然后再对其进行操作。这里看起来是将 "nop" 的内存地址放在 edx
.
mov [=12=]x80c5b08,%edx
下一次调用lea
加载有效地址将内存地址(偏移处)base pointer - 14
(0xd hex)字节复制到eax
注册。 a
的起始地址,以便可以将字符串 "nop" 复制到那里。
lea -0xd(%ebp),%eax
以下对 mov
的调用将 edx
指向的数据复制到 eax
中指定的内存位置。复制 "nop" 到 a
.
mov (%edx),%edx
mov %edx,(%eax)
下一个lea
将base pointer - 23
(0x17十六进制)b
的内存地址加载到eax
中,mov
将地址放在堆栈上在调用 gets
填充该位置的内存之前。
lea -0x17(%ebp),%eax
mov %eax,(%esp)
call 0x8049c60 <gets>
之后,有指令在调用printf
之前加载a
和b
的内存地址以及字符串静态部分的地址。希望这会有所帮助。