为什么ESP指向[ESP+;0xc]?
我想学习一些汇编,现在我有一个问题,为什么ESP指向[ESP+;0xc]?,c,assembly,x86,mingw,C,Assembly,X86,Mingw,我想学习一些汇编,现在我有一个问题,ESP在主函数的函数调用期间将初始化的整数移位到 C代码: #include<stdio.h> int main() { int hallo = 5; } 我希望最后一个汇编命令是mov DWORD PTR[esp+0xF],0x5, 由于堆栈从上到下不断增长,并且由于小端点,ESP必须定位在[ESP+0xF]上,以填充[ESP+0xc]否,到[ESP+0xF]的dword存储将在[ESP+0x0f..0x12]处写入4个字节,这甚至
ESP
在主函数的函数调用期间将初始化的整数移位到
C代码:
#include<stdio.h>
int main() {
int hallo = 5;
}
我希望最后一个汇编命令是mov DWORD PTR[esp+0xF],0x5
,
由于堆栈从上到下不断增长,并且由于小端点,ESP必须定位在
[ESP+0xF]
上,以填充[ESP+0xc]
否,到[ESP+0xF]
的dword存储将在[ESP+0x0f..0x12]处写入4个字节,这甚至不是dword对齐的
如果你被那些古老的答案弄糊涂了,那是可以理解的;他们完全错了,所以我贴了一个正确的
dword的地址始终是其任何组成字节的最低地址。(这适用于大端和小端系统)
保留16个字节并存储到[esp+0xc]
存储到这16个字节中的最高地址4个字节
在[esp+0xc]
处的dword是(按LSB到MSB的顺序)地址esp+0xc
、+0xd
、+0xe
和+0xf
处的字节
对于(假设的)大端字节x86,它的字节数相同,但顺序是MSB到LSB。dword的地址仍然是[esp+0xc]
所有这些都与push
doingesp-=4
而不是esp+=4
没有任何联系。堆栈向上增长的系统仍然使用字/dword中的最低字节地址作为该多字节整数的地址。与C语言一样,数组或结构的地址是第一个元素的地址。事实上,这就是为什么C地址是这样工作的
由于堆栈向下增长,因此gcc会选择在保存的EBP值的正下方放置一个本地,并在调用之前保留剩余空间作为堆栈对齐的填充(到CRT辅助函数\uuuuuu main
)
即使32位Windows ABI不需要16字节堆栈对齐,gcc仍然选择这样做(默认值为-mprefered stack boundary=4
:2^4=16)
顺便说一句,如果您在编译时启用了优化功能,显然所有这些噪音都会消失。然后main就可以ret
。或者可能仍然需要调用\uuuuu main
,但可以优化本地
您可以通过使GCC init成为易失性的,并使用-O3
编译来减少噪声,但仍然使它成为本地的。或者将其地址传递给另一个非内联函数
为什么ESP指向[ESP+0xc]
嗯?这根本没有道理。ESP指向[ESP]
。实际上,您在问为什么GCC选择使用寻址模式[esp+0xc]
,而不是其他置换。PS:我使用的是64位CPUTH局部变量可能已经优化了。它确实优化了,但这与endianness无关。“little endian”表示字节C、D、E、F分别为5,0,0,0。“big endian”意味着它们是0,0,0,5。“esp应该定位在esp+0xF上”毫无意义。。。esp是esp,不是esp+任何东西mov DWORD PTR[esp+0xc],0x5
表示:转到esp指向的位置,按0xc
前进,然后向该位置写入四个字节,然后向下三个字节(按递增顺序)写入。endianness告诉您字节是5,0,0,0还是0,0,5;堆栈方向与此无关顺便说一句:这里显示的汇编代码是32位代码,即使您的CPU是64位的。但这两条语句“否,到[esp+0xF]的dword存储将在[esp+0x0f..0x12]写入4个字节,这甚至不是dword对齐的。”和“保留16个字节并存储到[esp+0xc]不是吗?”存储到这16个字节中的最高地址4个字节。由于堆栈向下增长,gcc会选择在那里放置一个本地字节,就在保存的EBP值的正下方……”?如果[esp+0xF]将在[esp+0x0f..0x12]处写入4个字节,那么[esp+0xc]将在[esp+0xc..0x9]处写入4个字节?@Larslafler您似乎对“堆栈向下增长”的含义感到困惑。esp+0xC之后的地址是esp+0xD,这是内存寻址定义的事实。堆栈方向与此无关。我完全同意你的看法。所以esp+0xC向上,不管堆栈方向是什么。但是“[esp+0xF]将在[esp+0x0f..0x12]写入4个字节”不可能是真的,因为[esp+0xF]将在[esp+0xF..0x12]写入4个字节,不是吗?但我想我已经理解了为什么小Edian不相关,因为我们将[esp+0xc]中的4个字节写入[esp+0xF](因为这是内存寻址的定义)在这4个字节中,5存储为小Endian…对吗?@Larslafler,嗯?你写了“但是‘东西’不可能是真的,因为同样的东西”,,不确定你的问题是什么。
00401460 <_main>:
401460: 55 push ebp
401461: 89 e5 mov ebp,esp
401463: 83 e4 f0 and esp,0xfffffff0
401466: 83 ec 10 sub esp,0x10
401469: e8 42 05 00 00 call 4019b0 <___main>
40146e: c7 44 24 0c 05 00 00 mov DWORD PTR [esp+0xc],0x5
401475: 00
401476: b8 00 00 00 00 mov eax,0x0
40147b: c9 leave
40147c: c3 ret
40147d: 90 nop
40147e: 90 nop
40147f: 90 nop
00401480 <__setargv>:
401480: 55 push ebp
401481: 89 e5 mov ebp,esp
401483: 57 push edi
401484: 56 push esi
401485: 53 push ebx
--
004019b0 <___main>:
4019b0: a1 28 70 40 00 mov eax,ds:0x407028
4019b5: 85 c0 test eax,eax
4019b7: 74 07 je 4019c0 <___main+0x10>
4019b9: f3 c3 repz ret
4019bb: 90 nop
4019bc: 8d 74 26 00 lea esi,[esi+eiz*1+0x0]
4019c0: c7 05 28 70 40 00 01 mov DWORD PTR ds:0x407028,0x1
4019c7: 00 00 00
4019ca: eb 94 jmp 401960 <___do_global_ctors>
4019cc: 90 nop
4019cd: 90 nop
4019ce: 90 nop
4019cf: 90 nop
004019d0 <.text>:
4019d0: 83 ec 1c sub esp,0x1c
4019d3: 8b 44 24 24 mov eax,DWORD PTR [esp+0x24]
4019d7: 83 f8 03 cmp eax,0x3
4019da: 74 14 je 4019f0 <.text+0x20>
4019dc: 85 c0 test eax,eax