c/c++语言开发共享为什么在调用printf时会覆盖EDX的值?

我写了一个简单的汇编程序:

section .data str_out db "%d ",10,0 section .text extern printf extern exit global main main: MOV EDX, ESP MOV EAX, EDX PUSH EAX PUSH str_out CALL printf SUB ESP, 8 ; cleanup stack MOV EAX, EDX PUSH EAX PUSH str_out CALL printf SUB ESP, 8 ; cleanup stack CALL exit 

我是NASM汇编程序和GCC,用于将目标文件链接到linux上的可执行文件。

本质上,该程序首先将堆栈指针的值放入寄存器EDX,然后将该寄存器的内容打印两次。 但是,在第二次printf调用之后,打印到stdout的值与第一个不匹配。

这种行为似乎很奇怪。 当我用EBX替换此程序中EDX的每次使用时,输出的整数与预期的相同。 我只能推断在printf函数调用期间某些时候EDX会被覆盖。

为什么会这样? 如何确保我将来使用的寄存器与C lib函数不冲突?

    根据x86 ABI , EBXESIEDIEBP是被调用者保存寄存器, EAXECXEDX是调用者保存寄存器。

    这意味着函数可以自由使用和销毁以前的值EAXECXEDX 。 因此,如果您不希望更改其值,请在调用函数之前保存EAXECXEDX的值。 这就是“来电保存”的意思。

    或者更好的是,将其他寄存器用于函数调用后仍需要的值。 在函数的开始/结束处推送/弹出EBXEDX函数调用的循环中推送/弹出EDX要好得多。 如果可能,请使用call-clobbered寄存器作为调用后不需要的临时寄存器。 已经在内存中的值,因此在重新读取之前不需要写入,溢出也更便宜。


    由于EBXESIEDIEBP是被调用者保存寄存器,因此函数必须在返回之前将值恢复为他们修改的任何值。

    ESP也被callee保存,但除非你在某处复制返回地址,否则你不能搞砸了。 不匹配的call / ret对于性能来说很糟糕,因为现代CPU使用返回地址预测器。

    目标平台的ABI(例如32位x86 Linux)定义了函数可以使用哪些寄存器而不保存。 (也就是说,如果你想在电话中保留它们,你必须自己做)。

    链接到Windows和非Window,32和64位的ABI文档, url为https://stackoverflow.com/tags/x86/info

    有些寄存器不会在调用之间保留(可用作临时寄存器),这意味着函数可以更小。 简单的function通常可以避免进行任何push/pop保存/恢复。 这减少了指令的数量,从而导致更快的代码。

    每个部分都很重要:不得不将所有状态溢出到内存中,这会使非叶函数的代码膨胀,并减慢速度。 在被调用函数没有触及所有寄存器的情况下。

      以上就是c/c++开发分享为什么在调用printf时会覆盖EDX的值?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/560027.html

      (0)
      上一篇 2021年1月27日
      下一篇 2021年1月27日

      精彩推荐