0x123C语言,and esp, 0xfffffff0

这段代码分析了C/C++中栈对齐的机制,通过`and esp, 0xfffffff0`指令确保栈指针对齐到16字节边界。这样做是为了满足现代处理器对栈帧16字节对齐的要求,通常是因为SSE2指令集和128位寄存器的使用。栈对齐在函数调用和局部变量分配时确保了内存效率和处理器性能。
摘要由CSDN通过智能技术生成

问题

I don't entirely understand the line with comment in it below. I read a few posts on SO and in the gcc manual and learned that it is for stack address alignment but fail to understand how it does so. The code is show below:

(gdb) disas main

Dump of assembler code for function main:

0x08048414 : push ebp

0x08048415 : mov ebp,esp

0x08048417 : and esp,0xfffffff0 ; why??

0x0804841a : sub esp,0x10

0x0804841d : mov DWORD PTR [esp],0x8048510

0x08048424 : call 0x8048320

0x08048429 : mov DWORD PTR [esp],0x8048520

0x08048430 : call 0x8048330

0x08048435 : leave

0x08048436 : ret

End of assembler dump.

The code was generated using gcc (version 4.6.3) on linux. Thanks.

回答1:

and esp, 0xfffffff0 does a bitwise AND between the stack pointer and a constant, and stores the result back in the stack pointer.

The constant is chosen so that its low four bits are zero. Therefore the AND operation will set these bits to zero in the result, and leave the other bits of esp intact. This has the effect of rounding the stack pointer down to the nearest multiple of 16.

回答2:

It looks like it's part of some code to set up shop at the start of main.

Function start: save the base frame pointer on the stack (needed by the leave instruction later):

0x08048414 : push ebp

Now we align the stack pointer to a 16-byte bound, because the compiler (for whatever reason) wants it. This could be that it always wants 16-byte aligned frames, or that the local variables need 16-byte alignment (maybe someone used a uint128_t or they're using a type that uses gcc vector extensions). Basically, since the result will always be less than or equal to the current stack pointer, and the stack grows downward, it's just discarding bytes until it gets to a 16-byte aligned point.

0x08048415 : mov ebp,esp

0x08048417 : and esp,0xfffffff0

Next we subtract 16 from the stack pointer, creating 16 bytes of local variable space:

0x0804841a : sub esp,0x10

puts((const char*)0x8048510);

0x0804841d : mov DWORD PTR [esp],0x8048510

0x08048424 : call 0x8048320

system((const char*)0x8048520);

0x08048429 : mov DWORD PTR [esp],0x8048520

0x08048430 : call 0x8048330

Exit the function (see another answer about what leave does):

0x08048435 : leave

0x08048436 : ret

Example of "discarding bytes": say esp = 0x123C at the start of main. The first lines of code:

0x08048414 : push ebp

0x08048415 : mov ebp,esp

result in this memory map:

0x123C: (start of stack frame of calling function)

0x1238: (old ebp value)

Then:

0x08048417 : and esp,0xfffffff0

forces the last 4 bits of esp to 0, which does this:

0x123C: (start of stack frame of calling function)

0x1238: (old ebp value)

0x1234: (undefined)

0x1230: (undefined)

There's no way for the programmer to rely on a certain amount of memory being between esp and ebp at this point; therefore this memory is discarded and not used.

Finally, the program allocates 16 bytes of stack (local) storage:

Next we subtract 16 from the stack pointer, creating 16 bytes of local variable space:

0x0804841a : sub esp,0x10

giving us this map:

0x123C: (start of stack frame of calling function)

0x1238: (old ebp value)

0x1234: (undefined)

0x1230: (undefined)

0x123C: (undefined local space)

0x1238: (undefined local space)

0x1234: (undefined local space)

0x1230: (undefined local space)

At this point, the program can be sure there are 16 bytes of 16-byte aligned memory being pointed to by esp.

回答3:

i know it was posted long time ago, it might help for others down the line.

1) In modern processors, we know that GCC aligns the stack defaulting to 16-byte alignment.

2) 16 byte ( 128 bit ) is because of SSE2 instructions which have MMX and XMM registers and XMM registers are of 128 bit.

3) so when a function call is made, it is automatically aligned to 16 byte, outside the function it remains to 8 byte.

4) the logic of using 0xfffffff0 is to keep the lower 4 bit to 0 , this is because of simple Boolean math which says that in binary , the multiples of 16 have low 4 bit to zero ( why four bits? 2^4 = 16 ).

来源:https://stackoverflow.com/questions/24588858/and-esp-0xfffffff0

编程要求 根据下方所给的汇编代码,在右侧编辑器的代码文件的 Begin - End 区域内补充 C 语言代码。 08049172 <f>: 8049172: 55 push %ebp 8049173: 89 e5 mov %esp,%ebp 8049175: 53 push %ebx 8049176: 83 ec 04 sub $0x4,%esp 8049179: 83 7d 08 00 cmpl $0x0,0x8(%ebp) 804917d: 75 07 jne 8049186 <f+0x14> 804917f: b8 01 00 00 00 mov $0x1,%eax 8049184: eb 35 jmp 80491bb <f+0x49> 8049186: 83 7d 08 01 cmpl $0x1,0x8(%ebp) 804918a: 75 07 jne 8049193 <f+0x21> 804918c: b8 02 00 00 00 mov $0x2,%eax 8049191: eb 28 jmp 80491bb <f+0x49> 8049193: 8b 45 08 mov 0x8(%ebp),%eax 8049196: 83 e8 01 sub $0x1,%eax 8049199: 83 ec 0c sub $0xc,%esp 804919c: 50 push %eax 804919d: e8 d0 ff ff ff call 8049172 <f> 80491a2: 83 c4 10 add $0x10,%esp 80491a5: 89 c3 mov %eax,%ebx 80491a7: 8b 45 08 mov 0x8(%ebp),%eax 80491aa: 83 e8 02 sub $0x2,%eax 80491ad: 83 ec 0c sub $0xc,%esp 80491b0: 50 push %eax 80491b1: e8 bc ff ff ff call 8049172 <f> 80491b6: 83 c4 10 add $0x10,%esp 80491b9: 01 d8 add %ebx,%eax 80491bb: 8b 5d fc mov -0x4(%ebp),%ebx 80491be: c9 leave 80491bf: c3 ret 080491c0 <main>: 80491c0: 8d 4c 24 04 lea 0x4(%esp),%ecx 80491c4: 83 e4 f0 and $0xfffffff0,%esp 80491c7: ff 71 fc pushl -0x4(%ecx) 80491ca: 55 push %ebp 80491cb: 89 e5 mov %esp,%ebp 80491cd: 51 push %ecx 80491ce: 83 ec 14 sub $0x14,%esp 80491d1: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%ebp) 80491d8: 83 ec 08 sub $0x8,%esp 80491db: 8d 45 ec lea -0x14(%ebp),%eax 80491de: 50 push %eax 80491df: 68 08 a0 04 08 push $0x804a008 80491e4: e8 67 fe ff ff call 8049050 __isoc99_scanf@plt 80491e9: 83 c4 10 add $0x10,%esp 80491ec: 8b 45 ec mov -0x14(%ebp),%eax 80491ef: 83 ec 0c sub $0xc,%esp 80491f2: 50 push %eax 80491f3: e8 7a ff ff ff call 8049172 <f> 80491f8: 83 c4 10 add $0x10,%esp 80491fb: 89 45 f0 mov %eax,-0x10(%ebp) 80491fe: 83 ec 08 sub $0x8,%esp 8049201: ff 75 f0 pushl -0x10(%ebp) 8049204: 68 08 a0 04 08 push $0x804a008 8049209: e8 22 fe ff ff call 8049030 printf@plt 804920e: 83 c4 10 add $0x10,%esp 8049211: b8 00 00 00 00 mov $0x0,%eax 8049216: 8b 4d fc mov -0x4(%ebp),%ecx 8049219: c9 leave 804921a: 8d 61 fc lea -0x4(%ecx),%esp 804921d: c3 ret 测试说明 如果所补充C语言代码在测试集上的实际运行输出与预期输出相同,则测试成功。
最新发布
06-06
这是一个汇编语言程序段,可能是一个函数或者整个程序的一部分。以下是对这段程序的逐行解释: 1. push %ebp:将当前函数的基址指针(EBP)压入栈中,为后面的函数操作做准备。 2. mov %esp,%ebp:将当前栈指针(ESP)的值赋给EBP,用于定位参数和局部变量的地址。 3. and $0xfffffff0,%esp:将ESP的值与0xfffffff0进行按位与运算,将ESP向下舍入到最近的16字节边界,用于对齐栈帧。 4. sub $0x20,%esp:为局部变量分配20字节的栈空间。 5. movl:这里缺少操作数,无法确定该行指令的作用。 6. movl $0x6,0x10(%esp):将值0x6存储到ESP+0x10的内存地址中。 7. movl $0x64,0x14(%esp):将值0x64存储到ESP+0x14的内存地址中。 8. mov 0x14(%esp),%eax:将ESP+0x14的内存地址中的值赋给EAX寄存器。 9. mov 0x10(%esp),%edx:将ESP+0x10的内存地址中的值赋给EDX寄存器。 10. sub %eax,%edx:将EAX寄存器中的值减去EDX寄存器中的值,结果存储到EDX寄存器中。 11. mov %edx,%eax:将EDX寄存器中的值赋给EAX寄存器。 12. mov %eax,0x18(%esp):将EAX寄存器中的值存储到ESP+0x18的内存地址中。 13. mov 0x14(%esp),%eax:将ESP+0x14的内存地址中的值赋给EAX寄存器。 14. mov 0x10(%esp),%edx:将ESP+0x10的内存地址中的值赋给EDX寄存器。 15. add %edx,%eax:将EDX寄存器中的值加上EAX寄存器中的值,结果存储到EAX寄存器中。 16. mov %eax,0x1c(%esp):将EAX寄存器中的值存储到ESP+0x1c的内存地址中。 17. mov 0x1c(%esp),%eax:将ESP+0x1c的内存地址中的值赋给EAX寄存器。 18. mov %eax,0x8(%esp):将EAX寄存器中的值存储到ESP+0x8的内存地址中。 19. mov 0x18(%esp),%eax:将ESP+0x18的内存地址中的值赋给EAX寄存器。 20. mov %eax,0x4(%esp):将EAX寄存器中的值存储到ESP+0x4的内存地址中。 21. movl $0x0,(%esp):将值0x0存储到ESP的内存地址中。 22. call 4f <main+0x4f>:调用地址为4f的函数。 23. leave:释放当前函数的栈帧并恢复EBP和ESP的值。 24. ret:从函数返回。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值