我是汇编语言的新手,并试图理解一个简单的程序,它会添加两个nunbers并显示结果。
section .data
message1 db "value=%d%d",10,0
section .text
global main
extern printf
main:
mov eax, 55
mov ebx, 45
add eax,ebx
push eax
push ebx
push message1
call printf
add esp, 8
ret
现在输出结果是45 100
添加eax后,ebx指令结果将存储在eax寄存器中。
但现在接下来会发生什么
push eax // push 100 on to stack
push ebx // push 45 on to stack
push message1 // push "value=%d" on to stack // I m bit doubtful here
我想知道的是当执行“call printf”时会发生什么?
“添加esp,8”的用途是什么?
答案 0 :(得分:1)
printf
库可以通过多种方式实现,因此断言ALL
printf
例程将以THIS
{{1}的方式执行会很危险行为。
序列
push eax //将100推到堆栈 push ebx // push 45 on stack push message1 //将消息“value =%d”的地址推送到堆栈 call printf //将RETURN ADDRESS推送到堆栈
进入printf
例程,从BOTTOM读取堆栈
所以,printf
最有可能
PRINTF
返回地址并保存POP
指向消息的指针POP
MOV
到注册表或保存然后它可以执行它的任务 - 使用指向消息的指针,将每个字符写出来,直到遇到像STACK POINTER
这样的键字符串,其中“将某些内容打印为十进制”。所以%d
是堆栈中的下一个值(45,在POP
中推送),将其格式化为十进制并打印出来,然后继续使用ebx
字符串。
另一个printf
- 从%d
推送100,然后继续 - 直到找到指示字符串结尾的eax
字节。
现在需要返回的所有0
都是从存储的任何地方恢复printf
,并返回到返回地址 - 无论存储在何处。
当它返回时,堆栈将恢复到调用stack pointer
时的状态 - 当时printf
和EBX
已EAX
编辑。每个都是4个字节,因此PUSH
需要调整8个字节,以删除这两个stack pointer
指令存储的数据。
所以 - 为什么这样做 - 为什么不简单地让PUSH
来调整堆栈 - 它可以,因为它知道它被移除了8个字节用于显示(2 *%d)?
嗯,从本质上讲,它可以 - 但是假设消息只包含一个%d - 或3 - 或者消耗了8个字节以外的东西?返回时,PRINTF
将包含一个意外值 - 这取决于stack-pointer
如何解释字符串。非常难以拉动汇编程序技巧,例如在非常小心的情况下覆盖部分邮件。正如它所写的那样,PRINTF
函数总是以可预测的方式起作用,返回弹出消息地址,而不管其他任何考虑因素。由程序员来正确处理堆栈内容。