Code:
http://www.atelierweb.com/calling-64-bit-assembly-language-functions-lodged-inside-the-delphi-source-code/
http://www.codeproject.com/Articles/262819/Finally-Bit-Delphi-is-here-and-with-Bit-BASM
One thing you will notice immediately by looking at the code below is that 32-bit Assembly Language is totally different from 64-bit Assembly language. So, if you want to port 32-bit routines to 64-bit, forget about that and start new ones from scratch.
Code:
unit basmTestUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TBasmTest = class(TForm)
GroupBox1: TGroupBox;
lblCaption: TLabel;
edCaption: TEdit;
lblInput: TLabel;
edInput: TEdit;
btGo: TButton;
procedure btGoClick(Sender: TObject);
private
public
{ Public declarations }
end;
var
BasmTest: TBasmTest;
implementation
{$R *.dfm}
var
myReturnString : string = 'I am back in Delphi!';
charCount : integer;
type
bigarray = array[0..127] of char;
function assemblyTestFunction(myCaption: string; myText : string): bigarray;
{$IFDEF CPUX86}
asm
// This is the 32-bit case with the default Register (Borland Fastcall) calling convention
// where the Result is an extra var parameter.
// Arguments are passed in EAX, EDX and ECX, left to right. So, the Result (i.e, the
// return value pointer) will come to the function in ECX.
push edi
push esi
push dword ptr 0
push dword ptr myCaption
push dword ptr myText
push dword ptr 0
mov edi, ecx; // Save the return pointer to EDI because we need ECX as a counter and
// EDI is the destination pointer in a rep movsw instruction
call MessageBox
mov esi, dword ptr myReturnString
mov ecx, [charCount]
rep movsw
pop esi
pop edi
ret
end;
{$ELSE}
{$IFDEF CPUX64}
// This is the 64-bit case
// General rule: Integer and pointer arguments are passed left to right in RCX, RDX, R8
// and R9. HOWEVER, when there is a large return value, this is the case, RCX contains
// a pointer to the return space when the callee is called and all Registers usage are
// pushed one to the right
//
asm
push rsi
push rdi
push rbx
push rbp // Yes, it is a kludge. No need to push rbp, it is just to align the stack.
// The alternative is 'and rsp,-16'
sub rsp, 28h
xor r9, r9
mov rbx, rcx
mov rax, rdx
mov rdx, r8
mov r8, rax
xor rcx, rcx
call MessageBox
mov rdi, rbx
mov rsi, qword ptr myReturnString
mov ecx, [charCount]
rep movsw
add rsp, 28h
pop rbp
pop rbx
pop rdi
pop rsi
ret
end;
{$ENDIF CPUX64}
{$ENDIF}
procedure TBasmTest.btGoClick(Sender: TObject);
var
retValue : bigArray;
begin
fillchar(retValue, sizeof(bigArray),0);
charCount := length(myReturnString);
retValue := assemblyTestFunction(edCaption.Text, edInput.Text);
showMessage(retValue);
end;
Download Example: