如何在asm块中引发异常?

Joh*_*ica 5 delphi 64-bit assembly exception

我想在X64 asm块中引发异常.

让我们假设我有这样的函数:

function Example(Values: array of integer): integer;
asm
  or rcx,rcx
  jz @error
  ....
Run Code Online (Sandbox Code Playgroud)

我知道我只能读取指针并获得AV,但是我想提出一个更具描述性的错误.

我可以做一个额外的功能并调用那个:

asm
  or rcx,rcx
  jz @error
  ....
@error:
  mov ecx, 1
  mov rdx, ErrorString
  jmp RaiseError
  ....

function RaiseError(code: integer; const Msg: string);
begin
  case code of
    1: raise EEmptyArrayError.Create(Msg);
Run Code Online (Sandbox Code Playgroud)

但是,错误将在引起的函数之外发生.如何从(似乎)来自Example函数内部获得异常.

请注意,这是X64,因此适用于X86的所有SEH答案都不合适,因为X64使用VEH.

Joh*_*ica 4

raise 的完整语法是:

raise Exception at address  
Run Code Online (Sandbox Code Playgroud)

您需要做的就是将当前 IP 作为参数传递,错误过程可以将其传递给异常。

您可以使用 获取 RIP lea rax, [rip]

这样代码就变成了:

asm
  or rcx,rcx
  jz @error
  ....
@error:
  mov ecx, 1
  mov rdx, ErrorString
  lea r8,[rip]
  jmp RaiseError 
  ....

function RaiseError(code: integer; const Msg: string; address: pointer);
begin
  case code of
    1: raise EEmptyArrayError.Create(Msg) at address;
Run Code Online (Sandbox Code Playgroud)

当然在这种情况下使用起来更方便

function RaiseError(code: integer; const Msg: string);
begin
  case code of
    1: raise EEmptyArrayError.Create(Msg) at ReturnAddress;
Run Code Online (Sandbox Code Playgroud)

注意
在这种情况下,如果保留 jmp,则错误似乎源自调用例程,在这种情况下,这实际上是正确的。如果您希望异常将罪魁祸首指向您的 asm 代码,请使用调用。

  • 在 Delphi XE2+ 中,您可以(并且应该)使用 `System.ReturnAddress` 编译器内在函数,它在 32 位和 64 位中都可以工作: `procedure RaiseError(code: integer; const Msg: string); 开始...在 ReturnAddress 处引发 EEmptyArrayError.Create(Msg); ...结束;` (3认同)