Delphi汇编器:了解结果寄存器 [英] Delphi assembler: understanding the Result register

查看:114
本文介绍了Delphi汇编器:了解结果寄存器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆