这两个数字的相加如何在大会中工作

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 指向消息的指针 MOVe STACK POINTER 注册或保存

然后它可以开始它的任务 - 使用指向消息的指针,写出每个字符,直到它遇到像 %d 这样的键字符串,它说'打印一些作为小数。所以它@98​​7654333@s 是堆栈中的下一个值(45,在ebx 中推入),将其格式化为十进制并打印它,然后继续使用printf 字符串。

另一个%d - 从eax 推送的100,然后继续 - 直到找到指示字符串结尾的0 字节。

所有printf 现在返回所需要做的就是从它存储的任何地方恢复stack pointer,然后返回到返回地址 - 任何存储的地方。

当它返回时,堆栈将恢复到调用 printf 时的状态 - 那时,EBXEAX 已被 PUSHed。每个都是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的指针。就我而言,printfPRINTF 之间没有区别。大多数汇编程序都允许 - 我倾向于大写强调。不过最好保持一致——尤其是在学习环境中。 Peter 再次只是一个小查询,我们的 PRINTF 将弹出堆栈内容并将 SP 移动到正确的位置,并且在它上面我们显式调用 add esp,12,它不会占用 ESP tp 位置错误?? POPED printf 的返回地址将存储在哪里? 嗯 - 再次查看您的代码,经过几个小时的睡眠后,我建议将堆栈指针 IS NOT 更改为 CALL PRINTF。在原始列表中将8 添加到ESP应该添加12 - 4 个用于推送EBXEAX,4 个用于the pointer to MESSAGE1。那会更有意义。负责PLACING堆栈上数据的代码部分也将负责REMOVING它。 PRINTF 例程将简单地设置一个指向堆栈上数据的指针,该指针在进入 PRINTF 时为 ESP+4,返回地址为 4 个字节:最后一项被推送 再次感谢彼得,因此假设调用 PRINTF 将使用其他寄存器来存储堆栈地址而不是 ESP 是否安全,以及为什么我们不向 ESP 添加 16,因为返回地址也被推送上堆栈。

以上是关于这两个数字的相加如何在大会中工作的主要内容,如果未能解决你的问题,请参考以下文章

匿名函数如何在 React 组件中的 onClick 中工作?

.show() 和 .hide() 如何在 jquery 中工作 [重复]

.push_back 如何在 C++ 中工作?

嵌套组件如何在角度 5 或 6 中工作

两个分类器之间的投票如何在 sklearn 中工作?

"\x" 如何在字符串中工作?