├── .gitignore ├── LICENSE ├── README.md ├── build_gcc.sh ├── build_msvc.bat ├── build_tcc.bat ├── build_tcc.sh ├── example ├── ads1263.lua ├── ads1263.md ├── gl.lua ├── glfw.lua ├── gpib.lua ├── hello_glfw.lua ├── hp3458a.lua ├── hp3458a.md ├── mpsse.lua ├── readme.md ├── serial.lua ├── serial.md ├── spi.lua └── tcads.lua ├── lib ├── lauxlib.h ├── lua.h ├── lua54.def ├── lua54.lib ├── luaconf.h ├── lualib.h └── msvcrt.lib ├── src ├── asm_x64.h ├── call_sysV64.s ├── call_win64.asm ├── call_win64.s ├── ffi.c ├── sysV64.c ├── userdata.c └── win64.c ├── test.lua └── uffi.vcxproj /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs 2 | /uffi.vcxproj.user 3 | /uffi.sln 4 | /x64 5 | /*.dll 6 | /*.so 7 | /*.def 8 | /*.obj 9 | /*.lib 10 | /*.exp 11 | /*.exe 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uFFI 2 | FFI for Lua, https://habr.com/ru/articles/746658/ 3 | # Build 4 | Corresponding build_ .bat/.sh files 5 | # Usage 6 | ```Lua 7 | local ffi = require "ffi" 8 | ``` 9 | ## Load 10 | ### Single function 11 | ```Lua 12 | local msg = ffi("user32", "MessageBoxA") 13 | msg(0, "Text", "Caption", 1) 14 | ``` 15 | ### Global variable 16 | ```Lua 17 | local err = ffi("gpib", "user_iberr", 4) 18 | print(err:int()) 19 | ``` 20 | With number as [type](https://github.com/pavel212/uffi#types) (3rd argument) ffi creates and returns [userdata](https://github.com/pavel212/uffi#userdata) of the given size, pointing to library symbol 21 | ### List of functions 22 | ```Lua 23 | local gl = ffi("opengl32", {"glClearColor", "glClear", "glViewport"}) 24 | gl.glViewport(0, 0, 640, 480) 25 | ``` 26 | ### All functions from library 27 | ```Lua 28 | for k,v in pairs(ffi("glfw3", "*")) do _G[k] = v end 29 | glfwInit() 30 | ``` 31 | or 32 | ```Lua 33 | local glfw = {} 34 | for k,v in pairs(ffi("glfw3", "*")) do glfw[k:match("^glfw(.+)") or k] = v end 35 | glfw.Init() 36 | ``` 37 | ### Lazy load 38 | If only library name provided, ffi returns empty table with '__index' metamethod that loads functions at the moment when it is called for the first time (indexed). 39 | ```Lua 40 | local std = ffi("msvcrt") 41 | std.puts("Hello msvcrt") 42 | ``` 43 | #### List of libraries 44 | ```Lua 45 | libs = ffi({"msvcrt", "kernel32", "user32"}) 46 | libs.MessageBoxA(0, "Text", "Caption", 1) 47 | ``` 48 | ### OpenGL extensions example 49 | Adds wglGetProcAddress to gl = ffi("opengl32") functionality, and removes 'gl' prefix. 50 | ```Lua 51 | local gl = {} 52 | gl.GetProcAddress = ffi("opengl32", "wglGetProcAddress") 53 | local mt = getmetatable(gl) or {} 54 | function mt.__index(t, k) 55 | t[k] = ffi("opengl32", "gl"..k) or ffi(t.GetProcAddress("gl"..k)) or getmetatable(t).__lib_error(t, "gl"..k) 56 | return t[k] 57 | end 58 | function mt.__lib_error(t, k) 59 | error("Unable to load '"..k.."' from opengl32.dll or wglGetProcAddress") 60 | end 61 | setmetatable(gl, mt) 62 | 63 | gl.ShaderSource(id, 2, {"shder source code", "more shader source code"}, 0) 64 | ``` 65 | ## Types 66 | ### Specified 67 | As additional string, one character per argument, first - return value type 68 | ```Lua 69 | local cosf = ffi("msvcrt.dll", "cosf", "ff") 70 | print( cosf(math.pi / 3), math.cos(math.pi / 3) ) 71 | ``` 72 | * 'v' - void 73 | * 'i' - integer 74 | * 'f' - float 75 | * 'd' - double 76 | * 'b' - boolean 77 | * 'p' - pointer 78 | * 's' - string 79 | * ~~'t' - table~~ 80 | * ~~'l' - use Lua type of argument~~ 81 | 82 | Structures that are larger than 8 bytes should be passed to Cfunction as pointer(userdata) or string, <= 8 bytes must be packed in integer. 83 | ### Automatic 84 | When not specified, use Lua type of argument, but there are no single preision floats in Lua, only double. 85 | ```Lua 86 | local cosf = ffi("msvcrt.dll", "cosf") 87 | print( ffi.float( cosf( ffi.float(math.pi / 3) ) ) ) 88 | ``` 89 | * ffi.float(x) - convert function argument to float for Cfunction 90 | * ffi.float(cfunc(x)) - convert float result of Cfunction without specified type to lua_Number 91 | * ffi.double(cfunc(x)) - convert double result of Cfunction without specified type to lua_Number 92 | * ffi.int(cfunc(x)[, len]) - convert integer result of Cfunction without specified type to lua_Integer (default, omit) 93 | * ffi.bool(cfunc(x)[, len]) - convert integer result of Cfunction without specified type to boolean 94 | * ffi.string(cfunc(x)[, len]) - convert integer result (char * pointer) of Cfunction without specified type to string, 'len' bytes or until '\0' 95 | * ffi.pointer(cfunc(x)) - convert integer result of Cfunction without specified type to lightuserdata 96 | ## Callback 97 | When Lua function passed to ffi(lua_func, type_string) it is converted to callback and then could be passed as function pointer to C function. 98 | type_string must be present, no automatic type conversion for callbacks! 99 | ```Lua 100 | local GLFW = {KEY_ESCAPE = 256, PRESS = 1, RELEASE = 0, TRUE = 1, FALSE = 0} 101 | 102 | local function key_callback(window, key, scancode, action, mods) 103 | -- print(key,scancode,action) 104 | if (key == GLFW.KEY_ESCAPE and action == GLFW.PRESS) then 105 | glfw.SetWindowShouldClose(window, GLFW.TRUE) 106 | end 107 | end 108 | 109 | --typedef void(* GLFWkeyfun) (GLFWwindow *, int, int, int, int) 110 | key_callback = ffi(key_callback, "vpiiii") 111 | 112 | glfw.SetKeyCallback(window, key_callback); 113 | ``` 114 | ## Userdata 115 | 116 | * x = ffi.userdata(N) - allocates N bytes, to pass 'x' as pointer to C functions. 117 | * x:type(t) - sets type (function x:int, x:float, ...) for indexing userdata as array with [], not set by default 118 | * x:size(s) - sets size for indexing integer userdata as array with [], not set by default. 119 | * x[pos] - indexing of userdata as array of type which is set by x:type, 0-based. 120 | * x = ffi.userdata("qwerty") - allocates strlen + 1 bytes, and copies string data with '\0'. 121 | * x = ffi.userdata({"first string", "second string"}) - allocates array of char * pointers and then for each allocate and copy corresponding string with '\0', to pass x as char ** to C function. 122 | * x = ffi.userdata(N,K,M) - allocates NxKxM bytes, to pass 'x' as char * to C functions ~~indexing of multidimensional arrays as x[n][k][m]~~ 123 | * x = ffi.userdata({N,K,M}) - allocates two dimensional array with 3 elements, N, K, M bytes each, to pass 'x' as char ** pointer to C functions, nested tables for char ****... 124 | * x:int([value][,offset][, len]) - "dereference" userdata with offset*len byte offset and convert to signed integer, len = 1..8, default - length of userdata or 8, x:int(nil, offset, len) to read with offset. 125 | * x:uint([value][, offset][, len]) - "dereference" userdata and convert to unsigned integer, len = 1..8 126 | * x:float([value][, offset]) - "dereference" userdata and convert 4 bytes as float to lua number 127 | * x:double([value][, offset]) - "dereference" userdata and convert 8 bytes as double to lua number 128 | * x:boolean([value][, offset][, len]) - "dereference" userdata and convert len bytes to lua boolean, default 1 129 | * x:string([, value/len][, offset]) - if type(value) =="number" then "dereference" userdata and convert to lua string, 0 or nil for whole string, 130 | __tostring=x:string(). if type(value) == "string" then copy string into userdata 131 | * x:bits([value][, offset][, len]) "dereference" userdata and convert 'len' bits (<=64, default 1) with 'offset' to integer, if integer 'value' provided, write first 'len' bits of it to userdata with 'offset' (in bits, 0-based). 132 | For reading/writing bitfields in structures without byte read-modify-write with unpack/pack. 133 | * x:pack(fmt, v1, v2, ...) uses string.pack to pack binary data into userdata 134 | * ~~x[pos]:pack(fmt, v1, v2, ...) same but with offset~~ 135 | * x:unpack(fmt, [pos]) uses string.unpack to unpack binary data from userdata 136 | 137 | # [Examples](example/) 138 | -------------------------------------------------------------------------------- /build_gcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | gcc -m64 -s -z noexecstack -fpic -shared -I"lib" src/call_sysV64.s src/ffi.c src/userdata.c src/sysV64.c -llua5.4 -o ffi.so 3 | 4 | #gcc -g -c -fpic src/call_sysV64.s -o call_sysV64.o 5 | #gcc -g -m64 -z noexecstack -fpic -shared -I"lib" call_sysV64.o src/ffi.c src/userdata.c src/sysV64.c -llua5.4 -o ffi.so 6 | -------------------------------------------------------------------------------- /build_msvc.bat: -------------------------------------------------------------------------------- 1 | cl src\ffi.c src\userdata.c src\win64.c /c /GS- /sdl- /EHs-c- /GL /Oi /I"lib" /Zc:inline /Zc:forScope /fp:fast /O1 /MD 2 | ml64 /c src\call_win64.asm 3 | link *.obj "lib\*.lib" "kernel32.lib" /OUT:"ffi.dll" /MANIFEST:NO /LTCG /NXCOMPAT /DYNAMICBASE /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:WINDOWS /OPT:ICF /NOLOGO 4 | @rem /NODEFAULTLIB 5 | 6 | @rem upx --ultra-brute ffi.dll 7 | -------------------------------------------------------------------------------- /build_tcc.bat: -------------------------------------------------------------------------------- 1 | tcc -m64 -shared -I"lib" -D_WIN64 src\call_win64.S src\ffi.c src\userdata.c src\win64.c lib\lua54.def -o ffi.dll 2 | @rem 3 | @rem upx --ultra-brute ffi.dll 4 | -------------------------------------------------------------------------------- /build_tcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | tcc -shared -I"lib" src/call_sysV64.s src/ffi.c src/userdata.c src/sysV64.c -llua5.4 -o ffi.so 3 | 4 | #tcc -c src/call_sysV64.s -o call_sysV64.o 5 | #tcc -m64 -g -shared -I"lib" call_sysV64.o src/ffi.c src/userdata.c src/sysV64.c -llua5.4 -o ffi.so 6 | -------------------------------------------------------------------------------- /example/ads1263.lua: -------------------------------------------------------------------------------- 1 | local CMD = { NOP = 0x00, RESET = 0x06, START1 = 0x08, STOP1 = 0x0A, START2 = 0x0C, STOP2 = 0x0E, RDATA1 = 0x12, RDATA2 = 0x14, SYOCAL1 = 0x16, SYGCAL1 = 0x17, SFOCAL1 = 0x19, SYOCAL2 = 0x1B, SYGCAL2 = 0x1C, SFOCAL2 = 0x1E, RREG = 0x20, WREG = 0x40} 2 | 3 | local REG = { ID = 0x00, POWER = 0x01, INTERFACE = 0x02, MODE0 = 0x03, MODE1 = 0x04, MODE2 = 0x05, INPMUX = 0x06, OFCAL0 = 0x07, OFCAL1 = 0x08, OFCAL2 = 0x09, FSCAL0 = 0x0A, FSCAL1 = 0x0B, FSCAL2 = 0x0C, IDACMUX = 0x0D, IDACMAG = 0x0E, REFMUX = 0x0F, TDACP = 0x10, TDACN = 0x11, GPIOCON = 0x12, GPIODIR = 0x13, GPIODAT = 0x14, ADC2CFG = 0x15, ADC2MUX = 0x16, ADC2OFC0 = 0x17, ADC2OFC1 = 0x18, ADC2FSC0 = 0x19, ADC2FSC1 = 0x1A} 4 | 5 | local MASK = { 6 | STATUS = {ADC2 = 0x80, ADC1 = 0x40, EXTCLK = 0x20, REF_ALM = 0x10, PGAL_ALM = 0x08, PGAH_ALM = 0x04, PGAD_ALM = 0x02, RESET = 0x01}, 7 | POWER = {RESET = 0x10, VBIAS = 0x02, INTREF = 0x01}, 8 | INTERFACE = {TIMEOUT = 0x08, STATUS = 0x04, CRC_DISABLE = 0x00, CRC_SUM = 0x01, CRC_CRC8 = 0x02}, 9 | MODE0 = {REFREV = 0x80, RUNMODE = 0x40, CHOP_INPUT = 0x20, CHOP_IDAC = 0x10, DELAY_OFF = 0x00, DELAY_9us = 0x01, DELAY_17us = 0x02, DELAY_35us = 0x03, DELAY_69us = 0x04, DELAY_139us = 0x05, DELAY_278us = 0x06, DELAY_556us = 0x07, DELAY_1111us = 0x08, DELAY_2222us = 0x09, DELAY_4444us = 0x0A, DELAY_8888us = 0x0B}, 10 | MODE1 = {FILTER = 0xE0, FILTER_SINC1 = 0x00, FILTER_SINC2 = 0x20, FILTER_SINC3 = 0x40, FILTER_SINC4 = 0x60, FILTER_FIR = 0x80, SBADC = 0x10, SBPOL = 0x08, SBMAG_OFF = 0x00, SBMAG_500nA = 0x01, SBMAG_2uA = 0x02, SBMAG_10uA = 0x03, SBMAG_50uA = 0x04, SBMAG_200uA = 0x05, SBMAG_10MOhm = 0x06}, 11 | MODE2 = {BYPASS_PGA = 0x80, GAIN = 0x70, GAIN_1 = 0x00, GAIN_2 = 0x10, GAIN_4 = 0x20, GAIN_8 = 0x30, GAIN_16 = 0x40, GAIN_32 = 0x50, DR = 0x0F, DR_2SPS = 0x00, DR_5SPS = 0x01, DR_10SPS = 0x02, DR_17SPS = 0x03, DR_20SPS = 0x04, DR_50SPS = 0x05, DR_60SPS = 0x06, DR_100SPS = 0x07, DR_400SPS = 0x08, DR_1200SPS = 0x09, DR_2400SPS = 0x0A, DR_4800SPS = 0x0B, DR_7200SPS = 0x0C, DR_14400SPS = 0x0D, DR_19200SPS = 0x0E, DR_38400SPS = 0x0F}, 12 | INPMUX = {MUXP_AIN0 = 0x00, MUXP_AIN1 = 0x10, MUXP_AIN2 = 0x20, MUXP_AIN3 = 0x30, MUXP_AIN4 = 0x40, MUXP_AIN5 = 0x50, MUXP_AIN6 = 0x60, MUXP_AIN7 = 0x70, MUXP_AIN8 = 0x80, MUXP_AIN9 = 0x90, MUXP_AINCOM = 0xA0, MUXP_TEMP = 0xB0, MUXP_AVDD = 0xC0, MUXP_DVDD = 0xD0, MUXP_TDACP = 0xE0, MUXP_OPEN = 0xF0, MUXN_AIN0 = 0x00, MUXN_AIN1 = 0x01, MUXN_AIN2 = 0x02, MUXN_AIN3 = 0x03, MUXN_AIN4 = 0x04, MUXN_AIN5 = 0x05, MUXN_AIN6 = 0x06, MUXN_AIN7 = 0x07, MUXN_AIN8 = 0x08, MUXN_AIN9 = 0x09, MUXN_AINCOM = 0x0A, MUXN_TEMP = 0x0B, MUXN_AVDD = 0x0C, MUXN_DVDD = 0x0D, MUXN_TDACN = 0x0E, MUXN_OPEN = 0x0F}, 13 | IDACMUX = {MUX2_AIN0 = 0x00, MUX2_AIN1 = 0x10, MUX2_AIN2 = 0x20, MUX2_AIN3 = 0x30, MUX2_AIN4 = 0x40, MUX2_AIN5 = 0x50, MUX2_AIN6 = 0x60, MUX2_AIN7 = 0x70, MUX2_AIN8 = 0x80, MUX2_AIN9 = 0x90, MUX2_AINCOM = 0xA0, MUX2_OFF = 0xB0, MUX1_AIN0 = 0x00, MUX1_AIN1 = 0x01, MUX1_AIN2 = 0x02, MUX1_AIN3 = 0x03, MUX1_AIN4 = 0x04, MUX1_AIN5 = 0x05, MUX1_AIN6 = 0x06, MUX1_AIN7 = 0x07, MUX1_AIN8 = 0x08, MUX1_AIN9 = 0x09, MUX1_AINCOM = 0x0A, MUX1_OFF = 0x0B}, 14 | IDACMAG = {MAG2_OFF = 0x00, MAG2_50uA = 0x10, MAG2_100uA = 0x20, MAG2_250uA = 0x30, MAG2_500uA = 0x40, MAG2_7500uA = 0x50, MAG2_1000uA = 0x60 ,MAG2_1500uA = 0x70 ,MAG2_2000uA = 0x80 ,MAG2_2500uA = 0x90 ,MAG2_3000uA = 0xA0 ,MAG1_OFF = 0x00 ,MAG1_50uA = 0x01 ,MAG1_100uA = 0x02 ,MAG1_250uA = 0x03 ,MAG1_500uA = 0x04 ,MAG1_7500uA = 0x05 ,MAG1_1000uA = 0x06 ,MAG1_1500uA = 0x07 ,MAG1_2000uA = 0x08 ,MAG1_2500uA = 0x09 ,MAG1_3000uA = 0x0A}, 15 | REFMUX = {RMUXP_INT = 0x00, RMUXP_AIN0 = 0x08, RMUXP_AIN2 = 0x10, RMUXP_AIN4 = 0x18, RMUXP_AVDD = 0x20, RMUXN_INT = 0x00, RMUXN_AIN1 = 0x01, RMUXN_AIN3 = 0x02, RMUXN_AIN5 = 0x03, RMUXN_AVDD = 0x04}, 16 | TDACP = {OUTP = 0x80}, 17 | TDACN = {OUTN = 0x80}, 18 | ADC2CFG = {DR2_10SPS = 0x00, DR2_100SPS = 0x40, DR2_400SPS = 0x80, DR2_800SPS = 0xC0, REF2_INT = 0x00, REF2_AIN01 = 0x08, REF2_AIN23 = 0x10, REF2_AIN45 = 0x18, REF2_AVDD = 0x20, GAIN_1 = 0x00, GAIN_2 = 0x01, GAIN_4 = 0x02, GAIN_8 = 0x03, GAIN_16 = 0x04 ,GAIN_32 = 0x05, GAIN_64 = 0x06, GAIN_128 = 0x07}, 19 | ADC2MUX = {MUXP2_AIN0 = 0x00, MUXP2_AIN1 = 0x10, MUXP2_AIN2 = 0x20, MUXP2_AIN3 = 0x30, MUXP2_AIN4 = 0x40, MUXP2_AIN5 = 0x50, MUXP2_AIN6 = 0x60, MUXP2_AIN7 = 0x70, MUXP2_AIN8 = 0x80, MUXP2_AIN9 = 0x90, MUXP2_AINCOM = 0xA0, MUXP2_TEMP = 0xB0, MUXP2_AVDD = 0xC0, MUXP2_DVDD = 0xD0, MUXP2_TDACP = 0xE0, MUXP2_OPEN = 0xF0, MUXN2_AIN0 = 0x00, MUXN2_AIN1 = 0x01, MUXN2_AIN2 = 0x02, MUXN2_AIN3 = 0x03, MUXN2_AIN4 = 0x04, MUXN2_AIN5 = 0x05, MUXN2_AIN6 = 0x06, MUXN2_AIN7 = 0x07, MUXN2_AIN8 = 0x08, MUXN2_AIN9 = 0x09, MUXN2_AINCOM = 0x0A, MUXN2_TEMP = 0x0B, MUXN2_AVDD = 0x0C, MUXN2_DVDD = 0x0D, MUXN2_TDACN = 0x0E, MUXN2_OPEN = 0x0F} 20 | } 21 | 22 | local M = {} 23 | 24 | function M:new(spi, cs, reset) return setmetatable({spi = spi, REG = REG, MASK = MASK, CMD = CMD, cs_mask = cs or 0x08, reset_mask = reset or 0x10}, {__index = M}) end 25 | 26 | function M:init() 27 | end 28 | 29 | function M:cs(act) 30 | if act then self.spi:io_clr(self.cs_mask) else self.spi:io_set(self.cs_mask) end 31 | end 32 | 33 | function M:reset() 34 | self:reset_pin(true, 5) -- 5 * 200ns = 1us low pulse, > 4 clk of ~8MHz 35 | self:reset_pin(false) 36 | end 37 | 38 | function M:reset_pin(act, num) 39 | if self.reset_mask then for i = 1, (num or 1) do if act then self.spi:io_clr(self.reset_mask) else self.spi:io_set(self.reset_mask) end end end 40 | end 41 | 42 | function M:write(addr, data, len) 43 | len = len or 1 44 | local str = string.char(CMD.WREG + (addr & 0x1F), (len-1) & 0x1F) 45 | for i = 1, len do str = str .. string.char(data & 0xFF); data = data >> 8; end 46 | self:cs(true) 47 | self.spi:write(str) 48 | self:cs(false) 49 | self:flush() 50 | end 51 | 52 | function M:read(addr, len) 53 | len = len or 1 54 | local str = string.char(CMD.RREG + (addr & 0x1F), (len-1) & 0x1F) .. string.char(0):rep(len) 55 | self:cs(true) 56 | self.spi:transfer(str) 57 | self:cs(false) 58 | self:flush() 59 | str = self.spi:read(#str) 60 | local ret = 0 61 | for i = 3, len + 2 do ret = ret << 8; ret = ret | (str:byte(i) or 0) end 62 | return ret 63 | end 64 | 65 | function M:pulse() self:write(REG.MODE0, self:read(REG.MODE0) | MASK.MODE0.RUNMODE) end 66 | function M:cont() self:write(REG.MODE0, self:read(REG.MODE0) & ~MASK.MODE0.RUNMODE) end 67 | function M:filter(x) self:write(REG.MODE1, (self:read(REG.MODE1) & ~MASK.MODE1.FILTER) | ((x & 7) << 5)) end 68 | function M:gain(x) self:write(REG.MODE2, (self:read(REG.MODE2) & ~MASK.MODE2.GAIN) | ((x & 7) << 4)) end 69 | function M:rate(x) self:write(REG.MODE2, (self:read(REG.MODE2) & ~MASK.MODE2.DR) | (x & 0x0F)) end 70 | function M:mux(x) self:write(REG.INPMUX, x) end 71 | function M:start() self:cs(true) self.spi:write(string.char(CMD.START1)) self:cs(false) end 72 | function M:stop() self:cs(true) self.spi:write(string.char(CMD.STOP1)) self:cs(false) end 73 | 74 | function M:data_wait() self.spi:wait_high() end 75 | 76 | function M:flush() self.spi:flush() end 77 | 78 | function M:data_read() 79 | self:cs(true) 80 | self.spi:transfer(string.char(CMD.RDATA1,0,0,0,0,0,0)) 81 | self:cs(false) 82 | end 83 | 84 | function M:data() 85 | str = self.spi:read(7) 86 | local ret = 0 87 | for i = 3, 6 do ret = ret << 8; ret = ret | (str:byte(i) or 0) end 88 | if ret >= 2^31 then ret = ret - 2^32 end 89 | return ret 90 | end 91 | 92 | return setmetatable(M, {__call = M.new}) -------------------------------------------------------------------------------- /example/ads1263.md: -------------------------------------------------------------------------------- 1 | # Read data from ADS1263 2 | All 'adc:' and 'spi:' functions only put commands to internal buffer, :flush() sends all the data to MPSSE. 3 | 4 | adc:data() is blocking till adc data (requested by adc:data_read()) is not transfered. 5 | 6 | ```Lua 7 | local spi = require ("spi")(0) 8 | local ads1263 = require ("ads1263") 9 | 10 | spi:init(9) --30MHz / (9+1) = 3MHz sclk 11 | spi:polarity(true) 12 | spi:msb(true) 13 | spi:flush() 14 | spi:read() -- some strage single byte sometimes left in buffer after init??? 15 | 16 | local adc = ads1263(spi, 0x08, 0x10) 17 | 18 | print(("ADC ID: 0x%02X"):format(adc:read(adc.REG.ID))) -- read id 0x23 19 | 20 | adc:reset() 21 | adc:gain(0) 22 | adc:mux(0xCC) --VCC monitor 23 | adc:rate(0x02) --10Hz sampling rate 24 | adc:pulse() 25 | adc:flush() 26 | 27 | adc:start() 28 | adc:data_wait() 29 | adc:data_read() 30 | adc:flush() 31 | 32 | local voltage = adc:data() * 5.0 / 2.0^32 * 4 33 | 34 | print(voltage) 35 | ``` -------------------------------------------------------------------------------- /example/gl.lua: -------------------------------------------------------------------------------- 1 | local ffi = require ("ffi") 2 | local gl = {} 3 | 4 | gl.ClearColor = ffi("opengl32", "glClearColor", "vffff") --float conversion 5 | gl.GetProcAddress = ffi("opengl32", "wglGetProcAddress", "ps") 6 | 7 | setmetatable(gl, { 8 | __index = function(t, k) 9 | t[k] = ffi("opengl32", "gl"..k) or ffi(t.GetProcAddress("gl"..k)) or getmetatable(t).__lib_error("gl"..k) 10 | return t[k] 11 | end, 12 | __lib_error = function(name) error("Unable to load '"..name.."' from opengl32.dll or wglGetProcAddress") end 13 | }) 14 | 15 | local GL = setmetatable({}, {__index = function(t,k) 16 | -- local path = "D:\\soft\\tcc\\include\\GL\\" 17 | -- for s in io.lines(path.."gl.h") do if s:match("GL_"..k) then print(s) end end 18 | -- for s in io.lines(path.."glext.h") do if s:match("GL_"..k) then print(s) end end 19 | error ("missing definition of GL_"..k) 20 | end}) 21 | 22 | GL.TRUE = 1 23 | GL.FALSE = 0 24 | 25 | GL.COLOR_BUFFER_BIT = 0x00004000 26 | GL.VENDOR = 0x1F00 27 | GL.RENDERER = 0x1F01 28 | GL.VERSION = 0x1F02 29 | GL.EXTENSIONS = 0x1F03 30 | 31 | GL.COMPUTE_SHADER = 0x91B9 32 | GL.VERTEX_SHADER = 0x8B31 33 | GL.TESS_EVALUATION_SHADER = 0x8E87 34 | GL.TESS_CONTROL_SHADER = 0x8E88 35 | GL.GEOMETRY_SHADER = 0x8DD9 36 | GL.FRAGMENT_SHADER = 0x8B30 37 | 38 | GL.TRANSFORM_FEEDBACK = 0x8E22 39 | 40 | GL.COMPILE_STATUS = 0x8B81 41 | GL.LINK_STATUS = 0x8B82 42 | GL.INFO_LOG_LENGTH = 0x8B84 43 | GL.ATTACHED_SHADERS = 0x8B85 44 | GL.ACTIVE_UNIFORMS = 0x8B86 45 | GL.ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87 46 | GL.SHADER_SOURCE_LENGTH = 0x8B88 47 | GL.CURRENT_PROGRAM = 0x8B8D 48 | 49 | GL.FLOAT = 0x1406 50 | GL.FLOAT_VEC2 = 0x8B50 51 | GL.FLOAT_VEC3 = 0x8B51 52 | GL.FLOAT_VEC4 = 0x8B52 53 | GL.FLOAT_MAT2 = 0x8B5A 54 | GL.FLOAT_MAT3 = 0x8B5B 55 | GL.FLOAT_MAT4 = 0x8B5C 56 | 57 | GL.DOUBLE = 0x140A 58 | GL.DOUBLE_VEC2 = 0x8FFC 59 | GL.DOUBLE_VEC3 = 0x8FFD 60 | GL.DOUBLE_VEC4 = 0x8FFE 61 | GL.DOUBLE_MAT2 = 0x8F46 62 | GL.DOUBLE_MAT3 = 0x8F47 63 | GL.DOUBLE_MAT4 = 0x8F48 64 | 65 | GL.INT = 0x1404 66 | GL.INT_VEC2 = 0x8B53 67 | GL.INT_VEC3 = 0x8B54 68 | GL.INT_VEC4 = 0x8B55 69 | 70 | GL.UNSIGNED_INT = 0x1405 71 | GL.UNSIGNED_INT_VEC2 = 0x8DC6 72 | GL.UNSIGNED_INT_VEC3 = 0x8DC7 73 | GL.UNSIGNED_INT_VEC4 = 0x8DC8 74 | 75 | GL.BOOL = 0x8B56 76 | GL.BOOL_VEC2 = 0x8B57 77 | GL.BOOL_VEC3 = 0x8B58 78 | GL.BOOL_VEC4 = 0x8B59 79 | 80 | local function get_shader_int(id, name) 81 | local pint = ffi.userdata(4) 82 | gl.GetShaderiv(id, name, pint) 83 | return pint:int() 84 | end 85 | 86 | local function get_program_int(id, name) 87 | local pint = ffi.userdata(4) 88 | gl.GetProgramiv(id, name, pint) 89 | return pint:int() 90 | end 91 | 92 | local function get_int(name) 93 | local pint = ffi.userdata(4) 94 | gl.GetIntegerv(name, pint) 95 | return pint:int() 96 | end 97 | 98 | local function compile_status(id) 99 | if get_shader_int(id, GL.COMPILE_STATUS) == GL.FALSE then 100 | local len = get_shader_int(id, GL.INFO_LOG_LENGTH) 101 | local info = ffi.userdata(len) 102 | gl.GetShaderInfoLog(id, len, pint, info) 103 | return info:string(len) 104 | end 105 | end 106 | 107 | local function link_status(id) 108 | if get_program_int(id, GL.LINK_STATUS) == GL.FALSE then 109 | local len = get_program_int(id, GL.INFO_LOG_LENGTH) 110 | local info = ffi.userdata(len) 111 | gl.GetProgramInfoLog(id, len, pint, info) 112 | return info:string(len) 113 | end 114 | end 115 | 116 | local function uniforms(id) 117 | local num = get_program_int(id, GL.ACTIVE_UNIFORMS) 118 | local buff_size = get_program_int(id, GL.ACTIVE_UNIFORM_MAX_LENGTH) 119 | local length, type, size, name = ffi.userdata(4), ffi.userdata(4), ffi.userdata(4), ffi.userdata(buff_size) 120 | local types, sizes, locations = {}, {}, {} 121 | for i = 1, num do 122 | gl.GetActiveUniform(id, i-1, buff_size, length, size, type, name) 123 | local n = name:string(length:int()) 124 | types[n] = type:int() 125 | sizes[n] = size:int() 126 | locations[n] = gl.GetUniformLocation(id, n) -- i-1? 127 | end 128 | return types, sizes, locations 129 | end 130 | 131 | local uniform_set = { 132 | [GL.FLOAT] = "1fv", [GL.FLOAT_VEC2] = "2fv", [GL.FLOAT_VEC3] = "3fv", [GL.FLOAT_VEC4] = "4fv", 133 | [GL.DOUBLE] = "1dv", [GL.DOUBLE_VEC2] = "2dv", [GL.DOUBLE_VEC3] = "3dv", [GL.DOUBLE_VEC4] = "4dv", 134 | [GL.INT] = "1iv", [GL.INT_VEC2] = "2iv", [GL.INT_VEC3] = "3iv", [GL.INT_VEC4] = "4iv", 135 | [GL.UNSIGNED_INT] = "1uiv", [GL.UNSIGNED_INT_VEC2] = "2uiv", [GL.UNSIGNED_INT_VEC3] = "3uiv", [GL.UNSIGNED_INT_VEC4] = "4uiv", 136 | [GL.BOOL] = "1iv", [GL.BOOL_VEC2] = "2iv", [GL.BOOL_VEC3] = "3iv", [GL.BOOL_VEC4] = "4iv", 137 | [GL.FLOAT_MAT2] = "Matrix2fv", [GL.FLOAT_MAT3] = "Matrix3fv", [GL.FLOAT_MAT4] = "Matrix4fv", 138 | [GL.DOUBLE_MAT2] = "Matrix2dv", [GL.DOUBLE_MAT3] = "Matrix3dv", [GL.DOUBLE_MAT4] = "Matrix4dv" 139 | } 140 | 141 | local uniform_get = {} 142 | local uniform_num = {} 143 | local uniform_size = {} 144 | local uniform_pack = {} 145 | 146 | for k,v in pairs(uniform_set) do 147 | local t = v:gsub("Matrix",""):sub(2,2) 148 | uniform_get [k] = t.."v" 149 | uniform_size[k] = ({f = 4, d = 8, i = 4, u = 4, b = 4})[t] 150 | uniform_pack[k] = ({f = "f", d = "d", i = "i4", u = "I4", b = "i4"})[t] 151 | uniform_num [k] = tonumber(v:gsub("Matrix",""):sub(1,1)) 152 | if v:match("Matrix") then uniform_num[k] = uniform_num[k] * uniform_num[k] end 153 | end 154 | 155 | gl.shader = function(typ, ...) 156 | return setmetatable({id = gl.CreateShader(typ)}, { 157 | __call = function(self, ...) 158 | local src = {...} 159 | if #src > 0 then 160 | gl.ShaderSource(self.id, #src, src, 0) 161 | gl.CompileShader(self.id) 162 | local err = compile_status(self.id) 163 | assert(not err, err) 164 | end 165 | return self 166 | end, 167 | __gc = function(self) gl.DeleteShader(self.id) end 168 | })(...) --create, setmetatable, call with gl.shader arguments and return result 169 | end 170 | 171 | gl.compute_shader = function(...) return gl.shader(GL.COMPUTE_SHADER, ...) end 172 | gl.vertex_shader = function(...) return gl.shader(GL.VERTEX_SHADER, ...) end 173 | gl.tesselation_shader = function(...) return gl.shader(GL.TESSELATION_SHADER, ...) end 174 | gl.geometry_shader = function(...) return gl.shader(GL.GEOMETRY_SHADER, ...) end 175 | gl.fragment_shader = function(...) return gl.shader(GL.FRAGMENT_SHADER, ...) end 176 | 177 | gl.program = function(...) 178 | return setmetatable({id = gl.CreateProgram()}, { 179 | __call = function(self, ...) 180 | local shaders = {...} 181 | if #shaders > 0 then 182 | local num = get_program_int(self.id, GL.ATTACHED_SHADERS) 183 | if num > 0 then 184 | local pshaders = userdata(4*num) 185 | gl.GetAttachedShaders(self.id, num, 0, pshaders) 186 | for i = 0, num-1 do gl.DetachShader(self.id, pshaders:int(nil, i)) end 187 | end 188 | -- if type(shaders[1]) == "string" then shaders = {gl.shader(GL.VERTEX_SHADER, shaders[1]), gl.shader(GL.FRAGMENT_SHADER, shaders[2])} end 189 | for k, shader in pairs(shaders) do gl.AttachShader(self.id, shader.id) end 190 | end 191 | 192 | if get_program_int(self.id, GL.ATTACHED_SHADERS) > 0 then 193 | gl.LinkProgram(self.id) 194 | local err = link_status(self.id) 195 | assert(not err, err) 196 | gl.UseProgram(self.id) 197 | local types, sizes, locations = uniforms(self.id) 198 | 199 | getmetatable(self).__index = function(self,k) 200 | local t = types[k] 201 | local num = uniform_num[t] 202 | local size = uniform_size[t] 203 | local param = ffi.userdata(num * size * sizes[k]) 204 | gl["GetUniform"..uniform_get[t]](self.id, locations[k], param) 205 | local r = {param:unpack(uniform_pack[t]:rep(num))} 206 | return (#r > 1) and r or r[1] 207 | end 208 | 209 | getmetatable(self).__newindex = function(self,k,v) 210 | assert(get_int(GL.CURRENT_PROGRAM) == self.id, "Setting uniform of program ("..self.id.."), while GL_CURRENT_PROGRAM = "..get_int(GL.CURRENT_PROGRAM)) 211 | local t = types[k] 212 | local num = uniform_num[t] 213 | if type(v) ~= "table" then v = {v} end 214 | local param = uniform_pack[t]:rep(num * sizes[k]):pack(table.unpack(v)) 215 | if uniform_set[t]:match("Matrix") then gl["Uniform"..uniform_set[t]](locations[k], sizes[k], 0, param) 216 | else gl["Uniform"..uniform_set[t]](locations[k], sizes[k], param) end 217 | end 218 | end 219 | return self 220 | end, 221 | __gc = function(self) gl.DeleteProgram(self.id) end 222 | })(...) --create table {id = id}, setmetatable, call with gl.program arguments and return result 223 | end 224 | 225 | gl.GL = GL 226 | return gl 227 | -------------------------------------------------------------------------------- /example/glfw.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local glfw = {} 3 | --for k,v in pairs(ffi("glfw3", "*")) do glfw[k:match("^glfw(.+)")] = v end 4 | 5 | setmetatable(glfw, { 6 | __index = function(t, k) t[k] = ffi("glfw3", "glfw"..k) or ffi("libglfw.so", "glfw"..k) or getmetatable(t).__lib_error("glfw"..k); return t[k] end, 7 | __lib_error = function(name) error("Unable to load '"..name.."' from glfw3 lib") end 8 | }) 9 | 10 | local create_window = glfw.CreateWindow 11 | --local create_window = ffi("libglfw.so", "glfwCreateWindow", "piisii") 12 | function glfw.CreateWindow(...) return setmetatable({window = create_window(...)}, {__index = function(t,k) return function(self,...) return glfw[k](self.window,...) end end }) end 13 | 14 | --glfw.WindowShouldClose = ffi("glfw3", "glfwWindowShouldClose", "bp") --specify boolean type, otherwire 0 == true in Lua 15 | 16 | local GLFW = setmetatable({}, {__index = function(t,k) error ("missing definition of GLFW_"..k) end}) 17 | 18 | GLFW.KEY_ESCAPE = 256 19 | GLFW.PRESS = 1 20 | GLFW.RELEASE = 0 21 | GLFW.TRUE = 1 22 | GLFW.FALSE = 0 23 | 24 | glfw.GLFW = GLFW 25 | 26 | return glfw -------------------------------------------------------------------------------- /example/gpib.lua: -------------------------------------------------------------------------------- 1 | local ffi = require ("ffi") 2 | local gpib = setmetatable({}, {__index = function(t,k) t[k] = ffi("gpib", "l_ib"..k) return t[k] end}) 3 | 4 | local M = {} 5 | 6 | function M.timeout(t) if t > 0 then return math.floor(math.log(t, math.sqrt(10))+11.5) else return 0 end end 7 | 8 | function M:new(dev, pad, sad, timeout, eot, eos) 9 | return setmetatable({_dev = gpib.dev(dev or 0, pad or 0, sad or 0, self.timeout(timeout), eot or 0, eos or 0x140A)}, {__index = M}) 10 | end 11 | 12 | function M:delete() gpib.onl(self._dev, 0) end 13 | 14 | function M:rd(num) 15 | local buff = ffi.userdata(num) 16 | gpib.rd(self._dev, buff, num) 17 | return buff:string() 18 | end 19 | 20 | return setmetatable(M, {__call = M.new, __gc = M.delete, __index = function(t, k) return function(t, ...) gpib.k(self._dev, ...) end end }) -------------------------------------------------------------------------------- /example/hello_glfw.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local gl = require ("gl") 3 | local glfw = require ("glfw") 4 | local GL = gl.GL 5 | local GLFW = glfw.GLFW 6 | 7 | glfw.Init() 8 | local window = glfw.CreateWindow(640, 480, "Simple example", 0, 0) 9 | window:MakeContextCurrent() 10 | 11 | local key_callback = function(window, key, scancode, action, mods) 12 | if (key == GLFW.KEY_ESCAPE and action == GLFW.PRESS) then glfw.SetWindowShouldClose(window, GLFW.TRUE) end 13 | end 14 | key_callback = ffi(key_callback, "vpiiii") 15 | window:SetKeyCallback(key_callback) 16 | 17 | local vs = gl.shader(GL.VERTEX_SHADER, [[#version 150 18 | in vec2 p; 19 | void main(void){ gl_Position = vec4(p.xy, 0.0f, 1.0f); }]]) 20 | 21 | local fs = gl.shader(GL.FRAGMENT_SHADER, [[#version 150 22 | uniform vec2 resolution; 23 | uniform float zoom = 1.0; 24 | uniform vec2 pos = vec2(1.25, 0.05); 25 | void main(void){ 26 | vec2 uv = ((2.0 * gl_FragCoord.xy - resolution) / resolution.y) * zoom - pos; 27 | int i = 0; 28 | for (vec2 z = vec2(0.0); (dot(z, z) < 65536.0) && (i < 100); i++) z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + uv; 29 | gl_FragColor = vec4(vec3(sin(i * 0.05)) * vec3(0.5, 1.0, 1.3), 1.0); 30 | }]]) 31 | 32 | local prog = gl.program(fs, vs) 33 | local pwidth, pheight = ffi.userdata(4), ffi.userdata(4) --allocate 4 byte userdata in lua to pass as pointer to C function 34 | 35 | gl.ClearColor(0.3, 0.4, 0.5, 1.0) 36 | 37 | while window:WindowShouldClose() == GLFW.FALSE do 38 | window:GetFramebufferSize(pwidth, pheight) 39 | local w,h = pwidth:int(), pheight:int() --dereference userdata pointer to integer, same as pwidth:upack("I4") 40 | gl.Viewport(0, 0, w, h) 41 | prog.resolution = {w, h} --GLSL uniforms by name with __index/__newindex of prog, type convertion inside 42 | prog.zoom = math.exp(-5+5*math.cos(os.clock())) 43 | gl.Clear(GL.COLOR_BUFFER_BIT) 44 | gl.Rects(-1,-1,1,1) 45 | window:SwapBuffers() 46 | glfw.PollEvents() 47 | end 48 | 49 | window:DestroyWindow() 50 | glfw.Terminate() -------------------------------------------------------------------------------- /example/hp3458a.lua: -------------------------------------------------------------------------------- 1 | local gpib = require "gpib" 2 | 3 | local hp3458a = {} 4 | 5 | function hp3458a:new(addr, boardindex) 6 | boardindex = boardindex or 0 7 | this = {}; 8 | this.ib = gpib(boardindex, addr, 0, gpib.timeout(1), 0, 0x140A) 9 | --ibdev (int boardindex, int pad, int sad, int timeout, int eot, int eos) 10 | this.ib:clr() 11 | this.addr = addr 12 | this.status = 0 13 | this.termStr = "\013\010" 14 | setmetatable(this, {__index = hp3458a, __gc = hp3458a.delete}) 15 | return this 16 | end 17 | 18 | function hp3458a:delete() 19 | -- self.ib:onl(0) 20 | end 21 | 22 | function hp3458a:read(num) 23 | local s = "" 24 | while s:byte(-1) ~= 0x0a do s = s .. self.ib:rd(num or 256) end 25 | -- self.status = self.ib:ibsta() 26 | -- self.cntl = self.ib:ibcntl() 27 | -- self.error = self.ib:iberr() 28 | return s:sub(1, -3) 29 | end 30 | 31 | function hp3458a:write(...) 32 | -- print(string.format(...)) 33 | local str = string.format(...) .. (self.termStr) 34 | self.ib:wrt(str, #str) 35 | -- self.status = self.ib:sta() 36 | return self.gpib:cntl() 37 | end 38 | 39 | 40 | function hp3458a:init() 41 | self:write("ID?") 42 | local id = self:read() 43 | if id ~= "HP3458A" then print ("GPIB @ "..self.addr.." is not a HP3458A voltmeter, ID?="..id) return true end 44 | self:write("RESET") 45 | self:write("INBUF ON") 46 | -- self:write("TBUFF ON") 47 | self:write("ARANGE OFF") 48 | self:write("DCV 10") --10V input range 49 | self:write("NDIG 8") --accuracy, would be later overwriten by APER 50 | self:write("AZERO OFF") 51 | self:write("DELAY 0") 52 | self:write("DISP OFF") --with display tunred on, fast trigger makes error. 53 | self:write("APER 0.001") --1ms integrating time 54 | self:write("TIMER 0.005") --200Hz freq in timer-trigger mode (for offset meas) 55 | end 56 | 57 | function hp3458a:display(str) 58 | if str then return self:write("DISP MSG,'"..str.."'") else return self:write("DISP OFF") end 59 | end 60 | 61 | function hp3458a:trigger(num, period) 62 | self:write("OFORMAT ASCII") 63 | self:write("MFORMAT SREAL") 64 | self:write("TRIG AUTO") 65 | self:write("TARM HOLD") 66 | if num > 0 then 67 | self:display("EXT TRIGGER") 68 | self:write("MEM FIFO") 69 | self:write("NRDGS %d,EXT", num); 70 | self:write("TARM SGL"); 71 | elseif num < 0 then 72 | self:display("TIMER TRIGGER") 73 | if period then self:write("TIMER %G", period) end 74 | self:write("MEM FIFO") 75 | self:write("NRDGS %d,TIMER", -num); 76 | self:write("TARM SGL"); 77 | else 78 | self:display() 79 | self:write("MEM OFF") 80 | self:write("NRDGS 1,AUTO"); 81 | self:write("TARM SGL"); 82 | local d = tonumber(self:read()) 83 | self:display(d) 84 | return d 85 | end 86 | end 87 | 88 | function hp3458a:count() 89 | self:write("MCOUNT?") 90 | local s = self:read() 91 | return tonumber(s) 92 | end 93 | 94 | function hp3458a:memory(offset) 95 | self:write("RMEM %d,1,1", offset) 96 | return tonumber(self:read()) 97 | end 98 | 99 | function hp3458a:data(num) 100 | local readNum = 128 101 | if num == 0 then return tonumber(self:read()) end 102 | num = num or self:count() 103 | if num == 0 then return {} end 104 | local pos = 0 105 | local size = math.min(num - pos, readNum) 106 | if size == 0 then return {tonumber(self:read())} end 107 | local ascii_data = "" 108 | while size > 0 do 109 | self:write("RMEM %d,%d,1", pos+1, size) 110 | local str = self:read(size*18) 111 | ascii_data = ascii_data .. str .. "," 112 | pos = pos + size 113 | size = math.min(num - pos, readNum) 114 | end 115 | local data = {} 116 | for s in ascii_data:gmatch("[%deE%+%-%.]+") do table.insert(data, tonumber(s)) end 117 | return data 118 | end 119 | 120 | function hp3458a:measure() 121 | local s = self:read() 122 | if s then return tonumber(s) end 123 | end 124 | 125 | setmetatable(hp3458a, {__call = hp3458a.new}) 126 | 127 | return hp3458a -------------------------------------------------------------------------------- /example/hp3458a.md: -------------------------------------------------------------------------------- 1 | # HP3458A digital multimeter with GPIB inteface 2 | ```Lua 3 | local hp3458a = require ("hp3458a") 4 | os.sleep = require ("ffi")("kernel32", "Sleep") 5 | 6 | hp = hp3458a(24) 7 | hp:init() 8 | hp:write("APER 0.1") --100ms aperture 9 | hp:trigger(-10, 0.2) --200ms timer period, positive number of samples - external trigger, negative number of samples - from timer. 10 | os.sleep(3000) 11 | 12 | d = hp:download(10) 13 | 14 | for k,v in ipairs(d) do print(k,v) end 15 | ``` -------------------------------------------------------------------------------- /example/mpsse.lua: -------------------------------------------------------------------------------- 1 | local ffi = require ("ffi") 2 | local ft = setmetatable({}, {__index = function(t,k) t[k] = ffi("lftd2xx", "FT_"..k) return t[k] end}) 3 | 4 | local M = {} 5 | 6 | function M:new(dev) 7 | local handle = ft.Open(dev or 0); 8 | ft.SetUSBParameters(handle, 65536, 65535); --Set USB request transfer size 9 | ft.SetChars(handle, 0, 0, 0, 0); --Disable event and error characters 10 | ft.SetTimeouts(handle, 0, 0); --Sets the read and write timeouts in milliseconds for the FT2232H 11 | ft.SetLatencyTimer(handle, 16); --Set the latency timer 12 | ft.SetBitMode(handle, 0x0, 0x00); --Reset controller 13 | ft.SetBitMode(handle, 0x0, 0x02); --Enable MPSSE mode 14 | ft.SetDivisor(handle, 0); --div 1 15 | return setmetatable({handle = handle}, {__index = M}) 16 | end 17 | 18 | function M:delete() 19 | ft.Close(self.handle) 20 | end 21 | 22 | function M:write(str) 23 | local len = ffi.userdata(4) 24 | local status = ft.Write(self.handle, str, #str, len) 25 | return len:int(), status 26 | end 27 | 28 | function M:read(num) 29 | num = num or self:status() 30 | local buff = ffi.userdata(num) 31 | local len = ffi.userdata(4) 32 | local status = ft.Read(self.handle, buff, num, len) 33 | return buff:string(), status 34 | end 35 | 36 | function M:status() 37 | local RxBytes, TxBytes, Event = ffi.userdata(4), ffi.userdata(4), ffi.userdata(4) 38 | local status = ft.GetStatus(self.handle, RxBytes, TxBytes, Event) 39 | return RxBytes:int(), TxBytes:int(), Event:int(), status 40 | end 41 | 42 | setmetatable(M, {__call = M.new, __gc = M.delete}) 43 | 44 | return M 45 | -------------------------------------------------------------------------------- /example/readme.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | * [Mandelbrot fractal](hello_glfw.lua) with GLSL in [OpenGL](gl.lua) window with [glfw](glfw.lua) 4 | * [Serial port](serial.md), using [winapi CreateFile/ReadFile](serial.lua), kernel32.dll 5 | * [Reading data](ads1263.md) from [ADS1263](ads1263.lua) ADC [module](https://www.waveshare.com/18983.htm) with [SPI interface](spi.lua) of [MPSSE](mpsse.lua) from [FT232H module](https://www.adafruit.com/product/2264), ftd2xx.dll 6 | * [Reading data](hp3458a.md) from [HP3458A](hp3458a.lua) multimeter with [GPIB interface](gpib.lua), gpib.dll 7 | -------------------------------------------------------------------------------- /example/serial.lua: -------------------------------------------------------------------------------- 1 | local ffi = require ("ffi") 2 | local win = ffi("kernel32.dll") 3 | local M = {} 4 | 5 | --bist: 7/8; parity: 0/1/2/3/4 == NO/ODD/EVEN/MARK/SPACE; stop: 0/1/2 == 1/1.5/2 6 | function M:new(port, baudrate, bits, parity, stop) 7 | local this = {} 8 | setmetatable(this, {__index = M}) 9 | return port and this:open(port, baudrate, bits, parity, stop) or this 10 | end 11 | 12 | function M:delete() 13 | self:close() 14 | end 15 | 16 | function M:open(port, baudrate, bits, parity, stop) 17 | baudrate, bits, parity, stop = baudrate or 9600, bits or 8, parity or 0, stop or 1 18 | self.hCom = win.CreateFileA(port, 0xC0000000, 0, 0, 3, 0, 0) -- GENERIC_READ | GENERIC_WRITE, OPEN_EXISTING 19 | if self.hCom == 0 then 20 | print("could not open port "..port.." with error "..(win.GetLastError())) 21 | return nil 22 | end 23 | if win.SetCommTimeouts(self.hCom, ("I4"):rep(5):pack(0xFFFFFFFF,0,0,0,0)) == 0 then 24 | print("could not set timeouts for "..port.." with error "..(win.GetLastError())) 25 | self:close() 26 | return nil 27 | end 28 | if win.SetCommState(self.hCom, ("I4I4I4I2I2I2BBBbbbbbI2"):pack(28, baudrate, 0, 0, 0, 0, bits, parity, stop, 0, 0, 0, 0, 0, 0)) == 0 then 29 | print("could not set comm state for "..port.." with error "..(win.GetLastError())) 30 | self:close() 31 | return nil 32 | end 33 | return self 34 | end 35 | 36 | function M:close() 37 | win.CloseHandle(self.hCom) 38 | self.hCom = nil 39 | end 40 | 41 | function M:read(num) 42 | num = num or self:num() 43 | if num <= 0 then return "" end 44 | local buff = ffi.userdata(num) 45 | local plength = ffi.userdata(4) 46 | win.ReadFile(self.hCom, buff, num, plength, 0) 47 | return buff:string(plength:int()) 48 | end 49 | 50 | function M:write(str) 51 | local plength = ffi.userdata(4) 52 | win.WriteFile(self.hCom, str, #str, plength, 0) 53 | return plength:int() 54 | end 55 | 56 | function M:num() 57 | local stat = ffi.userdata(12) 58 | local err = ffi.userdata(4) 59 | win.ClearCommError(self.hCom, err, stat) 60 | local s, rx, tx = stat:unpack("I4I4I4") 61 | return rx, tx 62 | end 63 | 64 | function M:clear() 65 | win.PurgeComm(self.hCom, 0x08) --PURGE_RXCLEAR 66 | end 67 | 68 | function M:status() 69 | local stat = ffi.userdata(4) 70 | win.GetCommModemStatus(self.hCom, stat) 71 | return stat:int() 72 | end 73 | 74 | function M:rts(value) 75 | local dcb = ffi.userdata(28) 76 | win.GetCommState(self.hCom, dcb) 77 | dcb:bits(value and 1 or 0, 68, 2) --dcb.fRtsControl = RTS_CONTROL_ENABLE 78 | win.SetCommState(self.hCom, dcb) 79 | end 80 | 81 | function M:dtr(value) 82 | local dcb = ffi.userdata(28) 83 | win.GetCommState(self.hCom, dcb) 84 | dcb:bits(value and 1 or 0, 76, 2) --dcb.fDtrControl = DTR_CONTROL_ENABLE 85 | win.SetCommState(self.hCom, dcb) 86 | end 87 | 88 | function M:csr() return self:status() & 0x01 == 0x01 end --MS_CTS_ON 89 | function M:dsr() return self:status() & 0x02 == 0x02 end --MS_DSR_ON 90 | function M:ri() return self:status() & 0x04 == 0x04 end --MS_RING_ON 91 | function M:dcd() return self:status() & 0x08 == 0x08 end --MS_RLSD_ON 92 | 93 | return setmetatable(M, {__call = M.new, __gc = M.delete}) -------------------------------------------------------------------------------- /example/serial.md: -------------------------------------------------------------------------------- 1 | # Serial port 2 | Old NDP960 Position Display Unit serial port readout example 3 | ```Lua 4 | local serial = require("serial") 5 | 6 | local port = serial("COM3", 9600, 7, 2, 2) -- 7bit byte, Even parity, 2 stop bits, instead of standart 8N1 7 | 8 | port:rts(true) 9 | port:dtr(true) 10 | 11 | port:write("\x02") --CTRL-B == STX -> request data 12 | 13 | local str = "" 14 | while str:sub(-4) ~= string.char(0x0D,0x0A,0x0A,0x0A) do str = str .. port:read() end 15 | 16 | local x, y, z = str:gsub(" ", "0"):match("X=([%+%-%.%d]+)[%?]?R%c+Y=([%+%-%.%d]+)[%?]?R%c+Z=([%+%-%.%d]+)[%?]?R%c+") 17 | x, y, z = tonumber(x), tonumber(y), tonumber(z) 18 | 19 | print(str) --response string 20 | print(x, y, z) --parsed coordinates 21 | 22 | port:close() 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /example/spi.lua: -------------------------------------------------------------------------------- 1 | local spi = {} 2 | 3 | function spi:new(dev) return setmetatable({mpsse = require("mpsse")(dev or 0), buff = ""}, {__index = spi}) end 4 | 5 | function spi:init(clkdiv) 6 | self.mpsse.dirL = 0x1B -- GPIOL3=0, GPIOL2=0, DRDY=0, RESET=1, CS=1, MISO=0, MOSI=1, CLK=1 7 | self.mpsse.outL = 0x18 -- reset&cs high 8 | self.mpsse.dirH = 0x00 9 | self.mpsse.outH = 0x00 10 | self.cfg = 0x00 --shadow copy of CHA & POL & LSB/MSB config byte 11 | self:polarity(false) 12 | self:msb(true) 13 | self.mpsse:write(string.char(0x8A, 0x97, 0x8D, 0x86, (clkdiv or 0) & 0xFF, ((clkdiv or 0) >> 8) & 0xFF, 0x80, self.mpsse.outL, self.mpsse.dirL, 0x82, self.mpsse.outH, self.mpsse.dirH) ) 14 | end 15 | 16 | function spi:push(str) self.buff = self.buff .. str end 17 | function spi:flush() self.mpsse:write(self.buff); self.buff = "" end 18 | 19 | function spi:write(data) self:push( string.char(self.cfg | 0x10, (#data-1) & 0xFF, ((#data-1) >> 8) & 0xFF) .. data ) end 20 | function spi:transfer(data) self:push( string.char(self.cfg | 0x30, (#data-1) & 0xFF, ((#data-1) >> 8) & 0xFF) .. data ) end 21 | function spi:read(num) return self.mpsse:read(num or self.mpsse:status()) end 22 | function spi:wait_low() self:push( string.char(0x88) ) end 23 | function spi:wait_high() self:push( string.char(0x89) ) end 24 | 25 | function spi:io_set(mask) 26 | if (mask & 0x00FF) ~= 0 then self.mpsse.outL = self.mpsse.outL | (mask & 0xFF); self:push(string.char(0x80, self.mpsse.outL, self.mpsse.dirL)) end 27 | if (mask & 0xFF00) ~= 0 then self.mpsse.outH = self.mpsse.outH | ((mask>>8) & 0xFF); self:push(string.char(0x82, self.mpsse.outH, self.mpsse.dirH)) end 28 | end 29 | 30 | function spi:io_clr(mask) 31 | if (mask & 0x00FF) ~= 0 then self.mpsse.outL = self.mpsse.outL & ~(mask & 0xFF); self:push(string.char(0x80, self.mpsse.outL, self.mpsse.dirL)) end 32 | if (mask & 0xFF00) ~= 0 then self.mpsse.outH = self.mpsse.outH & ~((mask>>8) & 0xFF); self:push(string.char(0x82, self.mpsse.outH, self.mpsse.dirH)) end 33 | end 34 | 35 | function spi:polarity(x) 36 | if x then 37 | self.cfg = (self.cfg & ~0x05) | 0x04 38 | self.mpsse.outL = self.mpsse.outL | 0x01 39 | else 40 | self.cfg = (self.cfg & ~0x05) | 0x01 41 | self.mpsse.outL = self.mpsse.outL & ~0x01 42 | end 43 | self.mpsse:write(string.char(0x80, self.mpsse.outL, self.mpsse.dirL)) 44 | end 45 | 46 | function spi:msb(x) if x then self.cfg = (self.cfg & ~0x08) else self.cfg = (self.cfg | 0x08) end end 47 | 48 | setmetatable (spi, {__call = spi.new}) 49 | 50 | return spi -------------------------------------------------------------------------------- /example/tcads.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local lib = ffi("tcadsdll") 3 | 4 | local function adsaddr(a, p) return ("BBBBBBW"):pack(a[1], a[2], a[3], a[4], a[5] or 1, a[6] or 1, p) end 5 | 6 | function M:new(addr, port, group) 7 | local this = {addr = addr or {127,0,0,1,1,1}, port = port or 801, group = group or 0x4020} 8 | setmetatable(this, {__index = M}) 9 | return this:open() 10 | end 11 | 12 | function M:address(str) 13 | local port, addr = {} 14 | addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], port = str:match("(%d+).(%d+).(%d+).(%d+).(%d+).(%d+):(%d+)") 15 | if #addr == 6 then self.addr = addr end 16 | self.port = port or self.port 17 | end 18 | 19 | function M:delete() 20 | self:close() 21 | end 22 | 23 | function M:open() 24 | lib.AdsPortOpen() 25 | return self 26 | end 27 | 28 | function M:close() 29 | lib.AdsPortClose() 30 | end 31 | 32 | function M:version() 33 | return (lib.AdsGetDllVersion()) 34 | end 35 | 36 | function M:read(offset, length, group, addr, port) 37 | addr = addr or self.addr 38 | port = port or self.port 39 | group = group or self.group 40 | offset = offset or 0 41 | length = length or 1 42 | local data = ffi.userdata(length) 43 | lib.AdsSyncReadReq(adsaddr(addr, port), group, offset, length, data) 44 | return data:string(length) 45 | end 46 | 47 | function M:write(offset, data, group, addr, port) 48 | addr = addr or self.addr 49 | port = port or self.port 50 | group = group or self.group 51 | offset = offset or 0 52 | lib.AdsSyncWriteReq(adsaddr(addr, port), group, offset, #data, data) 53 | end 54 | 55 | function M:readwrite(offset, data, length, group, addr, port) 56 | 57 | 58 | -------------------------------------------------------------------------------- /lib/lauxlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lauxlib.h $ 3 | ** Auxiliary functions for building Lua libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lauxlib_h 9 | #define lauxlib_h 10 | 11 | 12 | #include 13 | #include 14 | 15 | #include "luaconf.h" 16 | #include "lua.h" 17 | 18 | 19 | /* global table */ 20 | #define LUA_GNAME "_G" 21 | 22 | 23 | typedef struct luaL_Buffer luaL_Buffer; 24 | 25 | 26 | /* extra error code for 'luaL_loadfilex' */ 27 | #define LUA_ERRFILE (LUA_ERRERR+1) 28 | 29 | 30 | /* key, in the registry, for table of loaded modules */ 31 | #define LUA_LOADED_TABLE "_LOADED" 32 | 33 | 34 | /* key, in the registry, for table of preloaded loaders */ 35 | #define LUA_PRELOAD_TABLE "_PRELOAD" 36 | 37 | 38 | typedef struct luaL_Reg { 39 | const char *name; 40 | lua_CFunction func; 41 | } luaL_Reg; 42 | 43 | 44 | #define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) 45 | 46 | LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); 47 | #define luaL_checkversion(L) \ 48 | luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) 49 | 50 | LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); 51 | LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); 52 | LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); 53 | LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); 54 | LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname); 55 | LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, 56 | size_t *l); 57 | LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, 58 | const char *def, size_t *l); 59 | LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); 60 | LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); 61 | 62 | LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); 63 | LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, 64 | lua_Integer def); 65 | 66 | LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); 67 | LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); 68 | LUALIB_API void (luaL_checkany) (lua_State *L, int arg); 69 | 70 | LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); 71 | LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); 72 | LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); 73 | LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); 74 | 75 | LUALIB_API void (luaL_where) (lua_State *L, int lvl); 76 | LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); 77 | 78 | LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, 79 | const char *const lst[]); 80 | 81 | LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); 82 | LUALIB_API int (luaL_execresult) (lua_State *L, int stat); 83 | 84 | 85 | /* predefined references */ 86 | #define LUA_NOREF (-2) 87 | #define LUA_REFNIL (-1) 88 | 89 | LUALIB_API int (luaL_ref) (lua_State *L, int t); 90 | LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); 91 | 92 | LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, 93 | const char *mode); 94 | 95 | #define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) 96 | 97 | LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, 98 | const char *name, const char *mode); 99 | LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); 100 | 101 | LUALIB_API lua_State *(luaL_newstate) (void); 102 | 103 | LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); 104 | 105 | LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, 106 | const char *p, const char *r); 107 | LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, 108 | const char *p, const char *r); 109 | 110 | LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); 111 | 112 | LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); 113 | 114 | LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, 115 | const char *msg, int level); 116 | 117 | LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, 118 | lua_CFunction openf, int glb); 119 | 120 | /* 121 | ** =============================================================== 122 | ** some useful macros 123 | ** =============================================================== 124 | */ 125 | 126 | 127 | #define luaL_newlibtable(L,l) \ 128 | lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) 129 | 130 | #define luaL_newlib(L,l) \ 131 | (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) 132 | 133 | #define luaL_argcheck(L, cond,arg,extramsg) \ 134 | ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) 135 | 136 | #define luaL_argexpected(L,cond,arg,tname) \ 137 | ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname)))) 138 | 139 | #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) 140 | #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) 141 | 142 | #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) 143 | 144 | #define luaL_dofile(L, fn) \ 145 | (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) 146 | 147 | #define luaL_dostring(L, s) \ 148 | (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) 149 | 150 | #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) 151 | 152 | #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) 153 | 154 | #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) 155 | 156 | 157 | /* 158 | ** Perform arithmetic operations on lua_Integer values with wrap-around 159 | ** semantics, as the Lua core does. 160 | */ 161 | #define luaL_intop(op,v1,v2) \ 162 | ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2))) 163 | 164 | 165 | /* push the value used to represent failure/error */ 166 | #define luaL_pushfail(L) lua_pushnil(L) 167 | 168 | 169 | /* 170 | ** Internal assertions for in-house debugging 171 | */ 172 | #if !defined(lua_assert) 173 | 174 | #if defined LUAI_ASSERT 175 | #include 176 | #define lua_assert(c) assert(c) 177 | #else 178 | #define lua_assert(c) ((void)0) 179 | #endif 180 | 181 | #endif 182 | 183 | 184 | 185 | /* 186 | ** {====================================================== 187 | ** Generic Buffer manipulation 188 | ** ======================================================= 189 | */ 190 | 191 | struct luaL_Buffer { 192 | char *b; /* buffer address */ 193 | size_t size; /* buffer size */ 194 | size_t n; /* number of characters in buffer */ 195 | lua_State *L; 196 | union { 197 | LUAI_MAXALIGN; /* ensure maximum alignment for buffer */ 198 | char b[LUAL_BUFFERSIZE]; /* initial buffer */ 199 | } init; 200 | }; 201 | 202 | 203 | #define luaL_bufflen(bf) ((bf)->n) 204 | #define luaL_buffaddr(bf) ((bf)->b) 205 | 206 | 207 | #define luaL_addchar(B,c) \ 208 | ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ 209 | ((B)->b[(B)->n++] = (c))) 210 | 211 | #define luaL_addsize(B,s) ((B)->n += (s)) 212 | 213 | #define luaL_buffsub(B,s) ((B)->n -= (s)) 214 | 215 | LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); 216 | LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); 217 | LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); 218 | LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); 219 | LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); 220 | LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); 221 | LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); 222 | LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); 223 | 224 | #define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) 225 | 226 | /* }====================================================== */ 227 | 228 | 229 | 230 | /* 231 | ** {====================================================== 232 | ** File handles for IO library 233 | ** ======================================================= 234 | */ 235 | 236 | /* 237 | ** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and 238 | ** initial structure 'luaL_Stream' (it may contain other fields 239 | ** after that initial structure). 240 | */ 241 | 242 | #define LUA_FILEHANDLE "FILE*" 243 | 244 | 245 | typedef struct luaL_Stream { 246 | FILE *f; /* stream (NULL for incompletely created streams) */ 247 | lua_CFunction closef; /* to close stream (NULL for closed streams) */ 248 | } luaL_Stream; 249 | 250 | /* }====================================================== */ 251 | 252 | /* 253 | ** {================================================================== 254 | ** "Abstraction Layer" for basic report of messages and errors 255 | ** =================================================================== 256 | */ 257 | 258 | /* print a string */ 259 | #if !defined(lua_writestring) 260 | #define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) 261 | #endif 262 | 263 | /* print a newline and flush the output */ 264 | #if !defined(lua_writeline) 265 | #define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) 266 | #endif 267 | 268 | /* print an error message */ 269 | #if !defined(lua_writestringerror) 270 | #define lua_writestringerror(s,p) \ 271 | (fprintf(stderr, (s), (p)), fflush(stderr)) 272 | #endif 273 | 274 | /* }================================================================== */ 275 | 276 | 277 | /* 278 | ** {============================================================ 279 | ** Compatibility with deprecated conversions 280 | ** ============================================================= 281 | */ 282 | #if defined(LUA_COMPAT_APIINTCASTS) 283 | 284 | #define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) 285 | #define luaL_optunsigned(L,a,d) \ 286 | ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) 287 | 288 | #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) 289 | #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) 290 | 291 | #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) 292 | #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) 293 | 294 | #endif 295 | /* }============================================================ */ 296 | 297 | 298 | 299 | #endif 300 | 301 | 302 | -------------------------------------------------------------------------------- /lib/lua.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lua.h $ 3 | ** Lua - A Scripting Language 4 | ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) 5 | ** See Copyright Notice at the end of this file 6 | */ 7 | 8 | 9 | #ifndef lua_h 10 | #define lua_h 11 | 12 | #include 13 | #include 14 | 15 | 16 | #include "luaconf.h" 17 | 18 | 19 | #define LUA_VERSION_MAJOR "5" 20 | #define LUA_VERSION_MINOR "4" 21 | #define LUA_VERSION_RELEASE "6" 22 | 23 | #define LUA_VERSION_NUM 504 24 | #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6) 25 | 26 | #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR 27 | #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE 28 | #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio" 29 | #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" 30 | 31 | 32 | /* mark for precompiled code ('Lua') */ 33 | #define LUA_SIGNATURE "\x1bLua" 34 | 35 | /* option for multiple returns in 'lua_pcall' and 'lua_call' */ 36 | #define LUA_MULTRET (-1) 37 | 38 | 39 | /* 40 | ** Pseudo-indices 41 | ** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty 42 | ** space after that to help overflow detection) 43 | */ 44 | #define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) 45 | #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) 46 | 47 | 48 | /* thread status */ 49 | #define LUA_OK 0 50 | #define LUA_YIELD 1 51 | #define LUA_ERRRUN 2 52 | #define LUA_ERRSYNTAX 3 53 | #define LUA_ERRMEM 4 54 | #define LUA_ERRERR 5 55 | 56 | 57 | typedef struct lua_State lua_State; 58 | 59 | 60 | /* 61 | ** basic types 62 | */ 63 | #define LUA_TNONE (-1) 64 | 65 | #define LUA_TNIL 0 66 | #define LUA_TBOOLEAN 1 67 | #define LUA_TLIGHTUSERDATA 2 68 | #define LUA_TNUMBER 3 69 | #define LUA_TSTRING 4 70 | #define LUA_TTABLE 5 71 | #define LUA_TFUNCTION 6 72 | #define LUA_TUSERDATA 7 73 | #define LUA_TTHREAD 8 74 | 75 | #define LUA_NUMTYPES 9 76 | 77 | 78 | 79 | /* minimum Lua stack available to a C function */ 80 | #define LUA_MINSTACK 20 81 | 82 | 83 | /* predefined values in the registry */ 84 | #define LUA_RIDX_MAINTHREAD 1 85 | #define LUA_RIDX_GLOBALS 2 86 | #define LUA_RIDX_LAST LUA_RIDX_GLOBALS 87 | 88 | 89 | /* type of numbers in Lua */ 90 | typedef LUA_NUMBER lua_Number; 91 | 92 | 93 | /* type for integer functions */ 94 | typedef LUA_INTEGER lua_Integer; 95 | 96 | /* unsigned integer type */ 97 | typedef LUA_UNSIGNED lua_Unsigned; 98 | 99 | /* type for continuation-function contexts */ 100 | typedef LUA_KCONTEXT lua_KContext; 101 | 102 | 103 | /* 104 | ** Type for C functions registered with Lua 105 | */ 106 | typedef int (*lua_CFunction) (lua_State *L); 107 | 108 | /* 109 | ** Type for continuation functions 110 | */ 111 | typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); 112 | 113 | 114 | /* 115 | ** Type for functions that read/write blocks when loading/dumping Lua chunks 116 | */ 117 | typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); 118 | 119 | typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); 120 | 121 | 122 | /* 123 | ** Type for memory-allocation functions 124 | */ 125 | typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); 126 | 127 | 128 | /* 129 | ** Type for warning functions 130 | */ 131 | typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); 132 | 133 | 134 | /* 135 | ** Type used by the debug API to collect debug information 136 | */ 137 | typedef struct lua_Debug lua_Debug; 138 | 139 | 140 | /* 141 | ** Functions to be called by the debugger in specific events 142 | */ 143 | typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); 144 | 145 | 146 | /* 147 | ** generic extra include file 148 | */ 149 | #if defined(LUA_USER_H) 150 | #include LUA_USER_H 151 | #endif 152 | 153 | 154 | /* 155 | ** RCS ident string 156 | */ 157 | extern const char lua_ident[]; 158 | 159 | 160 | /* 161 | ** state manipulation 162 | */ 163 | LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); 164 | LUA_API void (lua_close) (lua_State *L); 165 | LUA_API lua_State *(lua_newthread) (lua_State *L); 166 | LUA_API int (lua_closethread) (lua_State *L, lua_State *from); 167 | LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */ 168 | 169 | LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); 170 | 171 | 172 | LUA_API lua_Number (lua_version) (lua_State *L); 173 | 174 | 175 | /* 176 | ** basic stack manipulation 177 | */ 178 | LUA_API int (lua_absindex) (lua_State *L, int idx); 179 | LUA_API int (lua_gettop) (lua_State *L); 180 | LUA_API void (lua_settop) (lua_State *L, int idx); 181 | LUA_API void (lua_pushvalue) (lua_State *L, int idx); 182 | LUA_API void (lua_rotate) (lua_State *L, int idx, int n); 183 | LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); 184 | LUA_API int (lua_checkstack) (lua_State *L, int n); 185 | 186 | LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); 187 | 188 | 189 | /* 190 | ** access functions (stack -> C) 191 | */ 192 | 193 | LUA_API int (lua_isnumber) (lua_State *L, int idx); 194 | LUA_API int (lua_isstring) (lua_State *L, int idx); 195 | LUA_API int (lua_iscfunction) (lua_State *L, int idx); 196 | LUA_API int (lua_isinteger) (lua_State *L, int idx); 197 | LUA_API int (lua_isuserdata) (lua_State *L, int idx); 198 | LUA_API int (lua_type) (lua_State *L, int idx); 199 | LUA_API const char *(lua_typename) (lua_State *L, int tp); 200 | 201 | LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); 202 | LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); 203 | LUA_API int (lua_toboolean) (lua_State *L, int idx); 204 | LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); 205 | LUA_API lua_Unsigned (lua_rawlen) (lua_State *L, int idx); 206 | LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); 207 | LUA_API void *(lua_touserdata) (lua_State *L, int idx); 208 | LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); 209 | LUA_API const void *(lua_topointer) (lua_State *L, int idx); 210 | 211 | 212 | /* 213 | ** Comparison and arithmetic functions 214 | */ 215 | 216 | #define LUA_OPADD 0 /* ORDER TM, ORDER OP */ 217 | #define LUA_OPSUB 1 218 | #define LUA_OPMUL 2 219 | #define LUA_OPMOD 3 220 | #define LUA_OPPOW 4 221 | #define LUA_OPDIV 5 222 | #define LUA_OPIDIV 6 223 | #define LUA_OPBAND 7 224 | #define LUA_OPBOR 8 225 | #define LUA_OPBXOR 9 226 | #define LUA_OPSHL 10 227 | #define LUA_OPSHR 11 228 | #define LUA_OPUNM 12 229 | #define LUA_OPBNOT 13 230 | 231 | LUA_API void (lua_arith) (lua_State *L, int op); 232 | 233 | #define LUA_OPEQ 0 234 | #define LUA_OPLT 1 235 | #define LUA_OPLE 2 236 | 237 | LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); 238 | LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); 239 | 240 | 241 | /* 242 | ** push functions (C -> stack) 243 | */ 244 | LUA_API void (lua_pushnil) (lua_State *L); 245 | LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); 246 | LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); 247 | LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); 248 | LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); 249 | LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, 250 | va_list argp); 251 | LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); 252 | LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); 253 | LUA_API void (lua_pushboolean) (lua_State *L, int b); 254 | LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); 255 | LUA_API int (lua_pushthread) (lua_State *L); 256 | 257 | 258 | /* 259 | ** get functions (Lua -> stack) 260 | */ 261 | LUA_API int (lua_getglobal) (lua_State *L, const char *name); 262 | LUA_API int (lua_gettable) (lua_State *L, int idx); 263 | LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); 264 | LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); 265 | LUA_API int (lua_rawget) (lua_State *L, int idx); 266 | LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); 267 | LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); 268 | 269 | LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); 270 | LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); 271 | LUA_API int (lua_getmetatable) (lua_State *L, int objindex); 272 | LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n); 273 | 274 | 275 | /* 276 | ** set functions (stack -> Lua) 277 | */ 278 | LUA_API void (lua_setglobal) (lua_State *L, const char *name); 279 | LUA_API void (lua_settable) (lua_State *L, int idx); 280 | LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); 281 | LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); 282 | LUA_API void (lua_rawset) (lua_State *L, int idx); 283 | LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); 284 | LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); 285 | LUA_API int (lua_setmetatable) (lua_State *L, int objindex); 286 | LUA_API int (lua_setiuservalue) (lua_State *L, int idx, int n); 287 | 288 | 289 | /* 290 | ** 'load' and 'call' functions (load and run Lua code) 291 | */ 292 | LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, 293 | lua_KContext ctx, lua_KFunction k); 294 | #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) 295 | 296 | LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, 297 | lua_KContext ctx, lua_KFunction k); 298 | #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) 299 | 300 | LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, 301 | const char *chunkname, const char *mode); 302 | 303 | LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); 304 | 305 | 306 | /* 307 | ** coroutine functions 308 | */ 309 | LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, 310 | lua_KFunction k); 311 | LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg, 312 | int *nres); 313 | LUA_API int (lua_status) (lua_State *L); 314 | LUA_API int (lua_isyieldable) (lua_State *L); 315 | 316 | #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) 317 | 318 | 319 | /* 320 | ** Warning-related functions 321 | */ 322 | LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); 323 | LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont); 324 | 325 | 326 | /* 327 | ** garbage-collection function and options 328 | */ 329 | 330 | #define LUA_GCSTOP 0 331 | #define LUA_GCRESTART 1 332 | #define LUA_GCCOLLECT 2 333 | #define LUA_GCCOUNT 3 334 | #define LUA_GCCOUNTB 4 335 | #define LUA_GCSTEP 5 336 | #define LUA_GCSETPAUSE 6 337 | #define LUA_GCSETSTEPMUL 7 338 | #define LUA_GCISRUNNING 9 339 | #define LUA_GCGEN 10 340 | #define LUA_GCINC 11 341 | 342 | LUA_API int (lua_gc) (lua_State *L, int what, ...); 343 | 344 | 345 | /* 346 | ** miscellaneous functions 347 | */ 348 | 349 | LUA_API int (lua_error) (lua_State *L); 350 | 351 | LUA_API int (lua_next) (lua_State *L, int idx); 352 | 353 | LUA_API void (lua_concat) (lua_State *L, int n); 354 | LUA_API void (lua_len) (lua_State *L, int idx); 355 | 356 | LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); 357 | 358 | LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); 359 | LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); 360 | 361 | LUA_API void (lua_toclose) (lua_State *L, int idx); 362 | LUA_API void (lua_closeslot) (lua_State *L, int idx); 363 | 364 | 365 | /* 366 | ** {============================================================== 367 | ** some useful macros 368 | ** =============================================================== 369 | */ 370 | 371 | #define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) 372 | 373 | #define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) 374 | #define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) 375 | 376 | #define lua_pop(L,n) lua_settop(L, -(n)-1) 377 | 378 | #define lua_newtable(L) lua_createtable(L, 0, 0) 379 | 380 | #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) 381 | 382 | #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) 383 | 384 | #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) 385 | #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) 386 | #define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) 387 | #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) 388 | #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) 389 | #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) 390 | #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) 391 | #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) 392 | 393 | #define lua_pushliteral(L, s) lua_pushstring(L, "" s) 394 | 395 | #define lua_pushglobaltable(L) \ 396 | ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) 397 | 398 | #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) 399 | 400 | 401 | #define lua_insert(L,idx) lua_rotate(L, (idx), 1) 402 | 403 | #define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) 404 | 405 | #define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) 406 | 407 | /* }============================================================== */ 408 | 409 | 410 | /* 411 | ** {============================================================== 412 | ** compatibility macros 413 | ** =============================================================== 414 | */ 415 | #if defined(LUA_COMPAT_APIINTCASTS) 416 | 417 | #define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) 418 | #define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) 419 | #define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) 420 | 421 | #endif 422 | 423 | #define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1) 424 | #define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1) 425 | #define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1) 426 | 427 | #define LUA_NUMTAGS LUA_NUMTYPES 428 | 429 | /* }============================================================== */ 430 | 431 | /* 432 | ** {====================================================================== 433 | ** Debug API 434 | ** ======================================================================= 435 | */ 436 | 437 | 438 | /* 439 | ** Event codes 440 | */ 441 | #define LUA_HOOKCALL 0 442 | #define LUA_HOOKRET 1 443 | #define LUA_HOOKLINE 2 444 | #define LUA_HOOKCOUNT 3 445 | #define LUA_HOOKTAILCALL 4 446 | 447 | 448 | /* 449 | ** Event masks 450 | */ 451 | #define LUA_MASKCALL (1 << LUA_HOOKCALL) 452 | #define LUA_MASKRET (1 << LUA_HOOKRET) 453 | #define LUA_MASKLINE (1 << LUA_HOOKLINE) 454 | #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) 455 | 456 | 457 | LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); 458 | LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); 459 | LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); 460 | LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); 461 | LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); 462 | LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); 463 | 464 | LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); 465 | LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, 466 | int fidx2, int n2); 467 | 468 | LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); 469 | LUA_API lua_Hook (lua_gethook) (lua_State *L); 470 | LUA_API int (lua_gethookmask) (lua_State *L); 471 | LUA_API int (lua_gethookcount) (lua_State *L); 472 | 473 | LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit); 474 | 475 | struct lua_Debug { 476 | int event; 477 | const char *name; /* (n) */ 478 | const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ 479 | const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ 480 | const char *source; /* (S) */ 481 | size_t srclen; /* (S) */ 482 | int currentline; /* (l) */ 483 | int linedefined; /* (S) */ 484 | int lastlinedefined; /* (S) */ 485 | unsigned char nups; /* (u) number of upvalues */ 486 | unsigned char nparams;/* (u) number of parameters */ 487 | char isvararg; /* (u) */ 488 | char istailcall; /* (t) */ 489 | unsigned short ftransfer; /* (r) index of first value transferred */ 490 | unsigned short ntransfer; /* (r) number of transferred values */ 491 | char short_src[LUA_IDSIZE]; /* (S) */ 492 | /* private part */ 493 | struct CallInfo *i_ci; /* active function */ 494 | }; 495 | 496 | /* }====================================================================== */ 497 | 498 | 499 | /****************************************************************************** 500 | * Copyright (C) 1994-2023 Lua.org, PUC-Rio. 501 | * 502 | * Permission is hereby granted, free of charge, to any person obtaining 503 | * a copy of this software and associated documentation files (the 504 | * "Software"), to deal in the Software without restriction, including 505 | * without limitation the rights to use, copy, modify, merge, publish, 506 | * distribute, sublicense, and/or sell copies of the Software, and to 507 | * permit persons to whom the Software is furnished to do so, subject to 508 | * the following conditions: 509 | * 510 | * The above copyright notice and this permission notice shall be 511 | * included in all copies or substantial portions of the Software. 512 | * 513 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 514 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 515 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 516 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 517 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 518 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 519 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 520 | ******************************************************************************/ 521 | 522 | 523 | #endif 524 | -------------------------------------------------------------------------------- /lib/lua54.def: -------------------------------------------------------------------------------- 1 | LIBRARY lua54.dll 2 | 3 | EXPORTS 4 | luaL_addgsub 5 | luaL_addlstring 6 | luaL_addstring 7 | luaL_addvalue 8 | luaL_argerror 9 | luaL_buffinit 10 | luaL_buffinitsize 11 | luaL_callmeta 12 | luaL_checkany 13 | luaL_checkinteger 14 | luaL_checklstring 15 | luaL_checknumber 16 | luaL_checkoption 17 | luaL_checkstack 18 | luaL_checktype 19 | luaL_checkudata 20 | luaL_checkversion_ 21 | luaL_error 22 | luaL_execresult 23 | luaL_fileresult 24 | luaL_getmetafield 25 | luaL_getsubtable 26 | luaL_gsub 27 | luaL_len 28 | luaL_loadbufferx 29 | luaL_loadfilex 30 | luaL_loadstring 31 | luaL_newmetatable 32 | luaL_newstate 33 | luaL_openlibs 34 | luaL_optinteger 35 | luaL_optlstring 36 | luaL_optnumber 37 | luaL_prepbuffsize 38 | luaL_pushresult 39 | luaL_pushresultsize 40 | luaL_ref 41 | luaL_requiref 42 | luaL_setfuncs 43 | luaL_setmetatable 44 | luaL_testudata 45 | luaL_tolstring 46 | luaL_traceback 47 | luaL_typeerror 48 | luaL_unref 49 | luaL_where 50 | lua_absindex 51 | lua_arith 52 | lua_atpanic 53 | lua_callk 54 | lua_checkstack 55 | lua_close 56 | lua_closeslot 57 | lua_closethread 58 | lua_compare 59 | lua_concat 60 | lua_copy 61 | lua_createtable 62 | lua_dump 63 | lua_error 64 | lua_gc 65 | lua_getallocf 66 | lua_getfield 67 | lua_getglobal 68 | lua_gethook 69 | lua_gethookcount 70 | lua_gethookmask 71 | lua_geti 72 | lua_getinfo 73 | lua_getiuservalue 74 | lua_getlocal 75 | lua_getmetatable 76 | lua_getstack 77 | lua_gettable 78 | lua_gettop 79 | lua_getupvalue 80 | lua_iscfunction 81 | lua_isinteger 82 | lua_isnumber 83 | lua_isstring 84 | lua_isuserdata 85 | lua_isyieldable 86 | lua_len 87 | lua_load 88 | lua_newstate 89 | lua_newthread 90 | lua_newuserdatauv 91 | lua_next 92 | lua_pcallk 93 | lua_pushboolean 94 | lua_pushcclosure 95 | lua_pushfstring 96 | lua_pushinteger 97 | lua_pushlightuserdata 98 | lua_pushlstring 99 | lua_pushnil 100 | lua_pushnumber 101 | lua_pushstring 102 | lua_pushthread 103 | lua_pushvalue 104 | lua_pushvfstring 105 | lua_rawequal 106 | lua_rawget 107 | lua_rawgeti 108 | lua_rawgetp 109 | lua_rawlen 110 | lua_rawset 111 | lua_rawseti 112 | lua_rawsetp 113 | lua_resetthread 114 | lua_resume 115 | lua_rotate 116 | lua_setallocf 117 | lua_setcstacklimit 118 | lua_setfield 119 | lua_setglobal 120 | lua_sethook 121 | lua_seti 122 | lua_setiuservalue 123 | lua_setlocal 124 | lua_setmetatable 125 | lua_settable 126 | lua_settop 127 | lua_setupvalue 128 | lua_setwarnf 129 | lua_status 130 | lua_stringtonumber 131 | lua_toboolean 132 | lua_tocfunction 133 | lua_toclose 134 | lua_tointegerx 135 | lua_tolstring 136 | lua_tonumberx 137 | lua_topointer 138 | lua_tothread 139 | lua_touserdata 140 | lua_type 141 | lua_typename 142 | lua_upvalueid 143 | lua_upvaluejoin 144 | lua_version 145 | lua_warning 146 | lua_xmove 147 | lua_yieldk 148 | luaopen_base 149 | luaopen_coroutine 150 | luaopen_debug 151 | luaopen_io 152 | luaopen_math 153 | luaopen_os 154 | luaopen_package 155 | luaopen_string 156 | luaopen_table 157 | luaopen_utf8 158 | -------------------------------------------------------------------------------- /lib/lua54.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pavel212/uffi/11967d07e0fcb2ca8758b410dbae2702a812893e/lib/lua54.lib -------------------------------------------------------------------------------- /lib/luaconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: luaconf.h $ 3 | ** Configuration file for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef luaconf_h 9 | #define luaconf_h 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | ** =================================================================== 17 | ** General Configuration File for Lua 18 | ** 19 | ** Some definitions here can be changed externally, through the compiler 20 | ** (e.g., with '-D' options): They are commented out or protected 21 | ** by '#if !defined' guards. However, several other definitions 22 | ** should be changed directly here, either because they affect the 23 | ** Lua ABI (by making the changes here, you ensure that all software 24 | ** connected to Lua, such as C libraries, will be compiled with the same 25 | ** configuration); or because they are seldom changed. 26 | ** 27 | ** Search for "@@" to find all configurable definitions. 28 | ** =================================================================== 29 | */ 30 | 31 | 32 | /* 33 | ** {==================================================================== 34 | ** System Configuration: macros to adapt (if needed) Lua to some 35 | ** particular platform, for instance restricting it to C89. 36 | ** ===================================================================== 37 | */ 38 | 39 | /* 40 | @@ LUA_USE_C89 controls the use of non-ISO-C89 features. 41 | ** Define it if you want Lua to avoid the use of a few C99 features 42 | ** or Windows-specific features on Windows. 43 | */ 44 | /* #define LUA_USE_C89 */ 45 | 46 | 47 | /* 48 | ** By default, Lua on Windows use (some) specific Windows features 49 | */ 50 | #if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) 51 | #define LUA_USE_WINDOWS /* enable goodies for regular Windows */ 52 | #endif 53 | 54 | 55 | #if defined(LUA_USE_WINDOWS) 56 | #define LUA_DL_DLL /* enable support for DLL */ 57 | #define LUA_USE_C89 /* broadly, Windows is C89 */ 58 | #endif 59 | 60 | 61 | #if defined(LUA_USE_LINUX) 62 | #define LUA_USE_POSIX 63 | #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ 64 | #endif 65 | 66 | 67 | #if defined(LUA_USE_MACOSX) 68 | #define LUA_USE_POSIX 69 | #define LUA_USE_DLOPEN /* MacOS does not need -ldl */ 70 | #endif 71 | 72 | 73 | #if defined(LUA_USE_IOS) 74 | #define LUA_USE_POSIX 75 | #define LUA_USE_DLOPEN 76 | #endif 77 | 78 | 79 | /* 80 | @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. 81 | */ 82 | #define LUAI_IS32INT ((UINT_MAX >> 30) >= 3) 83 | 84 | /* }================================================================== */ 85 | 86 | 87 | 88 | /* 89 | ** {================================================================== 90 | ** Configuration for Number types. These options should not be 91 | ** set externally, because any other code connected to Lua must 92 | ** use the same configuration. 93 | ** =================================================================== 94 | */ 95 | 96 | /* 97 | @@ LUA_INT_TYPE defines the type for Lua integers. 98 | @@ LUA_FLOAT_TYPE defines the type for Lua floats. 99 | ** Lua should work fine with any mix of these options supported 100 | ** by your C compiler. The usual configurations are 64-bit integers 101 | ** and 'double' (the default), 32-bit integers and 'float' (for 102 | ** restricted platforms), and 'long'/'double' (for C compilers not 103 | ** compliant with C99, which may not have support for 'long long'). 104 | */ 105 | 106 | /* predefined options for LUA_INT_TYPE */ 107 | #define LUA_INT_INT 1 108 | #define LUA_INT_LONG 2 109 | #define LUA_INT_LONGLONG 3 110 | 111 | /* predefined options for LUA_FLOAT_TYPE */ 112 | #define LUA_FLOAT_FLOAT 1 113 | #define LUA_FLOAT_DOUBLE 2 114 | #define LUA_FLOAT_LONGDOUBLE 3 115 | 116 | 117 | /* Default configuration ('long long' and 'double', for 64-bit Lua) */ 118 | #define LUA_INT_DEFAULT LUA_INT_LONGLONG 119 | #define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE 120 | 121 | 122 | /* 123 | @@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. 124 | */ 125 | #define LUA_32BITS 0 126 | 127 | 128 | /* 129 | @@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for 130 | ** C89 ('long' and 'double'); Windows always has '__int64', so it does 131 | ** not need to use this case. 132 | */ 133 | #if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) 134 | #define LUA_C89_NUMBERS 1 135 | #else 136 | #define LUA_C89_NUMBERS 0 137 | #endif 138 | 139 | 140 | #if LUA_32BITS /* { */ 141 | /* 142 | ** 32-bit integers and 'float' 143 | */ 144 | #if LUAI_IS32INT /* use 'int' if big enough */ 145 | #define LUA_INT_TYPE LUA_INT_INT 146 | #else /* otherwise use 'long' */ 147 | #define LUA_INT_TYPE LUA_INT_LONG 148 | #endif 149 | #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT 150 | 151 | #elif LUA_C89_NUMBERS /* }{ */ 152 | /* 153 | ** largest types available for C89 ('long' and 'double') 154 | */ 155 | #define LUA_INT_TYPE LUA_INT_LONG 156 | #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE 157 | 158 | #else /* }{ */ 159 | /* use defaults */ 160 | 161 | #define LUA_INT_TYPE LUA_INT_DEFAULT 162 | #define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT 163 | 164 | #endif /* } */ 165 | 166 | 167 | /* }================================================================== */ 168 | 169 | 170 | 171 | /* 172 | ** {================================================================== 173 | ** Configuration for Paths. 174 | ** =================================================================== 175 | */ 176 | 177 | /* 178 | ** LUA_PATH_SEP is the character that separates templates in a path. 179 | ** LUA_PATH_MARK is the string that marks the substitution points in a 180 | ** template. 181 | ** LUA_EXEC_DIR in a Windows path is replaced by the executable's 182 | ** directory. 183 | */ 184 | #define LUA_PATH_SEP ";" 185 | #define LUA_PATH_MARK "?" 186 | #define LUA_EXEC_DIR "!" 187 | 188 | 189 | /* 190 | @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for 191 | ** Lua libraries. 192 | @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for 193 | ** C libraries. 194 | ** CHANGE them if your machine has a non-conventional directory 195 | ** hierarchy or if you want to install your libraries in 196 | ** non-conventional directories. 197 | */ 198 | 199 | #define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR 200 | #if defined(_WIN32) /* { */ 201 | /* 202 | ** In Windows, any exclamation mark ('!') in the path is replaced by the 203 | ** path of the directory of the executable file of the current process. 204 | */ 205 | #define LUA_LDIR "!\\lua\\" 206 | #define LUA_CDIR "!\\" 207 | #define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" 208 | 209 | #if !defined(LUA_PATH_DEFAULT) 210 | #define LUA_PATH_DEFAULT \ 211 | LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ 212 | LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ 213 | LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ 214 | ".\\?.lua;" ".\\?\\init.lua" 215 | #endif 216 | 217 | #if !defined(LUA_CPATH_DEFAULT) 218 | #define LUA_CPATH_DEFAULT \ 219 | LUA_CDIR"?.dll;" \ 220 | LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ 221 | LUA_CDIR"loadall.dll;" ".\\?.dll" 222 | #endif 223 | 224 | #else /* }{ */ 225 | 226 | #define LUA_ROOT "/usr/local/" 227 | #define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" 228 | #define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" 229 | 230 | #if !defined(LUA_PATH_DEFAULT) 231 | #define LUA_PATH_DEFAULT \ 232 | LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ 233 | LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ 234 | "./?.lua;" "./?/init.lua" 235 | #endif 236 | 237 | #if !defined(LUA_CPATH_DEFAULT) 238 | #define LUA_CPATH_DEFAULT \ 239 | LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" 240 | #endif 241 | 242 | #endif /* } */ 243 | 244 | 245 | /* 246 | @@ LUA_DIRSEP is the directory separator (for submodules). 247 | ** CHANGE it if your machine does not use "/" as the directory separator 248 | ** and is not Windows. (On Windows Lua automatically uses "\".) 249 | */ 250 | #if !defined(LUA_DIRSEP) 251 | 252 | #if defined(_WIN32) 253 | #define LUA_DIRSEP "\\" 254 | #else 255 | #define LUA_DIRSEP "/" 256 | #endif 257 | 258 | #endif 259 | 260 | /* }================================================================== */ 261 | 262 | 263 | /* 264 | ** {================================================================== 265 | ** Marks for exported symbols in the C code 266 | ** =================================================================== 267 | */ 268 | 269 | /* 270 | @@ LUA_API is a mark for all core API functions. 271 | @@ LUALIB_API is a mark for all auxiliary library functions. 272 | @@ LUAMOD_API is a mark for all standard library opening functions. 273 | ** CHANGE them if you need to define those functions in some special way. 274 | ** For instance, if you want to create one Windows DLL with the core and 275 | ** the libraries, you may want to use the following definition (define 276 | ** LUA_BUILD_AS_DLL to get it). 277 | */ 278 | #if defined(LUA_BUILD_AS_DLL) /* { */ 279 | 280 | #if defined(LUA_CORE) || defined(LUA_LIB) /* { */ 281 | #define LUA_API __declspec(dllexport) 282 | #else /* }{ */ 283 | #define LUA_API __declspec(dllimport) 284 | #endif /* } */ 285 | 286 | #else /* }{ */ 287 | 288 | #define LUA_API extern 289 | 290 | #endif /* } */ 291 | 292 | 293 | /* 294 | ** More often than not the libs go together with the core. 295 | */ 296 | #define LUALIB_API LUA_API 297 | #define LUAMOD_API LUA_API 298 | 299 | 300 | /* 301 | @@ LUAI_FUNC is a mark for all extern functions that are not to be 302 | ** exported to outside modules. 303 | @@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables, 304 | ** none of which to be exported to outside modules (LUAI_DDEF for 305 | ** definitions and LUAI_DDEC for declarations). 306 | ** CHANGE them if you need to mark them in some special way. Elf/gcc 307 | ** (versions 3.2 and later) mark them as "hidden" to optimize access 308 | ** when Lua is compiled as a shared library. Not all elf targets support 309 | ** this attribute. Unfortunately, gcc does not offer a way to check 310 | ** whether the target offers that support, and those without support 311 | ** give a warning about it. To avoid these warnings, change to the 312 | ** default definition. 313 | */ 314 | #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ 315 | defined(__ELF__) /* { */ 316 | #define LUAI_FUNC __attribute__((visibility("internal"))) extern 317 | #else /* }{ */ 318 | #define LUAI_FUNC extern 319 | #endif /* } */ 320 | 321 | #define LUAI_DDEC(dec) LUAI_FUNC dec 322 | #define LUAI_DDEF /* empty */ 323 | 324 | /* }================================================================== */ 325 | 326 | 327 | /* 328 | ** {================================================================== 329 | ** Compatibility with previous versions 330 | ** =================================================================== 331 | */ 332 | 333 | /* 334 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. 335 | ** You can define it to get all options, or change specific options 336 | ** to fit your specific needs. 337 | */ 338 | #if defined(LUA_COMPAT_5_3) /* { */ 339 | 340 | /* 341 | @@ LUA_COMPAT_MATHLIB controls the presence of several deprecated 342 | ** functions in the mathematical library. 343 | ** (These functions were already officially removed in 5.3; 344 | ** nevertheless they are still available here.) 345 | */ 346 | #define LUA_COMPAT_MATHLIB 347 | 348 | /* 349 | @@ LUA_COMPAT_APIINTCASTS controls the presence of macros for 350 | ** manipulating other integer types (lua_pushunsigned, lua_tounsigned, 351 | ** luaL_checkint, luaL_checklong, etc.) 352 | ** (These macros were also officially removed in 5.3, but they are still 353 | ** available here.) 354 | */ 355 | #define LUA_COMPAT_APIINTCASTS 356 | 357 | 358 | /* 359 | @@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod 360 | ** using '__lt'. 361 | */ 362 | #define LUA_COMPAT_LT_LE 363 | 364 | 365 | /* 366 | @@ The following macros supply trivial compatibility for some 367 | ** changes in the API. The macros themselves document how to 368 | ** change your code to avoid using them. 369 | ** (Once more, these macros were officially removed in 5.3, but they are 370 | ** still available here.) 371 | */ 372 | #define lua_strlen(L,i) lua_rawlen(L, (i)) 373 | 374 | #define lua_objlen(L,i) lua_rawlen(L, (i)) 375 | 376 | #define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) 377 | #define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) 378 | 379 | #endif /* } */ 380 | 381 | /* }================================================================== */ 382 | 383 | 384 | 385 | /* 386 | ** {================================================================== 387 | ** Configuration for Numbers (low-level part). 388 | ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* 389 | ** satisfy your needs. 390 | ** =================================================================== 391 | */ 392 | 393 | /* 394 | @@ LUAI_UACNUMBER is the result of a 'default argument promotion' 395 | @@ over a floating number. 396 | @@ l_floatatt(x) corrects float attribute 'x' to the proper float type 397 | ** by prefixing it with one of FLT/DBL/LDBL. 398 | @@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. 399 | @@ LUA_NUMBER_FMT is the format for writing floats. 400 | @@ lua_number2str converts a float to a string. 401 | @@ l_mathop allows the addition of an 'l' or 'f' to all math operations. 402 | @@ l_floor takes the floor of a float. 403 | @@ lua_str2number converts a decimal numeral to a number. 404 | */ 405 | 406 | 407 | /* The following definitions are good for most cases here */ 408 | 409 | #define l_floor(x) (l_mathop(floor)(x)) 410 | 411 | #define lua_number2str(s,sz,n) \ 412 | l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n)) 413 | 414 | /* 415 | @@ lua_numbertointeger converts a float number with an integral value 416 | ** to an integer, or returns 0 if float is not within the range of 417 | ** a lua_Integer. (The range comparisons are tricky because of 418 | ** rounding. The tests here assume a two-complement representation, 419 | ** where MININTEGER always has an exact representation as a float; 420 | ** MAXINTEGER may not have one, and therefore its conversion to float 421 | ** may have an ill-defined value.) 422 | */ 423 | #define lua_numbertointeger(n,p) \ 424 | ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ 425 | (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ 426 | (*(p) = (LUA_INTEGER)(n), 1)) 427 | 428 | 429 | /* now the variable definitions */ 430 | 431 | #if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ 432 | 433 | #define LUA_NUMBER float 434 | 435 | #define l_floatatt(n) (FLT_##n) 436 | 437 | #define LUAI_UACNUMBER double 438 | 439 | #define LUA_NUMBER_FRMLEN "" 440 | #define LUA_NUMBER_FMT "%.7g" 441 | 442 | #define l_mathop(op) op##f 443 | 444 | #define lua_str2number(s,p) strtof((s), (p)) 445 | 446 | 447 | #elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ 448 | 449 | #define LUA_NUMBER long double 450 | 451 | #define l_floatatt(n) (LDBL_##n) 452 | 453 | #define LUAI_UACNUMBER long double 454 | 455 | #define LUA_NUMBER_FRMLEN "L" 456 | #define LUA_NUMBER_FMT "%.19Lg" 457 | 458 | #define l_mathop(op) op##l 459 | 460 | #define lua_str2number(s,p) strtold((s), (p)) 461 | 462 | #elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ 463 | 464 | #define LUA_NUMBER double 465 | 466 | #define l_floatatt(n) (DBL_##n) 467 | 468 | #define LUAI_UACNUMBER double 469 | 470 | #define LUA_NUMBER_FRMLEN "" 471 | #define LUA_NUMBER_FMT "%.14g" 472 | 473 | #define l_mathop(op) op 474 | 475 | #define lua_str2number(s,p) strtod((s), (p)) 476 | 477 | #else /* }{ */ 478 | 479 | #error "numeric float type not defined" 480 | 481 | #endif /* } */ 482 | 483 | 484 | 485 | /* 486 | @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. 487 | @@ LUAI_UACINT is the result of a 'default argument promotion' 488 | @@ over a LUA_INTEGER. 489 | @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. 490 | @@ LUA_INTEGER_FMT is the format for writing integers. 491 | @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. 492 | @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. 493 | @@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. 494 | @@ lua_integer2str converts an integer to a string. 495 | */ 496 | 497 | 498 | /* The following definitions are good for most cases here */ 499 | 500 | #define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" 501 | 502 | #define LUAI_UACINT LUA_INTEGER 503 | 504 | #define lua_integer2str(s,sz,n) \ 505 | l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) 506 | 507 | /* 508 | ** use LUAI_UACINT here to avoid problems with promotions (which 509 | ** can turn a comparison between unsigneds into a signed comparison) 510 | */ 511 | #define LUA_UNSIGNED unsigned LUAI_UACINT 512 | 513 | 514 | /* now the variable definitions */ 515 | 516 | #if LUA_INT_TYPE == LUA_INT_INT /* { int */ 517 | 518 | #define LUA_INTEGER int 519 | #define LUA_INTEGER_FRMLEN "" 520 | 521 | #define LUA_MAXINTEGER INT_MAX 522 | #define LUA_MININTEGER INT_MIN 523 | 524 | #define LUA_MAXUNSIGNED UINT_MAX 525 | 526 | #elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ 527 | 528 | #define LUA_INTEGER long 529 | #define LUA_INTEGER_FRMLEN "l" 530 | 531 | #define LUA_MAXINTEGER LONG_MAX 532 | #define LUA_MININTEGER LONG_MIN 533 | 534 | #define LUA_MAXUNSIGNED ULONG_MAX 535 | 536 | #elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ 537 | 538 | /* use presence of macro LLONG_MAX as proxy for C99 compliance */ 539 | #if defined(LLONG_MAX) /* { */ 540 | /* use ISO C99 stuff */ 541 | 542 | #define LUA_INTEGER long long 543 | #define LUA_INTEGER_FRMLEN "ll" 544 | 545 | #define LUA_MAXINTEGER LLONG_MAX 546 | #define LUA_MININTEGER LLONG_MIN 547 | 548 | #define LUA_MAXUNSIGNED ULLONG_MAX 549 | 550 | #elif defined(LUA_USE_WINDOWS) /* }{ */ 551 | /* in Windows, can use specific Windows types */ 552 | 553 | #define LUA_INTEGER __int64 554 | #define LUA_INTEGER_FRMLEN "I64" 555 | 556 | #define LUA_MAXINTEGER _I64_MAX 557 | #define LUA_MININTEGER _I64_MIN 558 | 559 | #define LUA_MAXUNSIGNED _UI64_MAX 560 | 561 | #else /* }{ */ 562 | 563 | #error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ 564 | or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" 565 | 566 | #endif /* } */ 567 | 568 | #else /* }{ */ 569 | 570 | #error "numeric integer type not defined" 571 | 572 | #endif /* } */ 573 | 574 | /* }================================================================== */ 575 | 576 | 577 | /* 578 | ** {================================================================== 579 | ** Dependencies with C99 and other C details 580 | ** =================================================================== 581 | */ 582 | 583 | /* 584 | @@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. 585 | ** (All uses in Lua have only one format item.) 586 | */ 587 | #if !defined(LUA_USE_C89) 588 | #define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) 589 | #else 590 | #define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) 591 | #endif 592 | 593 | 594 | /* 595 | @@ lua_strx2number converts a hexadecimal numeral to a number. 596 | ** In C99, 'strtod' does that conversion. Otherwise, you can 597 | ** leave 'lua_strx2number' undefined and Lua will provide its own 598 | ** implementation. 599 | */ 600 | #if !defined(LUA_USE_C89) 601 | #define lua_strx2number(s,p) lua_str2number(s,p) 602 | #endif 603 | 604 | 605 | /* 606 | @@ lua_pointer2str converts a pointer to a readable string in a 607 | ** non-specified way. 608 | */ 609 | #define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) 610 | 611 | 612 | /* 613 | @@ lua_number2strx converts a float to a hexadecimal numeral. 614 | ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. 615 | ** Otherwise, you can leave 'lua_number2strx' undefined and Lua will 616 | ** provide its own implementation. 617 | */ 618 | #if !defined(LUA_USE_C89) 619 | #define lua_number2strx(L,b,sz,f,n) \ 620 | ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) 621 | #endif 622 | 623 | 624 | /* 625 | ** 'strtof' and 'opf' variants for math functions are not valid in 626 | ** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the 627 | ** availability of these variants. ('math.h' is already included in 628 | ** all files that use these macros.) 629 | */ 630 | #if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) 631 | #undef l_mathop /* variants not available */ 632 | #undef lua_str2number 633 | #define l_mathop(op) (lua_Number)op /* no variant */ 634 | #define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) 635 | #endif 636 | 637 | 638 | /* 639 | @@ LUA_KCONTEXT is the type of the context ('ctx') for continuation 640 | ** functions. It must be a numerical type; Lua will use 'intptr_t' if 641 | ** available, otherwise it will use 'ptrdiff_t' (the nearest thing to 642 | ** 'intptr_t' in C89) 643 | */ 644 | #define LUA_KCONTEXT ptrdiff_t 645 | 646 | #if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ 647 | __STDC_VERSION__ >= 199901L 648 | #include 649 | #if defined(INTPTR_MAX) /* even in C99 this type is optional */ 650 | #undef LUA_KCONTEXT 651 | #define LUA_KCONTEXT intptr_t 652 | #endif 653 | #endif 654 | 655 | 656 | /* 657 | @@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). 658 | ** Change that if you do not want to use C locales. (Code using this 659 | ** macro must include the header 'locale.h'.) 660 | */ 661 | #if !defined(lua_getlocaledecpoint) 662 | #define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) 663 | #endif 664 | 665 | 666 | /* 667 | ** macros to improve jump prediction, used mostly for error handling 668 | ** and debug facilities. (Some macros in the Lua API use these macros. 669 | ** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your 670 | ** code.) 671 | */ 672 | #if !defined(luai_likely) 673 | 674 | #if defined(__GNUC__) && !defined(LUA_NOBUILTIN) 675 | #define luai_likely(x) (__builtin_expect(((x) != 0), 1)) 676 | #define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) 677 | #else 678 | #define luai_likely(x) (x) 679 | #define luai_unlikely(x) (x) 680 | #endif 681 | 682 | #endif 683 | 684 | 685 | #if defined(LUA_CORE) || defined(LUA_LIB) 686 | /* shorter names for Lua's own use */ 687 | #define l_likely(x) luai_likely(x) 688 | #define l_unlikely(x) luai_unlikely(x) 689 | #endif 690 | 691 | 692 | 693 | /* }================================================================== */ 694 | 695 | 696 | /* 697 | ** {================================================================== 698 | ** Language Variations 699 | ** ===================================================================== 700 | */ 701 | 702 | /* 703 | @@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some 704 | ** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from 705 | ** numbers to strings. Define LUA_NOCVTS2N to turn off automatic 706 | ** coercion from strings to numbers. 707 | */ 708 | /* #define LUA_NOCVTN2S */ 709 | /* #define LUA_NOCVTS2N */ 710 | 711 | 712 | /* 713 | @@ LUA_USE_APICHECK turns on several consistency checks on the C API. 714 | ** Define it as a help when debugging C code. 715 | */ 716 | #if defined(LUA_USE_APICHECK) 717 | #include 718 | #define luai_apicheck(l,e) assert(e) 719 | #endif 720 | 721 | /* }================================================================== */ 722 | 723 | 724 | /* 725 | ** {================================================================== 726 | ** Macros that affect the API and must be stable (that is, must be the 727 | ** same when you compile Lua and when you compile code that links to 728 | ** Lua). 729 | ** ===================================================================== 730 | */ 731 | 732 | /* 733 | @@ LUAI_MAXSTACK limits the size of the Lua stack. 734 | ** CHANGE it if you need a different limit. This limit is arbitrary; 735 | ** its only purpose is to stop Lua from consuming unlimited stack 736 | ** space (and to reserve some numbers for pseudo-indices). 737 | ** (It must fit into max(size_t)/32 and max(int)/2.) 738 | */ 739 | #if LUAI_IS32INT 740 | #define LUAI_MAXSTACK 1000000 741 | #else 742 | #define LUAI_MAXSTACK 15000 743 | #endif 744 | 745 | 746 | /* 747 | @@ LUA_EXTRASPACE defines the size of a raw memory area associated with 748 | ** a Lua state with very fast access. 749 | ** CHANGE it if you need a different size. 750 | */ 751 | #define LUA_EXTRASPACE (sizeof(void *)) 752 | 753 | 754 | /* 755 | @@ LUA_IDSIZE gives the maximum size for the description of the source 756 | ** of a function in debug information. 757 | ** CHANGE it if you want a different size. 758 | */ 759 | #define LUA_IDSIZE 60 760 | 761 | 762 | /* 763 | @@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib 764 | ** buffer system. 765 | */ 766 | #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) 767 | 768 | 769 | /* 770 | @@ LUAI_MAXALIGN defines fields that, when used in a union, ensure 771 | ** maximum alignment for the other items in that union. 772 | */ 773 | #define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l 774 | 775 | /* }================================================================== */ 776 | 777 | 778 | 779 | 780 | 781 | /* =================================================================== */ 782 | 783 | /* 784 | ** Local configuration. You can use this space to add your redefinitions 785 | ** without modifying the main part of the file. 786 | */ 787 | 788 | 789 | 790 | 791 | 792 | #endif 793 | 794 | -------------------------------------------------------------------------------- /lib/lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | 14 | /* version suffix for environment variable names */ 15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR 16 | 17 | 18 | LUAMOD_API int (luaopen_base) (lua_State *L); 19 | 20 | #define LUA_COLIBNAME "coroutine" 21 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); 22 | 23 | #define LUA_TABLIBNAME "table" 24 | LUAMOD_API int (luaopen_table) (lua_State *L); 25 | 26 | #define LUA_IOLIBNAME "io" 27 | LUAMOD_API int (luaopen_io) (lua_State *L); 28 | 29 | #define LUA_OSLIBNAME "os" 30 | LUAMOD_API int (luaopen_os) (lua_State *L); 31 | 32 | #define LUA_STRLIBNAME "string" 33 | LUAMOD_API int (luaopen_string) (lua_State *L); 34 | 35 | #define LUA_UTF8LIBNAME "utf8" 36 | LUAMOD_API int (luaopen_utf8) (lua_State *L); 37 | 38 | #define LUA_MATHLIBNAME "math" 39 | LUAMOD_API int (luaopen_math) (lua_State *L); 40 | 41 | #define LUA_DBLIBNAME "debug" 42 | LUAMOD_API int (luaopen_debug) (lua_State *L); 43 | 44 | #define LUA_LOADLIBNAME "package" 45 | LUAMOD_API int (luaopen_package) (lua_State *L); 46 | 47 | 48 | /* open all previous libraries */ 49 | LUALIB_API void (luaL_openlibs) (lua_State *L); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /lib/msvcrt.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pavel212/uffi/11967d07e0fcb2ca8758b410dbae2702a812893e/lib/msvcrt.lib -------------------------------------------------------------------------------- /src/asm_x64.h: -------------------------------------------------------------------------------- 1 | /* 2 | #define _ARGN(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,...) A17 3 | #define _ARGC(...) _EXPAND_MSVC(_ARGN(__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)) 4 | #define _EXPAND_MSVC(x) x 5 | #define _B(x,...) _EXPAND_MSVC(_ARGN(__VA_ARGS__,B16,_B15,_B14,_B13,_B12,_B11,_B10,_B09,_B08,_B07,_B06,_B05,_B04,_B03,_B02,_B01) (x,__VA_ARGS__)) 6 | #define _B01(x,A) *(uint8_t*)x++ = (uint8_t)A 7 | #define _B02(x,A,B) ( _B01(x,A), _B01(x,B) ) 8 | #define _B03(x,A,B,C) ( _B02(x,A,B), _B01(x,C) ) 9 | #define _B04(x,A,B,C,D) ( _B03(x,A,B,C), _B01(x,D) ) 10 | #define _B05(x,A,B,C,D,E) ( _B04(x,A,B,C,D), _B01(x,E) ) 11 | #define _B06(x,A,B,C,D,E,F) ( _B05(x,A,B,C,D,E), _B01(x,F) ) 12 | #define _B07(x,A,B,C,D,E,F,G) ( _B06(x,A,B,C,D,E,F), _B01(x,G) ) 13 | #define _B08(x,A,B,C,D,E,F,G,H) ( _B07(x,A,B,C,D,E,F,G), _B01(x,H) ) 14 | #define _B09(x,A,B,C,D,E,F,G,H,I) ( _B08(x,A,B,C,D,E,F,G,H), _B01(x,I) ) 15 | #define _B10(x,A,B,C,D,E,F,G,H,I,J) ( _B09(x,A,B,C,D,E,F,G,H,I), _B01(x,J) ) 16 | #define _B11(x,A,B,C,D,E,F,G,H,I,J,K) ( _B10(x,A,B,C,D,E,F,G,H,I,J), _B01(x,K) ) 17 | #define _B12(x,A,B,C,D,E,F,G,H,I,J,K,L) ( _B11(x,A,B,C,D,E,F,G,H,I,J,K), _B01(x,L) ) 18 | #define _B13(x,A,B,C,D,E,F,G,H,I,J,K,L,M) ( _B12(x,A,B,C,D,E,F,G,H,I,J,K,L), _B01(x,M) ) 19 | #define _B14(x,A,B,C,D,E,F,G,H,I,J,K,L,M,N) ( _B13(x,A,B,C,D,E,F,G,H,I,J,K,L,M), _B01(x,N) ) 20 | #define _B15(x,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) ( _B14(x,A,B,C,D,E,F,G,H,I,J,K,L,M,N), _B01(x,O) ) 21 | #define _B16(x,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) ( _B15(x,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O), _B01(x,P) ) 22 | 23 | #define _DW(x) x, (x)>>8, (x)>>16, (x)>>24 24 | #define _QW(x) x, (x)>>8, (x)>>16, (x)>>24, (x)>>32, (x)>>40, (x)>>48, (x)>>56 25 | */ 26 | 27 | #define _ARGC(...) sizeof((const uint8_t[]){__VA_ARGS__}) 28 | //#define _B(p,...) ( memcpy(p, (const uint8_t[]){__VA_ARGS__}, _ARGC(__VA_ARGS__) ), *(uintptr_t*)(&p) += _ARGC(__VA_ARGS__) ) 29 | #define _B(p,...) ( memcpy(p, (const uint8_t[]){__VA_ARGS__}, _ARGC(__VA_ARGS__) ), p += _ARGC(__VA_ARGS__) ) 30 | 31 | #define _W(x) (uint8_t)(x), (uint8_t)((x)>>8) 32 | #define _DW(x) _W(x), _W((x)>>16) 33 | #define _QW(x) _DW(x), _DW((x)>>32) 34 | 35 | #define _push_rbx(p) _B(p, 0x53) 36 | #define _pop_rbx(p) _B(p, 0x5B) 37 | #define _sub_rsp_DW(p,x) _B(p, 0x48, 0x81, 0xEC, _DW(x)) 38 | #define _add_rsp_DW(p,x) _B(p, 0x48, 0x81, 0xC4, _DW(x)) 39 | 40 | #define _mov_rbx_rcx(p) _B(p, 0x48, 0x89, 0xCB) 41 | #define _mov_rcx_rbx(p) _B(p, 0x48, 0x89, 0xD9) 42 | 43 | #define _mov_rbx_rdi(p) _B(p, 0x48, 0x89, 0xFB) 44 | #define _mov_rdi_rbx(p) _B(p, 0x48, 0x89, 0xDF) 45 | 46 | #define _mov_rbx_rax(p) _B(p, 0x48, 0x89, 0xC3) 47 | #define _mov_rcx_rax(p) _B(p, 0x48, 0x89, 0xC1) 48 | #define _mov_rdx_rax(p) _B(p, 0x48, 0x89, 0xC2) 49 | #define _mov_rdi_rax(p) _B(p, 0x48, 0x89, 0xC7) 50 | #define _mov_rsi_rax(p) _B(p, 0x48, 0x89, 0xC6) 51 | #define _mov_r8_rax(p) _B(p, 0x49, 0x89, 0xC0) 52 | #define _mov_r9_rax(p) _B(p, 0x49, 0x89, 0xC1) 53 | 54 | #define _mov_rax_rbx(p) _B(p, 0x48, 0x89, 0xD8) 55 | #define _mov_rax_rcx(p) _B(p, 0x48, 0x89, 0xC8) 56 | #define _mov_rax_rdx(p) _B(p, 0x48, 0x89, 0xD0) 57 | #define _mov_rax_rdi(p) _B(p, 0x48, 0x89, 0xF8) 58 | #define _mov_rax_rsi(p) _B(p, 0x48, 0x89, 0xF0) 59 | #define _mov_rax_r8(p) _B(p, 0x4C, 0x89, 0xC0) 60 | #define _mov_rax_r9(p) _B(p, 0x4C, 0x89, 0xC8) 61 | 62 | #define _mov_eax_DW(p,x) _B(p, 0xB8, _DW(x)) 63 | #define _mov_rax_DW(p,x) _B(p, 0x48, 0xC7, 0xC0, _DW(x)) 64 | #define _mov_rbx_DW(p,x) _B(p, 0x48, 0xC7, 0xC3, _DW(x)) 65 | #define _mov_rcx_DW(p,x) _B(p, 0x48, 0xC7, 0xC1, _DW(x)) 66 | #define _mov_rdx_DW(p,x) _B(p, 0x48, 0xC7, 0xC2, _DW(x)) 67 | #define _mov_rdi_DW(p,x) _B(p, 0x48, 0xC7, 0xC7, _DW(x)) 68 | #define _mov_rsi_DW(p,x) _B(p, 0x48, 0xC7, 0xC6, _DW(x)) 69 | #define _mov_r8_DW(p,x) _B(p, 0x49, 0xC7, 0xC0, _DW(x)) 70 | #define _mov_r9_DW(p,x) _B(p, 0x49, 0xC7, 0xC1, _DW(x)) 71 | 72 | #define _mov_rax_QW(p,x) _B(p, 0x48, 0xB8, _QW(x)) 73 | #define _mov_rbx_QW(p,x) _B(p, 0x48, 0xBB, _QW(x)) 74 | #define _mov_rcx_QW(p,x) _B(p, 0x48, 0xB9, _QW(x)) 75 | #define _mov_rdx_QW(p,x) _B(p, 0x48, 0xBA, _QW(x)) 76 | #define _mov_rdi_QW(p,x) _B(p, 0x48, 0xBF, _QW(x)) 77 | #define _mov_rsi_QW(p,x) _B(p, 0x48, 0xBE, _QW(x)) 78 | #define _mov_r8_QW(p,x) _B(p, 0x49, 0xB8, _QW(x)) 79 | #define _mov_r9_QW(p,x) _B(p, 0x49, 0xB9, _QW(x)) 80 | 81 | #define _clr_rax(p) _B(p, 0x48, 0x31, 0xC0) 82 | #define _clr_rbx(p) _B(p, 0x48, 0x31, 0xDB) 83 | #define _clr_rcx(p) _B(p, 0x48, 0x31, 0xC9) 84 | #define _clr_rdx(p) _B(p, 0x48, 0x31, 0xD2) 85 | #define _clr_r8(p) _B(p, 0x4D, 0x31, 0xC0) 86 | #define _clr_r9(p) _B(p, 0x4D, 0x31, 0xC9) 87 | 88 | #define _ld_rax(p,x) _B(p, 0x48, 0x8B, 0x84, 0x24, _DW(x)) 89 | #define _ld_rbx(p,x) _B(p, 0x48, 0x8B, 0x9C, 0x24, _DW(x)) 90 | #define _ld_rcx(p,x) _B(p, 0x48, 0x8B, 0x8C, 0x24, _DW(x)) 91 | #define _ld_rdx(p,x) _B(p, 0x48, 0x8B, 0x94, 0x24, _DW(x)) 92 | #define _ld_rdi(p,x) _B(p, 0x48, 0x8B, 0xBC, 0x24, _DW(x)) 93 | #define _ld_rsi(p,x) _B(p, 0x48, 0x8B, 0xB4, 0x24, _DW(x)) 94 | #define _ld_r8(p,x) _B(p, 0x4C, 0x8B, 0x84, 0x24, _DW(x)) 95 | #define _ld_r9(p,x) _B(p, 0x4C, 0x8B, 0x8C, 0x24, _DW(x)) 96 | #define _ld_xmm0(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0x84, 0x24, _DW(x)) 97 | #define _ld_xmm1(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0x8C, 0x24, _DW(x)) 98 | #define _ld_xmm2(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0x94, 0x24, _DW(x)) 99 | #define _ld_xmm3(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0x9C, 0x24, _DW(x)) 100 | #define _ld_xmm4(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0xA4, 0x24, _DW(x)) 101 | #define _ld_xmm5(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0xAC, 0x24, _DW(x)) 102 | #define _ld_xmm6(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0xB4, 0x24, _DW(x)) 103 | #define _ld_xmm7(p,x) _B(p, 0xF3, 0x0F, 0x7E, 0xBC, 0x24, _DW(x)) 104 | #define _ld_xmm(p,r,x) _B(p, 0xF3, 0x0F, 0x7E, 0x84+(r)*8, 0x24, _DW(x)) 105 | 106 | #define _st_rax(p,x) _B(p, 0x48, 0x89, 0x84, 0x24, _DW(x)) 107 | #define _st_rbx(p,x) _B(p, 0x48, 0x89, 0x9C, 0x24, _DW(x)) 108 | #define _st_rcx(p,x) _B(p, 0x48, 0x89, 0x8C, 0x24, _DW(x)) 109 | #define _st_rdx(p,x) _B(p, 0x48, 0x89, 0x94, 0x24, _DW(x)) 110 | #define _st_rdi(p,x) _B(p, 0x48, 0x89, 0xBC, 0x24, _DW(x)) 111 | #define _st_rsi(p,x) _B(p, 0x48, 0x89, 0xB4, 0x24, _DW(x)) 112 | #define _st_r8(p,x) _B(p, 0x4C, 0x89, 0x84, 0x24, _DW(x)) 113 | #define _st_r9(p,x) _B(p, 0x4C, 0x89, 0x8C, 0x24, _DW(x)) 114 | #define _st_xmm0(p,x) _B(p, 0x66, 0x0F, 0xD6, 0x84, 0x24, _DW(x)) 115 | #define _st_xmm1(p,x) _B(p, 0x66, 0x0F, 0xD6, 0x8C, 0x24, _DW(x)) 116 | #define _st_xmm2(p,x) _B(p, 0x66, 0x0F, 0xD6, 0x94, 0x24, _DW(x)) 117 | #define _st_xmm3(p,x) _B(p, 0x66, 0x0F, 0xD6, 0x9C, 0x24, _DW(x)) 118 | #define _st_xmm4(p,x) _B(p, 0x66, 0x0F, 0xD6, 0xA4, 0x24, _DW(x)) 119 | #define _st_xmm5(p,x) _B(p, 0x66, 0x0F, 0xD6, 0xAC, 0x24, _DW(x)) 120 | #define _st_xmm6(p,x) _B(p, 0x66, 0x0F, 0xD6, 0xB4, 0x24, _DW(x)) 121 | #define _st_xmm7(p,x) _B(p, 0x66, 0x0F, 0xD6, 0xBC, 0x24, _DW(x)) 122 | #define _st_xmm(p,r,x) _B(p, 0x66, 0x0F, 0xD6, 0x84+(r)*8, 0x24, _DW(x)) 123 | 124 | #define _mov_xmm0f_xmm0(p) _B(p, 0xF2, 0x0F, 0x5A, 0xC0) 125 | #define _mov_xmm0_xmm0f(p) _B(p, 0xF3, 0x0F, 0x5A, 0xC0) 126 | 127 | #define _mov_xmm1_xmm0f(p) _B(p, 0xF3, 0x0F, 0x5A, 0xC8) 128 | #define _mov_xmm1_xmm1f(p) _B(p, 0xF3, 0x0F, 0x5A, 0xC9) 129 | 130 | #define _mov_xmm1_xmm0(p) _B(p, 0xF3, 0x0F, 0x7E, 0xC8) 131 | #define _mov_xmm0_xmm1(p) _B(p, 0xF3, 0x0F, 0x7E, 0xC1) 132 | 133 | #define _mov_rbx_xmm0(p) _B(p, 0x66, 0x48, 0x0F, 0x7E, 0xC3) 134 | #define _mov_xmm0_rbx(p) _B(p, 0x66, 0x48, 0x0F, 0x6E, 0xC3) 135 | 136 | #define _call_rax(p) _B(p, 0xFF, 0xD0) 137 | #define _ret(p) _B(p, 0xC3) 138 | 139 | #define _call(p,f) ( _mov_rax_QW(p, (uintptr_t)(f)), _call_rax(p) ) 140 | -------------------------------------------------------------------------------- /src/call_sysV64.s: -------------------------------------------------------------------------------- 1 | .globl func__call_auto 2 | 3 | .section .text 4 | 5 | func__call_auto: 6 | push %rbx 7 | push %r12 8 | push %r13 9 | push %r14 10 | push %r15 11 | 12 | mov %rdi, %rbx #first argument lua_State * L passed in rdi, store in rbx 13 | 14 | #mov %rbx, %rdi 15 | call lua_gettop 16 | mov %rax, %r12 #store (number of arguments+1) in r12 17 | 18 | shr $1, %eax 19 | shl $4, %eax 20 | sub %rax, %rsp #reserve stack ((n+1)/2)*16 [+1] - self 21 | 22 | #get C function 23 | mov %rbx, %rdi 24 | mov $1, %rsi 25 | call lua_touserdata 26 | push %rax #put C function on stack 27 | push %rbx #lua_state *L as well just to keep stack aligned 28 | 29 | #for (int i = 1; i < argc; i++) arg[i] = arg_to(L, i+1) 30 | mov $5, %r10 #argi 31 | mov $7, %r11 #argf 32 | xor %r15, %r15 #stack0 33 | xor %r14, %r14 #isfloat bitfield, <64 function float args! 34 | xor %r13, %r13 #i 35 | inc %r13 36 | arg_loop: 37 | cmp %r12, %r13 38 | jge arg_loop_end 39 | inc %r13 40 | 41 | mov %rbx, %rdi 42 | mov %r13, %rsi 43 | call luaF_isfloat 44 | and $1, %rax 45 | shl %r14 46 | add %rax, %r14 #r14 - arg_isfloat bitfield 47 | 48 | mov %rbx, %rdi 49 | mov %r13, %rsi 50 | call luaF_typeto #get pointer to proper lua_to function 51 | 52 | mov %rbx, %rdi 53 | mov %r13, %rsi 54 | xor %rdx, %rdx 55 | call * %rax #call lua_to 56 | 57 | test $1, %r14 58 | jz store_int 59 | 60 | #movq %xmm0, (%rsp,%r13,8) #store ,r13 +1 (self), +8 -> +16bytes, stack: func, L, args... 61 | #tcc bug 62 | 63 | movq %xmm0, %rax #store ,r13 +1 (self), +8 -> +16bytes, stack: func, L, args... 64 | movq %rax, (%rsp,%r13,8) #store ,r13 +1 (self), +8 -> +16bytes, stack: func, L, args... 65 | 66 | test %r11, %r11 67 | jz store_end 68 | dec %r11 69 | jmp store_end 70 | store_int: 71 | mov %rax, (%rsp,%r13,8) #store 72 | test %r10, %r10 73 | jz store_end 74 | dec %r10 75 | store_end: 76 | 77 | mov %r10, %rax 78 | imul %r11, %rax 79 | jz arg_loop #argi == 0 || argf == 0 80 | inc %r15 81 | 82 | jmp arg_loop 83 | arg_loop_end: 84 | 85 | #shift r14 to the left 86 | mov $65, %cl 87 | sub %r12b, %cl 88 | shl %cl, %r14 89 | 90 | #load args to registers/stack 91 | #for (int i = 1; i < argc; i++) load_arg[i] -> reg/stack before func call 92 | xor %r13, %r13 93 | inc %r13 94 | 95 | xor %r10, %r10 #r10 - argi counter 96 | xor %r11, %r11 #r11 - argf counter 97 | #r12 - number of arguments 98 | #r13 - i 99 | #r14 - bit mask for float args 100 | #r15 - offset for first stack arg 101 | mov %r15, %rbx 102 | 103 | ld_loop: 104 | cmp %r12, %r13 105 | jge ld_loop_end 106 | inc %r13 107 | 108 | mov (%rsp,%r13,8), %rax 109 | 110 | shl $1, %r14 111 | jc ld_float 112 | 113 | ld_int: 114 | #jump table?, PIC? 115 | cmp $0, %r10 116 | cmove %rax, %rdi 117 | cmp $1, %r10 118 | cmove %rax, %rsi 119 | cmp $2, %r10 120 | cmove %rax, %rdx 121 | cmp $3, %r10 122 | cmove %rax, %rcx 123 | cmp $4, %r10 124 | cmove %rax, %r8 125 | cmp $5, %r10 126 | cmove %rax, %r9 127 | cmp $6, %r10 128 | jl ld_end 129 | mov %rax, 16(%rsp,%rbx,8) 130 | inc %rbx 131 | jmp ld_end 132 | 133 | ld_float: 134 | cmp $0, %r11 135 | je ld_xmm0 136 | cmp $1, %r11 137 | je ld_xmm1 138 | cmp $2, %r11 139 | je ld_xmm2 140 | cmp $3, %r11 141 | je ld_xmm3 142 | cmp $4, %r11 143 | je ld_xmm4 144 | cmp $5, %r11 145 | je ld_xmm5 146 | cmp $6, %r11 147 | je ld_xmm6 148 | cmp $7, %r11 149 | je ld_xmm7 150 | mov %rax, 16(%rsp,%rbx,8) 151 | inc %rbx 152 | jmp ld_end 153 | 154 | ld_xmm0: 155 | movq %rax, %xmm0 156 | jmp ld_end 157 | ld_xmm1: 158 | movq %rax, %xmm1 159 | jmp ld_end 160 | ld_xmm2: 161 | movq %rax, %xmm2 162 | jmp ld_end 163 | ld_xmm3: 164 | movq %rax, %xmm3 165 | jmp ld_end 166 | ld_xmm4: 167 | movq %rax, %xmm4 168 | jmp ld_end 169 | ld_xmm5: 170 | movq %rax, %xmm5 171 | jmp ld_end 172 | ld_xmm6: 173 | movq %rax, %xmm6 174 | jmp ld_end 175 | ld_xmm7: 176 | movq %rax, %xmm7 177 | jmp ld_end 178 | 179 | ld_end: 180 | inc %r10 181 | inc %r11 182 | jmp ld_loop 183 | ld_loop_end: 184 | 185 | pop %rbx #lua_State * L 186 | pop %rax #function to call 187 | 188 | imul $8, %r15 189 | add %r15, %rsp # adjust stack to stack0 so nonreg arguments are at proper position 190 | 191 | call_cfunc: 192 | call *(%rax) 193 | movq %xmm0, %r14 194 | 195 | mov %rbx, %rdi 196 | mov %rax, %rsi 197 | call lua_pushinteger #first return integer 198 | 199 | mov %rbx, %rdi 200 | movq %r14, %xmm0 201 | call lua_pushnumber #then return floating point 202 | 203 | shr $1, %r12 204 | shl $4, %r12 205 | sub %r15, %r12 206 | add %r12, %rsp #restore stack 207 | 208 | 209 | pop %r15 210 | pop %r14 211 | pop %r13 212 | pop %r12 213 | pop %rbx 214 | 215 | mov $2, %eax 216 | ret 217 | -------------------------------------------------------------------------------- /src/call_win64.asm: -------------------------------------------------------------------------------- 1 | extrn lua_pushnumber : proc 2 | extrn lua_pushinteger: proc 3 | extrn lua_touserdata : proc 4 | extrn lua_gettop : proc 5 | extrn luaF_isfloat : proc 6 | extrn luaF_typeto : proc 7 | 8 | .code 9 | func__call_auto PROC 10 | push rbx 11 | push r12 12 | push r13 13 | push r14 14 | push r15 15 | 16 | sub rsp, 32 17 | 18 | mov rbx, rcx ;first argument lua_State * L passed in rcx, store in rbx 19 | 20 | mov rdx, 1 21 | call lua_touserdata 22 | mov r15, [rax] ;store function pointer in r15 23 | 24 | mov rcx, rbx 25 | call lua_gettop 26 | mov r12, rax ;store number of arguments in r12 27 | 28 | shr eax, 1 29 | shl eax, 4 30 | sub rsp, rax ;reserve stack ((n+1)/2)*16 [1] - self 31 | 32 | ;//for (int i = 1; i < argc; i++) arg[i] = arg_to(L, i+1) 33 | xor r13, r13 34 | inc r13 35 | arg_loop: 36 | cmp r13, r12 37 | jge arg_loop_end 38 | inc r13 39 | 40 | mov rcx, rbx 41 | mov rdx, r13 42 | call luaF_isfloat 43 | mov r14, rax ;r14 - arg_isfloat? 44 | 45 | mov rcx, rbx 46 | mov rdx, r13 47 | call luaF_typeto ;get pointer to proper lua_to function 48 | 49 | mov rcx, rbx 50 | mov rdx, r13 51 | xor r8, r8 52 | call rax ;call lua_to 53 | 54 | cmp r14, 0 55 | jz store_int 56 | store_float: 57 | movq QWORD PTR [rsp + r13*8 + 16], xmm0 ;store floating point arg 58 | jmp arg_loop 59 | store_int: 60 | mov [rsp + r13*8 + 16], rax ;store integer arg 61 | jmp arg_loop 62 | arg_loop_end: 63 | 64 | add rsp, 32 65 | 66 | ;load args to registers, both rcx & xmm0, faster than check for floating point / integer type 67 | ;and loading all 4 args (garbage if <4) probably also faster than checking for actual number of arguments 68 | 69 | ; mov r13, r12 70 | 71 | ; dec r13 72 | ; jz call_cfunc 73 | mov rcx, [rsp] 74 | movq xmm0, rcx 75 | 76 | ; dec r13 77 | ; je call_cfunc 78 | mov rdx, [rsp+8] 79 | movq xmm1, rdx 80 | 81 | ; dec r13 82 | ; jz call_cfunc 83 | mov r8, [rsp+16] 84 | movq xmm2, r8 85 | 86 | ; dec r13 87 | ; jz call_cfunc 88 | mov r9, [rsp+24] 89 | movq xmm3, r9 90 | 91 | call_cfunc: 92 | call r15 93 | movq r14, xmm0 94 | 95 | mov rcx, rbx 96 | mov rdx, rax 97 | call lua_pushinteger ;first return integer 98 | 99 | mov rcx, rbx 100 | movq xmm1, r14 101 | call lua_pushnumber ;then return floating point 102 | 103 | shr r12, 1 104 | shl r12, 4 105 | add rsp, r12 ;restore stack 106 | 107 | pop r15 108 | pop r14 109 | pop r13 110 | pop r12 111 | pop rbx 112 | 113 | mov eax, 2 114 | ret 115 | func__call_auto ENDP 116 | END -------------------------------------------------------------------------------- /src/call_win64.s: -------------------------------------------------------------------------------- 1 | .globl func__call_auto 2 | 3 | func__call_auto: 4 | push %rbx 5 | push %r12 6 | push %r13 7 | push %r14 8 | push %r15 9 | 10 | sub $32, %rsp 11 | 12 | mov %rcx, %rbx //first argument lua_State * L passed in rcx, store in rbx 13 | 14 | mov $1, %rdx 15 | call lua_touserdata 16 | mov (%rax), %r15 //store function pointer in r15 17 | 18 | mov %rbx, %rcx 19 | call lua_gettop 20 | mov %rax, %r12 //store number of arguments in r12 21 | 22 | shr $1, %eax 23 | shl $4, %eax 24 | sub %rax, %rsp //reserve stack ((n+1)/2)*16 [1] - self 25 | 26 | //for (int i = 1; i < argc; i++) arg[i] = arg_to(L, i+1) 27 | xor %r13, %r13 28 | inc %r13 29 | arg_loop: 30 | cmp %r12, %r13 31 | jge arg_loop_end 32 | inc %r13 33 | 34 | mov %rbx, %rcx 35 | mov %r13, %rdx 36 | call luaF_isfloat 37 | mov %rax, %r14 //r14 - arg_isfloat? 38 | 39 | mov %rbx, %rcx 40 | mov %r13, %rdx 41 | call luaF_typeto //get pointer to proper lua_to function 42 | 43 | mov %rbx, %rcx 44 | mov %r13, %rdx 45 | xor %r8, %r8 46 | call * %rax //call lua_to 47 | 48 | cmp $0, %r14 49 | je store_int 50 | movq %xmm0, %rax 51 | store_int: 52 | mov %rax, 16(%rsp,%r13,8) //store 53 | jmp arg_loop 54 | arg_loop_end: 55 | 56 | add $32, %rsp 57 | 58 | //load args to registers, both rcx & xmm0, faster than check for floating point / integer type 59 | //and loading all 4 args (garbage if <4) probably also faster than checking for actual number of arguments 60 | mov (%rsp), %rcx 61 | movq %rcx, %xmm0 62 | 63 | mov 8(%rsp), %rdx 64 | movq %rdx, %xmm1 65 | 66 | mov 16(%rsp), %r8 67 | movq %r8, %xmm2 68 | 69 | mov 24(%rsp), %r9 70 | movq %r9, %xmm3 71 | 72 | call_cfunc: 73 | call * %r15 74 | movq %xmm0, %r14 75 | 76 | mov %rbx, %rcx 77 | mov %rax, %rdx 78 | call lua_pushinteger //first return integer 79 | 80 | mov %rbx, %rcx 81 | movq %r14, %xmm1 82 | call lua_pushnumber //then return floating point 83 | 84 | shr $1, %r12 85 | shl $4, %r12 86 | add %r12, %rsp //restore stack 87 | 88 | pop %r15 89 | pop %r14 90 | pop %r13 91 | pop %r12 92 | pop %rbx 93 | 94 | mov $2, %eax 95 | ret -------------------------------------------------------------------------------- /src/ffi.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lua.h" 4 | #include "lauxlib.h" 5 | 6 | int ffi__call(lua_State* L); 7 | 8 | //call.asm 9 | int func__call_auto(lua_State* L); 10 | 11 | //userdata.c 12 | int ffi_userdata(lua_State* L); 13 | 14 | //win64.c / sysV64.c 15 | int mprotect_exec(void* addr, size_t len); 16 | int mprotect_noexec(void* addr, size_t len); 17 | 18 | void* libopen(const char* filename); 19 | void* libsym(void* handle, const char* symbol); 20 | int libclose(void* handle); 21 | const char* libsymname(uint32_t* lib, uint32_t idx); 22 | int libsymnum(uint32_t* lib); 23 | 24 | int make_func(uint8_t* code, const void* func, const char* argt); 25 | int make_cb(uint8_t* code, lua_State* L, int ref, const char* argt); 26 | 27 | 28 | 29 | 30 | //int ispackedfloat(double x){ return (((*(uint64_t*)&x) & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000); } 31 | //double packfloat(float x) { uint64_t u = 0xFFFFFFFF00000000 | *(uint32_t*)&x; return *(double*)&u; } 32 | //float unpackfloat(double x){ return *(float*)&x; } 33 | 34 | //gcc warnings... 35 | int ispackedfloat(double x){ uint64_t *p = (void*)&x; return ((0xFFFFFFFF00000000 & *p) == 0xFFFFFFFF00000000); } 36 | double packfloat(float x) { double d = 0; uint64_t *pu64 = (void*)&d; uint32_t *pu32 = (void*)&x; *pu64 = 0xFFFFFFFF00000000 | *pu32; return d;} 37 | float unpackfloat(double x){ float *p = (void*)&x; return *p; } 38 | 39 | void voidfunc() {} 40 | int luaF_isfloat (lua_State * L, int idx){ return ((lua_type(L, idx) == LUA_TNUMBER) && (!lua_isinteger(L, idx))); } 41 | void luaF_tonil(lua_State * L, int idx){} 42 | float luaF_tofloat(lua_State* L, int idx) { return unpackfloat(lua_tonumber(L, idx)); } 43 | void* luaF_topointer(lua_State * L, int idx) { return lua_isinteger(L, idx) ? (void*)lua_tointeger(L, idx) : lua_touserdata(L, idx); } 44 | 45 | void* luaF_totable(lua_State* L, int idx) { 46 | lua_rawgeti(L, idx, 1); 47 | if (LUA_TTABLE == lua_type(L, -1)) { 48 | lua_pop(L, 1); 49 | size_t num = lua_rawlen(L, idx); 50 | void** data = lua_newuserdatauv(L, num * sizeof(void*), 0); 51 | for (size_t i = 0; i < num; i++) { 52 | lua_rawgeti(L, idx, i + 1); 53 | data[i] = luaF_totable(L, -1); 54 | } 55 | return data; 56 | } 57 | 58 | if (LUA_TSTRING == lua_type(L, -1)) { 59 | lua_pop(L, 1); 60 | size_t num = lua_rawlen(L, idx); 61 | const char ** data = lua_newuserdatauv(L, num * sizeof(char*), 0); 62 | for (size_t i = 0; i < num; i++) { 63 | lua_rawgeti(L, idx, i + 1); 64 | data[i] = lua_tostring(L, -1); 65 | } 66 | return data; 67 | } 68 | 69 | ///////////////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!///////////////////////////// 70 | if (lua_isinteger(L, -1)) { 71 | lua_pop(L, 1); 72 | size_t num = lua_rawlen(L, idx); 73 | uint8_t * data = lua_newuserdatauv(L, num * sizeof(char), 0); 74 | for (size_t i = 0; i < num; i++) { 75 | lua_rawgeti(L, idx, i + 1); 76 | data[i] = (uint8_t)lua_tointeger(L, -1); 77 | } 78 | return data; 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | void * luaF_typeto (lua_State * L, int idx){ 85 | int t = lua_type(L, idx); 86 | switch (t){ 87 | case LUA_TNONE: 88 | case LUA_TNIL: return luaF_tonil; 89 | case LUA_TBOOLEAN: return lua_toboolean; 90 | case LUA_TLIGHTUSERDATA: return lua_touserdata; 91 | case LUA_TNUMBER: return lua_isinteger(L, idx) ? (void*)lua_tointegerx : ispackedfloat(lua_tonumber(L, idx)) ? (void*)luaF_tofloat : (void*)lua_tonumberx; 92 | case LUA_TSTRING: return lua_tolstring; 93 | case LUA_TTABLE: return luaF_totable; //luaL_error(L, "ffi: type of argument %d is 'table'", idx); return luaF_tonil; 94 | case LUA_TFUNCTION: break; 95 | case LUA_TUSERDATA: return lua_touserdata; 96 | case LUA_TTHREAD: break; 97 | } 98 | luaL_error(L, "ffi: type of argument %d unknown type %d", idx, t); 99 | return luaF_tonil; 100 | } 101 | 102 | void * luaF_to (const char t){ 103 | switch (t){ 104 | case 'b': return lua_toboolean; 105 | case 'd': return lua_tonumberx; 106 | case 'f': return lua_tonumberx; 107 | case 'i': return lua_tointegerx; 108 | case 'p': return luaF_topointer; 109 | case 's': return lua_tolstring; 110 | case 't': return luaF_totable; 111 | case 'v': return luaF_tonil; 112 | } 113 | return luaF_tonil; 114 | } 115 | 116 | void * luaF_push (const char t){ 117 | switch (t){ 118 | case 'b': return lua_pushboolean; 119 | case 'd': return lua_pushnumber; 120 | case 'f': return lua_pushnumber; 121 | case 'i': return lua_pushinteger; 122 | case 'p': return lua_pushlightuserdata; 123 | case 's': return lua_pushstring; 124 | case 'v': return lua_pushnil; 125 | } 126 | return voidfunc; 127 | } 128 | 129 | int func__call_typed(lua_State * L){ 130 | int (*f)(lua_State *) = lua_touserdata(L, 1); 131 | return f ? f(L) : 0; 132 | } 133 | 134 | int func__call_cb(lua_State * L){ //get rid of self argument and call lua function by reference from uservalue 135 | lua_getiuservalue(L, 1, 1); 136 | if (lua_type(L, -1) == LUA_TNUMBER) { 137 | lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, -1)); 138 | lua_insert(L, 2); //put lua callback function above self 139 | lua_pop(L, 1); //pop ref 140 | int num = lua_gettop(L) - 2; //+2: [1] = self, [2] func 141 | lua_call(L, num, LUA_MULTRET); 142 | return lua_gettop(L) - num; 143 | } 144 | lua_pop(L, 1); 145 | return 0; 146 | } 147 | 148 | int func__gc(lua_State * L){ 149 | lua_getiuservalue(L, 1, 1); 150 | if (lua_islightuserdata(L, -1)){ 151 | void * lib = lua_touserdata(L, -1); 152 | if (lib) libclose(lib); 153 | } 154 | if (lua_isinteger(L, -1)){ 155 | int ref = (int)lua_tointeger(L, -1); 156 | luaL_unref(L, LUA_REGISTRYINDEX, ref); 157 | } 158 | lua_pop(L, 1); 159 | // mprotect_noexec(lua_touserdata(L, 1), lua_rawlen(L, 1)); 160 | return 0; 161 | } 162 | 163 | static int codesize_func_arg(char t){ 164 | return 0; 165 | } 166 | 167 | static int codesize_func(const char * argt){ 168 | int size = 1024; 169 | while (*argt) size += codesize_func_arg(*argt++); 170 | return size; 171 | } 172 | 173 | static int codesize_cb_arg(char t){ 174 | return 0; 175 | } 176 | 177 | static int codesize_cb(const char * argt){ 178 | int size = 1024; 179 | while (*argt) size += codesize_cb_arg(*argt++); 180 | return size; 181 | } 182 | 183 | static void pushfuncmetatable(lua_State * L, int(*__call)(lua_State*)){ 184 | lua_createtable(L, 0, 2); 185 | lua_pushcfunction(L, func__gc); 186 | lua_setfield(L, -2, "__gc"); 187 | lua_pushcfunction(L, __call); 188 | lua_setfield(L, -2, "__call"); 189 | } 190 | 191 | int dbg__call_auto(lua_State * L){ 192 | return func__call_auto(L); 193 | } 194 | 195 | //generate code for library function call and push it as userdata on lua stack 196 | static void pushfunc(lua_State* L, void* lib, void* func, const char* argt) { 197 | if (argt) { 198 | int size = codesize_func(argt); 199 | uint8_t* code = lua_newuserdatauv(L, size, 1); //1 uservalue to store lib pointer for FreeLibrary in __gc 200 | pushfuncmetatable(L, func__call_typed); 201 | lua_setmetatable(L, -2); 202 | size = make_func(code, func, argt); 203 | int err = mprotect_exec(code, size); 204 | } else { 205 | uintptr_t* code = lua_newuserdatauv(L, sizeof(uintptr_t*), 1); //void* userdata to store func pointer, 1 uservalue to store lib pointer for FreeLibrary in __gc 206 | // pushfuncmetatable(L, func__call_auto); 207 | pushfuncmetatable(L, dbg__call_auto); 208 | lua_setmetatable(L, -2); 209 | *code = (uintptr_t)func; 210 | } 211 | if (lib) { 212 | lua_pushlightuserdata(L, lib); 213 | lua_setiuservalue(L, -2, 1); 214 | } 215 | } 216 | 217 | int lib__index(lua_State* L) { // stack: self, func 218 | lua_getmetatable(L, 1); // stack: self, func, metatable 219 | lua_pushstring(L, "lib"); // stack: self, func, metatable, "lib" 220 | int libtype = lua_rawget(L, -2); // stack: self, func, metatable, libt 221 | lua_insert(L, 2); // stack: self, libt, func, metatable 222 | lua_pop(L, 1); // stack: self, libt, func 223 | 224 | int len = 0; 225 | if (libtype == LUA_TTABLE) len = (int)lua_rawlen(L, 2); 226 | if (libtype == LUA_TSTRING) len = 1; 227 | 228 | for (int i = 0; i < len; i++) { 229 | lua_pushcfunction(L, ffi__call); // stack: self, libt, func, ffi_call 230 | lua_pushvalue(L, 1); // stack: self, libt, func, ffi_call, self 231 | 232 | if (libtype == LUA_TSTRING) lua_pushvalue(L, 2); 233 | // stack: self, lib, func, ffi_call, self, lib 234 | if (libtype == LUA_TTABLE) lua_rawgeti(L, 2, i + 1); 235 | // stack: self, libt, func, ffi_call, self, lib 236 | lua_pushvalue(L, 3); // stack: self, libt, func, ffi_call, self, lib, func 237 | lua_call(L, 3, 1); // stack: self, libt, func, code 238 | if (lua_type(L, -1) == LUA_TUSERDATA) { 239 | lua_pushvalue(L, -1); // stack: self, libt, func, code, code 240 | lua_insert(L, 3); // stack: self, libt, code, func, code, 241 | lua_settable(L, 1); // self[func] = code // stack: self, libt, code 242 | return 1; 243 | } 244 | else lua_pop(L, 1); 245 | } 246 | return 0; 247 | } 248 | int ffi__call(lua_State* L) { 249 | if (((lua_type(L,2) == LUA_TTABLE) || (lua_type(L,2) == LUA_TSTRING)) && ((lua_type(L,3) == LUA_TNONE) || (lua_type(L,3) == LUA_TNIL))){ 250 | //return empty table with __index metamethod that load functions when first called (indexed) 251 | lua_createtable(L, 0, 0); //self, lib, {} 252 | lua_createtable(L, 0, 2); //self, lib, {}, mt 253 | lua_pushcfunction(L, lib__index); //self, lib, {}, mt, __index 254 | lua_setfield(L, -2, "__index"); //self, lib, {}, mt 255 | lua_pushvalue(L, 2); //lib name //self, lib, {}, mt, lib 256 | lua_setfield(L, -2, "lib"); //self, lib, {}, mt 257 | lua_setmetatable(L, -2); //self, lib, {} 258 | return 1; 259 | } 260 | switch (lua_type(L, 2)) { //ffi("lib.dll"[, "func"][, "typestr"]): [1] - self, [2] - lib, [3] - func, [4] - types 261 | case LUA_TSTRING:{ //lib name 262 | const char* libname = lua_tostring(L, 2); 263 | switch (lua_type(L, 3)) { 264 | case LUA_TSTRING: { //func name 265 | const char* funcname = lua_tostring(L, 3); 266 | if ((funcname[0] == '*') && (funcname[1] == '\0')) {// funcname == "*", load all 267 | void* lib = libopen(libname); 268 | if (lib == 0) return 0; 269 | int num = libsymnum(lib); 270 | libclose(lib); 271 | lua_createtable(L, 0, num); 272 | for (int i = 0; i < num; i++) { 273 | void* lib = libopen(libname); //loadlibrary for each function to increment internal counter 274 | if (lib == 0) return 0; 275 | const char* funcname = libsymname(lib, i); 276 | if (funcname == 0) { libclose(lib); return 0; } 277 | void* func = libsym(lib, funcname); 278 | if (func == 0) { libclose(lib); continue; } 279 | lua_pushstring(L, funcname); //push key 280 | pushfunc(L, lib, func, 0); //push value 281 | lua_rawset(L, -3); //t[key]=value 282 | } 283 | return 1; 284 | } 285 | void* lib = libopen(libname); 286 | if (lib == 0) return 0; 287 | void* func = libsym(lib, funcname); 288 | if (func == 0) { libclose(lib); return 0; } 289 | if (lua_type(L, 4) == LUA_TNUMBER) { 290 | lua_pushcfunction(L, ffi_userdata); 291 | lua_pushlightuserdata(L, func); 292 | lua_pushvalue(L, 4); 293 | lua_call(L, 1, 1); 294 | } else { 295 | pushfunc(L, lib, func, lua_tostring(L, 4)); 296 | } 297 | } return 1; 298 | 299 | case LUA_TTABLE: { //list of functions 300 | int num = (int)lua_rawlen(L, 3); 301 | lua_createtable(L, 0, num); 302 | for (int i = 0; i < num; i++) { 303 | void* lib = libopen(libname); 304 | if (lib == 0) return 0; 305 | lua_rawgeti(L, 3, i + 1); //push key 306 | const char * funcname = lua_tostring(L, -1); 307 | if (funcname == 0) { lua_pop(L, 1); libclose(lib); return 0; } 308 | void * func = libsym(lib, funcname); 309 | if (func == 0) { lua_pop(L, 1); libclose(lib); return 0; } 310 | pushfunc(L, lib, func, 0); //push value 311 | lua_rawset(L, -3); //t[key]=value 312 | } 313 | } return 1; 314 | } 315 | } return 0; 316 | 317 | case LUA_TNUMBER: { //function pointer 318 | void* func = (void*)lua_tointeger(L, 2); 319 | if (func == 0) return 0; 320 | pushfunc(L, 0, func, lua_tostring(L, 3)); 321 | } return 1; 322 | 323 | case LUA_TUSERDATA: //function pointer 324 | case LUA_TLIGHTUSERDATA: { //function pointer 325 | void* func = lua_touserdata(L, 2); 326 | if (func == 0) return 0; 327 | pushfunc(L, 0, func, lua_tostring(L, 3)); 328 | } return 1; 329 | 330 | case LUA_TFUNCTION:{ //callback 331 | lua_pushvalue(L, 2); //make reference to lua function to store it in user value. 332 | int ref = luaL_ref(L, LUA_REGISTRYINDEX); 333 | const char* argt = lua_tostring(L, 3); 334 | int size = codesize_cb(argt); 335 | uint8_t* code = lua_newuserdatauv(L, size, 1); //1 uservalue to store lua function reference for luaL_unref, for __gc 336 | lua_pushinteger(L, ref); 337 | lua_setiuservalue(L, -2, 1); 338 | pushfuncmetatable(L, func__call_cb); 339 | lua_setmetatable(L, -2); 340 | make_cb(code, L, ref, argt); 341 | mprotect_exec(code, size); 342 | } return 1; 343 | } 344 | return 0; 345 | } 346 | 347 | int ffi_float(lua_State* L) { //__call_auto func returns two values: integer 'rax' and double 'xmm0' 348 | if (lua_isinteger(L, 1) && lua_isnumber(L, 2)) lua_pushnumber(L, unpackfloat(lua_tonumber(L, 2))); 349 | else lua_pushnumber(L, packfloat((float)lua_tonumber(L, 1))); 350 | return 1; 351 | } 352 | 353 | int ffi_double(lua_State* L) { 354 | lua_pushvalue(L, 2); 355 | return 1; 356 | } 357 | 358 | int ffi_int(lua_State* L) { 359 | lua_pushvalue(L, 1); 360 | return 1; 361 | } 362 | 363 | int ffi_string(lua_State* L) { 364 | if (lua_isinteger(L, 2)) lua_pushlstring(L, (char*)lua_tointeger(L, 1), lua_tointeger(L, 2)); 365 | else lua_pushstring(L, (char*)lua_tointeger(L, 1)); 366 | return 1; 367 | } 368 | 369 | int ffi_pointer(lua_State* L) { 370 | if (lua_isinteger(L, 1)) { 371 | lua_pushlightuserdata(L, (void*)lua_tointeger(L, 1)); 372 | return 1; 373 | } 374 | uint64_t* p = lua_touserdata(L, 1); 375 | return p ? (lua_pushinteger(L, *p), 1) : 0; 376 | } 377 | 378 | int ffi_bool(lua_State* L) { 379 | lua_pushboolean(L, (int)lua_tointeger(L, 1)); 380 | return 1; 381 | } 382 | 383 | int userdata_pointer(lua_State* L); 384 | int userdata_string(lua_State* L); 385 | int userdata_int(lua_State* L); 386 | int userdata_float(lua_State* L); 387 | int userdata_double(lua_State* L); 388 | int userdata_bits(lua_State* L); 389 | int userdata_pack(lua_State* L); 390 | int userdata_unpack(lua_State* L); 391 | int userdata_type(lua_State* L); 392 | int userdata__index(lua_State* L); 393 | 394 | //#define X(x) {ffi_##x,#x} 395 | //const luaL_Reg lib[] = { X(string), X(int), X(float), X(double), X(bool), X(pointer), X(userdata), { 0, 0 } }; 396 | 397 | //extern "C" 398 | #ifdef _WIN64 399 | __declspec(dllexport) 400 | #endif 401 | int luaopen_ffi(lua_State * L){ 402 | // luaL_newlib(L, lib); 403 | 404 | lua_createtable(L, 0, 7); //lib 405 | lua_pushcfunction(L, ffi_string); 406 | lua_setfield(L, -2, "string"); 407 | lua_pushcfunction(L, ffi_int); 408 | lua_setfield(L, -2, "int"); 409 | lua_pushcfunction(L, ffi_float); 410 | lua_setfield(L, -2, "float"); 411 | lua_pushcfunction(L, ffi_double); 412 | lua_setfield(L, -2, "double"); 413 | lua_pushcfunction(L, ffi_bool); 414 | lua_setfield(L, -2, "bool"); 415 | lua_pushcfunction(L, ffi_pointer); 416 | lua_setfield(L, -2, "pointer"); 417 | 418 | lua_createtable(L, 0, 8); //ffi.userdata table 419 | lua_pushcfunction(L, userdata_pointer); 420 | lua_setfield(L, -2, "pointer"); 421 | lua_pushcfunction(L, userdata_string); 422 | lua_setfield(L, -2, "string"); 423 | lua_pushcfunction(L, userdata_int); 424 | lua_setfield(L, -2, "int"); 425 | lua_pushcfunction(L, userdata_float); 426 | lua_setfield(L, -2, "float"); 427 | lua_pushcfunction(L, userdata_double); 428 | lua_setfield(L, -2, "double"); 429 | lua_pushcfunction(L, userdata_bits); 430 | lua_setfield(L, -2, "bits"); 431 | lua_pushcfunction(L, userdata_pack); 432 | lua_setfield(L, -2, "pack"); 433 | lua_pushcfunction(L, userdata_unpack); 434 | lua_setfield(L, -2, "unpack"); 435 | lua_pushcfunction(L, userdata_type); 436 | lua_setfield(L, -2, "type"); 437 | 438 | lua_createtable(L, 0, 1); //ffi.userdata metatable 439 | lua_pushcfunction(L, ffi_userdata); 440 | lua_setfield(L, -2, "__call"); 441 | // lua_pushcfunction(L, userdata__index); 442 | // lua_setfield(L, -2, "__index"); 443 | lua_setmetatable(L, -2); 444 | 445 | lua_setfield(L, -2, "userdata"); 446 | 447 | lua_createtable(L, 0, 1); //ffi metatable 448 | lua_pushcfunction(L, ffi__call); 449 | lua_setfield(L, -2, "__call"); 450 | lua_setmetatable(L, -2); 451 | 452 | return 1; 453 | } 454 | -------------------------------------------------------------------------------- /src/sysV64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "lua.h" 5 | #include "lauxlib.h" 6 | #include "asm_x64.h" 7 | 8 | #include 9 | 10 | #include 11 | 12 | //tcc does not like 'link.h' 13 | #define RTLD_LAZY 1 14 | #define RTLD_DI_LINKMAP 2 15 | 16 | struct link_map{ 17 | Elf64_Addr l_addr; 18 | char *l_name; 19 | Elf64_Dyn *l_ld; 20 | //... 21 | }; 22 | 23 | void *dlopen(const char *filename, int flags); 24 | int dlinfo(void *restrict handle, int request, void *restrict info); 25 | char *dlerror(void); 26 | void *dlsym(void *handle, const char *symbol); 27 | int dlclose(void *handle); 28 | 29 | //dynlib 30 | void* libopen(const char* filename){ return dlopen(filename, RTLD_LAZY); } 31 | void* libsym(void* lib, const char* name){ return dlsym(lib, name); } 32 | int libclose(void* lib){ return dlclose(lib); } 33 | 34 | static int libsyminfo(uint32_t* lib, Elf64_Sym ** symtab, char ** strtab){ 35 | if (lib == 0) return 0; 36 | struct link_map * map = 0; 37 | dlinfo(lib, RTLD_DI_LINKMAP, &map); 38 | int syment = 0; 39 | for (Elf64_Dyn * section = map->l_ld; section->d_tag != DT_NULL; section++){ 40 | switch(section->d_tag){ 41 | case DT_SYMTAB: *symtab = (Elf64_Sym *)section->d_un.d_ptr; break; 42 | case DT_STRTAB: *strtab = (char*)section->d_un.d_ptr; break; 43 | case DT_SYMENT: syment = section->d_un.d_val; break; 44 | } 45 | } 46 | return (*strtab - (char*)*symtab) / syment; 47 | } 48 | 49 | const char* libsymname(uint32_t* lib, uint32_t idx) { 50 | Elf64_Sym * symtab = 0; 51 | char * strtab = 0; 52 | int size = libsyminfo(lib, &symtab, &strtab); 53 | int num = 0; 54 | for (int i = 0; i < size; i++){ 55 | if ((symtab[i].st_shndx != SHN_UNDEF) && (ELF64_ST_TYPE(symtab[i].st_info) == STT_FUNC)){ 56 | if (num == idx) return &strtab[symtab[i].st_name]; 57 | num += 1; 58 | } 59 | } 60 | return 0; 61 | } 62 | 63 | int libsymnum(uint32_t* lib) { 64 | Elf64_Sym * symtab = 0; 65 | char * strtab = 0; 66 | int size = libsyminfo(lib, &symtab, &strtab); 67 | int num = 0; 68 | for (int i = 0; i < size; i++){ 69 | if ((symtab[i].st_shndx != SHN_UNDEF) && (ELF64_ST_TYPE(symtab[i].st_info) == STT_FUNC)) num += 1; 70 | } 71 | return num; 72 | } 73 | 74 | int mprotect_exec(void* addr, size_t len) { 75 | const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; 76 | len += (uintptr_t)addr & page_mask; 77 | addr = (void*) ((uintptr_t)addr & ~page_mask); 78 | return mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC); 79 | } 80 | 81 | int mprotect_noexec(void* addr, size_t len) { 82 | const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; 83 | len += (uintptr_t)addr & page_mask; 84 | addr = (void*) ((uintptr_t)addr & ~page_mask); 85 | return mprotect(addr, len, PROT_READ | PROT_WRITE); 86 | } 87 | 88 | //codegen 89 | void* luaF_typeto(lua_State* L, int idx); 90 | void* luaF_to(const char t); 91 | void* luaF_push(const char t); 92 | 93 | //rdi,rsi,rdx,rcx,r8,r9 / xmm0..7 94 | int make_func(uint8_t* code, const void* func, const char* argt) { 95 | int argc = (int)strlen(argt); 96 | int stack = 16 * ((argc + 1) >> 1); //space for function arguments multiple of 16 bytes to keep stack alignment 97 | int argi = 6, argf = 8, args = 0, stack0 = 0; //number of arguments: integer reg, float reg, on stack. 98 | 99 | uint8_t* p = code; 100 | { 101 | //prologue 102 | _push_rbx(p); //additional push rbx makes stack aligned to 16. 103 | _mov_rbx_rdi(p); //as we are in luaCfunction: int f(lua_State * L); L is passed in rdi. store lua_State * L in rbx, 104 | _sub_rsp_DW(p, stack); //reserve stack. 105 | 106 | //get arguments from lua stack and store them on stack 107 | for (int i = 1; i < argc; i++) { //argt[0] - return type 108 | if (argt[i] == 'l') { //automatic, from Lua type at runtime 109 | _mov_rdi_rbx(p); //first argument lua_State * L 110 | _mov_rsi_DW(p, i + 1); //second argument n+1 - position of argument on lua stack, [1] == self, [2] == first arg, ... 111 | _call(p, luaF_typeto); 112 | } 113 | else _mov_rax_QW(p, (uintptr_t)luaF_to(argt[i])); 114 | 115 | _mov_rdi_rbx(p); //first argument lua_State * L 116 | _mov_rsi_DW(p, i + 1); //second argument n+1 - position of argument on lua stack, [1] == self, [2] == first arg, ... 117 | _clr_rdx(p); //some lua_to functions have 3rd argument, #define lua_tostring(L, i) lua_tolstring(L, i, 0) 118 | _call_rax(p); 119 | 120 | if (argt[i] == 'f') _mov_xmm0f_xmm0(p); //double -> float conversion, double lua_tonumber(); 121 | if (argt[i] == 'f' || argt[i] == 'd'){ //store argument on stack 122 | _st_xmm0(p, i * 8 - 8); 123 | if (argf) argf--; 124 | } else { 125 | _st_rax(p, i * 8 - 8); 126 | if (argi) argi--; 127 | } 128 | if (argf && argi) stack0 += 8; //position of first arg that did not fit into regs 129 | } 130 | 131 | //put back arguments into registers 132 | argf = argi = args = 0; 133 | for (int i = 1; i < argc; i++){ 134 | if (argt[i] == 'f' || argt[i] == 'd'){ 135 | switch(argf++) { 136 | case 0: _ld_xmm0(p, i * 8 - 8); break; 137 | case 1: _ld_xmm1(p, i * 8 - 8); break; 138 | case 2: _ld_xmm2(p, i * 8 - 8); break; 139 | case 3: _ld_xmm3(p, i * 8 - 8); break; 140 | case 4: _ld_xmm4(p, i * 8 - 8); break; 141 | case 5: _ld_xmm5(p, i * 8 - 8); break; 142 | case 6: _ld_xmm6(p, i * 8 - 8); break; 143 | case 7: _ld_xmm7(p, i * 8 - 8); break; 144 | default: _ld_rax(p, i * 8 - 8); _st_rax(p, stack0 + 8 * args++); break; 145 | } 146 | } else { 147 | switch(argi++) { 148 | case 0: _ld_rdi(p, i * 8 - 8); break; 149 | case 1: _ld_rsi(p, i * 8 - 8); break; 150 | case 2: _ld_rdx(p, i * 8 - 8); break; 151 | case 3: _ld_rcx(p, i * 8 - 8); break; 152 | case 4: _ld_r8 (p, i * 8 - 8); break; 153 | case 5: _ld_r9 (p, i * 8 - 8); break; 154 | default:_ld_rax(p, i * 8 - 8); _st_rax(p, stack0 + 8 * args++); break; 155 | } 156 | } 157 | } 158 | 159 | _add_rsp_DW(p, stack0); //adjust rsp to first nonreg argument 160 | 161 | _call(p, func); 162 | 163 | //lua_push() function return value to lua stack 164 | _mov_rdi_rbx(p); //first argument lua_State * L 165 | if (argt[0] == 'f') _mov_xmm1_xmm0f(p); //convert float to double and mov return value(xmm0) to (xmm1) second argument of lua_push 166 | else if (argt[0] == 'd') _mov_xmm1_xmm0(p); //mov double without conversion 167 | else _mov_rsi_rax(p); //other types returned in rax -> second argument in rsi 168 | _clr_rdx(p); //some lua_push functions could have 3rd argument 169 | _call(p, luaF_push(argt[0])); 170 | //return 1 171 | _mov_rax_DW(p, 1); //return 1, even void func() returns 1 and lua_pushnil just for uniformity. 172 | _add_rsp_DW(p, stack - stack0); //restore stack pointer 173 | _pop_rbx(p); //and rbx 174 | _ret(p); 175 | } 176 | return (int)(p - code); //length of generated code 177 | } 178 | 179 | int make_cb(uint8_t* code, lua_State* L, int ref, const char* argt) { 180 | int argc = (int)strlen(argt); 181 | int stack = 16 * ((argc + 1) >> 1); //space for function arguments multiple of 16 bytes to keep stack alignment 182 | uint8_t* p = code; 183 | { 184 | //prologue 185 | _push_rbx(p); //push rbx to align stack to 16 and store lua_State * L in rbx 186 | _mov_rbx_QW(p, (uintptr_t)L); //as we are generating ordinary C function, lua_State * L is passed as argument from ffi and hardcoded. 187 | 188 | _sub_rsp_DW(p, stack); 189 | 190 | //store arguments from regs onto stack before calling rawgeti that gets lua function and lua_push to put arguments on lua stack 191 | int argf = 0, argi = 0, args = 0; 192 | for (int i = 1; i < argc; i++){ 193 | if (argt[i] == 'f' || argt[i] == 'd'){ 194 | switch(argf++) { 195 | case 0: _st_xmm0(p, i * 8 - 8); break; 196 | case 1: _st_xmm1(p, i * 8 - 8); break; 197 | case 2: _st_xmm2(p, i * 8 - 8); break; 198 | case 3: _st_xmm3(p, i * 8 - 8); break; 199 | case 4: _st_xmm4(p, i * 8 - 8); break; 200 | case 5: _st_xmm5(p, i * 8 - 8); break; 201 | case 6: _st_xmm6(p, i * 8 - 8); break; 202 | case 7: _st_xmm7(p, i * 8 - 8); break; 203 | default: _ld_rax(p, stack + 8 + 8 * args++); _st_rax(p, i * 8 - 8); 204 | } 205 | } else { 206 | switch(argi++) { 207 | case 0: _st_rdi(p, i * 8 - 8); break; 208 | case 1: _st_rsi(p, i * 8 - 8); break; 209 | case 2: _st_rdx(p, i * 8 - 8); break; 210 | case 3: _st_rcx(p, i * 8 - 8); break; 211 | case 4: _st_r8 (p, i * 8 - 8); break; 212 | case 5: _st_r9 (p, i * 8 - 8); break; 213 | default: _ld_rax(p, stack + 8 + 8 * args++); _st_rax(p, i * 8 - 8); 214 | } 215 | } 216 | } 217 | 218 | //push lua function 219 | _mov_rdi_rbx(p); 220 | _mov_rsi_DW(p, LUA_REGISTRYINDEX); 221 | _mov_rdx_DW(p, ref); //lua function we are going to wrap (ref) as C callback is stored in lua registry, so it is not garbage collected accidentally 222 | _call(p, lua_rawgeti); //get lua function on stack from registry lua_rawgeti(L, REIGSTRYINDEX, funcref) 223 | 224 | //push arguments to lua stack 225 | for (int i = 1; i < argc; i++) { 226 | _mov_rdi_rbx(p); //first argument lua_State * L 227 | if (argt[i] == 'f' || argt[i] == 'd') _ld_xmm0(p, i * 8 - 8); else _ld_rsi(p, i * 8 - 8); //get second argument for lua_push from stack 228 | if (argt[i] == 'f') _mov_xmm0_xmm0f(p); //float -> double conversion for lua_pushnumber 229 | _clr_rdx(p); //some lua_push functions have 3rd argument 230 | _call(p, luaF_push(argt[i])); 231 | } 232 | 233 | //lua_call 234 | _mov_rdi_rbx(p); 235 | _mov_rsi_DW(p, argc - 1); 236 | _mov_rdx_DW(p, 1); 237 | _clr_rcx(p); 238 | _clr_r8(p); 239 | _call(p, lua_callk); //lua_callk(L, argc-1, 1, 0, 0); lua function always return 1 value, nil for void f() callback 240 | 241 | //get return value to C with lua_to 242 | _mov_rdi_rbx(p); //first argument lua_State * L 243 | _mov_rsi_DW(p, -1); //return value is on top of the lua stack after lua_call 244 | _clr_rdx(p); //some functions have 3rd argument, lua_tostring == lua_tolstring(L, idx, 0); 245 | _call(p, luaF_to(argt[0])); 246 | 247 | //lua_pop return value 248 | _mov_rdi_rbx(p); //first argument lua_State * L, we do not need L anymore, so save return value in rbx while calling lua_pop 249 | if (argt[0] == 'f' || argt[0] == 'd') _mov_rbx_xmm0(p); else _mov_rbx_rax(p); //store return value in rbx to call lua_pop(L, 1) 250 | _mov_rsi_DW(p, -2); 251 | _call(p, lua_settop); //lua_pop(L, 1) == lua_settop(L, -2); 252 | if (argt[0] == 'f' || argt[0] == 'd') _mov_xmm0_rbx(p); else _mov_rax_rbx(p); //load return value of lua_to() back to rax/xmm0 253 | 254 | //return 255 | _add_rsp_DW(p, stack); //restore stack 256 | _pop_rbx(p); //and rbx 257 | _ret(p); 258 | } 259 | return (int)(p - code); 260 | } -------------------------------------------------------------------------------- /src/userdata.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "lua.h" 4 | #include "lauxlib.h" 5 | 6 | static void* getuserdatapointer(lua_State* L, int idx, int* size) { 7 | void* p = lua_touserdata(L, idx); 8 | if (lua_getiuservalue(L, idx, 1) == LUA_TNUMBER) { 9 | p = *(void**)p; 10 | if (size) *size = (int)lua_tointeger(L, -1); 11 | } else if (size) *size = (int)lua_rawlen(L, idx); 12 | lua_pop(L, 1); 13 | return p; 14 | } 15 | 16 | int userdata_pointer(lua_State* L) { 17 | lua_pushinteger(L, (uint64_t)getuserdatapointer(L, 1, 0)); 18 | return 1; 19 | } 20 | 21 | int userdata_string(lua_State* L) { //userdata:string(size, offset=0) / userdata:string("str", offset=0) 22 | int len = 0; 23 | char* p = getuserdatapointer(L, 1, &len); 24 | if (p == 0) return 0; 25 | int offset = (int)lua_tointeger(L, 3); 26 | if (lua_type(L, 2) == LUA_TSTRING) { //write 27 | int size = (int)lua_rawlen(L, 2); 28 | if ((size <= 0) || (offset + size > len)) size = len - offset; 29 | memcpy(&p[offset], lua_tostring(L, 2), size); 30 | lua_pushvalue(L, 1); 31 | } 32 | else { //read 33 | int size = 0; 34 | if (lua_isinteger(L, 2)) size = (int)lua_tointeger(L, 2); 35 | if ((size <= 0) || (offset + size > len)) size = len - offset; 36 | lua_pushlstring(L, &p[offset], size); 37 | } 38 | return 1; 39 | } 40 | 41 | int userdata_int(lua_State* L) { //userdata:int([value][, offset][, size=userdata length]) 42 | int len = 0; 43 | uint8_t* p = getuserdatapointer(L, 1, &len); 44 | if (p == 0) return 0; 45 | int64_t v = lua_tointeger(L, 2); 46 | int size = len; 47 | int offset = (int)lua_tointeger(L, 3); 48 | if (lua_isinteger(L, 4)) size = (int)lua_tointeger(L, 4); 49 | if (size > 8) size = 8; 50 | if ((size <=0) || (size*(offset+1) > len)) return 0; 51 | if (lua_isinteger(L, 2)) { 52 | memcpy(&p[size * offset], &v, size); 53 | lua_pushvalue(L, 1); 54 | } 55 | else { 56 | memcpy(&v, &p[size * offset], size); 57 | lua_pushinteger(L, v); 58 | } 59 | return 1; 60 | } 61 | 62 | int userdata_float(lua_State* L) { //userdata:float([value][, offset]) 63 | int len = 0; 64 | float* p = getuserdatapointer(L, 1, &len); 65 | if (p == 0) return 0; 66 | int offset = (int)lua_tointeger(L, 3); 67 | if (sizeof(float) * (offset + 1) > len) return 0; 68 | if (lua_isnumber(L, 2)) { 69 | p[offset] = (float)lua_tonumber(L, 2); 70 | lua_pushvalue(L, 1); 71 | } 72 | else { 73 | lua_pushnumber(L, p[offset]); 74 | } 75 | return 1; 76 | } 77 | 78 | int userdata_double(lua_State* L) { //userdata:float([value][, offset]) 79 | int len = 0; 80 | double* p = getuserdatapointer(L, 1, &len); 81 | if (p == 0) return 0; 82 | int offset = (int)lua_tointeger(L, 3); 83 | if (sizeof(double) * (offset + 1) > len) return 0; 84 | if (lua_isnumber(L, 2)) { 85 | p[offset] = lua_tonumber(L, 2); 86 | lua_pushvalue(L, 1); 87 | } 88 | else { 89 | lua_pushnumber(L, p[offset]); 90 | } 91 | return 1; 92 | } 93 | 94 | static uint64_t read_bits(const uint64_t* data, size_t offset, uint8_t len) { 95 | data += offset >> 6; 96 | uint8_t pos = offset & 0x3F; 97 | uint64_t ret = data[0] >> pos; 98 | if ((pos + len) > 64) ret |= data[1] << (64 - pos); 99 | return ret & ((1ULL << len) - 1); 100 | } 101 | 102 | static void write_bits(uint64_t* data, size_t offset, uint8_t len, uint64_t value) { 103 | data += offset >> 6; 104 | uint8_t pos = offset & 0x3F; 105 | uint64_t mask = (((1ULL << len) - 1) << pos); 106 | data[0] &= ~mask; 107 | data[0] |= (value << pos) & mask; 108 | if ((pos + len) > 64) { 109 | len = pos + len - 64; 110 | uint64_t mask = ((1ULL << len) - 1); 111 | data[1] &= ~mask; 112 | data[1] |= (value >> (64 - pos)) & mask; 113 | } 114 | } 115 | 116 | int userdata_bits(lua_State* L) { //userdata:bits([,data: write if present, otherwise read][offset=0][, size=1]) 117 | int len = 0; 118 | uint64_t* p = getuserdatapointer(L, 1, &len); 119 | if (p == 0) return 0; 120 | int size = 1; 121 | int offset = (int)lua_tointeger(L, 3); 122 | if (lua_isinteger(L, 2)) size = (int)lua_tointeger(L, 4); 123 | if (size > 64) size = 64; 124 | if ((size <= 0) || (size * (offset + 1) > len*8)) return 0; 125 | if (lua_isinteger(L, 2)) { 126 | write_bits(p, offset, size, lua_tointeger(L, 2)); 127 | lua_pushvalue(L, 1); 128 | } 129 | else { 130 | lua_pushinteger(L, read_bits(p, offset, size)); 131 | } 132 | return 1; 133 | } 134 | 135 | int userdata_pack(lua_State* L) { //:pack(fmt, values....) 136 | int len = 0; 137 | uint64_t* p = getuserdatapointer(L, 1, &len); 138 | lua_getglobal(L, "string"); 139 | lua_getfield(L, -1, "pack"); 140 | lua_insert(L, 2); //stack: [1]=self, [2]=string.pack, [3]=fmt, [4...]=values, ... [-1]=string 141 | lua_pop(L, 1); //stack: [1]=self, [2]=string.pack, [3]=fmt, [4...]=values, ... 142 | lua_call(L, lua_gettop(L) - 2, 1); 143 | const char* s = lua_tostring(L, -1); 144 | if (len < lua_rawlen(L, -1)) len = (int)lua_rawlen(L, -1); 145 | if (s) memcpy(p, s, len); 146 | lua_pop(L, 1); //remove result of string.pack and return self 147 | return 1; 148 | } 149 | 150 | int userdata_type(lua_State* L) { 151 | int type = lua_type(L, 2); 152 | lua_getmetatable(L, 1); 153 | 154 | if ((type == LUA_TNIL) || (type == LUA_TNONE)) { // get type 155 | lua_getfield(L, -1, "__type"); //stack: self, ..., [nil], metatable, type 156 | return 1; 157 | } 158 | 159 | if (type == LUA_TSTRING) { //set __type to ffi.userdata[str] 160 | lua_getfield(L, -1, "__userdata"); //stack: self, ..., metatable, __index 161 | lua_pushvalue(L, 2); //stack: self, ..., metatable, __index, arg 162 | lua_rawget(L, -2); //stack: self, ..., metatable, __index, userdata[arg] 163 | lua_setfield(L, -3, "__type"); 164 | lua_settop(L, 1); 165 | return 1; 166 | } 167 | 168 | if (type == LUA_TFUNCTION) { 169 | lua_pushvalue(L, 2); //stack: self, ..., metatable, arg 170 | lua_setfield(L, -2, "__type"); 171 | lua_settop(L, 1); 172 | return 1; 173 | } 174 | return 0; 175 | } 176 | 177 | int userdata_size(lua_State* L) { 178 | int type = lua_type(L, 2); 179 | lua_getmetatable(L, 1); 180 | if ((type == LUA_TNIL) || (type == LUA_TNONE)) { // get size 181 | lua_getfield(L, -1, "__size"); //stack: self, ..., [nil], metatable, type 182 | lua_remove(L, -2); //remove metatable 183 | if (type == LUA_TNIL) lua_remove(L, -2); //remove nil 184 | return 1; 185 | } 186 | 187 | if (type == LUA_TNUMBER) { //set __size for indexing 188 | lua_pushvalue(L, 2); //stack: self, ..., metatable, arg 189 | lua_setfield(L, -2, "__size"); 190 | lua_pop(L, 1); 191 | } 192 | return 0; 193 | } 194 | 195 | //__index(t,k) x = ffi.userdata(size):type("float"); x(0), x(1), x(2) 196 | int userdata__index(lua_State* L) { //x = ffi.userdata():type("float") -> x.getmetatable().__type = userdata.float; then x(n) -> x.metatable.__type(x, nil, n) -> x:float(nil, n) 197 | int type = lua_type(L, 2); //key 198 | lua_getmetatable(L, 1); 199 | if (type == LUA_TNUMBER) { 200 | if (lua_getfield(L, -1, "__type") != LUA_TFUNCTION) return 0; 201 | lua_pushvalue(L, 1); 202 | lua_pushnil(L); 203 | lua_pushvalue(L, 2); 204 | lua_getfield(L, -5, "__size"); 205 | lua_call(L, 4, 1); 206 | // lua_remove(L, -2); 207 | return 1; 208 | } else { 209 | lua_getfield(L, -1, "__userdata"); 210 | lua_pushvalue(L, 2); 211 | lua_gettable(L, -2); 212 | return 1; 213 | } 214 | return 0; 215 | } 216 | //__newindex(t,k,v) (ffi.userdata()) [k] = v 217 | int userdata__newindex(lua_State* L) { //x = ffi.userdata():type("float") -> userdata.metatable.__type = userdata.float; x[n] -> x.metatable.__type(x, value, n) -> x:float(value, n) 218 | int type = lua_type(L, 2); //key 219 | if (type == LUA_TNUMBER) { 220 | lua_getmetatable(L, 1); 221 | lua_getfield(L, -1, "__type"); 222 | lua_pushvalue(L, 1); 223 | lua_pushvalue(L, 3); 224 | lua_pushvalue(L, 2); 225 | lua_getfield(L, -5, "__size"); 226 | lua_call(L, 4, 1); 227 | // lua_remove(L, -2); 228 | } 229 | return 0; 230 | } 231 | 232 | int userdata_unpack(lua_State* L) { //:unpack(fmt, pos) 233 | int len = 0; 234 | uint8_t* p = getuserdatapointer(L, 1, &len); 235 | lua_getglobal(L, "string"); 236 | lua_getfield(L, -1, "unpack"); 237 | lua_insert(L, 2); //stack: [1]=self, [2]=string.unpack, [3]=fmt, [4]=pos, [-1]=string 238 | lua_pop(L, 1); //stack: [1]=self, [2]=string.unpack, [3]=fmt, [4]=pos, 239 | lua_pushlstring(L, (const char *)p, len); 240 | lua_insert(L, 4); 241 | lua_call(L, lua_gettop(L) - 2, LUA_MULTRET); 242 | return lua_gettop(L) - 1; 243 | } 244 | 245 | int ffi_userdata(lua_State* L) { 246 | switch (lua_type(L, 2)) { 247 | case LUA_TNUMBER: { 248 | int length = (int)lua_tointeger(L, 2); 249 | if (length <= 0) return 0; 250 | // lua_newuserdatauv(L, length, 0); 251 | void* data = lua_newuserdatauv(L, length, 0); 252 | memset(data, 0, length); 253 | } break; 254 | 255 | case LUA_TSTRING: { 256 | size_t length = lua_rawlen(L, 2); 257 | char* data = lua_newuserdatauv(L, length + 1, 0); 258 | memcpy(data, lua_tostring(L, 2), length + 1); 259 | } break; 260 | 261 | case LUA_TTABLE: { 262 | size_t length = lua_rawlen(L, 2); 263 | uintptr_t* data = lua_newuserdatauv(L, sizeof(uintptr_t) * length, 0); 264 | for (size_t i = 0; i < length; i++) { 265 | lua_pushcfunction(L, ffi_userdata); 266 | lua_pushvalue(L, 1); 267 | lua_rawgeti(L, 1, i + 1); 268 | lua_call(L, 2, 1); 269 | data[i] = (uintptr_t)lua_touserdata(L, -1); 270 | } 271 | 272 | } break; 273 | 274 | case LUA_TLIGHTUSERDATA: { 275 | void* p = lua_touserdata(L, 2); 276 | void** data = lua_newuserdatauv(L, sizeof(void*), 1); 277 | lua_pushvalue(L, 3); 278 | lua_setiuservalue(L, -2, 1); 279 | *data = p; 280 | } break; 281 | 282 | case LUA_TUSERDATA: { 283 | lua_settop(L, 2); //remove other arguments, if any 284 | } break; 285 | default: return 0; 286 | } 287 | 288 | lua_createtable(L, 0, 5); //userdata metatable 289 | lua_pushcfunction(L, userdata_string); 290 | lua_setfield(L, -2, "__tostring"); 291 | 292 | lua_pushvalue(L, 1); //ffi.userdata 293 | lua_setfield(L, -2, "__userdata"); //for indexing of ffi.userdata functions 294 | 295 | lua_pushcfunction(L, userdata__index); 296 | lua_setfield(L, -2, "__call"); //for now () for indexing as array instead of []: http://lua-users.org/lists/lua-l/2023-08/msg00122.html 297 | 298 | lua_pushcfunction(L, userdata__index); 299 | lua_setfield(L, -2, "__index"); 300 | 301 | lua_pushcfunction(L, userdata__newindex); 302 | lua_setfield(L, -2, "__newindex"); 303 | 304 | lua_setmetatable(L, -2); 305 | 306 | return 1; 307 | } 308 | -------------------------------------------------------------------------------- /src/win64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "lua.h" 4 | #include "lauxlib.h" 5 | #include "asm_x64.h" 6 | 7 | #ifndef _DEBUG 8 | int _fltused = 0; 9 | BOOL WINAPI _DllMainCRTStartup(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) { 10 | return TRUE; 11 | } 12 | #endif 13 | 14 | //dynlib 15 | void* libopen(const char* filename){ return LoadLibrary(filename); } 16 | void* libsym(void* lib, const char* name){ return GetProcAddress(lib, name); } 17 | int libclose(void* lib){ return FreeLibrary(lib); } 18 | 19 | const char* libsymname(uint32_t* lib, uint32_t idx) { 20 | if (lib == 0) return 0; 21 | uint32_t* p = lib; 22 | if ((p[0] & 0xFFFF) != 0x5A4D) return 0; //MZ 23 | p = &lib[p[15] >> 2]; //e_lfanew 24 | if (p[0] != 0x00004550) return 0; //signature 25 | if ((p[1] & 0xFFFF) != 0x8664) return 0; //machine 26 | p = &lib[p[34] >> 2]; //EXPORT_DIRECTORY 27 | if (idx >= p[6]) return 0;//NumberOfNames 28 | p = &lib[(p[8] >> 2) + idx]; //AddressOfNames[idx] 29 | return &((char*)lib)[*p]; 30 | } 31 | 32 | int libsymnum(uint32_t* lib) { 33 | if (lib == 0) return 0; 34 | uint32_t* p = lib; 35 | if ((p[0] & 0xFFFF) != 0x5A4D) return 0; //MZ 36 | p = &lib[p[15] >> 2]; //e_lfanew 37 | if (p[0] != 0x00004550) return 0; //signature 38 | if ((p[1] & 0xFFFF) != 0x8664) return 0; //machine 39 | p = &lib[p[34] >> 2]; //EXPORT_DIRECTORY 40 | return p[6]; //NumberOfNames 41 | } 42 | 43 | int mprotect_exec(void* addr, size_t len) { 44 | DWORD protect; 45 | return VirtualProtect(addr, len, PAGE_EXECUTE_READWRITE, &protect); 46 | } 47 | 48 | int mprotect_noexec(void* addr, size_t len) { 49 | DWORD protect; 50 | return VirtualProtect(addr, len, PAGE_READWRITE, &protect); 51 | } 52 | 53 | //codegen 54 | void* luaF_typeto(lua_State* L, int idx); 55 | void* luaF_to(const char t); 56 | void* luaF_push(const char t); 57 | 58 | int make_func(uint8_t* code, const void* func, const char* argt) { 59 | int argc = (int)strlen(argt); 60 | int stack = 16 * ((argc + 4) >> 1); //32 bytes of shadow space + space for function arguments multiple of 16 bytes to keep stack alignment 61 | uint8_t* p = code; 62 | { 63 | //prologue 64 | _push_rbx(p); //additional push rbx makes stack aligned to 16. 65 | _mov_rbx_rcx(p); //as we are in luaCfunction: int f(lua_State * L); L is passed in rcx. store lua_State * L in rbx, 66 | _sub_rsp_DW(p, stack); //reserve stack 67 | 68 | //get arguments from lua stack and store them on stack 69 | for (int i = 1; i < argc; i++) { //argt[0] - return type 70 | if (argt[i] == 'l') { //automatic, from Lua type at runtime 71 | _mov_rcx_rbx(p); //first argument lua_State * L 72 | _mov_rdx_DW(p, i + 1); //second argument n+1 - position of argument on lua stack, [1] == self, [2] == first arg, ... 73 | _call(p, luaF_typeto); 74 | } 75 | else _mov_rax_QW(p, (uintptr_t)luaF_to(argt[i])); 76 | 77 | _mov_rcx_rbx(p); //first argument lua_State * L 78 | _mov_rdx_DW(p, i + 1); //second argument n+1 - position of argument on lua stack, [1] == self, [2] == first arg, ... 79 | _clr_r8(p); //some lua_to functions have 3rd argument, #define lua_tostring(L, i) lua_tolstring(L, i, 0) 80 | _call_rax(p); 81 | 82 | if (argt[i] == 'f') _mov_xmm0f_xmm0(p); //double -> float conversion, double lua_tonumber(); 83 | if (argt[i] == 'f' || argt[i] == 'd') _st_xmm0(p, 24 + i * 8); else _st_rax(p, 24 + i * 8); //store argument on stack with 32 bytes offset of shadow store 84 | } 85 | 86 | _add_rsp_DW(p, 32); //adjust stack by shadow 32 bytes that were reserved for lua_to functions, so other (4+) arguments on stack with a proper offset 87 | 88 | //put back first four arguments to registers 89 | if (argc > 1) { if (argt[1] == 'f' || argt[1] == 'd') _ld_xmm0(p, 0); else _ld_rcx(p, 0); } 90 | if (argc > 2) { if (argt[2] == 'f' || argt[2] == 'd') _ld_xmm1(p, 8); else _ld_rdx(p, 8); } 91 | if (argc > 3) { if (argt[3] == 'f' || argt[3] == 'd') _ld_xmm2(p, 16); else _ld_r8(p, 16); } 92 | if (argc > 4) { if (argt[4] == 'f' || argt[4] == 'd') _ld_xmm3(p, 24); else _ld_r9(p, 24); } 93 | 94 | _call(p, func); 95 | 96 | //lua_push() function return value to lua stack 97 | _mov_rcx_rbx(p); //first argument lua_State * L 98 | if (argt[0] == 'f') _mov_xmm1_xmm0f(p); //convert float to double and mov return value(xmm0) to (xmm1) second argument of lua_push 99 | else if (argt[0] == 'd') _mov_xmm1_xmm0(p); //mov double without conversion 100 | else _mov_rdx_rax(p); //other types returned in rax -> second argument in rdx 101 | _clr_r8(p); //some lua_push functions could have 3rd argument 102 | _call(p, luaF_push(argt[0])); 103 | //return 1 104 | _mov_rax_DW(p, 1); //return 1, even void func() returns 1 and lua_pushnil just for uniformity. 105 | _add_rsp_DW(p, stack - 32); //restore stack pointer 106 | _pop_rbx(p); //and rbx 107 | _ret(p); 108 | } 109 | return (int)(p - code); //length of generated code 110 | } 111 | 112 | int make_cb(uint8_t* code, lua_State* L, int ref, const char* argt) { 113 | int argc = (int)strlen(argt); 114 | uint8_t* p = code; 115 | { 116 | _push_rbx(p); //push rbx to align stack to 16 and store lua_State * L in rbx 117 | _mov_rbx_QW(p, (uintptr_t)L); //as we are generating ordinary C function, lua_State * L is passed as argument from ffi and stored as immediate constant in code. 118 | 119 | if (argc > 1) if (argt[1] == 'f' || argt[1] == 'd') _st_xmm0(p, 16); else _st_rcx(p, 16); //store 4 arguments in shadow 120 | if (argc > 2) if (argt[2] == 'f' || argt[2] == 'd') _st_xmm1(p, 24); else _st_rdx(p, 24); 121 | if (argc > 3) if (argt[3] == 'f' || argt[3] == 'd') _st_xmm2(p, 32); else _st_r8(p, 32); 122 | if (argc > 4) if (argt[4] == 'f' || argt[4] == 'd') _st_xmm3(p, 40); else _st_r9(p, 40); 123 | 124 | _sub_rsp_DW(p, 48); //32 shadow space + additional 8 bytes for 5th argument of lua_callk + 8 bytes to keep 16 bytes alignment 125 | 126 | _mov_rcx_rbx(p); 127 | _mov_rdx_DW(p, LUA_REGISTRYINDEX); 128 | _mov_r8_DW(p, ref); //lua function we are going to wrap (ref) as C callback is stored in lua registry, so it is not garbage collected accidentally 129 | _call(p, lua_rawgeti); //get lua function on stack from registry lua_rawgeti(L, REIGSTRYINDEX, funcref) 130 | 131 | for (int i = 1; i < argc; i++) { 132 | _mov_rcx_rbx(p); //first argument lua_State * L 133 | if (argt[i] == 'f' || argt[i] == 'd') _ld_xmm1(p, 56 + i * 8); else _ld_rdx(p, 56 + i * 8); //get second argument for lua_push from stack 134 | if (argt[i] == 'f') _mov_xmm1_xmm1f(p); //float -> double conversion for lua_pushnumber 135 | _clr_r8(p); //some lua_push functions have 3rd argument 136 | _call(p, luaF_push(argt[i])); 137 | } 138 | 139 | _mov_rcx_rbx(p); 140 | _mov_rdx_DW(p, argc - 1); 141 | _mov_r8_DW(p, 1); 142 | _clr_r9(p); 143 | _st_r9(p, 32); 144 | _call(p, lua_callk); //lua_callk(L, argc-1, 1, 0, 0); lua function always return 1 value, nil for void f() callback 145 | 146 | _mov_rcx_rbx(p); //first argument lua_State * L 147 | _mov_rdx_DW(p, -1); //return value is on top of the lua stack after lua_call 148 | _clr_r8(p); //some functions have 3rd argument, lua_tostring == lua_tolstring(L, idx, 0); 149 | _call(p, luaF_to(argt[0])); 150 | 151 | if (argt[0] == 'f' || argt[0] == 'd') _st_xmm0(p, 32); else _st_rax(p, 32); //store return value on stack to call lua_pop(L, 1) 152 | 153 | _mov_rcx_rbx(p); 154 | _mov_rdx_DW(p, -2); 155 | _call(p, lua_settop); //lua_pop(L, 1) == lua_settop(L, -2); 156 | 157 | if (argt[0] == 'f' || argt[0] == 'd') _ld_xmm0(p, 32); else _ld_rax(p, 32); //return value in rax/xmm0 158 | 159 | _add_rsp_DW(p, 48); //restore stack 160 | _pop_rbx(p); //and rbx 161 | _ret(p); 162 | } 163 | return (int)(p - code); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | local ffi = require ("ffi") 2 | local cosf = ffi("libm.so.6", "cosf", "ff") 3 | print("cosf:", cosf(1.57)) 4 | 5 | local cos = ffi("libm.so.6", "cos") 6 | print("cos:", cos(1.57)) 7 | os.exit() 8 | 9 | 10 | io.read() 11 | local ffi = require ("ffi") 12 | local lib = ffi({"user32","msvcrt"}) 13 | local msg = ffi("user32","MessageBoxA") 14 | local c = ffi("msvcrt", "cos") 15 | msg(0,"C","D",0) 16 | print(c(math.pi/3)) 17 | lib.MessageBoxA(0,"A","B",0) 18 | print(lib.cos(math.pi/4)) 19 | print(ffi.float(lib.cosf(ffi.float(math.pi/3)))) 20 | os.exit() 21 | 22 | 23 | package.path = package.path ..";.\\example\\?.lua" 24 | local ffi = require ("ffi") 25 | local gl = require ("gl") 26 | os.exit() 27 | 28 | package.path = package.path ..";.\\example\\?.lua" 29 | dofile ("example/hello_glfw.lua") 30 | os.exit() 31 | 32 | local ffi = require("ffi") 33 | local win = ffi({"user32", "kernel32"}) 34 | local hInstance = win.GetModuleHandleA(0) 35 | os.exit() 36 | 37 | local ffi = require("ffi") 38 | x=ffi.userdata(256):type("float") 39 | print(x:float()) 40 | print(x(0), x(1)) 41 | x:pack("ff", 42.0, 43.0) 42 | x[2] = 44 43 | print(x:float()) 44 | print(x(0), x(1), x(2)) 45 | print(x[0], x[1], x[2]) 46 | os.exit() -------------------------------------------------------------------------------- /uffi.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 16.0 37 | Win32Proj 38 | {1e841532-c923-4808-8e40-42dd6a37b45b} 39 | uffi 40 | 10.0 41 | 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | DynamicLibrary 58 | true 59 | v143 60 | NotSet 61 | 62 | 63 | DynamicLibrary 64 | false 65 | v143 66 | true 67 | NotSet 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | false 90 | false 91 | 92 | 93 | false 94 | 95 | 96 | 97 | Level3 98 | true 99 | WIN32;_DEBUG;UFFI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 100 | true 101 | Use 102 | pch.h 103 | 104 | 105 | Windows 106 | true 107 | false 108 | 109 | 110 | 111 | 112 | Level3 113 | true 114 | true 115 | true 116 | WIN32;NDEBUG;UFFI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 117 | true 118 | Use 119 | pch.h 120 | 121 | 122 | Windows 123 | true 124 | true 125 | true 126 | false 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | _DEBUG;UFFI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 134 | true 135 | NotUsing 136 | pch.h 137 | lib;%(AdditionalIncludeDirectories) 138 | CompileAsC 139 | false 140 | false 141 | All 142 | 143 | 144 | Windows 145 | true 146 | false 147 | lua54.lib;%(AdditionalDependencies) 148 | ffi.dll 149 | false 150 | lib 151 | 152 | 153 | 154 | 155 | Level3 156 | true 157 | true 158 | false 159 | NDEBUG;UFFI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 160 | true 161 | NotUsing 162 | pch.h 163 | lib;%(AdditionalIncludeDirectories) 164 | Size 165 | MinSpace 166 | false 167 | false 168 | All 169 | false 170 | 171 | 172 | Windows 173 | true 174 | true 175 | false 176 | false 177 | lua54.lib;%(AdditionalDependencies) 178 | true 179 | ffi.dll 180 | lib 181 | 182 | 183 | false 184 | 185 | 186 | false 187 | 3 188 | 189 | 190 | 191 | 192 | 193 | 194 | --------------------------------------------------------------------------------