Assembly 两个数字相加在汇编中是如何工作的

Assembly 两个数字相加在汇编中是如何工作的,assembly,x86,Assembly,X86,我不熟悉汇编语言,我试图理解一个简单的程序,它将添加两个NUNBER并显示结果 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

我不熟悉汇编语言,我试图理解一个简单的程序,它将添加两个NUNBER并显示结果

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
现在产量是45100

添加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 
我想知道的是执行“callprintf”时会发生什么情况


“添加esp,8”的姿势是什么

printf库可能以多种方式实现,因此断言
所有
printf
例程将以
printf
动作的方式执行是危险的

序列

推送eax//将100推送至堆栈 将ebx//推45到堆栈上 push message1//将消息“value=%d”的地址推送到堆栈上 调用printf//将返回地址推送到堆栈

使用进入
printf
例程,从底部读取堆栈

  • 回信地址
  • 指向消息的指针
  • 一些参数值
  • 所以,
    PRINTF
    最有可能

  • POP
    返回地址并保存
  • POP
    指向消息的指针
  • MOV
    e将
    堆栈指针
    移到寄存器或保存它
  • 然后它就可以开始它的任务了——使用指向消息的指针,写出每个字符,直到它遇到一个像
    %d
    这样的键串,上面写着“将某物打印为十进制”。因此,它
    POP
    s堆栈中的下一个值(45,在
    ebx
    中推入),将其格式化为十进制并打印,然后继续使用
    printf
    字符串

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

    现在要返回的所有
    printf
    需要做的就是将
    堆栈指针
    从其存储的位置还原,并返回到返回地址-无论其存储在何处

    当它返回时,堆栈将恢复到调用
    printf
    时的状态-当时,
    EBX
    EAX
    已经
    PUSH
    ed。每个是4个字节,因此,
    堆栈指针
    需要调整8个字节,以删除这两条
    推送
    指令存储的数据

    那么-为什么要这样做-为什么不简单地使用allw
    PRINTF
    来调整堆栈-它可以调整堆栈,因为它知道它已删除8个字节用于显示(2*%d)


    实际上,它可以-但假设消息只包含一个%d-或3-或消耗8字节以外的内容?返回时,
    堆栈指针
    将包含意外值-这取决于
    PRINTF
    如何解释字符串。如果不特别小心,很难使用汇编程序技巧,例如覆盖部分消息。正如所写的那样,
    printf
    函数始终以可预测的方式运行,在弹出消息地址后返回,而不考虑任何其他因素。由程序员来正确处理堆栈内容。

    调用printf将是您自己的汇编语言独有的功能,可以弹出或使用推送到堆栈上的打印数据。add esp 8位使堆栈指针跳转到ret命令的正确位置。这将弹出堆栈并直接跳到该位置。如果是错误的值,程序将返回错误的内存位置并崩溃。(您可以尝试删除add esp,8,看看会发生什么)有3个参数,应该是
    add esp,12
    。我喜欢将其写成添加esp,4*3,这样可以很容易地更改参数的数量…我想你是对的,Frank。对于3个参数,它应该是添加esp 12,但在上面的例子中,“call printf”也将一个参数推到堆栈中,从而添加esp,16。想听听你那边的一两句话。感谢Peter的友好回复,有一件事我想知道push message1会将message1在Memory中的地址推送到存储字符串常量“value=%d”的位置,这样说安全吗?printf和printf的区别推送的值是Message1的第一个字节的地址,即指向Message1的指针。就我而言,
    printf
    printf
    之间没有区别。大多数汇编器都会允许这两种情况——我倾向于用大写字母强调。但最好保持一致性,尤其是在学习环境中。Peter再次提出一个小问题,我们的PRINTF将弹出堆栈内容,并将SP移动到正确的位置,在其上方,我们显式地称之为add esp,12,ESP tp的位置不对吗?printf的返回地址将存储在哪里?嗯-再次查看您的代码,在几个小时的睡眠后,我建议堆栈指针
    不会被
    调用printf
    更改。在原始列表中将
    8
    添加到
    ESP
    时,应将
    12
    -4分别添加到
    EBX
    EAX
    上,4分别添加到
    指向消息1的指针上。这会更有意义。负责
    在堆栈上放置
    数据的代码部分也负责
    删除
    数据。
    PRINTF
    例程只需设置一个指向堆栈上数据的指针,返回地址为
    PRINTF
    4字节时,堆栈上的数据将为ESP+4:最后一个项再次按下hanks-Peter,因此可以安全地假设Call PRINTF将使用其他寄存器来存储堆栈地址,而不是ESP,以及为什么我们不向ESP添加16,因为返回地址也被推送到堆栈上。