delphi - Assembly calls to System unit functions on FreePascal x64 -


i have delphi/assembly code compiles , works fine (xe2) win32, win64, , osx 32. however, since need work on linux, have been looking @ compiling fpc versions of (so far, win32/64, linux32/64).

by , large, works well, 1 thing have not been able work calls/jumps delphi system unit functions, such:

  jmp system.@fillchar 

this appears have desired effect on fpc win32/linux32, fails exception on fpc win64/linux64. (i quite familiar calling convention differences among platforms, don't think that's reason.)

what correct way of doing on fpc x64 platforms?

[edit1] --- in response david's comment, here simplified program illustrates problem (at least hope accurately):

program fpcx64example; {$ifdef fpc}   {$mode delphi}   {$asmmode intel} {$else}   {$apptype console} {$endif}  procedure fillmemcall (p: pointer; len: longword; val: byte); asm   // function , system function have same parameters   // in same order -- in proper places here   jmp system.@fillchar end;  function makestring (c: ansichar; len: longword): ansistring; begin   setlength (result, len);   if len > 0 fillmemcall (pansichar(result), len, byte(c)); end;  begin   try     writeln (makestring ('x',10));   except     writeln ('exception!');   end; end. 

to compile fpc: [win32:] fpc.exe fpcx64example.dpr, [win64:] ppcrossx64.exe fpcx64example.dpr, [linux32:] fpc.exe -tlinux -xpi386-linux- -fd[path]\fpc\bin\i386-linux fpcx64example.dpr, [linux64:] ppcrossx64.exe -tlinux -xpx86_64-linux- -fd[fpcpath]\bin\x86_64-linux fpcx64example.dpr.

works fine delphi (win32/64). fpc, removing jmp system.@fillchar above gets rid of exception on x64.

the solution (thanks fpk):

delphi , fpc not generate stack frames functions under exact same conditions, rsp register may have different alignment in versions compiled two. solution avoid difference. 1 way of doing so, fillmemcall example above, such:

{$ifdef cpu64} {$define cpux64} {$endif} // delphi compatibility procedure fillmemcall (p: pointer; len: longword; val: byte);   {$ifdef fpc} nostackframe; {$endif} //force same fpc behaviour in delphi asm   {$ifdef cpux64}     {$ifndef fpc} .noframe {$endif} // make explicit (delphi)...     // rsp = ###0h @ site of last call instruction,     // since return address (qword) pushed onto stack call,     // must ###8h -- if nobody touched rsp.     movdqa xmm0, dqword ptr [rsp + 8] // <- testing rsp misalignment -- crash if not aligned dqword boundary   {$endif}   jmp system.@fillchar end; 

this isn't beautiful, works win/linux 32/64 both delphi , fpc.

short answer: correct way using call instruction.

long answer: x86-64 code requires stack 16 byte aligned, fillmemcall contains @ entry point compiler generated sub rsp,8 , add rsp,8 @ exit (the other 8 bytes added/remove call/ret pair). fillchar on other hand hand-coded assembler , uses nostackframe directive not contain compiler generated sub/add pair , fillchar left, stack messed because fillchar not contain add rsp,8 before ret instruction.

workarounds using nostackframe directive fillmemcall or adjusting stack before doing jmp might possible subject broken future compiler change.


Comments

Popular posts from this blog

Change php variable from jquery value using ajax (same page) -

Pull out data related to my apps from Android Play Store and iOS App Store -

How can I fetch data from a web server in an android application? -