#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 $0x28,%esp
mov $0x80c5b08,%edx
lea -0xd(%ebp),%eax
mov (%edx),%edx
mov %edx,(%eax)
lea -0x17(%ebp),%eax
mov %eax,(%esp)
call 0x8049c60 <gets>
我因某些原因感到困惑。首先,如果sub $0x28,%esp
占8个字节,char *argv[]
占4个,int argc
占8个,a
,我们为什么会b
占40个字节?帐号为12 - &gt; 8 + 4 + 8 + 12 = 32?
我也在努力查看strcpy发生的位置以及两个内存地址$0x80c5b08
和0x8049c60
的原因。
答案 0 :(得分:0)
局部变量后可能会有一些填充
因为gets()
的参数需要(32位对齐)空间
以及将通过呼叫指令保存的PC寄存器。
注意:ebp
寄存器必须指向下一个可用的堆栈地址
在本地堆栈框架之后。
注意:永远不要使用gets()
函数,
有几个原因。请改用fgets()
。
编译器将strcpy()
替换为宏调用。
该宏产生了以下内容:
mov $0x80c5b08,%edx
lea -0xd(%ebp),%eax
mov (%edx),%edx
我也在努力查看
的原因strcpy()
发生的位置以及两个内存地址$ 0x80c5b08和0x8049c60&#34;
0x80c5b08是要复制到变量中的文字的地址。
0x8049c60是gets()
函数的链接地址。
答案 1 :(得分:0)
好吧,我会尽我所能给你,但我的集会有点生疏。首先,让我们从您所看到的内容开始。使用AT&amp; T语法,与英特尔语法(operation data register
)相比,您基本上必须向后读取地址操作(operation register data
),这是某些人更喜欢阅读英特尔的原因之一。
从概述的角度来看,汇编调用并不难以消化。如果查看前两个命令,第一个命令会将先前的base pointer
地址推送到堆栈以保存它。 (当该程序退出时,将恢复先前的基本指针地址,这是调用例程中的执行将重新拾取的位置)。第二行将此程序的base pointer
地址移动到current stack pointer
地址(堆栈顶部)以开始执行程序。这两行都称为assembly prolog
。
push %ebp
mov %esp,%ebp
来自subtracts 40 bytes (28 hex)
的下一行stack pointer
(堆栈增长较低)为局部变量a
和b
创建空间,其中&#34; nop&# 34;数据和gets
的结果将被复制。我不确定它尝试实现的精确对齐,但a
的存储空间为5个字节且b
10。
sub $0x28,%esp
以下行将指针地址0x80c5b08
移动到通用dx
寄存器(edx
,用于80386 32位寄存器)。在汇编中,在使用它之前,将要操作的数据的地址放入其中一个CPU寄存器中。在这里,它看起来是将内存地址放在&#34; nop&#34;在edx
。
mov $0x80c5b08,%edx
下一个调用lea
加载有效地址将内存地址(偏移量)base pointer - 14
(0xd十六进制)字节复制到eax
寄存器中。起始地址为a
,以便字符串&#34; nop&#34;可以在那里复制。
lea -0xd(%ebp),%eax
以下对mov
的调用将edx
指向的数据复制到eax
中指定的内存位置。复制&#34; nop&#34;到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>
然后,在调用a
之前,有指令将b
和printf
的内存地址以及字符串的静态部分的地址加载到字符串。希望这会有所帮助。