View Full Version : Dynamic assembly machine code in thinBasic
ErosOlmi
29-02-2008, 17:11
For those loving ASM and its power, next thinBasic preview will have a modified version of CALL statement able to call dynamic assembly generated at runtime.
A big thanks to Charles Pegge from José Roca Forum (http://www.jose.it-berater.org/smfforum/index.php)
An example below. Code seems very long because it is commented but in reality it is very simple in its principle:
identify the external function
push parameter into the stack (attention to the REVERSE ORDER and to BYREF/BYVAL needs)
call function
get back value (only LONG or DWORD accepted)
:
'---------------------------------------------------------------------------
' Dynamic assembler using thinBasic CALL DWORD ... [TO ...] statement
'---------------------------------------------------------------------------
'---Reference:
'---http://developer.intel.com/design/pentiumii/manuals/243191.htm
'---------------------------------------------------------------------------
DECLARE FUNCTION LoadLibrary LIB "KERNEL32.DLL" _
ALIAS "LoadLibraryA" _
(lpLibFileName AS ASCIIZ) AS LONG
DECLARE FUNCTION GetProcAddress LIB "KERNEL32.DLL" _
ALIAS "GetProcAddress" _
(BYVAL hModule AS DWORD, lpProcName AS ASCIIZ) AS LONG
dim hLib , _ '---Used to store external Lib handle
hFun , _ '---Used to store a pointer to function
psASM as long '---Used for passing a pointer to dynamic assembly
dim sASM , _ '---Dynamic assembly string
sMessage , _ '---MessageBox message
sTitle AS string '---MessageBox title
dim RetVal as long
'---Load library and get handle
hLib = LoadLibrary("User32.dll")
'---If handle was ok
if hLib then
'---Get function pointer
hFun = GetProcAddress(hLib, "MessageBoxA")
if hFun then
sTitle = "Dynamic Assembly Demo"
sMessage = "Hello World!"
'----------------------------------------------
' Compose ASSEMBLE MACHINE CODE STRING
'----------------------------------------------
sASM = _
CHR$(&h68) + MKL$(0) + _ ' 01 push 0 for style
CHR$(&h68) + MKL$(strPTR(sTitle)) + _ ' 06 push title address
CHR$(&h68) + MKL$(strPTR(sMessage)) + _ ' 11 push message address
CHR$(&h68) + MKL$(0) + _ ' 16 push 0 for hWnd handle
CHR$(&hFF) + CHR$(&h15) + MKL$(VARPTR(hFun)) + _ ' 21 call messagebox
CHR$(&HC3) ' 27 return
'----------------------------------------------
'---Get the address of the ASM string
psASM = strPTR(sASM) ' address of code
'---Fire the direct call using dynamic asm
CALL DWORD psASM to RetVal ' make the call and get the return value
'---Show return value
msgbox 0, RetVal
end if
end if
We are still tuning it for example finding a way to avoid the CHR$ usage in the creation of the ASM string.
But so far it is working fine.
Ciao
Eros
PS:
Attached a thinCore.dll with new CALL DWORD ... statement implemented.
Any feedback appreciated.
Update:
attached file removed because new version updated
Petr Schreiber
29-02-2008, 17:54
What a hack ;D
Very nice, and pretty hardcore :D
Maybe at least header file could be done, where $PUSH, $POP ... could be defined.
O maybe BEGIN ASM stringName / END ASM blocks.
Wow, this is wild :D
Petr
Michael Hartlef
29-02-2008, 20:10
You guys are nuts. But in a positive way. I think thinBasic will be the first interpreter who support assembly. ;D
This is insane stuff. Way beyond me at the moment, but I can't believe you guys are able to get this working. Amazing thanks for showing us some really cool things.
Eros can you guys do a comparison loop to show how much faster ASM will be compared to regular fast thinBasic loop?
ErosOlmi
01-03-2008, 10:01
Kent,
this is not real ASM but the processor codes pushed/called directly as hex data.
We will not get any more speed because the interpreted time taken to make the string is huge compared to the direct function calling. Maybe we will get some ... tricks for some particular situation but nothing else as far as I can imagine now.
Also considering I'm not an ASM guru. I can just understand the basis, I've neved done anything with ASM.
Charles gave me some other ideas http://www.jose.it-berater.org/smfforum/index.php?topic=1589.msg5529#msg5529
We will see ;)
Ciao
Eros
Michael Hartlef
01-03-2008, 12:03
Well, I can see that by an assembler generated object code could be loaded into a string and then be called.
Petr Schreiber
01-03-2008, 13:56
Eros,
if I understand it correctly, is this approach identical to using inline asm in PB, just with some minor possible slowdowns caused by string building and CALL DWORDing? So no extra preprocessing done inside thinBASIC, no emulation?
Bye,
Petr
ErosOlmi
01-03-2008, 21:48
Yes, Petr. There is no extra processing in thinBasic other than Power Basic does not support CALL DWORD ... TO ... but just CALL DWORD. To get back a value in Power Basic you need CALL DWORD USING ... clause.
Regardin inline ASM, thinBasic is not able to replicate it so far due to the fact that while interpreting it destroy current stack status. I do not think I will be able to replicate something like inline ASM. But it is something I really would like to study. I was always far from ASM but recently I feel very attracted by it.
New CALL DWORD ... TO ... statement is very similar to current external function interface thinBasic has. The big difference is that enternal function interface is driven by the DECLARE statement so, when needed, thinBasic has all the info to call the external function. With CALL DWORD you can difine all the needed data at script runtime on the fly.
Ciao
Eros
Petr Schreiber
01-03-2008, 22:10
Hi Eros,
thanks for the reply! Now I get it :)
I think it should be possible, as Charles Pegge did some machine code magic in its mini R$ RPN interpreter I think.
Petr
Charles Pegge
04-03-2008, 22:34
Well yes I bear much responsibility for this madness. ;D In fact opcodes are quite easy to remember and using them is nothing compared to the challenges of programming in the Windows SDK and its innumerable libraries.
But I have been toying with the idea of developing a full dynamic assembler using the regular Intel syntax. I think it would be quite easy to provide it in modular/DLL form.
Will ThinBasic support multiline string literals? This would be the ideal form in which to feed assembler source code to such a module. - I have been studying your module interface for FreeBasic, which I think would make a versatile host language for the dynamic assembler.
Your thoughts?
ErosOlmi
04-03-2008, 22:55
Ciao Charles and welcome here.
Well, FreeBasic SDK interface for thinBasic is very rudimental compared with the one for PowerBasic but I can bring it to a similar lever.
What do you mean by "multiline string literals"?
I suppose you are referring to the syntax you suggested here: http://www.jose.it-berater.org/smfforum/index.php?topic=1589.msg5529#msg5529
sasm={
68 NL0
68 #sTitle
68 #sMessage
68 NL0
FF 15 #hFun
C3
}
thinBasic already manage multiline strings. For example the following is a valid thinBasic statement:
dim MyString as string value "this is a multiline
string up to ...
a lot of bytes"
msgbox 0, MyString
If you give me some ideas I can think to a way to parse it.
Ciao
Eros
Charles Pegge
05-03-2008, 00:05
Thanks Eros, I am delighted to be here!
That example is almost perfect. The only thing you can't do is embed inner quotes within the string.
For example " mov al,'a' ". Hence my use of curly braces to signify an envelope of data which could incorporate quote marks
dim MyString as string {
this is a multiline
_string up to ...
a lot of bytes
including quote marks
' ' " "
and further nested { .. } curly braces
}
msgbox 0, MyString
As you can see from languages that adopt C syntax, the versatile braces encompass a multitude of sins. I think you will find them useful for ThinBasic in a whole variety of ways of expressing data and language extensions.
Hwyl!
Charles
Charles Pegge
05-03-2008, 10:51
Here is a parsing function and test code written in PB. It parses string s from b and returns the boundary index e. It enables the structure to be captured in its entirety.
' PB v8.04
#COMPILE EXE
#DIM ALL
SUB pcb(s AS STRING, b AS LONG, e AS LONG)
LOCAL k,n AS LONG
LOCAL p AS BYTE PTR
p=STRPTR(s)
e=p+LEN(s)
p=p+b-1
n=0 ' nesting level
DO
IF p>=e THEN p=e: EXIT DO
k=@p ' ascii
IF k=123 THEN INCR n ' {
IF k=125 THEN DECR n: IF n<=0 THEN INCR p:EXIT DO ' }
IF (k=34)OR(k=39) THEN ' skip quotes
DO
INCR p
IF p>=e THEN EXIT DO
IF @p=k THEN EXIT DO
LOOP
END IF
INCR p
LOOP
e=p-STRPTR(s)+1
END SUB
FUNCTION PBMAIN () AS LONG
LOCAL s AS STRING
LOCAL b,e AS LONG
' test string: { {{}} "{" '{' } !!
s=" { {{ }} "+CHR$(34)+"{"+CHR$(34)+" "+CHR$(39)+"{"+CHR$(39)+" } !!"
b=1
e=LEN(s)
pcb s,b,e
MSGBOX MID$(s,b,e-b)
END FUNCTION
Petr Schreiber
05-03-2008, 12:52
Charles,
thanks for interesting ideas!
Only problem I would see with curly braces is that it is next token to parse in special way and that it is not much BASIC looking. But the functionality is perfect, thats is for sure.
Now the string you show using {} can be written too, as:
dim MyString as string = "
this is a multiline
string up to ...
a lot of bytes
including quote marks
"+CHR$(39)+" "+CHR$(39)+" "+$DQ+" "+$DQ+"
and further nested { .. } curly braces
"
msgbox 0, MyString
We will see what Eros thinks about it :),
Petr
ErosOlmi
05-03-2008, 13:24
Thanks a lot for those ideas an even for code.
I think here it is not a parsing problem, I have all the intrument in thinCore to parse whatever I can imagine.
I think the problem here is the sintax we want to apply to have the assembly string done. I'm sorry not to be an ASM person so I do not have all the knowledge to understand what it the right road. But I can implement the parsing if someone give me the rule.
For example the following code is for me a rule:
sasm= ASM
68 NL0
68 #sTitle
68 #sMessage
68 NL0
FF 15 #hFun
C3
END ASM
So ASM/END ASM give the start/end of the block. Than what's inside the block?
Every new line is an instruction. Instructions starts with an hex number (32bit code) followed by ... [here I lose my knowledge]. What do I have to expect?
If # sign if found, it will assume a variable just after. In this case it will return 4 bytes pointer to that variable
And so on.
Even if in priciple I like { ... } scoping blocks I would ike to avoid them because not in the philosophy of BASIC languages. But this is not a decision, just thinking anc confronting ideas.
I hope to have expressed my doubts.
As reference, FBSL (http://www.fbsl.net) script engine has CallAbsolute function that is something very similar to what we are talking about. See http://gedd123.free.fr/Fbsl/Help/files/callabsolute.xml
Ciao
Eros
Charles Pegge
05-03-2008, 14:56
Hi Petr and Eros,
Yes curly braces are alien to traditional Basic, but we see them in FreeBasic for assigning data to arrays. For UDT element data it uses round brackets. And arrays of UDT data would look like this:
dim as MyUDT a(1 to 4) => { (..),(..),(..),(..) }
But the curly braces are only notional. Your scheme will do the same and also patch in the variable pointers.
I would call this hexadecimal stuff machine code. Assembler, by comparison is a high level language :)
ErosOlmi
06-03-2008, 00:54
OK, I think I've got something.
I've created a new function called MC_Eval$ (stands for Machine Code Eval). An example usage:
sASM = MC_Eval$ "
68 NL0
68 #sTitle
68 #sMessage
68 NL0
FF 15 #hFun
C3
"
MC_Eval$ accept a string expression as input.
String expression is evaluated and parsed using some of the Charle suggestions done in the following post (http://www.jose.it-berater.org/smfforum/index.php?topic=1589.msg5529#msg5529). For the moment just the following rules are parsed but I will add more:
hex bytes: FF 52 5A ... or ... &Hff &H68 &H15 ...
Decimal longs: NL followed by a decimal number. Example: NL1234
Automatic variable addresses can be given using # prefix followed by the variable name.
The following variable types are handled: any numeric type, dynamic strings (STRPTR will be used), fixed strings (VARPTR is used), GUID, VARIANT, UDT (just main variable name and not UDT elements with dotted notation).
Variables will be taken from the current scoping level (function level). If not found it will be taken from the global scope level
Another limit (for the moment) is that if variable is an array, you cannot indicate element position but just the variable name. A pointer to the first element will be generated.
Here an example using the previous posting code example:
'---------------------------------------------------------------------------
' Dynamic assembler using thinBasic CALL DWORD ... [TO ...] statement
'---------------------------------------------------------------------------
'---Reference:
'---http://developer.intel.com/design/pentiumii/manuals/243191.htm
'---------------------------------------------------------------------------
DECLARE FUNCTION LoadLibrary LIB "KERNEL32.DLL" _
ALIAS "LoadLibraryA" _
(lpLibFileName AS ASCIIZ) AS LONG
DECLARE FUNCTION FreeLibrary LIB "KERNEL32.DLL" _
ALIAS "FreeLibrary" _
(BYVAL hLibModule AS DWORD) AS LONG
DECLARE FUNCTION GetProcAddress LIB "KERNEL32.DLL" _
ALIAS "GetProcAddress" _
(BYVAL hModule AS DWORD, lpProcName AS ASCIIZ) AS LONG
dim hLib , _ '---Used to store external Lib handle
hFun , _ '---Used to store a pointer to function
psASM as long '---Used for passing a pointer to dynamic assembly
dim sASM , _ '---Dynamic assembly string
sMessage , _ '---MessageBox message
sTitle AS string '---MessageBox title
dim RetVal as long
'---Load library and get handle
hLib = LoadLibrary("User32.dll")
'---If handle was ok
if hLib then
'---Get function pointer
hFun = GetProcAddress(hLib, "MessageBoxA")
if hFun then
sTitle = "Dynamic Assembly Demo"
sMessage = "Hello World!"
'----------------------------------------------
' Compose ASSEMBLE MACHINE CODE STRING
'----------------------------------------------
sASM = MC_Eval$ "
68 NL0
68 #sTitle
68 #sMessage
68 NL0
FF 15 #hFun
C3
"
'----------------------------------------------
'---Get the address of the ASM string
psASM = strPTR(sASM) ' address of code
'---Fire the direct call using dynamic asm
CALL DWORD psASM to RetVal ' make the call and get the return value
'---Show return value
msgbox 0, RetVal
end if
FreeLibrary(hLib)
end if
And below the attached new thinCore.dll (substitute the one you have in \thinBasic\ directory)
ATTENTION: not much error proof so save your work before using because it can hang your OS if wrong data is passed.
UPDATEs:
2008.03.06
Added MC_Exec(MachineCodeString) function. MC_Exec substitute CALL DWORD ... statement avoiding to have to calculate pointer to the machine code string.
In case of MC_Eval found some parsing error, no runtime errors are generated but &HC3 string will be returned
2008.03.10
Attached file removed because included in a sticky post in this forum
Let me know if all ok.
Eros
Charles Pegge
06-03-2008, 08:09
Yes that works fine Eros. You might like to try this:
'----------------------------------------------
' Compose ASSEMBLE MACHINE CODE STRING
'----------------------------------------------
sASM = MC_Eval$ "
b8 #sMessage ' load address into eax then patch the string
c7 40 06 45 72 6f 73 ' Eros
c6 40 0a 21 ' !
c6 40 0b 20 ' space
68 NL0 '
68 #sTitle '
68 #sMessage '
68 NL0 '
FF 15 #hFun '
C3
"
'----------------------------------------------
With regard to error trapping, say an undefined variable, I suggest replacing the string content with C3. to prevent GPFs.
ErosOlmi
06-03-2008, 08:55
I hate the position in which I am because I love this new stuff but I cannot understand it as I would like :-[
I definitely need to get into processors and machine code.
Thanks a lot for the new example and the suggestion about runtime errors. I'm still deciding what to do in case I find some error in parsing string: generate a script runtime error or just return C3 code ang go on. I suppose a runtime error is better because there can be important steps inside the machine code string. Will see.
I will preperare more examples other than simple MessageBox execution.
Ciao and thanks again.
Eros
PS: do you know a good place where to find info about machine codes and their usage?
A "... for dummies" introduction ;)
Charles Pegge
06-03-2008, 12:36
This is the ultimate and essential reference manual for x86 32 bit coding. It is not for dummies but it is superbly written, has excellent tables and goes into the finest iota of detail should you need it.
http://www.intel.com/design/intarch/manuals/243191.htm
Zipped below a rough extract from Appendix B which I use for quick reference.
You will find that you only use a very small subset of these.
Presumably ThinBasic already has a large number of SDK addresses for its own use. - are these accessible?
Charles Pegge
06-03-2008, 18:48
Here is another example. This one uses a loop.
' Array filled with PI
'----------------------------------------------
dim sgl(16) as single
'----------------------------------------------
sASM = MC_Eval$ "
b8 #sgl ' address to eax
b9 NL16 ' mov ecx,16 16 repeats
' do '
d9 eb ' fldpi load pi
d9 18 ' fstp [eax] store 32bit float and pop
05 NL4 ' add eax,4 next element
49 ' dec ecx
7f f4 ' jg do repeat 12 bytes back
' '
b8 NL2 ' mov eax,2 retval 2 in eax
C3
"
'----------------------------------------------
'---Get the address of the ASM string
psASM = strPTR(sASM) ' address of code
'---Fire the direct call using dynamic asm
CALL DWORD psASM to RetVal ' make the call and get the return value
'---Show return value
MsgBox 0, sgl(1)+" "+sgl(16)
Petr Schreiber
06-03-2008, 20:14
Hi Charles,
pure magic with that PI :)
Thanks,
Petr
ErosOlmi
06-03-2008, 23:02
Pure magic for sure. Try to substitute 16 with 16 millions
' Array filled with PI
'----------------------------------------------
dim sgl(16000000) as single
'----------------------------------------------
sASM = MC_Eval$ "
b8 #sgl ' address to eax
b9 NL16000000 ' mov ecx,16 16 repeats
' do '
d9 eb ' fldpi load pi
d9 18 ' fstp [eax] store 32bit float and pop
05 NL4 ' add eax,4 next element
49 ' dec ecx
7f f4 ' jg do repeat 12 bytes back
' '
b8 NL2 ' mov eax,2 retval 2 in eax
C3
"
'----------------------------------------------
'---Get the address of the ASM string
psASM = strPTR(sASM) ' address of code
'---Fire the direct call using dynamic asm
CALL DWORD psASM to RetVal ' make the call and get the return value
'---Show return value
MsgBox 0, sgl(1)+" "+sgl(16000000)
Speed is ... inconsistent.
ErosOlmi
07-03-2008, 00:23
Updated thinCore.dll. New DLL is attached to the following post http://community.thinbasic.com/index.php?topic=1561.msg11307#msg11307
Just download and substitute thinCore.dll you have into \thinBasic\ directory.
Added MC_Exec(StringMachineCode) function in substitution to CALL DWORD ...
With MC_Exec there is no need to calculate pointer to string to be passed to CALL DWORD ... statement. Just pass the machine code string and you will get back return LONG.
So previous code can be rewritte to:
' Array filled with PI
'----------------------------------------------
dim sgl(16) as single
'----------------------------------------------
sASM = MC_Eval "
b8 #sgl ' address to eax
b9 NL16 ' mov ecx,16 16 repeats
' do '
d9 eb ' fldpi load pi
d9 18 ' fstp [eax] store 32bit float and pop
05 NL4 ' add eax,4 next element
49 ' dec ecx
7f f4 ' jg do repeat 12 bytes back
' '
b8 NL2 ' mov eax,2 retval 2 in eax
C3
"
'----------------------------------------------
'---Invoke the machine code string
RetVal = MC_Exec(sASM)
'---No need to calculate STRPTR(sASM) to be used into CALL DWORD ...
'----------------------------------------------
'---Show return value
MsgBox 0, RetVal & $crlf & sgl(1)+" "+sgl(16)
As usual, update will be present in next preview release.
Ciao
Eros
Charles Pegge
07-03-2008, 00:32
Yes, Ive just tested out to 160million, it is the operating system, memory management and various other processes that are able to interrupt the procedings. These will inevitably cause irregular timings. But if the script is run several times, it settles to a fairly stable figure. - about 0.625 seconds for 160 million elements on my PC.
When the FPU instructions are removed (not forgetting to adjust the loop jump), the time drops to 0.115 secs. The FPU is thorough but slow as you will see with trig functions. In fact you can do a lot of useful work on the CPU while the FPU is thinking about the next cosine, so even at the single core level timing is not entirely predictable. Even individual CPU registers can compute in parallel.
PS thanks for the Exec function!
ErosOlmi
07-03-2008, 01:09
A pleasure Charles.
I've updated again thinCore.dll here: http://community.thinbasic.com/index.php?topic=1561.msg11307#msg11307
In case of MC_Eval found some parsing error, no runtime errors are generated but &HC3 string will be returned as suggested.
If machine string will be equal to &HC3, MC_Exec will not get back any value but just zero will be returned.
Petr Schreiber
07-03-2008, 09:41
Thanks for improvements Eros,
sadly ( or luckily ? ) I could not get any inconsistent results, just lightning fast execution on high numbers of iterations.
Bye,
Petr
Michael Clease
07-03-2008, 16:12
I may have missed it but can you modify the string while the script is executing then call it get the value back modify it again and call it....you get the idea is it fixed as soon as the script is executed.
ErosOlmi
07-03-2008, 16:51
Abraxas, is it a question?
Sorry I do not understand if you are asking a confirmation or not.
If it is aquestion, yes. You can change (or create) the string dynamically outside MC_Eval.
Then call MC_Eval to get back a binary form of the string.
Than call MC_Exec
Eros
Michael Clease
07-03-2008, 17:17
yes it was a question, just badly worded :D
you answer it it anyway and it was the answer I wanted.
thanks
Charles Pegge
07-03-2008, 17:47
The ThinAir IDE, I find is a very congenial environment for creating these opcodes. You can test it as you write, often instruction by instruction. And the GPFs have not been disruptive (so far!). This example calculates the resultant on 10 million xyz vectors, which takes about 0.23 seconds on my PC - about 40 million vectors per second.
'----------------------------------------------
' Pythagoras
'----------------------------------------------
type vec3
x as single
y as single
z as single
end type
dim vv(10000000) as vec3 ' source vectore
dim py(10000000) as single ' pythagoras result
vv(1).x=3:vv(1).y=4:vv(1).z=0 ' initial value to be copied throughout
dim t as single = 0 ' for timer
'----------------------------------------------
' Quick fill vectors to initialise
'----------------------------------------------
dim sFill as string = MC_Eval$ "
53 ' push ebx
bb #vv '
ba #vv '
b9 NL10000000 ' ecx for downcount
'do '
8b 03 ' mov eax,[ebx]
89 02 ' mov [edx],eax
8b 43 04 ' mov eax [ebx+04]
89 42 04 ' mov [edx+04],eax
8b 43 08 ' mov eax,[ebx+08]
89 42 08 ' mov [edx+08],eax
81 c2 #NL12 ' add edx,12
7f e7 ' 25 bytes back
b8 #NL1 ' retval
5b ' pop ebp
c3
"
'----------------------------------------------
' Pythagoras
' calculates sqr(x^2+y^2+z^2) for all vectors
'----------------------------------------------
dim sPyth as string = MC_Eval$ "
b8 #vv ' eax source address
b9 NL10000000 ' ecx 1e7 repeats
ba #py ' edx dest address
' do
d9 00 ' fld [eax]
d8 c8 ' fmul st(0),st(0)
05 NL4 ' add eax,4
d9 00 ' fld [eax]
d8 c8 ' fmul st(0),st(0)
05 NL4 ' add eax,4
d9 00 ' fld [eax]
d8 c8 ' fmul st(0),st(0)
05 NL4 ' add eax,4
de c1 ' faddp st(1),st(0)
de c1 ' faddp st(1),st(0)
d9 fa ' fsqrt
d9 1a ' fstp [edx] store 32bit float and pop
81 c2 NL4 ' add edx,4 next dest element
49 ' dec ecx
7f d4 ' jg repeat 44 bytes back
' '
b8 NL2 ' retval 2
C3
"
'----------------------------------------------
'---Invoke the machine code string
RetVal = MC_Exec(sFill) ' fill vector array
t=timer
RetVal = MC_Exec(sPyth)
MsgBox 0, len(sPyth)+$crlf+vv(1).x+$crlf+py(1)+$crlf+str$(timer-t)
'----------------------------------------------
RobertoBianchi
07-03-2008, 18:36
Charles,
I you want you can use ThinAIR also with assembler source file, I never tried to use it directly with an assembler like MASM, NASM or FASM but with some adjustment it should work.
Ciao,
Roberto
Charles Pegge
07-03-2008, 19:09
Thank you Roberto. I must try it with the 'AS' assembler that is used by FreeBasic. This is the same GNU 'GAS' assembler that works at the back end of the GCC compiler and is primarily intended to take assembler input from high level languages, but it's friendly enough to use on its own.
If you ever wanted to create a cross-platform ThinBasic compiler, this is an easy infrastructure to use.
http://www.jose.it-berater.org/smfforum/index.php?topic=1579.0
Petr Schreiber
07-03-2008, 19:17
Hi Charles,
again fantastic example! Interesting we get the same execution time :)
I agree, thinAir is my favourite IDE now, I like it a lot.
When the GPFs will be gone it will be unbeatable.
For timing tests, I think better is to use GetTickCount or HiResTimer_Init=>HiResTimer_Get, as they provide perfect precision.
Bye,
Petr
Charles Pegge
07-03-2008, 19:52
Hi Petr,
I hasten to add that the GPFs were of my own making due to op code errors or jumping to the wrong place. Machine code is not subtle in indicating that an error has occured. ThinAir is the innocent party.
With regard to timing, I have found one gets more consistent results by doing a long test. This is almost certainly due to OS interrupts which interfere with short term timings and give an unstable reading.
I am also too lazy to set up a high precision test :)
Michael Clease
07-03-2008, 23:00
Charles I think the GPF's Petr is talking about are caused by thinair not your script but they are being investigated.
Here is somemore information about asm commands and their codes, I know its quite old but it has alot of useful stuf.
thanks
Charles Pegge
07-03-2008, 23:51
Thanks! That covers the 386 instruction set, but not the 486 floating point and above. What would be really useful would be a reference in html form that would give rapid access to opcode information and code samples. The Intel manual is thorough but quite ponderous to use when you need a quick answer during coding. I have not come across anything like that yet.
ErosOlmi
08-03-2008, 09:58
What about this one: http://jsimlo.sk/docs/cpu/index.php/
ErosOlmi
08-03-2008, 10:06
Post moved to forum dedicated to machine code in thinBasic.
Michael Clease
08-03-2008, 10:30
Charles is this better?
Petr Schreiber
08-03-2008, 10:56
Hi Abraxas,
very nice program!
And you are right, I was refering to some occasional GPFs of thinAir itself.
Bye,
Petr
Charles Pegge
08-03-2008, 11:16
Thank you both, they are useful quick references to have around. OpCodes2 has the more specialised SIMD and 3DNOW instructions should we need them.
Petr Schreiber
08-03-2008, 17:03
Charles,
is there any way to determine whether CPU can run for example SSE instructions.
With high performance code in strings, we could test on script startup whether MMX or SSE is supported and then assign apropriate values ( once ) to the machine code variable. So kind of JIT script optimization :)
Petr
Charles Pegge
08-03-2008, 18:31
Yes Petr, the magic instruction is CPUID (0F A2) which will give chapter and verse on the CPU. The manual goes into great detail from page 3-111. I'll have to study it, and find out what codings AMD and VIA use on their chips, in addition to the standard codings.
http://developer.intel.com/design/pentiumii/manuals/243191.htm