News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Lua Assembler Host

Started by Biterider, December 24, 2023, 02:09:08 AM

Previous topic - Next topic

Biterider

Hi
Lua was primarily developed to be embedded in all kinds of applications, even in assembly language applications  :cool:

I started by translating the latest header files (currently version 5.4.6) and compiled the Lua project from the official sources into a DLL. Compiling for 32 or 64 bit was no big deal. An alternative is a static lib that can be built directly into the application. I will look at this at a later date. To simplify things, I changed the calling convention to STDCALL where possible.

As a starting point, I used the VBS host from the ObjAsm repository and made some internal changes to adapt it to the new scripting engine.

I played with the host and wrote some Lua files to see how it works. The host implements the "Output" object, which is a Lua table. It has some basic methods to handle the output of the application (bottom RichEdit of the application). In the same way, the RGB function has been defined programmatically.

The file complex.lua is an example of a module that works with ComplexArithmetic.lua.

The attachment contains all the files required to run the host. The application and the Lua DLL are 32-bit versions for those who only want to run 32-bit applications  :rolleyes:

Lua has incredible potential, is mature and has a lot of support. You can find tonnes of material on the web.

Have fun discovering it!  :thumbsup:

Biterider

jj2007

Interesting stuff, but for use with Assembly the documentation is not that helpful. I tested a simple string-to-DWORD routine:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals luaState, luaLibs, luaResult
  Init
  Dll "Lua546.dll"
  Declare LuaState, 0 Alias "_luaL_newstate@0"
  Declare LuaString2Number, C:2 Alias "_lua_stringtonumber@8"
  mov luaResult, LuaString2Number(LuaState(), "123456789")
  mov eax, [esp-100h]
  Inkey Str$("The result is %i\n", eax)
EndOfCode

It works fine, but grabbing the result from [esp-100h] is kind of exotic :cool:

Biterider

Hi jj

Quote from: jj2007 on December 24, 2023, 07:51:02 AMIt works fine, but grabbing the result from [esp-100h] is kind of exotic
Yes, because it is not intended to work this way.
After calling lua_stringtonumber  you can use lua_tonumberx to get the lua_Number from stack.

Once you get used to the Lua stack concept, it is easy to use.  :thumbsup:

Biterider

PS: you can check the sources here
https://github.com/ObjAsm/ObjAsm-C.2/tree/master/Projects/X/LuaHost
https://github.com/ObjAsm/ObjAsm-C.2/blob/master/Code/Objects/LuaHost.inc

jj2007

Quote from: Biterider on December 24, 2023, 08:14:44 AMAfter calling ]lua_stringtonumber  you can use lua_tonumberx to get the lua_Number from stack.

I'm afraid I can't get that to work :sad:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals luaState, luaLibs, luaResult, luaDouble:REAL8=1234567890.1234567890
  Init
  Cls 3
  Dll "Lua546.dll"
  Declare LuaState, 0 Alias "_luaL_newstate@0"
  Declare LuaString2Number, 2 Alias "_lua_stringtonumber@8"
  Declare Lua2Number, 3 Alias "_lua_tonumberx@12"
  mov luaState, LuaState()
  mov luaResult, LuaString2Number(luaState, "123456789")
  Print Str$("S2N #chars = %i\n", luaResult)
  mov eax, [esp-0F8h] ; works fine if applied directly after lua_stringtonumber
  Print Str$("Result A  is %i (expected: 123456789)\n", eax)
  ; ********** trouble starts here: **********
  mov eax, Lua2Number(luaState, 1, addr luaDouble) ; index 1 is the only one that has effect
  Print Str$("Result B1 is %i\n", eax)
  Inkey Str$("Result B0 is %Jf\n", luaDouble)
EndOfCode
S2N #chars = 10
Result A  is 123456789 (expected: 123456789)
Result B1 is 1
Result B0 is 1234567168.000000238

I've tried all combinations, no luck. Passing addr luaDouble sets the low DWORD to 1. Using zero has no effect on the return value.

Do you have a working example for lua_tonumberx?

Biterider

#4
Hi jj
Here an example  :biggrin:

  invoke lua_stringtonumber, xbx, $OfsCStrA("123456")
  invoke lua_tointegerx, xbx, -1, NULL
  mov dResult, eax
  DbgDec dResult

  invoke lua_stringtonumber, xbx, $OfsCStrA("123456")
  invoke lua_tonumberx, xbx, -1, NULL
  DbgFPU

Compiling for 32 bit, the result of lua_tonumberx is stored in ST(0). For 64 bit the result is in the lower half of XMM0.

The DebugCenter output looks like
dResult = 123456
FPU DUMP
FPU Levels : 1
Conditional: ST > Source
Exceptions : e s p u o z d i
  st(0) = 1.2345600E+0005

Note: The DLL of the above posted example was compiled using the switch LUA_32BITS = 1 and no symbolic information (Release).
This results in
lua_Integer equ SDWORD
lua_Number equ REAL4

Regards, Biterider

jj2007

Quote from: Biterider on December 24, 2023, 06:08:52 PMinvoke lua_tonumberx, xbx, -1, NULL

That did the trick, thanks :thumbsup:

I had tried 0, 1, 2 but I would never have guessed that minus 1 is the right index :cool:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals state, luaResult
  Init
  Dll "Lua546.dll"
  Declare LuaState, 0 Alias "_luaL_newstate@0"
  Declare LuaString2Number, 2 Alias "_lua_stringtonumber@8"
  Declare Lua2Number, 3 Alias "_lua_tonumberx@12"
  mov state, LuaState()
  mov luaResult, LuaString2Number(state, "1234567890.1234567890")
  Print Str$("S2N #chars = %i\n", luaResult)
  void Lua2Number(state, -1,0)
  Print Str$("Result Lua is %Jf\n", ST(0)v)
  MovVal ST(0), "1234567890.1234567890"
  Inkey Str$("Result Val is %Jf\n", ST(0)v)
EndOfCode

It's even reasonably accurate:
S2N #chars = 22
Result Lua is 1234567890.123456716
Result Val is 1234567890.123456789

TimoVJL

Quote4.1 – The Stack
Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value (nil, number, string, etc.). Functions in the API can access this stack through the Lua state parameter that they receive.

Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active. This stack initially contains any arguments to the C function and it is where the C function can store temporary Lua values and must push its results to be returned to the caller (see lua_CFunction).

For convenience, most query operations in the API do not follow a strict stack discipline. Instead, they can refer to any element in the stack by using an index: A positive index represents an absolute stack position (starting at 1); a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, then index 1 represents the first element (that is, the element that was pushed onto the stack first) and index n represents the last element; index -1 also represents the last element (that is, the element at the top) and index -n represents the first element.
May the source be with you

Greenhorn

Lua rocks !  :thumbsup:

SciTE uses Lua to implement Add-ins, for example.
Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

Biterider

Hi
While searching for more material, I found a pretty good Lua IDE. 
I tested the free version, which contains a lot of examples that are worth checking out.  :thumbsup:

Take a look at https://studio.zerobrane.com/

Biterider

jj2007

Quote from: Biterider on December 26, 2023, 06:03:53 AMI found a pretty good Lua IDE

Looks nice, but where are the compiled executables? I tried C:\Users\[USER]\Downloads\ZeroBraneStudio\myprograms\common-samples\demo.lua, it works fine and compiles fine but there is no exe :cool:

C:\Users\[USER]\Downloads\ZeroBraneStudio\bin\lua54.dll seems to have none of the exports of your dll, though :rolleyes:

TimoVJL

Quote from: jj2007 on December 26, 2023, 06:43:30 AMC:\Users\[USER]\Downloads\ZeroBraneStudio\bin\lua54.dll seems to have none of the exports of your dll, though :rolleyes:
undecorated exports, so what are missing ?
May the source be with you

jj2007

You are right, Timo, now I got both versions working :thumbsup:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals state, luaResult
  Init
  Cls 3
  if 1
    Dll "lua54"
    Declare LuaState, 0 Alias "luaL_newstate"
    Declare LuaString2Number, 2 Alias "lua_stringtonumber"
    Declare Lua2Number, 3 Alias "lua_tonumberx"
    Declare Lua2Number2, 2 Alias "lua_tonumber"        ; not found
  else
    Dll "Lua546"
    Declare LuaState, 0 Alias "_luaL_newstate@0"
    Declare LuaString2Number, 2 Alias "_lua_stringtonumber@8"
    Declare Lua2Number, 3 Alias "_lua_tonumberx@12"
    Declare Lua2Number2, 2 Alias "_lua_tonumber@8"
  endif
  mov state, LuaState()
  mov luaResult, LuaString2Number(state, "1234567890.1234567890")
  Print Str$("S2N #chars = %i\n", luaResult)
  void Lua2Number(state, -1,0)
  ; void Lua2Number2(state, -1)    ; no luck
  Print Str$("Result Lua is %Jf\n", ST(0)v)
  MovVal ST(0), "1234567890.1234567890"
  Inkey Str$("Result Val is %Jf\n", ST(0)v)
EndOfCode

S2N #chars = 22
Result Lua is 1234567890.123456716
Result Val is 1234567890.123456789

However, _lua_tonumber@8 is not present, neither in lua54.dll nor in lua546.dll :cool:

There is a discussion here:
QuoteLuaL_checknumber vs. lua_tonumber: How do they differ?

Apology for the lack of specificity in the question. Both attempts to convert the item on the stack to  lua_Number  . While  lua_tonumber  can also convert a string that denotes a numeric value, it is uncertain how  luaL_checknumber  handles a non-numeric input.

Additionally, there are  luaL_checklong  and  luaL_checkinteger  . Do they have similar characteristics to  (int)luaL_checknumber  and  (long)luaL_checknumber  correspondingly?
...
How do I call C++ functions from a Lua, A couple of other nits with the C code are that the numeric type really should be spelled lua_Number for portability, and that it would be conventional to use luaL_checknumber() rather than lua_tonumber() to enforce the required argument to the function.

Lua seems to be a little bit confused; Val() and MovVal() are a lot clearer, and simpler to use :cool:

Biterider

Quote from: jj2007 on December 26, 2023, 08:40:17 AMHowever, _lua_tonumber@8 is not present, neither in lua54.dll nor in lua546.dll

Lua.h defines it as follows

#define lua_tonumber(L,i)    lua_tonumberx(L,(i),NULL)
Biterider

jj2007

Quote from: Biterider on December 26, 2023, 10:11:45 AM#define lua_tonumber(L,i)    lua_tonumberx(L,(i),NULL)

So it's a macro (kind of), not directly implemented in the DLL; ok :thumbsup:

Biterider

Quote from: jj2007 on December 26, 2023, 06:43:30 AMLooks nice, but where are the compiled executables? I tried C:\Users\[USER]\Downloads\ZeroBraneStudio\myprograms\common-samples\demo.lua, it works fine and compiles fine but there is no exe
QuoteNote that the compilation doesn't produce any compiled files (like luac does), it simply checks for Lua syntax errors.
SOF
Note: compilation in this context means byte-code generation  :icon_idea:

If you are looking for an EXE from a Lua script, check this project (untested) Luastatic

Biterider