I have the following code that is written in pure Delphi.
procedure Test;
var
i2: Integer;
begin
i2 := 0;
i2 := 0 div i2;
end;
try
Test1;
except
WriteLn('runtime error');
end;
Then I copied all the assembly code that generated by Delphi compiler in the CPU view under debugger.
procedure Test;
asm
push rbp
sub rsp,$10
mov rbp,rsp
mov [rbp+$0c],$0000007b
mov [rbp+$08],$00000000
mov eax,[rbp+$0c]
cdq
idiv dword ptr [rbp+$08]
mov [rbp+$08],eax
lea rsp,[rbp+$10]
pop rbp
end;
try
Test1;
except
WriteLn('runtime error');
end;
But the program crashed due to unable unwind exception. But the pure Pascal version works correctly to catch the exception. Why it happens since they are the same assembly code?
Is there any documentation to explain this different behavior? I have found a documentation explaining MacOS inline assembly (PC-Mapped Exceptions - RAD Studio). But I suppose that does not fit Win64.
Is there any special rule to write assembly code in Win64 and properly let Delphi handing runtime error?
Use MASM to do this. Although BASM do provide some Pseudo-Ops similar to MASM, it lacks some important Pseudo-Ops to manage the stack and generate extra info in the prologue (.allocstack, .setframe, etc). https://docwiki.embarcadero.com/RADStudio/Athens/en/Assembly_Procedures_and_Functions https://learn.microsoft.com/en-us/cpp/assembler/masm/dot-setframe?view=msvc-170
ml64 /c test.asm
test.asm
_text SEGMENT
Test PROC FRAME
push rbp
.pushreg rbp
sub rsp, 010h
.allocstack 010h
mov rbp, rsp
.setframe rbp, 0
.endprolog
mov dword ptr [rbp+0Ch], 7Bh
mov dword ptr [rbp+08h], 0
mov eax, dword ptr [rbp+0Ch]
cdq
idiv dword ptr [rbp+08h]
mov dword ptr [rbp+08h], eax
lea rsp, [rbp+10h]
pop rbp
ret
Test ENDP
_text ENDS
END
test.pas
{$L test.obj}
procedure Test; external;
try
Test;
except
WriteLn('Handled!');
end;