Delphi汇编器:了解结果寄存器 [英] Delphi assembler: understanding the Result register
问题描述
我在Delphi中搞乱了ASM。据我了解,EAX持有结果。接下来,我必须将RET放在最后,否则Result不正确(如果输入为0,则正确)。我在做什么错,或者我应该说,对此我不了解?
I'm messing around with ASM in Delphi. From my understanding, EAX holds Result. In the following, I have to put RET at the end, otherwise Result is not correct (it is correct if the input is 0). What am I doing wrong, or should I say, what don't I understand about this?
function MSb(const Val: Integer): Integer;
label
Go;
asm
CMP EAX, 0
JNZ Go
MOV EAX, -1
RET
Go:
BSR EBX, EAX
MOV EAX, EBX
RET
end;
如果我说以下话:
MOV Result, EBX
然后我得到以下编译结果:
Then I get the following compilation:
MOV [EPB-$04], EBX
MOV EAX, [EPB-$04]
但是,我上面的代码具有以下后记:
However, my code above has the following postscript:
MOV EAX, EDX
RET
推荐答案
至少在未启用优化的情况下,您的函数具有前同步码和后同步码。看看:
At least without optimization enabled, your function has a pre-amble and a post-amble. Have a look at it:
Project46.dpr.13: asm
0041A1F4 55 push ebp
0041A1F5 8BEC mov ebp,esp
0041A1F7 83C4F8 add esp,-$08
0041A1FA 8945F8 mov [ebp-$08],eax
Project46.dpr.14: CMP EAX, 0
0041A1FD 83F800 cmp eax,$00
Project46.dpr.15: JNZ Go
0041A200 7506 jnz $0041a208
Project46.dpr.16: MOV EAX, -1
0041A202 B8FFFFFFFF mov eax,$ffffffff
Project46.dpr.17: RET
0041A207 C3 ret
Project46.dpr.19: BSR EBX, EAX
0041A208 0FBDD8 bsr ebx,eax
Project46.dpr.20: MOV EAX, EBX
0041A20B 89D8 mov eax,ebx
Project46.dpr.21: RET
0041A20D C3 ret
Project46.dpr.22: end;
0041A20E 8B45FC mov eax,[ebp-$04]
0041A211 59 pop ecx
0041A212 59 pop ecx
0041A213 5D pop ebp
0041A214 C3 ret
因此,前同步码设置了堆栈帧。它节省了 ebp
寄存器,并修改了 ebp
和 esp
寄存器。另请注意后同步码。您确实需要执行该代码来恢复保存的寄存器。
So the pre-amble sets up the stack frame. It saves away the ebp
register, and modifies both the ebp
and esp
registers. Notice also the post-amble. You do need to execute that code to restore the saved registers.
通常的处理方法是跳转到函数的末尾,而不是使用 ret
。因此,像这样编写代码:
The usual way to deal with this is to jump to the end of the function instead of using ret
. So write your code like this:
function MSb(const Val: Integer): Integer;
asm
CMP EAX, 0
JNZ @@go
MOV EAX, -1
JMP @@exit
@@go:
BSR EBX, EAX
MOV EAX, EBX
@@exit:
end;
这样可以确保后同步码得以执行。您确实应该养成以这种方式编写代码的习惯,以确保执行任何前同步码。
This way you ensure that the post-amble is executed. You really should get into the habit of writing the code this way to ensure that any pre-amble is executed.
现在,除此之外,我怀疑您在问题中提到的问题实际上与与使用Pascal标签而不是asm标签有关的编译器错误有关。好吧,也许这是一个编译器错误,但使用Pascal标签也许只是一个错误。请考虑以下程序:
Now, beyond that I suspect that the problem you mention in the question actually relates to a compiler bug relating to your use of a Pascal label rather than an asm label. Well, perhaps it is a compiler bug, but perhaps it is just a mistake to use a Pascal label. Consider the following program:
{$APPTYPE CONSOLE}
function MSb(const Val: Integer): Integer;
asm
CMP EAX, 0
JNZ @@Go
MOV EAX, -1
JMP @@exit
@@Go:
BSR EBX, EAX
MOV EAX, EBX
@@exit:
end;
function MSb2(const Val: Integer): Integer;
label
Go;
asm
CMP EAX, 0
JNZ Go
MOV EAX, -1
RET
Go:
BSR EBX, EAX
MOV EAX, EBX
end;
begin
Writeln(Msb(0));
Writeln(Msb(1));
Writeln(Msb2(0));
Writeln(Msb2(1));
Readln;
end.
经过优化编译后的输出为:
The output when compiled with optimization is:
-1
0
-1
4
所以,那么奇怪的 4
呢?好吧,让我们来看一下 Msb2
的汇编代码,它实际上是您的代码:
So, what about that rather odd 4
. Well, let's look at the assembled code for Msb2
, which is essentially your code:
004059E8 83F800 cmp eax,$00
004059EB 7506 jnz $004059f3
004059ED B8FFFFFFFF mov eax,$ffffffff
004059F2 C3 ret
004059F3 0FBDD8 bsr ebx,eax
004059F6 89D8 mov eax,ebx
004059F8 8BC2 mov eax,edx
004059FA C3 ret
为什么这是价值 edx
的一个未分配值的易失性寄存器,在函数返回之前被移至 eax
中。这是您要报告的问题。我的猜测是,使用Pascal标签会混淆汇编程序。贴上asm标签。
Why on earth is the value of edx
, a volatile register whose value has not been assigned, being moved into eax
just before the function returns. This is the problem that you are reporting. My guess is that the use of a Pascal label is confusing the assembler. Stick to asm labels.
这是 Msb
的汇编代码:
004059D4 83F800 cmp eax,$00
004059D7 7506 jnz $004059df
004059D9 B8FFFFFFFF mov eax,$ffffffff
004059DE C3 ret
004059DF 0FBDD8 bsr ebx,eax
004059E2 89D8 mov eax,ebx
004059E4 C3 ret
那更像它!请注意,编译器如何知道此处没有可发布的内容,然后将 jmp @@ exit
替换为直接的 ret
。
That's more like it! Notice how the compiler knows that there is no post-able here, and replaces the jmp @@exit
with a straight ret
.
这篇关于Delphi汇编器:了解结果寄存器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!