这两个数字的相加如何在大会中工作
Posted
技术标签:
【中文标题】这两个数字的相加如何在大会中工作【英文标题】:How does this adding of two numbers works in Assembly 【发布时间】:2013-06-06 10:56:28 【问题描述】:我是汇编语言的新手,并试图理解一个简单的程序,它将添加两个数字并显示结果。
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”的目的是什么?
【问题讨论】:
调用 printf 将专属于您自己的汇编语言风格,弹出或使用压入堆栈的打印数据。 add esp 8 位使堆栈指针跳转到 ret 命令的正确位置。这会弹出堆栈并直接跳转到该位置。如果它是错误的值,程序将返回到错误的内存位置并崩溃。 (您可以尝试删除 add esp,8 看看会发生什么) 有3个参数,应该是add esp, 12
。我喜欢把它写成add esp, 4 * 3
- 可以很容易地改变参数的数量...
我猜你是对的弗兰克。使用 3 个参数应该添加 esp 12 但在上述情况下,“调用 printf”也将一个参数推送到堆栈,使其添加 esp ,16。想听听你的一两个词。
【参考方案1】:
printf
库可能以多种方式实现,因此断言ALL
printf
例程将以THIS
printf
的行为方式执行是很危险的。
顺序
push eax // 将 100 压入堆栈 push ebx // 将 45 推入堆栈 push message1 // 将消息“value=%d”的地址推入堆栈 call printf // 将返回地址压入堆栈
进入printf
例程,从底部读取堆栈
-
返回地址
指向消息的指针
一些参数值
所以,PRINTF
很可能
POP
返回地址并保存
POP
指向消息的指针
MOV
e STACK POINTER
注册或保存
然后它可以开始它的任务 - 使用指向消息的指针,写出每个字符,直到它遇到像 %d
这样的键字符串,它说'打印一些作为小数。所以它@987654333@s 是堆栈中的下一个值(45,在ebx
中推入),将其格式化为十进制并打印它,然后继续使用printf
字符串。
另一个%d
- 从eax
推送的100,然后继续 - 直到找到指示字符串结尾的0
字节。
所有printf
现在返回所需要做的就是从它存储的任何地方恢复stack pointer
,然后返回到返回地址 - 任何存储的地方。
当它返回时,堆栈将恢复到调用 printf
时的状态 - 那时,EBX
和 EAX
已被 PUSH
ed。每个都是4个字节,所以stack pointer
需要调整8个字节才能去掉这两条PUSH
指令存储的数据。
那么 - 为什么要这样做 - 为什么不简单地让 PRINTF
调整堆栈 - 它可以,因为它知道它已删除 8 个字节以供显示 (2*%d)?
嗯,从本质上讲,它可以——但假设消息只包含一个 %d——或 3——或者消耗了 8 个字节以外的东西?返回时,stack-pointer
将包含一个意外值 - 这取决于 PRINTF
如何解释字符串。非常难以使用汇编程序技巧,例如在不特别小心的情况下覆盖部分消息。正如它所写的,printf
函数总是以可预测的方式运行,返回已弹出消息地址,而不管其他任何考虑。由程序员正确处理堆栈内容。
【讨论】:
感谢 Peter 的友好回复,我想知道 push message1 会将 message1 的地址推送到存储字符串常量“value=%d”的内存中,可以安全地说那?以及 printf 和 PRINTF 有何不同 推送的值是Message1的第一个字节的地址,称为message1的指针。就我而言,printf
和 PRINTF
之间没有区别。大多数汇编程序都允许 - 我倾向于大写强调。不过最好保持一致——尤其是在学习环境中。
Peter 再次只是一个小查询,我们的 PRINTF 将弹出堆栈内容并将 SP 移动到正确的位置,并且在它上面我们显式调用 add esp,12,它不会占用 ESP tp 位置错误?? POPED printf 的返回地址将存储在哪里?
嗯 - 再次查看您的代码,经过几个小时的睡眠后,我建议将堆栈指针 IS NOT
更改为 CALL PRINTF
。在原始列表中将8
添加到ESP
应该添加12
- 4 个用于推送EBX
和EAX
,4 个用于the pointer to MESSAGE1
。那会更有意义。负责PLACING
堆栈上数据的代码部分也将负责REMOVING
它。 PRINTF
例程将简单地设置一个指向堆栈上数据的指针,该指针在进入 PRINTF
时为 ESP+4,返回地址为 4 个字节:最后一项被推送
再次感谢彼得,因此假设调用 PRINTF 将使用其他寄存器来存储堆栈地址而不是 ESP 是否安全,以及为什么我们不向 ESP 添加 16,因为返回地址也被推送上堆栈。以上是关于这两个数字的相加如何在大会中工作的主要内容,如果未能解决你的问题,请参考以下文章
匿名函数如何在 React 组件中的 onClick 中工作?