Hi,
Update available on the site and Git.
Changes:
1) (Just for AW27 ;) ) Added Delphi 32bit fastcall as a language type, so you can use PROC DELPHI etc..
2) Improved linux System V invoke.
3) Renamed some OO stuff in the macro library to avoid conflicts (documentation updated)
4) Added a new option for OPTION PROC: .. it can now take the following:
OPTION PROC:NONE
OPTION PROC:DEFAULT
OPTION PROC:MyPrologue,MyEpilogue
Which do what you'd expect, the first two are just short-hands to switch off/on the prologue epilogue via option prologue, option epilogue and same goes for the 3rd form which just allows you to specify both macros in one go.
Cheers,
John
Quote from: johnsa on April 21, 2017, 10:39:37 PM
1) (Just for AW27 ;) ) Added Delphi 32bit fastcall as a language type, so you can use PROC DELPHI etc..
That is very nice! :t
I found an important small problem, registers edx and ecx are swapped.
.686
.XMM
.MODEL FLAT, DELPHI
option casemap:none
.code
proc1 proc public Val1:dword, Val2:dword, Val3:dword, Val4:dword
mov eax, Val1
add eax, Val2
add eax, Val3
add eax, Val4
ret
proc1 endp
end
COMMENT ?
procedure TForm4.btGoClick(Sender: TObject);
var
retValue : integer;
begin
retValue:=proc1(2,3,4,5);
end;
testDelphiCall.pas.36: retValue:=proc1(2,3,4,5);
005CBC18 6A05 push $05
005CBC1A B904000000 mov ecx,$00000004
005CBC1F BA03000000 mov edx,$00000003
005CBC24 B802000000 mov eax,$00000002
005CBC29 E812000000 call proc1
proc1:
005CBC40 55 push ebp
005CBC41 8BEC mov ebp,esp
005CBC43 8BC0 mov eax,eax
005CBC45 03C1 add eax,ecx ; should be add eax, edx
005CBC47 03C2 add eax,edx ; should be add eax, ecx
005CBC49 034508 add eax,[ebp+$08]
005CBC4C 5D pop ebp
005CBC4D C3 ret
?
Will fix/update shortly ! :)
Packages and git updated, please try again.
Thanks!
John
Perfect for my sources, John :t
Speed has increased a bit, especially for the 64-bit version, which is now only 10% slower than AsmC.
If I had one wish free, it would be a console print flush after each module of a library has finished. Both ML 6.15 and AsmC do it that way - kind of a progress indicator. HJWasm starts assembling and remains silent for two seconds, then suddenly throws out all results in one go. Probably just a matter of taste, though.
"Under the register convention, up to three parameters are passed in CPU registers, and the rest (if any) are passed on the stack. The parameters are passed in order of declaration (as with the pascal convention), and the first three parameters that qualify are passed in the EAX, EDX, and ECX registers, in that order. Real, method-pointer, variant, Int64, and structured types do not qualify as register parameters, but all other parameters do. If more than three parameters qualify as register parameters, the first three are passed in EAX, EDX, and ECX, and the remaining parameters are pushed onto the stack in order of declaration."
So, when I have a function in Delphi declared like this:
function proc2(val1:single; val2:integer; val3:integer; val4:integer):single; register; external;
As is now, in ASM I would have to declare it like this:
proc2 proc public Val2:dword, Val3:dword, Val4:dword, Val1:real4
and not like this:
proc2 proc public Val1:real4, Val2:dword, Val3:dword, Val4:dword
because the compiler does not see Val1 does not qualify to come in a register.
On it :)
Quote from: jj2007 on April 22, 2017, 01:57:13 AM
Perfect for my sources, John :t
Speed has increased a bit, especially for the 64-bit version, which is now only 10% slower than AsmC.
If I had one wish free, it would be a console print flush after each module of a library has finished. Both ML 6.15 and AsmC do it that way - kind of a progress indicator. HJWasm starts assembling and remains silent for two seconds, then suddenly throws out all results in one go. Probably just a matter of taste, though.
So we should flush output after each processed file, IE: on returning from an included source file, flush any console output relating to that file then continue ?
deleted
Quote from: johnsa on April 22, 2017, 04:54:07 AMSo we should flush output after each processed file, IE: on returning from an included source file, flush any console output relating to that file then continue ?
Yes, that is the idea. Not relevant for single file assembly, but when you have 30 modules, it just flows better. Switching the behaviour with a commandline option (-flush) would be fine, too. Don't invest real time, though, it's really minor cosmetics ;-)
Here is a simple example with DELPHI, tell me where is somthing wrong:
Quote
.386
.model flat,DELPHI
option casemap:none
.data
myreal REAL4 1.2
source db 'delphi is crappy',0
.data?
destiny db 64 dup(0)
.code
CopyString PROC public USES ebx cnt:DWORD,dest:DWORD,src:DWORD,num:DWORD
mov ebx,num
@@:
movzx ebx,BYTE PTR [ecx+eax]
mov BYTE PTR [edx+eax],bl
sub eax,1
jns @b
ret
CopyString ENDP
proc2 proc public Val1:real4, Val2:real4, Val3:dword, Val4:dword
mov eax, Val1
add eax, Val2
add eax, Val3
add eax, Val4
ret
proc2 endp
WinMainCRTStartup proc uses EBX
local bob:DWORD
invoke proc2 ,myreal, 1.2, 3, 4
mov bob,15
invoke CopyString,bob,OFFSET destiny,OFFSET source,bob
ret
WinMainCRTStartup endp
END
1: .386
2: .model flat,DELPHI
3: option casemap:none
4:
5: .data
6: myreal REAL4 1.2
7: source db 'delphi is crappy',0
8: .data?
9: destiny db 64 dup(0)
10: .code
11:
12: CopyString PROC public USES ebx cnt:DWORD,dest:DWORD,src:DWORD,num:DWORD
00ED1024 55 push ebp
00ED1025 8B EC mov ebp,esp
00ED1027 53 push ebx
13: mov ebx,num
00ED1028 8B 5D 08 mov ebx,dword ptr [num]
14: @@:
15: movzx ebx,BYTE PTR [ecx+eax]
00ED102B 0F B6 1C 08 movzx ebx,byte ptr [eax+ecx]
16: mov BYTE PTR [edx+eax],bl
00ED102F 88 1C 10 mov byte ptr [eax+edx],bl
17: sub eax,1
00ED1032 83 E8 01 sub eax,1
18: jns @b
00ED1035 79 F4 jns CopyString+7h (0ED102Bh)
19: ret
00ED1037 5B pop ebx
00ED1038 C9 leave
00ED1039 C3 ret
20: CopyString ENDP
21:
22: proc2 proc public Val1:real4, Val2:real4, Val3:dword, Val4:dword
00ED103A 55 push ebp
00ED103B 8B EC mov ebp,esp
23: mov eax, Val1
00ED103D 8B C0 mov eax,eax
24: add eax, Val2
00ED103F 03 C2 add eax,edx
25: add eax, Val3
00ED1041 03 C1 add eax,ecx
26: add eax, Val4
00ED1043 03 45 08 add eax,dword ptr [Val4]
27: ret
00ED1046 C9 leave
00ED1047 C3 ret
28: proc2 endp
29:
30: WinMainCRTStartup proc uses EBX
00ED1048 55 push ebp
00ED1049 8B EC mov ebp,esp
00ED104B 83 EC 04 sub esp,4
00ED104E 53 push ebx
31: local bob:DWORD
32: invoke proc2 ,myreal, 1.2, 3, 4
00ED104F A1 00 40 ED 00 mov eax,dword ptr ds:[00ED4000h]
00ED1054 BA 9A 99 99 3F mov edx,3F99999Ah
00ED1059 B9 03 00 00 00 mov ecx,3
00ED105E 6A 04 push 4
00ED1060 E8 D5 FF FF FF call proc2 (0ED103Ah)
33: mov bob,15
00ED1065 C7 45 FC 0F 00 00 00 mov dword ptr [bob],0Fh
34: invoke CopyString,bob,OFFSET destiny,OFFSET source,bob
00ED106C 8B 45 FC mov eax,dword ptr [bob]
00ED106F BA 14 41 ED 00 mov edx,0ED4114h
00ED1074 B9 04 40 ED 00 mov ecx,0ED4004h
00ED1079 FF 75 FC push dword ptr [bob]
34: invoke CopyString,bob,OFFSET destiny,OFFSET source,bob
00ED107C E8 A3 FF FF FF call CopyString (0ED1024h)
35: ret
00ED1081 5B pop ebx
00ED1082 C9 leave
00ED1083 C3 ret
Quote from: habran on April 22, 2017, 06:14:07 AM
Here is a simple example with DELPHI, tell me where is somthing wrong:
It is wrong, Delphi calls like this:
push dword ptr [ebp-$10] ; in your demo change to "push dword ptr [00ED4000h]"
push $3f99999a
mov edx,$00000004
mov eax,$00000003
call proc2
Your code wants to send reals in CPU registers. In CPU registers you can only send dwords, words, bytes, or their signed equivalents and
pointers (except pointers to class methods (functions), called method pointers).
Most of the other data types default to be sent by reference - so you receive a pointer to them, which can be placed in a CPU register as well. However, reals and big integers (int64, uint64) are always pushed on the stack (unless you force them to be sent them by reference).
So watch for reals and big integers and you shall be good.
Quote from: aw27 on April 22, 2017, 03:35:18 PMIn CPU registers you can only send dwords, words, bytes, or their signed equivalents and pointers
This is assembler, not C 8)
include \Masm32\MasmBasic\Res\JBasic.inc ; ## console demo, builds in 32- or 64-bit mode with ML, AsmC, JWasm, HJWasm ##
.code
usedeb=1
MyInt DQ 1234567812345678
MyR4 REAL4 1234.567
MyR8 REAL8 123456789.123456789
Demo proc <cb> arg1:REAL4, arg2:REAL8, arg3:QWORD
deb 4, "received:", arg1, arg2, arg3
ret
Demo endp
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
jinvoke Demo, MyR4, MyR8, MyInt
mov eax, MyR4
mov rdx, MyR8
mov rcx, MyInt
jinvoke Demo, eax, rdx, rcx
Inkey "OK?"
EndOfCode
Output:
This code was assembled with ml64 in 64-bit format
received:
arg1 1234.567016602
arg2 123456789.123456790
arg3 1234567812345678
received:
arg1 1234.567016602
arg2 123456789.123456790
arg3 1234567812345678
Quote from: jj2007 on April 22, 2017, 06:18:37 PM
Quote from: aw27 on April 22, 2017, 03:35:18 PMIn CPU registers you can only send dwords, words, bytes, or their signed equivalents and pointers
This is assembler, not C 8)
include \Masm32\MasmBasic\Res\JBasic.inc ; ## console demo, builds in 32- or 64-bit mode with ML, AsmC, JWasm, HJWasm ##
.code
usedeb=1
MyInt DQ 1234567812345678
MyR4 REAL4 1234.567
MyR8 REAL8 123456789.123456789
Demo proc <cb> arg1:REAL4, arg2:REAL8, arg3:QWORD
deb 4, "received:", arg1, arg2, arg3
ret
Demo endp
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
jinvoke Demo, MyR4, MyR8, MyInt
mov eax, MyR4
mov rdx, MyR8
mov rcx, MyInt
jinvoke Demo, eax, rdx, rcx
Inkey "OK?"
EndOfCode
Output:This code was assembled with ml64 in 64-bit format
received:
arg1 1234.567016602
arg2 123456789.123456790
arg3 1234567812345678
received:
arg1 1234.567016602
arg2 123456789.123456790
arg3 1234567812345678
I know, what I mean is that in the Delphi API they are not sent.
I don't remember any API (Intel chips) that sends or receives floats in general purpose registers, but my memory fails many times.
Thanks JJ for support :biggrin:
aw27, this looks perfectly legal and natural as well as faster then pushing on the stack:
Quote
32: invoke proc2 ,myreal, 1.2, 3, 4
00ED104F A1 00 40 ED 00 mov eax,dword ptr ds:[00ED4000h]
00ED1054 BA 9A 99 99 3F mov edx,3F99999Ah
00ED1059 B9 03 00 00 00 mov ecx,3
00ED105E 6A 04 push 4
00ED1060 E8 D5 FF FF FF call proc2 (0ED103Ah)
however, if you insist we can make it the way as it is done in embarcadero delphi, even though that will require much more work.
It'll also require some more time to be done.
Quote from: habran on April 22, 2017, 09:43:54 PM
aw27, this looks perfectly legal and natural as well as faster then pushing on the stack:
I can't call it like that from Delphi.
PS: I have survived without it, but I think it would be a nice addition and no other assembler has it. There are many Delphi fanatics out there that know assembly language as well.
deleted
I start study macros from Irvin's book, so found some fresh bugs 8) in macro system:
Simple code:
row = -1
REPT 8
row = row SHR 4
%ECHO row = @CatStr(%row)
ENDM
MASM Output:
row = 268435455
row = 16777215
row = 1048575
row = 65535
row = 4095
row = 255
row = 15
row = 0
HJWASM(HJWasm v2.25) Output:
row = 4294967295
row = 4294967295
row = 4294967295
row = 4294967295
row = 4294967295
row = 4294967295
row = 4294967295
row = 4294967295
This is x86 code, but hjwasm think 'row' is qword?
Another thing, I think you should not call it DELPHI calling convention because it is also the default calling convention for Lazarus/Free Pascal.
It's real name is Borland Register or Borland Fastcall calling convention, the guys at Embarcadero are simply boasting they invented a wheel already invented (something other guys do as well).
deleted
Quote from: aw27 on April 23, 2017, 02:44:10 AMIt's real name is Borland Register or Borland Fastcall calling convention
Don't forget you can write a PROLOG macro. If you give me a concise and comprehensible description of what exactly Delphi & Pascal pass to the DLL or object file, I can give it a try. Really, exotic stuff like that doesn't have to be hardcoded into HJWasm.
nidud :t
jj here (http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Program_Control#Register_Convention) is all info you need
If you succeed to make macros that work we can put them in macrolib.c :biggrin:
Quote from: jj2007 on April 23, 2017, 07:53:38 AM
Really, exotic stuff like that doesn't have to be hardcoded into HJWasm.
It is not exotic,
hundreds of famous software were and are being developed in PASCAL language. (https://jonlennartaasenden.wordpress.com/2014/11/06/famous-software-made-with-delphi/)
Quote from: aw27 on April 23, 2017, 04:06:07 PM
It is not exotic, hundreds of famous software were and are being developed in PASCAL language. (https://jonlennartaasenden.wordpress.com/2014/11/06/famous-software-made-with-delphi/)
And Skype on top of the list of Famous Delphi titles! Well, rank #2 after Nero. Reminds me of the claims of the QT freaks:
What programming language was Skype originally written in? (https://www.quora.com/What-programming-language-was-Skype-originally-written-in)
QuoteThe original internal alpha version of UI was built in QT and we hoped to do few platforms at same take. However the result looked like crap, our progress seemed slow and we ditched the QT about 2 months before public beta release.
:lol:
Btw I like Pascal. My former favourite Basic dialect, Gfa, which inspired MasmBasic, was a mix of traditional BASIC and PASCAL elements. Much ahead of other dialects when it came out in 1987 or so.
Really, serving the Delphi community can be done with a simple PROLOG. Some years ago I managed to convince VBA to accept my code as a DLL - that was tough ::)
Quote from: jj2007 on April 23, 2017, 06:03:31 PM
And Skype on top of the list of Famous Delphi titles!
Since Microsoft acquired it, it is not being developed anymore in Delphi. Yes, you can see the end result.
Quote
The original internal alpha version of UI was built in QT
QT is too much bloated to develop anything with a good future.
I have split the topic so that the technical data on this release of HJWASM is not confused with the following discussion on licencing.
; Start studying 'VARARG' with HJWasm v2.25. ::)
_ShowMessageBox proc lpBuffer:QWORD, par1:DWORD, par2:DWORD,par3:DWORD
LOCAL tmpBuff[1024]:byte
invoke wsprintf,addr tmpBuff, lpBuffer,par1,par2,par3
invoke MessageBox,0,addr tmpBuff,"Info",MB_OK
ret
_ShowMessageBox endp
_ShowMessageBox2 proc lpBuffer:QWORD, vargs:VARARG
LOCAL tmpBuff[1024]:byte
invoke wvsprintf,addr tmpBuff, lpBuffer,addr vargs
invoke MessageBox,0,addr tmpBuff,"Info",MB_OK
ret
_ShowMessageBox2 endp
start proc
mov rbx,11223344h
mov rdx,55555555h
invoke _ShowMessageBox,"arg1=%08lX arg2=%04lX arg3=%02lX",edx,ebx,ebx
mov rdx,55555555h
invoke _ShowMessageBox2,"arg1=%08lX arg2=%04lX arg3=%02lX",edx,ebx,ebx ; Error A2165: Register value overwritten by INVOKE
invoke ExitProcess,0
start endp
end start
I don't insert 'FRAME' in the begining of proc's, anymore. 8)
Quote from: aw27 on April 23, 2017, 02:44:10 AM
Another thing, I think you should not call it DELPHI calling convention because it is also the default calling convention for Lazarus/Free Pascal.
It's real name is Borland Register or Borland Fastcall calling convention, the guys at Embarcadero are simply boasting they invented a wheel already invented (something other guys do as well).
We're going to re-name this while working on the fixes, should we just call it BORLAND instead?
Quote from: johnsa on April 24, 2017, 07:56:39 PM
We're going to re-name this while working on the fixes, should we just call it BORLAND instead?
Looks better for me :t