本文介绍了为什么正在调用printf时EDX的值覆盖?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've written a simple assembly program:

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上的可执行文件。

I am the NASM assembler and the GCC to link the object file to an executable on linux.

本质上,这个方案首先将堆栈指针的值写入寄存器EDX,它然后打印的这个寄存器的内容两次。然而,第二个printf呼叫后,打印到标准输出值不匹配第一

Essentially, this program is first putting the value of the stack pointer into register EDX, it is then printing the contents of this register twice. However, after the second printf call, the value printed to the stdout does not match the first.

此行​​为似乎奇怪。当我更换EDX的每一个使用此计划与EBX,预期输出的整数是相同的。我只能推断,EDX是printf函数调用期间的某个点覆盖。

This behaviour seems strange. When I replace every usage of EDX in this program with EBX, the outputted integers are identical as expected. I can only infer that EDX is overwritten at some point during the printf function call.

为什么会出现这种情况?我怎样才能确保我在今后的使用寄存器不使用C LIB功能冲突?

Why is this the case? And how can I make sure that the registers I use in future don't conflict with C lib functions?

推荐答案

按照, EBX ESI EDI EBP 被调用函数保存寄存器和 EAX ECX EDX 是调用者保存的寄存器。

According to the x86 ABI, EBX, ESI, EDI, and EBP are callee-save registers and EAX, ECX and EDX are caller-save registers.

这意味着函数可以自由使用并销毁previous值 EAX ECX EDX
出于这个原因,节省 EAX ECX EDX 调用函数之前,如果你不希望自己的价值观来改变。这是什么调用者保存的意思。

It means that functions can freely use and destroy previous values EAX, ECX, and EDX.For that reason, save values of EAX, ECX, EDX before calling functions if you don't want their values to change. It is what "caller-save" mean.

或者更好的,用于该你还是会一个函数调用后需要值的其他寄存器。在函数的开始/结束推/ EBX 的流行是内部比 EDX 的推/流行好得多循环,使一个函数调用。如果可能的话,使用来电破坏寄存器的呼叫后,不需要临时。如果该值已经在内存中,所以他们并不需要被重新读取之前书面,也便宜溢出。

Or better, use other registers for values that you're still going to need after a function call. push/pop of EBX at the start/end of a function is much better than push/pop of EDX inside a loop that makes a function call. When possible, use call-clobbered registers for temporaries that aren't needed after the call. Values that are already in memory, so they don't need to written before being re-read, are also cheaper to spill.

由于 EBX ESI EDI ,和 EBP 被调用函数保存寄存器,功能有恢复值到原来的任何那些他们返回之前修改的。

Since EBX, ESI, EDI, and EBP are callee-save registers, functions have to restore the values to the original for any of those they modify, before returning.

ESP 也被调用方保存,但你不能搞砸了,除非你的地方复制的返回地址。因为现代的CPU使用返回地址predictor不匹配的呼叫/ RET是可怕的性能。

ESP is also callee-saved, but you can't mess this up unless you copy the return address somewhere. Mismatched call/ret is terrible for performance because modern CPUs use a return-address predictor.

这篇关于为什么正在调用printf时EDX的值覆盖?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 10:28