├── generate_call_h.bat ├── .gitignore ├── dynasm ├── dasm_x64.lua ├── dasm_proto.h ├── dasm_ppc.h ├── dasm_arm.h ├── dasm_x86.h └── dasm_arm.lua ├── msvc ├── inttypes.h ├── stdbool.h └── stdint.h ├── test_includes.sh ├── Makefile ├── msvcbuild.bat ├── README.md ├── pretty.lua ├── ctype.c ├── call.c ├── ffi.h ├── call_arm.dasc ├── test.c └── test.lua /generate_call_h.bat: -------------------------------------------------------------------------------- 1 | lua.exe dynasm\dynasm.lua -LNE -D X32WIN -o call_x86.h call_x86.dasc 2 | lua.exe dynasm\dynasm.lua -LNE -D X64 -o call_x64.h call_x86.dasc 3 | lua.exe dynasm\dynasm.lua -LNE -D X64 -D X64WIN -o call_x64win.h call_x86.dasc 4 | lua.exe dynasm\dynasm.lua -LNE -o call_arm.h call_arm.dasc 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | call_*.h 2 | *.dll 3 | *.exp 4 | *.lib 5 | *.pdb 6 | *.ilk 7 | .*.swp 8 | *.user 9 | /BuildLog.htm 10 | *.o 11 | *.so 12 | .*.swo 13 | .DS_Store 14 | /luaffi.xcodeproj 15 | *.ncb 16 | *.sln 17 | *.suo 18 | *.dSYM 19 | *.vcproj 20 | /luaffi 21 | /test_includes/ 22 | *.swp 23 | *.dylib 24 | /tmp 25 | -------------------------------------------------------------------------------- /dynasm/dasm_x64.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM x64 module. 3 | -- 4 | -- Copyright (C) 2005-2011 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | -- This module just sets 64 bit mode for the combined x86/x64 module. 8 | -- All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | x64 = true -- Using a global is an ugly, but effective solution. 12 | return require("dasm_x86") 13 | -------------------------------------------------------------------------------- /msvc/inttypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Signed integers */ 4 | #define PRId8 "d" 5 | #define PRId16 "d" 6 | #define PRId32 "d" 7 | #define PRId64 "I64d" 8 | #define PRIi8 "i" 9 | #define PRIi16 "i" 10 | #define PRIi32 "i" 11 | #define PRIi64 "I64i" 12 | 13 | /* Unsigned integers */ 14 | #define PRIo8 "o" 15 | #define PRIo16 "o" 16 | #define PRIo32 "o" 17 | #define PRIo64 "I64o" 18 | #define PRIu8 "u" 19 | #define PRIu16 "u" 20 | #define PRIu32 "u" 21 | #define PRIu64 "I64u" 22 | #define PRIx8 "x" 23 | #define PRIx16 "x" 24 | #define PRIx32 "x" 25 | #define PRIx64 "I64x" 26 | #define PRIX8 "X" 27 | #define PRIX16 "X" 28 | #define PRIX32 "X" 29 | #define PRIX64 "I64X" 30 | #define PRIxPTR PRIx32 31 | #define PRIXPTR PRIX32 32 | -------------------------------------------------------------------------------- /test_includes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make test || exit 3 | rm -rf test_includes 4 | mkdir -p test_includes 5 | for f in /usr/include/*.h 6 | do 7 | gcc -E -c "${f}" > tmp 2>/dev/null 8 | if [ $? == 0 ] 9 | then 10 | echo "${f}"; 11 | lua -e ' 12 | local str = io.read("*a") 13 | -- remove preprocessor commands eg line directives 14 | str = str:gsub("#[^\n]*", "") 15 | -- remove inline function definitions and declarations 16 | str = str:gsub("extern%s+__inline__", "static") 17 | str = str:gsub("extern%s+__inline", "static") 18 | str = str:gsub("static[^;(]+__attribute__%s*%b()", "static ") 19 | str = str:gsub("static[^;(]+__attribute__%s*%b()", "static ") 20 | str = str:gsub("static[^;(]+%b()%s*%b{}", "") 21 | str = str:gsub("static[^;(]+%b()%s*;", "") 22 | io.write(str)' > "test_includes/`basename $f`" < tmp 23 | lua -e 'ffi = require("ffi"); ffi.cdef(io.read("*a"))' < "test_includes/`basename $f`" 24 | fi 25 | done 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean test 2 | 3 | PKG_CONFIG=pkg-config 4 | LUA=lua 5 | 6 | LUA_CFLAGS=`$(PKG_CONFIG) --cflags lua5.2 2>/dev/null || $(PKG_CONFIG) --cflags lua` 7 | SOCFLAGS=-fPIC 8 | SOCC=$(CC) -shared $(SOCFLAGS) 9 | CFLAGS=-fPIC -g -Wall -Werror $(LUA_CFLAGS) -fvisibility=hidden -Wno-unused-function --std=gnu99 10 | 11 | MODNAME=ffi 12 | MODSO=$(MODNAME).so 13 | 14 | all: 15 | if [ `uname` = "Darwin" ]; then $(MAKE) macosx; else $(MAKE) posix; fi 16 | 17 | test: 18 | if [ `uname` = "Darwin" ]; then $(MAKE) test_macosx; else $(MAKE) test_posix; fi 19 | 20 | macosx: 21 | $(MAKE) posix "SOCC=MACOSX_DEPLOYMENT_TARGET=10.3 $(CC) -dynamiclib -single_module -undefined dynamic_lookup $(SOCFLAGS)" 22 | 23 | test_macosx: 24 | $(MAKE) test_posix "SOCC=MACOSX_DEPLOYMENT_TARGET=10.3 $(CC) -dynamiclib -single_module -undefined dynamic_lookup $(SOCFLAGS)" 25 | 26 | posix: $(MODSO) test_cdecl.so 27 | 28 | clean: 29 | rm -f *.o *.so call_*.h 30 | 31 | call_x86.h: call_x86.dasc dynasm/*.lua 32 | $(LUA) dynasm/dynasm.lua -LN -o $@ $< 33 | 34 | call_x64.h: call_x86.dasc dynasm/*.lua 35 | $(LUA) dynasm/dynasm.lua -D X64 -LN -o $@ $< 36 | 37 | call_x64win.h: call_x86.dasc dynasm/*.lua 38 | $(LUA) dynasm/dynasm.lua -D X64 -D X64WIN -LN -o $@ $< 39 | 40 | %.o: %.c *.h dynasm/*.h call_x86.h call_x64.h call_x64win.h 41 | $(CC) $(CFLAGS) -o $@ -c $< 42 | 43 | $(MODSO): ffi.o ctype.o parser.o call.o 44 | $(SOCC) $^ -o $@ 45 | 46 | test_cdecl.so: test.o 47 | $(SOCC) $^ -o $@ 48 | 49 | test_posix: test_cdecl.so $(MODSO) 50 | LD_LIBRARY_PATH=./ $(LUA) test.lua 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /msvc/stdbool.h: -------------------------------------------------------------------------------- 1 | /* vim: ts=4 sw=4 sts=4 et 2 | * 3 | * Copyright (c) 2009 James R. McKaskill 4 | * 5 | * This software is licensed under the stock MIT license: 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | * 25 | * ---------------------------------------------------------------------------- 26 | */ 27 | 28 | #pragma once 29 | 30 | 31 | #if defined __cplusplus 32 | typedef bool _Bool; 33 | 34 | #else 35 | #pragma warning(disable:4244) /* conversion from int to _Bool */ 36 | typedef unsigned char _Bool; 37 | #define bool _Bool 38 | #define true 1 39 | #define false 0 40 | #define __bool_true_false_are_defined 1 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /dynasm/dasm_proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM encoding engine prototypes. 3 | ** Copyright (C) 2005-2011 Mike Pall. All rights reserved. 4 | ** Released under the MIT/X license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #ifndef _DASM_PROTO_H 8 | #define _DASM_PROTO_H 9 | 10 | #include 11 | #include 12 | 13 | #define DASM_IDENT "DynASM 1.3.0" 14 | #define DASM_VERSION 10300 /* 1.3.0 */ 15 | 16 | #ifndef Dst_DECL 17 | #define Dst_DECL dasm_State **Dst 18 | #endif 19 | 20 | #ifndef Dst_REF 21 | #define Dst_REF (*Dst) 22 | #endif 23 | 24 | #ifndef DASM_FDEF 25 | #define DASM_FDEF extern 26 | #endif 27 | 28 | #ifndef DASM_M_GROW 29 | #define DASM_M_GROW(ctx, t, p, sz, need) \ 30 | do { \ 31 | size_t _sz = (sz), _need = (need); \ 32 | if (_sz < _need) { \ 33 | if (_sz < 16) _sz = 16; \ 34 | while (_sz < _need) _sz += _sz; \ 35 | (p) = (t *)realloc((p), _sz); \ 36 | if ((p) == NULL) exit(1); \ 37 | (sz) = _sz; \ 38 | } \ 39 | } while(0) 40 | #endif 41 | 42 | #ifndef DASM_M_FREE 43 | #define DASM_M_FREE(ctx, p, sz) free(p) 44 | #endif 45 | 46 | /* Internal DynASM encoder state. */ 47 | typedef struct dasm_State dasm_State; 48 | 49 | 50 | /* Initialize and free DynASM state. */ 51 | DASM_FDEF void dasm_init(Dst_DECL, int maxsection); 52 | DASM_FDEF void dasm_free(Dst_DECL); 53 | 54 | /* Setup global array. Must be called before dasm_setup(). */ 55 | DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); 56 | 57 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 58 | DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); 59 | 60 | /* Setup encoder. */ 61 | DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); 62 | 63 | /* Feed encoder with actions. Calls are generated by pre-processor. */ 64 | DASM_FDEF void dasm_put(Dst_DECL, int start, ...); 65 | 66 | /* Link sections and return the resulting size. */ 67 | DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); 68 | 69 | /* Encode sections into buffer. */ 70 | DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); 71 | 72 | /* Get PC label offset. */ 73 | DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); 74 | 75 | #ifdef DASM_CHECKS 76 | /* Optional sanity checker to call between isolated encoding steps. */ 77 | DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); 78 | #else 79 | #define dasm_checkstep(a, b) 0 80 | #endif 81 | 82 | 83 | #endif /* _DASM_PROTO_H */ 84 | -------------------------------------------------------------------------------- /msvcbuild.bat: -------------------------------------------------------------------------------- 1 | @if not defined INCLUDE goto :FAIL 2 | 3 | @setlocal 4 | 5 | @if "%1"=="debug-5.1" goto :DEBUG_5_1 6 | 7 | rem These should not have quotes 8 | @set LUA_INCLUDE=Z:\c\lua-5.2.0\src 9 | @set LUA_LIB=Z:\c\lua-5.2.0\lua5.2.lib 10 | @set LUA_EXE=Z:\c\lua-5.2.0\lua.exe 11 | rem This the name of the dll that can be handed to LoadLibrary. This should not have a path. 12 | @set LUA_DLL=lua5.2.dll 13 | @goto :DEBUG 14 | 15 | :DEBUG_5_1 16 | @set LUA_INCLUDE=Z:\c\lua-5.1.4\src 17 | @set LUA_LIB=Z:\c\lua-5.1.4\lua5.1.lib 18 | @set LUA_EXE=Z:\c\lua-5.1.4\lua.exe 19 | @set LUA_DLL=lua5.1.dll 20 | 21 | :DEBUG 22 | @set DO_CL=cl.exe /nologo /c /MDd /FC /Zi /Od /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /DLUA_FFI_BUILD_AS_DLL /I"msvc" 23 | @set DO_LINK=link /nologo /debug 24 | @set DO_MT=mt /nologo 25 | 26 | @if "%1"=="debug" goto :COMPILE 27 | @if "%1"=="debug-5.1" goto :COMPILE 28 | @if "%1"=="test" goto :COMPILE 29 | @if "%1"=="clean" goto :CLEAN 30 | @if "%1"=="release" goto :RELEASE 31 | @if "%1"=="test-release" goto :RELEASE 32 | 33 | :RELEASE 34 | @set DO_CL=cl.exe /nologo /c /MD /Ox /W3 /Zi /WX /D_CRT_SECURE_NO_DEPRECATE /DLUA_FFI_BUILD_AS_DLL /I"msvc" 35 | @set DO_LINK=link.exe /nologo /debug 36 | @set DO_MT=mt.exe /nologo 37 | @goto :COMPILE 38 | 39 | :COMPILE 40 | "%LUA_EXE%" dynasm\dynasm.lua -LNE -D X32WIN -o call_x86.h call_x86.dasc 41 | "%LUA_EXE%" dynasm\dynasm.lua -LNE -D X64 -o call_x64.h call_x86.dasc 42 | "%LUA_EXE%" dynasm\dynasm.lua -LNE -D X64 -D X64WIN -o call_x64win.h call_x86.dasc 43 | "%LUA_EXE%" dynasm\dynasm.lua -LNE -o call_arm.h call_arm.dasc 44 | %DO_CL% /I"." /I"%LUA_INCLUDE%" /DLUA_DLL_NAME="%LUA_DLL%" call.c ctype.c ffi.c parser.c 45 | %DO_LINK% /DLL /OUT:ffi.dll "%LUA_LIB%" *.obj 46 | if exist ffi.dll.manifest^ 47 | %DO_MT% -manifest ffi.dll.manifest -outputresource:"ffi.dll;2" 48 | 49 | %DO_CL% /Gd test.c /Fo"test_cdecl.obj" 50 | %DO_CL% /Gz test.c /Fo"test_stdcall.obj" 51 | %DO_CL% /Gr test.c /Fo"test_fastcall.obj" 52 | %DO_LINK% /DLL /OUT:test_cdecl.dll test_cdecl.obj 53 | %DO_LINK% /DLL /OUT:test_stdcall.dll test_stdcall.obj 54 | %DO_LINK% /DLL /OUT:test_fastcall.dll test_fastcall.obj 55 | if exist test_cdecl.dll.manifest^ 56 | %DO_MT% -manifest test_cdecl.dll.manifest -outputresource:"test_cdecl.dll;2" 57 | if exist test_stdcall.dll.manifest^ 58 | %DO_MT% -manifest test_stdcall.dll.manifest -outputresource:"test_stdcall.dll;2" 59 | if exist test_fastcall.dll.manifest^ 60 | %DO_MT% -manifest test_fastcall.dll.manifest -outputresource:"test_fastcall.dll;2" 61 | 62 | @if "%1"=="test" "%LUA_EXE%" test.lua 63 | @if "%1"=="test-5.2" "%LUA_EXE%" test.lua 64 | @if "%1"=="test-release" "%LUA_EXE%" test.lua 65 | @goto :CLEAN_OBJ 66 | 67 | :CLEAN 68 | del *.dll 69 | :CLEAN_OBJ 70 | del *.obj *.manifest 71 | @goto :END 72 | 73 | :FAIL 74 | @echo You must open a "Visual Studio .NET Command Prompt" to run this script 75 | :END 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ----- 3 | This is a library for calling C function and manipulating C types from lua. It 4 | is designed to be interface compatible with the FFI library in luajit (see 5 | http://luajit.org/ext_ffi.html). It can parse C function declarations and 6 | struct definitions that have been directly copied out of C header files and 7 | into lua source as a string. 8 | 9 | License 10 | ------- 11 | Copyright (c) 2011 James R. McKaskill. 12 | MIT same as Lua 5.1. See full license text in ffi.h. 13 | 14 | Source 15 | ------ 16 | https://github.com/jmckaskill/luaffi 17 | 18 | Platforms 19 | --------- 20 | Currently supported: 21 | - windows x86/x64 22 | - linux x86/x64 23 | - windows CE ARM little endian (ARMv4+) 24 | - OSX x86/x64 25 | 26 | Currently only dll builds are supported (ie no static). 27 | 28 | Runs with both Lua 5.1 and Lua 5.2 beta. 29 | 30 | Build 31 | ----- 32 | 33 | On windows use msvcbuild.bat in a visual studio cmd prompt. Available targets are: 34 | - nothing or release: default release build 35 | - debug: debug build 36 | - test: build and run the test debug build 37 | - test-release: build and run the test release build 38 | - clean: cleanup object files 39 | 40 | Edit msvcbuild.bat if your lua exe, lib, lua include path, or lua dll name 41 | differ from c:\Lua5.1 and lua5.1.dll. 42 | 43 | The build script does not build for CE as this is non-trivial and very 44 | dependent on which CE profile (or even a custom one). Instead to build on CE, 45 | add generate_call_h.bat as a pre-build event and then build *.c with UNDER_CE 46 | defined plus whatever defines windows.h requires. 47 | 48 | On posix use make. Available targets are: 49 | - nothing or all: default release build 50 | - debug: debug build 51 | - test: build and run the test build 52 | - clean: cleanup object files 53 | - macosx: release build for Mac OSX 54 | 55 | Edit the Makefile if your lua exe differs from `lua5.1` or if you can't get 56 | the include and lib arguments from pkg-config. 57 | 58 | Known Issues 59 | ------------ 60 | - Has not been bullet proof tested 61 | - Casting is different from luajit. For the moment this follows C++ 62 | - ffi.cast is equivalent to a C cast in C++ (T t = (T) f) 63 | - ffi.new and ctype() is equivalent to an implicit cast in C++ (T t = f) 64 | - since this follows C++ semantics void* does not cast to T* (an explicit 65 | cast using ffi.cast is required) 66 | - Comparing a ctype pointer to nil doesn't work the same as luajit. This is 67 | unfixable with the current metamethod semantics. Instead use ffi.C.NULL 68 | - Constant expressions can't handle non integer intermediate values (eg 69 | offsetof won't work because it manipulates pointers) 70 | - Not all metamethods work with lua 5.1 (eg char* + number). This is due to 71 | the way metamethods are looked up with mixed types in Lua 5.1. If you need 72 | this upgrade to Lua 5.2 or use boxed numbers (uint64_t and uintptr_t). 73 | - All bitfields are treated as unsigned (does anyone even use signed 74 | bitfields?). Note that "int s:8" is unsigned on unix x86/x64, but signed on 75 | windows. 76 | 77 | Todo 78 | ---- 79 | See Github issues for the most up to date list. 80 | - Fix arm support - broken since the callback refactor 81 | - Vectors 82 | - C++ reference types 83 | - Subtracting one pointer from another 84 | - Variable sized members in unions (is this needed?) 85 | 86 | How it works 87 | ------------ 88 | Types are represented by a struct ctype structure and an associated user value 89 | table. The table is shared between all related types for structs, unions, and 90 | functions. It's members have the types of struct members, function argument 91 | types, etc. The struct ctype structure then contains the modifications from 92 | the base type (eg number of pointers, array size, etc). 93 | 94 | Types are pushed into lua as a userdata containing the struct ctype with a 95 | user value (or fenv in 5.1) set to the shared type table. 96 | 97 | Boxed cdata types are pushed into lua as a userdata containing the struct 98 | cdata structure (which contains the struct ctype of the data as its header) 99 | followed by the boxed data. 100 | 101 | The functions in ffi.c provide the cdata and ctype metatables and ffi.* 102 | functions which manipulate these two types. 103 | 104 | C functions (and function pointers) are pushed into lua as a lua c function 105 | with the function pointer cdata as the first upvalue. The actual code is JITed 106 | using dynasm (see call_x86.dasc). The JITed code does the following in order: 107 | 1. Calls the needed unpack functions in ffi.c placing each argument on the HW stack 108 | 2. Updates errno 109 | 3. Performs the c call 110 | 4. Retrieves errno 111 | 5. Pushes the result back into lua from the HW register or stack 112 | 113 | -------------------------------------------------------------------------------- /pretty.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Julio Manuel Fernandez-Diaz 3 | Date: January 12, 2007 4 | (For Lua 5.1) 5 | 6 | Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount() 7 | 8 | Formats tables with cycles recursively to any depth. 9 | The output is returned as a string. 10 | References to other tables are shown as values. 11 | Self references are indicated. 12 | 13 | The string returned is "Lua code", which can be procesed 14 | (in the case in which indent is composed by spaces or "--"). 15 | Userdata and function keys and values are shown as strings, 16 | which logically are exactly not equivalent to the original code. 17 | 18 | This routine can serve for pretty formating tables with 19 | proper indentations, apart from printing them: 20 | 21 | print(table.show(t, "t")) -- a typical use 22 | 23 | Heavily based on "Saving tables with cycles", PIL2, p. 113. 24 | 25 | Arguments: 26 | t is the table. 27 | name is the name of the table (optional) 28 | indent is a first indentation (optional). 29 | --]] 30 | local debug = require('debug') 31 | local dbg_getfenv = debug.getfenv or debug.getuservalue 32 | 33 | function table.show(t, name, indent) 34 | local cart -- a container 35 | local autoref -- for self references 36 | 37 | --[[ counts the number of elements in a table 38 | local function tablecount(t) 39 | local n = 0 40 | for _, _ in pairs(t) do n = n+1 end 41 | return n 42 | end 43 | ]] 44 | -- (RiciLake) returns true if the table is empty 45 | local function isemptytable(t) return type(t) == "table" and next(t) == nil end 46 | 47 | local function basicSerialize (o) 48 | local so = tostring(o) 49 | if type(o) == "function" then 50 | local info = debug.getinfo(o, "S") 51 | -- info.name is nil because o is not a calling level 52 | if info.what == "C" then 53 | return string.format("%q", so .. ", C function") 54 | else 55 | -- the information is defined through lines 56 | return string.format("%q", so .. ", defined in (" .. 57 | info.linedefined .. "-" .. info.lastlinedefined .. 58 | ")" .. info.source) 59 | end 60 | elseif type(o) == "number" or type(o) == "boolean" then 61 | return so 62 | else 63 | return string.format("%q", so) 64 | end 65 | end 66 | 67 | local function addtocart (value, name, indent, saved, field) 68 | indent = indent or "" 69 | saved = saved or {} 70 | field = field or name 71 | 72 | cart = cart .. indent .. field 73 | 74 | if type(value) == "table" then 75 | if saved[value] then 76 | cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n" 77 | autoref = autoref .. name .. " = " .. saved[value] .. ";\n" 78 | else 79 | saved[value] = name 80 | --if tablecount(value) == 0 then 81 | if isemptytable(value) then 82 | cart = cart .. " = {};\n" 83 | else 84 | cart = cart .. " = {\n" 85 | for k, v in pairs(value) do 86 | k = basicSerialize(k) 87 | local fname = string.format("%s[%s]", name, k) 88 | field = string.format("[%s]", k) 89 | -- three spaces between levels 90 | addtocart(v, fname, indent .. " ", saved, field) 91 | end 92 | for k, v in pairs{env = dbg_getfenv(value), mt = debug.getmetatable(value)} do 93 | k = basicSerialize(k) 94 | local fname = string.format("%s[%s]", name, k) 95 | field = string.format("[%s]", k) 96 | -- three spaces between levels 97 | addtocart(v, fname, indent .. " ", saved, field) 98 | end 99 | cart = cart .. indent .. "};\n" 100 | end 101 | end 102 | elseif type(value) == "userdata" then 103 | if saved[value] then 104 | cart = cart .. " = " .. basicSerialize(value) .. "; -- " .. saved[value] .. " (self reference)\n" 105 | autoref = autoref .. name .. " = " .. saved[value] .. ";\n" 106 | else 107 | saved[value] = name 108 | cart = cart .. " = " .. basicSerialize(value) .. " {\n" 109 | for k, v in pairs{env = dbg_getfenv(value), mt = debug.getmetatable(value)} do 110 | k = basicSerialize(k) 111 | local fname = string.format("%s[%s]", name, k) 112 | field = string.format("[%s]", k) 113 | -- three spaces between levels 114 | addtocart(v, fname, indent .. " ", saved, field) 115 | end 116 | cart = cart .. indent .. "};\n" 117 | end 118 | elseif type(value) == "function" then 119 | cart = cart .. " = " .. basicSerialize(value) 120 | if debug.getupvalue(value, 1) == nil then 121 | cart = cart .. ";\n" 122 | else 123 | cart = cart .. " {\n" 124 | local i = 1 125 | while true do 126 | local k, v = debug.getupvalue(value, i) 127 | if k == nil and v == nil then break end 128 | k = basicSerialize(i) 129 | local fname = string.format("%s[%s]", name, k) 130 | field = string.format("[%s]", k) 131 | -- three spaces between levels 132 | addtocart(v, fname, indent .. " ", saved, field) 133 | i = i + 1 134 | end 135 | cart = cart .. indent .. "};\n" 136 | end 137 | else 138 | cart = cart .. " = " .. basicSerialize(value) .. ";\n" 139 | end 140 | end 141 | 142 | name = name or "__unnamed__" 143 | if type(t) ~= "table" and type(t) ~= 'userdata' then 144 | return name .. " = " .. basicSerialize(t) 145 | end 146 | cart, autoref = "", "" 147 | addtocart(t, name, indent) 148 | return cart .. autoref 149 | end 150 | 151 | -------------------------------------------------------------------------------- /msvc/stdint.h: -------------------------------------------------------------------------------- 1 | // boost cstdint.hpp header file ------------------------------------------// 2 | 3 | // (C) Copyright Beman Dawes 1999. 4 | // (C) Copyright Jens Mauer 2001 5 | // (C) Copyright John Maddock 2001 6 | // Distributed under the Boost 7 | // Software License, Version 1.0. (See accompanying file 8 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | 10 | // See http://www.boost.org/libs/integer for documentation. 11 | 12 | // Revision History 13 | // 31 Oct 01 use BOOST_HAS_LONG_LONG to check for "long long" (Jens M.) 14 | // 16 Apr 01 check LONGLONG_MAX when looking for "long long" (Jens Maurer) 15 | // 23 Jan 01 prefer "long" over "int" for int32_t and intmax_t (Jens Maurer) 16 | // 12 Nov 00 Merged (Jens Maurer) 17 | // 23 Sep 00 Added INTXX_C macro support (John Maddock). 18 | // 22 Sep 00 Better 64-bit support (John Maddock) 19 | // 29 Jun 00 Reimplement to avoid including stdint.h within namespace boost 20 | // 8 Aug 99 Initial version (Beman Dawes) 21 | 22 | 23 | #ifndef STDINT_H 24 | #define STDINT_H 25 | 26 | #ifndef UNDER_CE 27 | #include 28 | #endif 29 | 30 | #include 31 | 32 | // These are fairly safe guesses for some 16-bit, and most 32-bit and 64-bit 33 | // platforms. For other systems, they will have to be hand tailored. 34 | // 35 | // Because the fast types are assumed to be the same as the undecorated types, 36 | // it may be possible to hand tailor a more efficient implementation. Such 37 | // an optimization may be illusionary; on the Intel x86-family 386 on, for 38 | // example, byte arithmetic and load/stores are as fast as "int" sized ones. 39 | 40 | // 8-bit types ------------------------------------------------------------// 41 | 42 | # if UCHAR_MAX == 0xff 43 | typedef signed char int8_t; 44 | typedef signed char int_least8_t; 45 | typedef signed char int_fast8_t; 46 | typedef unsigned char uint8_t; 47 | typedef unsigned char uint_least8_t; 48 | typedef unsigned char uint_fast8_t; 49 | # else 50 | # error defaults not correct; you must hand modify boost/cstdint.hpp 51 | # endif 52 | 53 | // 16-bit types -----------------------------------------------------------// 54 | 55 | # if USHRT_MAX == 0xffff 56 | # if defined(__crayx1) 57 | // The Cray X1 has a 16-bit short, however it is not recommend 58 | // for use in performance critical code. 59 | typedef short int16_t; 60 | typedef short int_least16_t; 61 | typedef int int_fast16_t; 62 | typedef unsigned short uint16_t; 63 | typedef unsigned short uint_least16_t; 64 | typedef unsigned int uint_fast16_t; 65 | # else 66 | typedef short int16_t; 67 | typedef short int_least16_t; 68 | typedef short int_fast16_t; 69 | typedef unsigned short uint16_t; 70 | typedef unsigned short uint_least16_t; 71 | typedef unsigned short uint_fast16_t; 72 | # endif 73 | # elif (USHRT_MAX == 0xffffffff) && defined(CRAY) 74 | // no 16-bit types on Cray: 75 | typedef short int_least16_t; 76 | typedef short int_fast16_t; 77 | typedef unsigned short uint_least16_t; 78 | typedef unsigned short uint_fast16_t; 79 | # else 80 | # error defaults not correct; you must hand modify boost/cstdint.hpp 81 | # endif 82 | 83 | // 32-bit types -----------------------------------------------------------// 84 | 85 | # if ULONG_MAX == 0xffffffff 86 | typedef long int32_t; 87 | typedef long int_least32_t; 88 | typedef long int_fast32_t; 89 | typedef unsigned long uint32_t; 90 | typedef unsigned long uint_least32_t; 91 | typedef unsigned long uint_fast32_t; 92 | # elif UINT_MAX == 0xffffffff 93 | typedef int int32_t; 94 | typedef int int_least32_t; 95 | typedef int int_fast32_t; 96 | typedef unsigned int uint32_t; 97 | typedef unsigned int uint_least32_t; 98 | typedef unsigned int uint_fast32_t; 99 | # else 100 | # error defaults not correct; you must hand modify boost/cstdint.hpp 101 | # endif 102 | 103 | // 64-bit types + intmax_t and uintmax_t ----------------------------------// 104 | 105 | // 106 | // we have Borland/Intel/Microsoft __int64: 107 | // 108 | typedef __int64 intmax_t; 109 | typedef unsigned __int64 uintmax_t; 110 | typedef __int64 int64_t; 111 | typedef __int64 int_least64_t; 112 | typedef __int64 int_fast64_t; 113 | typedef unsigned __int64 uint64_t; 114 | typedef unsigned __int64 uint_least64_t; 115 | typedef unsigned __int64 uint_fast64_t; 116 | 117 | 118 | 119 | /**************************************************** 120 | 121 | Macro definition section: 122 | 123 | Define various INTXX_C macros only if 124 | __STDC_CONSTANT_MACROS is defined. 125 | 126 | Undefine the macros if __STDC_CONSTANT_MACROS is 127 | not defined and the macros are (cf ). 128 | 129 | Added 23rd September 2000 (John Maddock). 130 | Modified 11th September 2001 to be excluded when 131 | BOOST_HAS_STDINT_H is defined (John Maddock). 132 | 133 | ******************************************************/ 134 | 135 | #if defined(__STDC_CONSTANT_MACROS) || !defined(__cplusplus) 136 | // 137 | // Borland/Intel/Microsoft compilers have width specific suffixes: 138 | // 139 | # define INT8_C(value) value##i8 140 | # define INT16_C(value) value##i16 141 | # define INT32_C(value) value##i32 142 | # define INT64_C(value) value##i64 143 | # define UINT8_C(value) value##ui8 144 | # define UINT16_C(value) value##ui16 145 | # define UINT32_C(value) value##ui32 146 | # define UINT64_C(value) value##ui64 147 | # define INTMAX_C(value) value##i64 148 | # define UINTMAX_C(value) value##ui64 149 | 150 | #endif // __STDC_CONSTANT_MACROS_DEFINED etc. 151 | 152 | #if defined(__STDC_LIMIT_MACROS) || !defined(__cplusplus) 153 | # define INT8_MIN INT8_C(-127)-1 154 | # define INT8_MAX INT8_C(127) 155 | # define INT16_MIN INT16_C(-32767)-1 156 | # define INT16_MAX INT16_C(32767) 157 | # define INT32_MIN INT32_C(-2147483647)-1 158 | # define INT32_MAX INT32_C(2147483647) 159 | # define INT64_MAX INT64_C(9223372036854775807) 160 | # define UINT8_MAX UINT8_C(255) 161 | # define UINT16_MAX UINT16_C(65535) 162 | # define UINT32_MAX UINT32_C(4294967295) 163 | # define UINT64_MAX UINT64_C(18446744073709551615) 164 | #endif 165 | 166 | #ifdef UNDER_CE 167 | typedef unsigned long uintptr_t; 168 | typedef long intptr_t; 169 | #endif 170 | 171 | 172 | 173 | #endif // BOOST_CSTDINT_HPP 174 | 175 | -------------------------------------------------------------------------------- /ctype.c: -------------------------------------------------------------------------------- 1 | /* vim: ts=4 sw=4 sts=4 et tw=78 2 | * Copyright (c) 2011 James R. McKaskill. See license in ffi.h 3 | */ 4 | #include "ffi.h" 5 | 6 | static int to_define_key; 7 | 8 | static void update_on_definition(lua_State* L, int ct_usr, int ct_idx) 9 | { 10 | ct_usr = lua_absindex(L, ct_usr); 11 | ct_idx = lua_absindex(L, ct_idx); 12 | 13 | lua_pushlightuserdata(L, &to_define_key); 14 | lua_rawget(L, ct_usr); 15 | 16 | if (lua_isnil(L, -1)) { 17 | lua_pop(L, 1); /* pop the nil */ 18 | 19 | /* {} */ 20 | lua_newtable(L); 21 | 22 | /* {__mode='k'} */ 23 | lua_newtable(L); 24 | lua_pushliteral(L, "k"); 25 | lua_setfield(L, -2, "__mode"); 26 | 27 | /* setmetatable({}, {__mode='k'}) */ 28 | lua_setmetatable(L, -2); 29 | 30 | /* usr[TO_UPDATE_KEY] = setmetatable({}, {__mode='k'}) */ 31 | lua_pushlightuserdata(L, &to_define_key); 32 | lua_pushvalue(L, -2); 33 | lua_rawset(L, ct_usr); 34 | 35 | /* leave the table on the stack */ 36 | } 37 | 38 | /* to_update[ctype or cdata] = true */ 39 | lua_pushvalue(L, ct_idx); 40 | lua_pushboolean(L, 1); 41 | lua_rawset(L, -3); 42 | 43 | /* pop the to_update table */ 44 | lua_pop(L, 1); 45 | } 46 | 47 | void set_defined(lua_State* L, int ct_usr, struct ctype* ct) 48 | { 49 | ct_usr = lua_absindex(L, ct_usr); 50 | 51 | ct->is_defined = 1; 52 | 53 | /* update ctypes and cdatas that were created before the definition came in */ 54 | lua_pushlightuserdata(L, &to_define_key); 55 | lua_rawget(L, ct_usr); 56 | 57 | if (!lua_isnil(L, -1)) { 58 | lua_pushnil(L); 59 | 60 | while (lua_next(L, -2)) { 61 | struct ctype* upd = (struct ctype*) lua_touserdata(L, -2); 62 | upd->base_size = ct->base_size; 63 | upd->align_mask = ct->align_mask; 64 | upd->is_defined = 1; 65 | upd->is_variable_struct = ct->is_variable_struct; 66 | upd->variable_increment = ct->variable_increment; 67 | assert(!upd->variable_size_known); 68 | lua_pop(L, 1); 69 | } 70 | 71 | lua_pop(L, 1); 72 | /* usr[TO_UPDATE_KEY] = nil */ 73 | lua_pushlightuserdata(L, &to_define_key); 74 | lua_pushnil(L); 75 | lua_rawset(L, ct_usr); 76 | } else { 77 | lua_pop(L, 1); 78 | } 79 | } 80 | 81 | struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct) 82 | { 83 | struct ctype* ret; 84 | ct_usr = lua_absindex(L, ct_usr); 85 | 86 | ret = (struct ctype*) lua_newuserdata(L, sizeof(struct ctype)); 87 | *ret = *ct; 88 | 89 | push_upval(L, &ctype_mt_key); 90 | lua_setmetatable(L, -2); 91 | 92 | #if LUA_VERSION_NUM == 501 93 | if (!ct_usr || lua_isnil(L, ct_usr)) { 94 | push_upval(L, &niluv_key); 95 | lua_setfenv(L, -2); 96 | } 97 | #endif 98 | 99 | if (ct_usr && !lua_isnil(L, ct_usr)) { 100 | lua_pushvalue(L, ct_usr); 101 | lua_setuservalue(L, -2); 102 | } 103 | 104 | if (!ct->is_defined && ct_usr && !lua_isnil(L, ct_usr)) { 105 | update_on_definition(L, ct_usr, -1); 106 | } 107 | 108 | return ret; 109 | } 110 | 111 | size_t ctype_size(lua_State* L, const struct ctype* ct) 112 | { 113 | if (ct->pointers - ct->is_array) { 114 | return sizeof(void*) * (ct->is_array ? ct->array_size : 1); 115 | 116 | } else if (!ct->is_defined || ct->type == VOID_TYPE) { 117 | return luaL_error(L, "can't calculate size of an undefined type"); 118 | 119 | } else if (ct->variable_size_known) { 120 | assert(ct->is_variable_struct && !ct->is_array); 121 | return ct->base_size + ct->variable_increment; 122 | 123 | } else if (ct->is_variable_array || ct->is_variable_struct) { 124 | return luaL_error(L, "internal error: calc size of variable type with unknown size"); 125 | 126 | } else { 127 | return ct->base_size * (ct->is_array ? ct->array_size : 1); 128 | } 129 | } 130 | 131 | void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct) 132 | { 133 | struct cdata* cd; 134 | size_t sz = ct->is_reference ? sizeof(void*) : ctype_size(L, ct); 135 | ct_usr = lua_absindex(L, ct_usr); 136 | 137 | /* This is to stop valgrind from complaining. Bitfields are accessed in 8 138 | * byte chunks so that the code doesn't have to deal with different access 139 | * patterns, but this means that occasionally it will read past the end of 140 | * the struct. As its not setting the bits past the end (only reading and 141 | * then writing the bits back) and the read is aligned its a non-issue, 142 | * but valgrind complains nonetheless. 143 | */ 144 | if (ct->has_bitfield) { 145 | sz = ALIGN_UP(sz, 7); 146 | } 147 | 148 | cd = (struct cdata*) lua_newuserdata(L, sizeof(struct cdata) + sz); 149 | *(struct ctype*) &cd->type = *ct; 150 | memset(cd+1, 0, sz); 151 | 152 | /* TODO: handle cases where lua_newuserdata returns a pointer that is not 153 | * aligned */ 154 | #if 0 155 | assert((uintptr_t) (cd + 1) % 8 == 0); 156 | #endif 157 | 158 | #if LUA_VERSION_NUM == 501 159 | if (!ct_usr || lua_isnil(L, ct_usr)) { 160 | push_upval(L, &niluv_key); 161 | lua_setfenv(L, -2); 162 | } 163 | #endif 164 | 165 | if (ct_usr && !lua_isnil(L, ct_usr)) { 166 | lua_pushvalue(L, ct_usr); 167 | lua_setuservalue(L, -2); 168 | } 169 | 170 | push_upval(L, &cdata_mt_key); 171 | lua_setmetatable(L, -2); 172 | 173 | if (!ct->is_defined && ct_usr && !lua_isnil(L, ct_usr)) { 174 | update_on_definition(L, ct_usr, -1); 175 | } 176 | 177 | return cd+1; 178 | } 179 | 180 | void push_callback(lua_State* L, cfunction f) 181 | { 182 | cfunction* pf = (cfunction*) lua_newuserdata(L, sizeof(cfunction)); 183 | *pf = f; 184 | 185 | push_upval(L, &callback_mt_key); 186 | lua_setmetatable(L, -2); 187 | } 188 | 189 | /* returns the value as a ctype, pushes the user value onto the stack */ 190 | void check_ctype(lua_State* L, int idx, struct ctype* ct) 191 | { 192 | if (lua_isstring(L, idx)) { 193 | struct parser P; 194 | P.line = 1; 195 | P.prev = P.next = lua_tostring(L, idx); 196 | P.align_mask = DEFAULT_ALIGN_MASK; 197 | parse_type(L, &P, ct); 198 | parse_argument(L, &P, -1, ct, NULL, NULL); 199 | lua_remove(L, -2); /* remove the user value from parse_type */ 200 | 201 | } else if (lua_getmetatable(L, idx)) { 202 | if (!equals_upval(L, -1, &ctype_mt_key) 203 | && !equals_upval(L, -1, &cdata_mt_key)) { 204 | goto err; 205 | } 206 | 207 | lua_pop(L, 1); /* pop the metatable */ 208 | *ct = *(struct ctype*) lua_touserdata(L, idx); 209 | lua_getuservalue(L, idx); 210 | 211 | } else { 212 | goto err; 213 | } 214 | 215 | return; 216 | 217 | err: 218 | luaL_error(L, "expected cdata, ctype or string for arg #%d", idx); 219 | } 220 | 221 | /* to_cdata returns the struct cdata* and pushes the user value onto the 222 | * stack. If the index is not a ctype then ct is not touched, a nil is pushed, 223 | * NULL is returned, and ct->type is set to INVALID_TYPE. Also dereferences 224 | * references */ 225 | void* to_cdata(lua_State* L, int idx, struct ctype* ct) 226 | { 227 | struct cdata* cd; 228 | 229 | ct->type = INVALID_TYPE; 230 | if (!lua_isuserdata(L, idx) || !lua_getmetatable(L, idx)) { 231 | lua_pushnil(L); 232 | return NULL; 233 | } 234 | 235 | if (!equals_upval(L, -1, &cdata_mt_key)) { 236 | lua_pop(L, 1); /* mt */ 237 | lua_pushnil(L); 238 | return NULL; 239 | } 240 | 241 | lua_pop(L, 1); /* mt */ 242 | cd = (struct cdata*) lua_touserdata(L, idx); 243 | *ct = cd->type; 244 | lua_getuservalue(L, idx); 245 | 246 | if (ct->is_reference) { 247 | ct->is_reference = 0; 248 | return *(void**) (cd+1); 249 | 250 | } else if (ct->pointers && !ct->is_array) { 251 | return *(void**) (cd+1); 252 | 253 | } else { 254 | return cd + 1; 255 | } 256 | } 257 | 258 | /* check_cdata returns the struct cdata* and pushes the user value onto the 259 | * stack. Also dereferences references. */ 260 | void* check_cdata(lua_State* L, int idx, struct ctype* ct) 261 | { 262 | void* p = to_cdata(L, idx, ct); 263 | if (ct->type == INVALID_TYPE) { 264 | luaL_error(L, "expected cdata for arg #%d", idx); 265 | } 266 | return p; 267 | } 268 | 269 | -------------------------------------------------------------------------------- /call.c: -------------------------------------------------------------------------------- 1 | /* vim: ts=4 sw=4 sts=4 et tw=78 2 | * Copyright (c) 2011 James R. McKaskill. See license in ffi.h 3 | */ 4 | #include "ffi.h" 5 | 6 | static cfunction compile(Dst_DECL, lua_State* L, cfunction func, int ref); 7 | 8 | static void* reserve_code(struct jit* jit, lua_State* L, size_t sz); 9 | static void commit_code(struct jit* jit, void* p, size_t sz); 10 | 11 | static void push_int(lua_State* L, int val) 12 | { lua_pushnumber(L, val); } 13 | 14 | static void push_uint(lua_State* L, unsigned int val) 15 | { lua_pushnumber(L, val); } 16 | 17 | static void push_float(lua_State* L, float val) 18 | { lua_pushnumber(L, val); } 19 | 20 | #ifndef _WIN32 21 | static int GetLastError(void) 22 | { return errno; } 23 | static void SetLastError(int err) 24 | { errno = err; } 25 | #endif 26 | 27 | #ifdef NDEBUG 28 | #define shred(a,b,c) 29 | #else 30 | #define shred(p,s,e) memset((uint8_t*)(p)+(s),0xCC,(e)-(s)) 31 | #endif 32 | 33 | 34 | #ifdef _WIN64 35 | #include "dynasm/dasm_x86.h" 36 | #include "call_x64win.h" 37 | #elif defined __amd64__ 38 | #include "dynasm/dasm_x86.h" 39 | #include "call_x64.h" 40 | #elif defined __arm__ || defined __arm || defined __ARM__ || defined __ARM || defined ARM || defined _ARM_ || defined ARMV4I || defined _M_ARM 41 | #include "dynasm/dasm_arm.h" 42 | #include "call_arm.h" 43 | #else 44 | #include "dynasm/dasm_x86.h" 45 | #include "call_x86.h" 46 | #endif 47 | 48 | struct jit_head { 49 | size_t size; 50 | int ref; 51 | uint8_t jump[JUMP_SIZE]; 52 | }; 53 | 54 | #define LINKTABLE_MAX_SIZE (sizeof(extnames) / sizeof(extnames[0]) * (JUMP_SIZE)) 55 | 56 | static cfunction compile(struct jit* jit, lua_State* L, cfunction func, int ref) 57 | { 58 | struct jit_head* code; 59 | size_t codesz; 60 | int err; 61 | 62 | dasm_checkstep(jit, -1); 63 | if ((err = dasm_link(jit, &codesz)) != 0) { 64 | char buf[32]; 65 | sprintf(buf, "%x", err); 66 | luaL_error(L, "dasm_link error %s", buf); 67 | } 68 | 69 | codesz += sizeof(struct jit_head); 70 | code = (struct jit_head*) reserve_code(jit, L, codesz); 71 | code->ref = ref; 72 | code->size = codesz; 73 | compile_extern_jump(jit, L, func, code->jump); 74 | 75 | if ((err = dasm_encode(jit, code+1)) != 0) { 76 | char buf[32]; 77 | sprintf(buf, "%x", err); 78 | commit_code(jit, code, 0); 79 | luaL_error(L, "dasm_encode error %s", buf); 80 | } 81 | 82 | commit_code(jit, code, codesz); 83 | return (cfunction) (code+1); 84 | } 85 | 86 | typedef uint8_t jump_t[JUMP_SIZE]; 87 | 88 | int get_extern(struct jit* jit, uint8_t* addr, int idx, int type) 89 | { 90 | struct page* page = jit->pages[jit->pagenum-1]; 91 | jump_t* jumps = (jump_t*) (page+1); 92 | struct jit_head* h = (struct jit_head*) ((uint8_t*) page + page->off); 93 | uint8_t* jmp; 94 | ptrdiff_t off; 95 | 96 | if (idx == jit->function_extern) { 97 | jmp = h->jump; 98 | } else { 99 | jmp = jumps[idx]; 100 | } 101 | 102 | /* compensate for room taken up for the offset so that we can work rip 103 | * relative */ 104 | addr += BRANCH_OFF; 105 | 106 | /* see if we can fit the offset in the branch displacement, if not use the 107 | * jump instruction */ 108 | off = *(uint8_t**) jmp - addr; 109 | 110 | if (MIN_BRANCH <= off && off <= MAX_BRANCH) { 111 | return (int32_t) off; 112 | } else { 113 | return (int32_t)(jmp + sizeof(uint8_t*) - addr); 114 | } 115 | } 116 | 117 | static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) 118 | { 119 | struct page* page; 120 | size_t off = (jit->pagenum > 0) ? jit->pages[jit->pagenum-1]->off : 0; 121 | size_t size = (jit->pagenum > 0) ? jit->pages[jit->pagenum-1]->size : 0; 122 | 123 | if (off + sz >= size) { 124 | int i; 125 | uint8_t* pdata; 126 | cfunction func; 127 | 128 | /* need to create a new page */ 129 | jit->pages = (struct page**) realloc(jit->pages, (++jit->pagenum) * sizeof(jit->pages[0])); 130 | 131 | size = ALIGN_UP(sz + LINKTABLE_MAX_SIZE + sizeof(struct page), jit->align_page_size); 132 | 133 | page = (struct page*) AllocPage(size); 134 | jit->pages[jit->pagenum-1] = page; 135 | pdata = (uint8_t*) page; 136 | page->size = size; 137 | page->off = sizeof(struct page); 138 | 139 | lua_newtable(L); 140 | 141 | #define ADDFUNC(DLL, NAME) \ 142 | lua_pushliteral(L, #NAME); \ 143 | func = DLL ? (cfunction) GetProcAddressA(DLL, #NAME) : NULL; \ 144 | func = func ? func : (cfunction) &NAME; \ 145 | lua_pushcfunction(L, (lua_CFunction) func); \ 146 | lua_rawset(L, -3) 147 | 148 | ADDFUNC(NULL, check_double); 149 | ADDFUNC(NULL, check_float); 150 | ADDFUNC(NULL, check_uint64); 151 | ADDFUNC(NULL, check_int64); 152 | ADDFUNC(NULL, check_int32); 153 | ADDFUNC(NULL, check_uint32); 154 | ADDFUNC(NULL, check_uintptr); 155 | ADDFUNC(NULL, check_enum); 156 | ADDFUNC(NULL, check_typed_pointer); 157 | ADDFUNC(NULL, check_typed_cfunction); 158 | ADDFUNC(NULL, check_complex_double); 159 | ADDFUNC(NULL, check_complex_float); 160 | ADDFUNC(NULL, unpack_varargs_stack); 161 | ADDFUNC(NULL, unpack_varargs_stack_skip); 162 | ADDFUNC(NULL, unpack_varargs_reg); 163 | ADDFUNC(NULL, unpack_varargs_float); 164 | ADDFUNC(NULL, unpack_varargs_int); 165 | ADDFUNC(NULL, push_cdata); 166 | ADDFUNC(NULL, push_int); 167 | ADDFUNC(NULL, push_uint); 168 | ADDFUNC(NULL, push_float); 169 | ADDFUNC(jit->kernel32_dll, SetLastError); 170 | ADDFUNC(jit->kernel32_dll, GetLastError); 171 | ADDFUNC(jit->lua_dll, luaL_error); 172 | ADDFUNC(jit->lua_dll, lua_pushnumber); 173 | ADDFUNC(jit->lua_dll, lua_pushboolean); 174 | ADDFUNC(jit->lua_dll, lua_gettop); 175 | ADDFUNC(jit->lua_dll, lua_rawgeti); 176 | ADDFUNC(jit->lua_dll, lua_pushnil); 177 | ADDFUNC(jit->lua_dll, lua_callk); 178 | ADDFUNC(jit->lua_dll, lua_settop); 179 | ADDFUNC(jit->lua_dll, lua_remove); 180 | #undef ADDFUNC 181 | 182 | for (i = 0; extnames[i] != NULL; i++) { 183 | 184 | if (strcmp(extnames[i], "FUNCTION") == 0) { 185 | shred(pdata + page->off, 0, JUMP_SIZE); 186 | jit->function_extern = i; 187 | 188 | } else { 189 | lua_getfield(L, -1, extnames[i]); 190 | func = (cfunction) lua_tocfunction(L, -1); 191 | 192 | if (func == NULL) { 193 | luaL_error(L, "internal error: missing link for %s", extnames[i]); 194 | } 195 | 196 | compile_extern_jump(jit, L, func, pdata + page->off); 197 | lua_pop(L, 1); 198 | } 199 | 200 | page->off += JUMP_SIZE; 201 | } 202 | 203 | page->freed = page->off; 204 | lua_pop(L, 1); 205 | 206 | } else { 207 | page = jit->pages[jit->pagenum-1]; 208 | EnableWrite(page, page->size); 209 | } 210 | 211 | return (uint8_t*) page + page->off; 212 | } 213 | 214 | static void commit_code(struct jit* jit, void* code, size_t sz) 215 | { 216 | struct page* page = jit->pages[jit->pagenum-1]; 217 | page->off += sz; 218 | EnableExecute(page, page->size); 219 | { 220 | #if 0 221 | FILE* out = fopen("\\Hard Disk\\out.bin", "wb"); 222 | fwrite(page, page->off, 1, out); 223 | fclose(out); 224 | #endif 225 | } 226 | } 227 | 228 | /* push_func_ref pushes a copy of the upval table embedded in the compiled 229 | * function func. 230 | */ 231 | void push_func_ref(lua_State* L, cfunction func) 232 | { 233 | struct jit_head* h = ((struct jit_head*) func) - 1; 234 | lua_rawgeti(L, LUA_REGISTRYINDEX, h->ref); 235 | } 236 | 237 | void free_code(struct jit* jit, lua_State* L, cfunction func) 238 | { 239 | size_t i; 240 | struct jit_head* h = ((struct jit_head*) func) - 1; 241 | for (i = 0; i < jit->pagenum; i++) { 242 | struct page* p = jit->pages[i]; 243 | 244 | if ((uint8_t*) h < (uint8_t*) p || (uint8_t*) p + p->size <= (uint8_t*) h) { 245 | continue; 246 | } 247 | 248 | luaL_unref(L, LUA_REGISTRYINDEX, h->ref); 249 | 250 | EnableWrite(p, p->size); 251 | p->freed += h->size; 252 | 253 | shred(h, 0, h->size); 254 | 255 | if (p->freed < p->off) { 256 | EnableExecute(p, p->size); 257 | return; 258 | } 259 | 260 | FreePage(p, p->size); 261 | memmove(&jit->pages[i], &jit->pages[i+1], (jit->pagenum - (i+1)) * sizeof(jit->pages[0])); 262 | jit->pagenum--; 263 | return; 264 | } 265 | 266 | assert(!"couldn't find func in the jit pages"); 267 | } 268 | 269 | 270 | -------------------------------------------------------------------------------- /dynasm/dasm_ppc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM PPC encoding engine. 3 | ** Copyright (C) 2005-2011 Mike Pall. All rights reserved. 4 | ** Released under the MIT/X license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "ppc" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. */ 19 | enum { 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, 21 | /* The following actions need a buffer position. */ 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, 23 | /* The following actions also have an argument. */ 24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, 25 | DASM__MAX 26 | }; 27 | 28 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 29 | #define DASM_MAXSECPOS 25 30 | 31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 32 | #define DASM_S_OK 0x00000000 33 | #define DASM_S_NOMEM 0x01000000 34 | #define DASM_S_PHASE 0x02000000 35 | #define DASM_S_MATCH_SEC 0x03000000 36 | #define DASM_S_RANGE_I 0x11000000 37 | #define DASM_S_RANGE_SEC 0x12000000 38 | #define DASM_S_RANGE_LG 0x13000000 39 | #define DASM_S_RANGE_PC 0x14000000 40 | #define DASM_S_RANGE_REL 0x15000000 41 | #define DASM_S_UNDEF_LG 0x21000000 42 | #define DASM_S_UNDEF_PC 0x22000000 43 | 44 | /* Macros to convert positions (8 bit section + 24 bit index). */ 45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 47 | #define DASM_SEC2POS(sec) ((sec)<<24) 48 | #define DASM_POS2SEC(pos) ((pos)>>24) 49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 50 | 51 | /* Action list type. */ 52 | typedef const unsigned int *dasm_ActList; 53 | 54 | /* Per-section structure. */ 55 | typedef struct dasm_Section { 56 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 57 | int *buf; /* True buffer pointer. */ 58 | size_t bsize; /* Buffer size in bytes. */ 59 | int pos; /* Biased buffer position. */ 60 | int epos; /* End of biased buffer position - max single put. */ 61 | int ofs; /* Byte offset into section. */ 62 | } dasm_Section; 63 | 64 | /* Core structure holding the DynASM encoding state. */ 65 | struct dasm_State { 66 | size_t psize; /* Allocated size of this structure. */ 67 | dasm_ActList actionlist; /* Current actionlist pointer. */ 68 | int *lglabels; /* Local/global chain/pos ptrs. */ 69 | size_t lgsize; 70 | int *pclabels; /* PC label chains/pos ptrs. */ 71 | size_t pcsize; 72 | void **globals; /* Array of globals (bias -10). */ 73 | dasm_Section *section; /* Pointer to active section. */ 74 | size_t codesize; /* Total size of all code sections. */ 75 | int maxsection; /* 0 <= sectionidx < maxsection. */ 76 | int status; /* Status code. */ 77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 78 | }; 79 | 80 | /* The size of the core structure depends on the max. number of sections. */ 81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 82 | 83 | 84 | /* Initialize DynASM state. */ 85 | void dasm_init(Dst_DECL, int maxsection) 86 | { 87 | dasm_State *D; 88 | size_t psz = 0; 89 | int i; 90 | Dst_REF = NULL; 91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 92 | D = Dst_REF; 93 | D->psize = psz; 94 | D->lglabels = NULL; 95 | D->lgsize = 0; 96 | D->pclabels = NULL; 97 | D->pcsize = 0; 98 | D->globals = NULL; 99 | D->maxsection = maxsection; 100 | for (i = 0; i < maxsection; i++) { 101 | D->sections[i].buf = NULL; /* Need this for pass3. */ 102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 103 | D->sections[i].bsize = 0; 104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 105 | } 106 | } 107 | 108 | /* Free DynASM state. */ 109 | void dasm_free(Dst_DECL) 110 | { 111 | dasm_State *D = Dst_REF; 112 | int i; 113 | for (i = 0; i < D->maxsection; i++) 114 | if (D->sections[i].buf) 115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 118 | DASM_M_FREE(Dst, D, D->psize); 119 | } 120 | 121 | /* Setup global label array. Must be called before dasm_setup(). */ 122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 123 | { 124 | dasm_State *D = Dst_REF; 125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 127 | } 128 | 129 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 130 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 131 | { 132 | dasm_State *D = Dst_REF; 133 | size_t osz = D->pcsize; 134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 136 | } 137 | 138 | /* Setup encoder. */ 139 | void dasm_setup(Dst_DECL, const void *actionlist) 140 | { 141 | dasm_State *D = Dst_REF; 142 | int i; 143 | D->actionlist = (dasm_ActList)actionlist; 144 | D->status = DASM_S_OK; 145 | D->section = &D->sections[0]; 146 | memset((void *)D->lglabels, 0, D->lgsize); 147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 148 | for (i = 0; i < D->maxsection; i++) { 149 | D->sections[i].pos = DASM_SEC2POS(i); 150 | D->sections[i].ofs = 0; 151 | } 152 | } 153 | 154 | 155 | #ifdef DASM_CHECKS 156 | #define CK(x, st) \ 157 | do { if (!(x)) { \ 158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) 159 | #define CKPL(kind, st) \ 160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) 162 | #else 163 | #define CK(x, st) ((void)0) 164 | #define CKPL(kind, st) ((void)0) 165 | #endif 166 | 167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 168 | void dasm_put(Dst_DECL, int start, ...) 169 | { 170 | va_list ap; 171 | dasm_State *D = Dst_REF; 172 | dasm_ActList p = D->actionlist + start; 173 | dasm_Section *sec = D->section; 174 | int pos = sec->pos, ofs = sec->ofs; 175 | int *b; 176 | 177 | if (pos >= sec->epos) { 178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 182 | } 183 | 184 | b = sec->rbuf; 185 | b[pos++] = start; 186 | 187 | va_start(ap, start); 188 | while (1) { 189 | unsigned int ins = *p++; 190 | unsigned int action = (ins >> 16); 191 | if (action >= DASM__MAX) { 192 | ofs += 4; 193 | } else { 194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; 195 | switch (action) { 196 | case DASM_STOP: goto stop; 197 | case DASM_SECTION: 198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); 199 | D->section = &D->sections[n]; goto stop; 200 | case DASM_ESC: p++; ofs += 4; break; 201 | case DASM_REL_EXT: break; 202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; 203 | case DASM_REL_LG: 204 | n = (ins & 2047) - 10; pl = D->lglabels + n; 205 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ 206 | pl += 10; n = *pl; 207 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 208 | goto linkrel; 209 | case DASM_REL_PC: 210 | pl = D->pclabels + n; CKPL(pc, PC); 211 | putrel: 212 | n = *pl; 213 | if (n < 0) { /* Label exists. Get label pos and store it. */ 214 | b[pos] = -n; 215 | } else { 216 | linkrel: 217 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 218 | *pl = pos; 219 | } 220 | pos++; 221 | break; 222 | case DASM_LABEL_LG: 223 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 224 | case DASM_LABEL_PC: 225 | pl = D->pclabels + n; CKPL(pc, PC); 226 | putlabel: 227 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 228 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 229 | } 230 | *pl = -pos; /* Label exists now. */ 231 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 232 | break; 233 | case DASM_IMM: 234 | #ifdef DASM_CHECKS 235 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 236 | if (ins & 0x8000) 237 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 238 | else 239 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 240 | #endif 241 | b[pos++] = n; 242 | break; 243 | } 244 | } 245 | } 246 | stop: 247 | va_end(ap); 248 | sec->pos = pos; 249 | sec->ofs = ofs; 250 | } 251 | #undef CK 252 | 253 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 254 | int dasm_link(Dst_DECL, size_t *szp) 255 | { 256 | dasm_State *D = Dst_REF; 257 | int secnum; 258 | int ofs = 0; 259 | 260 | #ifdef DASM_CHECKS 261 | *szp = 0; 262 | if (D->status != DASM_S_OK) return D->status; 263 | { 264 | int pc; 265 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 266 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 267 | } 268 | #endif 269 | 270 | { /* Handle globals not defined in this translation unit. */ 271 | int idx; 272 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 273 | int n = D->lglabels[idx]; 274 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 275 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 276 | } 277 | } 278 | 279 | /* Combine all code sections. No support for data sections (yet). */ 280 | for (secnum = 0; secnum < D->maxsection; secnum++) { 281 | dasm_Section *sec = D->sections + secnum; 282 | int *b = sec->rbuf; 283 | int pos = DASM_SEC2POS(secnum); 284 | int lastpos = sec->pos; 285 | 286 | while (pos != lastpos) { 287 | dasm_ActList p = D->actionlist + b[pos++]; 288 | while (1) { 289 | unsigned int ins = *p++; 290 | unsigned int action = (ins >> 16); 291 | switch (action) { 292 | case DASM_STOP: case DASM_SECTION: goto stop; 293 | case DASM_ESC: p++; break; 294 | case DASM_REL_EXT: break; 295 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 296 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 297 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 298 | case DASM_IMM: pos++; break; 299 | } 300 | } 301 | stop: (void)0; 302 | } 303 | ofs += sec->ofs; /* Next section starts right after current section. */ 304 | } 305 | 306 | D->codesize = ofs; /* Total size of all code sections */ 307 | *szp = ofs; 308 | return DASM_S_OK; 309 | } 310 | 311 | #ifdef DASM_CHECKS 312 | #define CK(x, st) \ 313 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 314 | #else 315 | #define CK(x, st) ((void)0) 316 | #endif 317 | 318 | /* Pass 3: Encode sections. */ 319 | int dasm_encode(Dst_DECL, void *buffer) 320 | { 321 | dasm_State *D = Dst_REF; 322 | char *base = (char *)buffer; 323 | unsigned int *cp = (unsigned int *)buffer; 324 | int secnum; 325 | 326 | /* Encode all code sections. No support for data sections (yet). */ 327 | for (secnum = 0; secnum < D->maxsection; secnum++) { 328 | dasm_Section *sec = D->sections + secnum; 329 | int *b = sec->buf; 330 | int *endb = sec->rbuf + sec->pos; 331 | 332 | while (b != endb) { 333 | dasm_ActList p = D->actionlist + *b++; 334 | while (1) { 335 | unsigned int ins = *p++; 336 | unsigned int action = (ins >> 16); 337 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 338 | switch (action) { 339 | case DASM_STOP: case DASM_SECTION: goto stop; 340 | case DASM_ESC: *cp++ = *p++; break; 341 | case DASM_REL_EXT: 342 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); 343 | goto patchrel; 344 | case DASM_ALIGN: 345 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; 346 | break; 347 | case DASM_REL_LG: 348 | CK(n >= 0, UNDEF_LG); 349 | case DASM_REL_PC: 350 | CK(n >= 0, UNDEF_PC); 351 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); 352 | patchrel: 353 | CK((n & 3) == 0 && 354 | (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> 355 | ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); 356 | cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); 357 | break; 358 | case DASM_LABEL_LG: 359 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 360 | break; 361 | case DASM_LABEL_PC: break; 362 | case DASM_IMM: 363 | cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); 364 | break; 365 | default: *cp++ = ins; break; 366 | } 367 | } 368 | stop: (void)0; 369 | } 370 | } 371 | 372 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 373 | return DASM_S_PHASE; 374 | return DASM_S_OK; 375 | } 376 | #undef CK 377 | 378 | /* Get PC label offset. */ 379 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 380 | { 381 | dasm_State *D = Dst_REF; 382 | if (pc*sizeof(int) < D->pcsize) { 383 | int pos = D->pclabels[pc]; 384 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 385 | if (pos > 0) return -1; /* Undefined. */ 386 | } 387 | return -2; /* Unused or out of range. */ 388 | } 389 | 390 | #ifdef DASM_CHECKS 391 | /* Optional sanity checker to call between isolated encoding steps. */ 392 | int dasm_checkstep(Dst_DECL, int secmatch) 393 | { 394 | dasm_State *D = Dst_REF; 395 | if (D->status == DASM_S_OK) { 396 | int i; 397 | for (i = 1; i <= 9; i++) { 398 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 399 | D->lglabels[i] = 0; 400 | } 401 | } 402 | if (D->status == DASM_S_OK && secmatch >= 0 && 403 | D->section != &D->sections[secmatch]) 404 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 405 | return D->status; 406 | } 407 | #endif 408 | 409 | -------------------------------------------------------------------------------- /dynasm/dasm_arm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM ARM encoding engine. 3 | ** Copyright (C) 2005-2011 Mike Pall. All rights reserved. 4 | ** Released under the MIT/X license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "arm" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. */ 19 | enum { 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, 21 | /* The following actions need a buffer position. */ 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, 23 | /* The following actions also have an argument. */ 24 | DASM_REL_PC, DASM_LABEL_PC, 25 | DASM_LONG, DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, 26 | DASM__MAX 27 | }; 28 | 29 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 30 | #define DASM_MAXSECPOS 25 31 | 32 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 33 | #define DASM_S_OK 0x00000000 34 | #define DASM_S_NOMEM 0x01000000 35 | #define DASM_S_PHASE 0x02000000 36 | #define DASM_S_MATCH_SEC 0x03000000 37 | #define DASM_S_RANGE_I 0x11000000 38 | #define DASM_S_RANGE_SEC 0x12000000 39 | #define DASM_S_RANGE_LG 0x13000000 40 | #define DASM_S_RANGE_PC 0x14000000 41 | #define DASM_S_RANGE_REL 0x15000000 42 | #define DASM_S_UNDEF_LG 0x21000000 43 | #define DASM_S_UNDEF_PC 0x22000000 44 | 45 | /* Macros to convert positions (8 bit section + 24 bit index). */ 46 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 47 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 48 | #define DASM_SEC2POS(sec) ((sec)<<24) 49 | #define DASM_POS2SEC(pos) ((pos)>>24) 50 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 51 | 52 | /* Action list type. */ 53 | typedef const unsigned int *dasm_ActList; 54 | 55 | /* Per-section structure. */ 56 | typedef struct dasm_Section { 57 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 58 | int *buf; /* True buffer pointer. */ 59 | size_t bsize; /* Buffer size in bytes. */ 60 | int pos; /* Biased buffer position. */ 61 | int epos; /* End of biased buffer position - max single put. */ 62 | int ofs; /* Byte offset into section. */ 63 | } dasm_Section; 64 | 65 | /* Core structure holding the DynASM encoding state. */ 66 | struct dasm_State { 67 | size_t psize; /* Allocated size of this structure. */ 68 | dasm_ActList actionlist; /* Current actionlist pointer. */ 69 | int *lglabels; /* Local/global chain/pos ptrs. */ 70 | size_t lgsize; 71 | int *pclabels; /* PC label chains/pos ptrs. */ 72 | size_t pcsize; 73 | void **globals; /* Array of globals (bias -10). */ 74 | dasm_Section *section; /* Pointer to active section. */ 75 | size_t codesize; /* Total size of all code sections. */ 76 | int maxsection; /* 0 <= sectionidx < maxsection. */ 77 | int status; /* Status code. */ 78 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 79 | }; 80 | 81 | /* The size of the core structure depends on the max. number of sections. */ 82 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 83 | 84 | 85 | /* Initialize DynASM state. */ 86 | void dasm_init(Dst_DECL, int maxsection) 87 | { 88 | dasm_State *D; 89 | size_t psz = 0; 90 | int i; 91 | Dst_REF = NULL; 92 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 93 | D = Dst_REF; 94 | D->psize = psz; 95 | D->lglabels = NULL; 96 | D->lgsize = 0; 97 | D->pclabels = NULL; 98 | D->pcsize = 0; 99 | D->globals = NULL; 100 | D->maxsection = maxsection; 101 | for (i = 0; i < maxsection; i++) { 102 | D->sections[i].buf = NULL; /* Need this for pass3. */ 103 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 104 | D->sections[i].bsize = 0; 105 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 106 | } 107 | } 108 | 109 | /* Free DynASM state. */ 110 | void dasm_free(Dst_DECL) 111 | { 112 | dasm_State *D = Dst_REF; 113 | int i; 114 | for (i = 0; i < D->maxsection; i++) 115 | if (D->sections[i].buf) 116 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 117 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 118 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 119 | DASM_M_FREE(Dst, D, D->psize); 120 | } 121 | 122 | /* Setup global label array. Must be called before dasm_setup(). */ 123 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 124 | { 125 | dasm_State *D = Dst_REF; 126 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 127 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 128 | } 129 | 130 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 131 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 132 | { 133 | dasm_State *D = Dst_REF; 134 | size_t osz = D->pcsize; 135 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 136 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 137 | } 138 | 139 | /* Setup encoder. */ 140 | void dasm_setup(Dst_DECL, const void *actionlist) 141 | { 142 | dasm_State *D = Dst_REF; 143 | int i; 144 | D->actionlist = (dasm_ActList)actionlist; 145 | D->status = DASM_S_OK; 146 | D->section = &D->sections[0]; 147 | memset((void *)D->lglabels, 0, D->lgsize); 148 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 149 | for (i = 0; i < D->maxsection; i++) { 150 | D->sections[i].pos = DASM_SEC2POS(i); 151 | D->sections[i].ofs = 0; 152 | } 153 | } 154 | 155 | 156 | #ifdef DASM_CHECKS 157 | #define CK(x, st) \ 158 | do { if (!(x)) { \ 159 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) 160 | #define CKPL(kind, st) \ 161 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 162 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) 163 | #else 164 | #define CK(x, st) ((void)0) 165 | #define CKPL(kind, st) ((void)0) 166 | #endif 167 | 168 | static int dasm_imm12(unsigned int n) 169 | { 170 | int i; 171 | for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) 172 | if (n <= 255) return (int)(n + (i << 8)); 173 | return -1; 174 | } 175 | 176 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 177 | void dasm_put(Dst_DECL, int start, ...) 178 | { 179 | va_list ap; 180 | dasm_State *D = Dst_REF; 181 | dasm_ActList p = D->actionlist + start; 182 | dasm_Section *sec = D->section; 183 | int pos = sec->pos, ofs = sec->ofs; 184 | int *b; 185 | 186 | if (pos >= sec->epos) { 187 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 188 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 189 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 190 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 191 | } 192 | 193 | b = sec->rbuf; 194 | b[pos++] = start; 195 | 196 | va_start(ap, start); 197 | while (1) { 198 | unsigned int ins = *p++; 199 | unsigned int action = (ins >> 16); 200 | if (action >= DASM__MAX) { 201 | ofs += 4; 202 | } else { 203 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; 204 | switch (action) { 205 | case DASM_STOP: goto stop; 206 | case DASM_SECTION: 207 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); 208 | D->section = &D->sections[n]; goto stop; 209 | case DASM_ESC: p++; ofs += 4; break; 210 | case DASM_REL_EXT: break; 211 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; 212 | case DASM_REL_LG: 213 | n = (ins & 2047) - 10; pl = D->lglabels + n; 214 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ 215 | pl += 10; n = *pl; 216 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 217 | goto linkrel; 218 | case DASM_REL_PC: 219 | pl = D->pclabels + n; CKPL(pc, PC); 220 | putrel: 221 | n = *pl; 222 | if (n < 0) { /* Label exists. Get label pos and store it. */ 223 | b[pos] = -n; 224 | } else { 225 | linkrel: 226 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 227 | *pl = pos; 228 | } 229 | pos++; 230 | break; 231 | case DASM_LABEL_LG: 232 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 233 | case DASM_LABEL_PC: 234 | pl = D->pclabels + n; CKPL(pc, PC); 235 | putlabel: 236 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 237 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 238 | } 239 | *pl = -pos; /* Label exists now. */ 240 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 241 | break; 242 | case DASM_LONG: 243 | ofs += 4; 244 | b[pos++] = n; 245 | break; 246 | case DASM_IMM: 247 | case DASM_IMM16: 248 | #ifdef DASM_CHECKS 249 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 250 | if ((ins & 0x8000)) 251 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 252 | else 253 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 254 | #endif 255 | b[pos++] = n; 256 | break; 257 | case DASM_IMML8: 258 | case DASM_IMML12: 259 | CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : 260 | (((-n)>>((ins>>5)&31)) == 0), RANGE_I); 261 | b[pos++] = n; 262 | break; 263 | case DASM_IMM12: 264 | CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); 265 | b[pos++] = n; 266 | break; 267 | } 268 | } 269 | } 270 | stop: 271 | va_end(ap); 272 | sec->pos = pos; 273 | sec->ofs = ofs; 274 | } 275 | #undef CK 276 | 277 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 278 | int dasm_link(Dst_DECL, size_t *szp) 279 | { 280 | dasm_State *D = Dst_REF; 281 | int secnum; 282 | int ofs = 0; 283 | 284 | #ifdef DASM_CHECKS 285 | *szp = 0; 286 | if (D->status != DASM_S_OK) return D->status; 287 | { 288 | int pc; 289 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 290 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 291 | } 292 | #endif 293 | 294 | { /* Handle globals not defined in this translation unit. */ 295 | int idx; 296 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 297 | int n = D->lglabels[idx]; 298 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 299 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 300 | } 301 | } 302 | 303 | /* Combine all code sections. No support for data sections (yet). */ 304 | for (secnum = 0; secnum < D->maxsection; secnum++) { 305 | dasm_Section *sec = D->sections + secnum; 306 | int *b = sec->rbuf; 307 | int pos = DASM_SEC2POS(secnum); 308 | int lastpos = sec->pos; 309 | 310 | while (pos != lastpos) { 311 | dasm_ActList p = D->actionlist + b[pos++]; 312 | while (1) { 313 | unsigned int ins = *p++; 314 | unsigned int action = (ins >> 16); 315 | switch (action) { 316 | case DASM_STOP: case DASM_SECTION: goto stop; 317 | case DASM_ESC: p++; break; 318 | case DASM_REL_EXT: break; 319 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 320 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 321 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 322 | case DASM_LONG: case DASM_IMM: case DASM_IMM12: case DASM_IMM16: 323 | case DASM_IMML8: case DASM_IMML12: pos++; break; 324 | } 325 | } 326 | stop: (void)0; 327 | } 328 | ofs += sec->ofs; /* Next section starts right after current section. */ 329 | } 330 | 331 | D->codesize = ofs; /* Total size of all code sections */ 332 | *szp = ofs; 333 | return DASM_S_OK; 334 | } 335 | 336 | #ifdef DASM_CHECKS 337 | #define CK(x, st) \ 338 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 339 | #else 340 | #define CK(x, st) ((void)0) 341 | #endif 342 | 343 | /* Pass 3: Encode sections. */ 344 | int dasm_encode(Dst_DECL, void *buffer) 345 | { 346 | dasm_State *D = Dst_REF; 347 | char *base = (char *)buffer; 348 | unsigned int *cp = (unsigned int *)buffer; 349 | int secnum; 350 | 351 | /* Encode all code sections. No support for data sections (yet). */ 352 | for (secnum = 0; secnum < D->maxsection; secnum++) { 353 | dasm_Section *sec = D->sections + secnum; 354 | int *b = sec->buf; 355 | int *endb = sec->rbuf + sec->pos; 356 | 357 | while (b != endb) { 358 | dasm_ActList p = D->actionlist + *b++; 359 | while (1) { 360 | unsigned int ins = *p++; 361 | unsigned int action = (ins >> 16); 362 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 363 | switch (action) { 364 | case DASM_STOP: case DASM_SECTION: goto stop; 365 | case DASM_ESC: *cp++ = *p++; break; 366 | case DASM_REL_EXT: 367 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); 368 | goto patchrel; 369 | case DASM_ALIGN: 370 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; 371 | break; 372 | case DASM_REL_LG: 373 | CK(n >= 0, UNDEF_LG); 374 | case DASM_REL_PC: 375 | CK(n >= 0, UNDEF_PC); 376 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; 377 | patchrel: 378 | if ((ins & 0x800) == 0) { 379 | CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); 380 | cp[-1] |= ((n >> 2) & 0x00ffffff); 381 | } else if ((ins & 0x1000)) { 382 | CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); 383 | goto patchimml8; 384 | } else { 385 | CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); 386 | goto patchimml12; 387 | } 388 | break; 389 | case DASM_LABEL_LG: 390 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 391 | break; 392 | case DASM_LABEL_PC: break; 393 | case DASM_LONG: 394 | *cp++ = n; 395 | break; 396 | case DASM_IMM: 397 | cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); 398 | break; 399 | case DASM_IMM12: 400 | cp[-1] |= dasm_imm12((unsigned int)n); 401 | break; 402 | case DASM_IMM16: 403 | cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); 404 | break; 405 | case DASM_IMML8: patchimml8: 406 | cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : 407 | ((-n & 0x0f) | ((-n & 0xf0) << 4)); 408 | break; 409 | case DASM_IMML12: patchimml12: 410 | cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); 411 | break; 412 | default: *cp++ = ins; break; 413 | } 414 | } 415 | stop: (void)0; 416 | } 417 | } 418 | 419 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 420 | return DASM_S_PHASE; 421 | return DASM_S_OK; 422 | } 423 | #undef CK 424 | 425 | /* Get PC label offset. */ 426 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 427 | { 428 | dasm_State *D = Dst_REF; 429 | if (pc*sizeof(int) < D->pcsize) { 430 | int pos = D->pclabels[pc]; 431 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 432 | if (pos > 0) return -1; /* Undefined. */ 433 | } 434 | return -2; /* Unused or out of range. */ 435 | } 436 | 437 | #ifdef DASM_CHECKS 438 | /* Optional sanity checker to call between isolated encoding steps. */ 439 | int dasm_checkstep(Dst_DECL, int secmatch) 440 | { 441 | dasm_State *D = Dst_REF; 442 | if (D->status == DASM_S_OK) { 443 | int i; 444 | for (i = 1; i <= 9; i++) { 445 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 446 | D->lglabels[i] = 0; 447 | } 448 | } 449 | if (D->status == DASM_S_OK && secmatch >= 0 && 450 | D->section != &D->sections[secmatch]) 451 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 452 | return D->status; 453 | } 454 | #endif 455 | 456 | -------------------------------------------------------------------------------- /ffi.h: -------------------------------------------------------------------------------- 1 | /* vim: ts=4 sw=4 sts=4 et tw=78 2 | * 3 | * Copyright (c) 2011 James R. McKaskill 4 | * 5 | * This software is licensed under the stock MIT license: 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | * 25 | * ---------------------------------------------------------------------------- 26 | */ 27 | 28 | #pragma once 29 | 30 | #ifdef _MSC_VER 31 | #define _CRT_SECURE_NO_WARNINGS 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | # include 43 | # include 44 | } 45 | # define EXTERN_C extern "C" 46 | #else 47 | # include 48 | # include 49 | # define EXTERN_C extern 50 | #endif 51 | 52 | #ifdef _WIN32 53 | #include 54 | #else 55 | #include 56 | #include 57 | #include 58 | #include 59 | #endif 60 | 61 | #if __STDC_VERSION__+0 >= 199901L 62 | #include 63 | #define HAVE_COMPLEX 64 | #define HAVE_LONG_DOUBLE 65 | #endif 66 | 67 | #ifndef NDEBUG 68 | #define DASM_CHECKS 69 | #endif 70 | 71 | struct jit; 72 | #define Dst_DECL struct jit* Dst 73 | #define Dst_REF (Dst->ctx) 74 | #define DASM_EXTERN(a,b,c,d) get_extern(a,b,c,d) 75 | 76 | #include "dynasm/dasm_proto.h" 77 | 78 | #if defined LUA_FFI_BUILD_AS_DLL 79 | # define EXPORT __declspec(dllexport) 80 | #elif defined __GNUC__ 81 | # define EXPORT __attribute__((visibility("default"))) 82 | #else 83 | # define EXPORT 84 | #endif 85 | 86 | EXTERN_C EXPORT int luaopen_ffi(lua_State* L); 87 | 88 | static int lua_absindex2(lua_State* L, int idx) { 89 | return (LUA_REGISTRYINDEX <= idx && idx < 0) 90 | ? lua_gettop(L) + idx + 1 91 | : idx; 92 | } 93 | /* use our own version of lua_absindex such that lua_absindex(L, 0) == 0 */ 94 | #define lua_absindex(L, idx) lua_absindex2(L, idx) 95 | 96 | #if LUA_VERSION_NUM == 501 97 | static void lua_callk(lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k) 98 | { 99 | lua_call(L, nargs, nresults); 100 | } 101 | /* 102 | ** set functions from list 'l' into table at top - 'nup'; each 103 | ** function gets the 'nup' elements at the top as upvalues. 104 | ** Returns with only the table at the stack. 105 | */ 106 | static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { 107 | luaL_checkstack(L, nup, "too many upvalues"); 108 | for (; l && l->name; l++) { /* fill the table with given functions */ 109 | int i; 110 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ 111 | lua_pushvalue(L, -nup); 112 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ 113 | lua_setfield(L, -(nup + 2), l->name); 114 | } 115 | lua_pop(L, nup); /* remove upvalues */ 116 | } 117 | #define lua_setuservalue lua_setfenv 118 | #define lua_getuservalue lua_getfenv 119 | #define lua_rawlen lua_objlen 120 | static char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) { 121 | if (sz > LUAL_BUFFERSIZE) { 122 | luaL_error(B->L, "string too long"); 123 | } 124 | return luaL_prepbuffer(B); 125 | } 126 | #endif 127 | 128 | /* architectures */ 129 | #if defined _WIN32 && defined UNDER_CE 130 | # define OS_CE 131 | #elif defined _WIN32 132 | # define OS_WIN 133 | #elif defined __APPLE__ && defined __MACH__ 134 | # define OS_OSX 135 | #elif defined __linux__ 136 | # define OS_LINUX 137 | #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ 138 | # define OS_BSD 139 | #elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION 140 | # define OS_POSIX 141 | #endif 142 | 143 | /* architecture */ 144 | #if defined __i386__ || defined _M_IX86 145 | # define ARCH_X86 146 | #elif defined __amd64__ || defined _M_X64 147 | # define ARCH_X64 148 | #elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm 149 | # define ARCH_ARM 150 | #else 151 | # error 152 | #endif 153 | 154 | 155 | #ifdef _WIN32 156 | 157 | # ifdef UNDER_CE 158 | static void* DoLoadLibraryA(const char* name) { 159 | wchar_t buf[MAX_PATH]; 160 | int sz = MultiByteToWideChar(CP_UTF8, 0, name, -1, buf, 512); 161 | if (sz > 0) { 162 | buf[sz] = 0; 163 | return LoadLibraryW(buf); 164 | } else { 165 | return NULL; 166 | } 167 | } 168 | # define LoadLibraryA DoLoadLibraryA 169 | # else 170 | # define GetProcAddressA GetProcAddress 171 | # endif 172 | 173 | # define LIB_FORMAT_1 "%s.dll" 174 | # define AllocPage(size) VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE) 175 | # define FreePage(data, size) VirtualFree(data, 0, MEM_RELEASE) 176 | # define EnableExecute(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_EXECUTE, &old); FlushInstructionCache(GetCurrentProcess(), data, size);} while (0) 177 | # define EnableWrite(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_READWRITE, &old);} while (0) 178 | 179 | #else 180 | # define LIB_FORMAT_1 "%s.so" 181 | # define LIB_FORMAT_2 "lib%s.so" 182 | # define LoadLibraryA(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL) 183 | # define GetProcAddressA(lib, name) dlsym(lib, name) 184 | # define AllocPage(size) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0) 185 | # define FreePage(data, size) munmap(data, size) 186 | # define EnableExecute(data, size) mprotect(data, size, PROT_READ|PROT_EXEC) 187 | # define EnableWrite(data, size) mprotect(data, size, PROT_READ|PROT_WRITE) 188 | #endif 189 | 190 | #if defined ARCH_X86 || defined ARCH_X64 191 | #define ALLOW_MISALIGNED_ACCESS 192 | #endif 193 | 194 | struct token; 195 | 196 | struct parser { 197 | int line; 198 | const char* next; 199 | const char* prev; 200 | unsigned align_mask; 201 | }; 202 | 203 | struct page { 204 | size_t size; 205 | size_t off; 206 | size_t freed; 207 | }; 208 | 209 | struct jit { 210 | lua_State* L; 211 | int32_t last_errno; 212 | dasm_State* ctx; 213 | size_t pagenum; 214 | struct page** pages; 215 | size_t align_page_size; 216 | void** globals; 217 | int function_extern; 218 | void* lua_dll; 219 | void* kernel32_dll; 220 | }; 221 | 222 | #define ALIGN_DOWN(PTR, MASK) \ 223 | (((uintptr_t) (PTR)) & (~ ((uintptr_t) (MASK)) )) 224 | #define ALIGN_UP(PTR, MASK) \ 225 | (( ((uintptr_t) (PTR)) + ((uintptr_t) (MASK)) ) & (~ ((uintptr_t) (MASK)) )) 226 | 227 | /* struct cdata/struct ctype */ 228 | 229 | #define PTR_ALIGN_MASK (sizeof(void*) - 1) 230 | #define FUNCTION_ALIGN_MASK (sizeof(void (*)()) - 1) 231 | #define DEFAULT_ALIGN_MASK 7 232 | 233 | #ifdef OS_OSX 234 | /* TODO: figure out why the alignof trick doesn't work on OS X */ 235 | #define ALIGNED_DEFAULT 7 236 | #elif defined __GNUC__ 237 | #define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1) 238 | #else 239 | #define ALIGNED_DEFAULT PTR_ALIGN_MASK 240 | #endif 241 | 242 | extern int jit_key; 243 | extern int ctype_mt_key; 244 | extern int cdata_mt_key; 245 | extern int cmodule_mt_key; 246 | extern int callback_mt_key; 247 | extern int constants_key; 248 | extern int types_key; 249 | extern int gc_key; 250 | extern int callbacks_key; 251 | extern int functions_key; 252 | extern int abi_key; 253 | extern int next_unnamed_key; 254 | extern int niluv_key; 255 | extern int asmname_key; 256 | 257 | int equals_upval(lua_State* L, int idx, int* key); 258 | void push_upval(lua_State* L, int* key); 259 | void set_upval(lua_State* L, int* key); 260 | struct jit* get_jit(lua_State* L); 261 | 262 | /* both ctype and cdata are stored as userdatas 263 | * 264 | * usr value is a table shared between the related subtypes which has: 265 | * name -> member ctype (for structs and unions) 266 | * +ves -> member ctype - in memory order (for structs) 267 | * +ves -> argument ctype (for function prototypes) 268 | * 0 -> return ctype (for function prototypes) 269 | * light userdata -> misc 270 | */ 271 | 272 | enum { 273 | C_CALL, 274 | STD_CALL, 275 | FAST_CALL, 276 | }; 277 | 278 | enum { 279 | INVALID_TYPE, 280 | VOID_TYPE, 281 | FLOAT_TYPE, 282 | DOUBLE_TYPE, 283 | LONG_DOUBLE_TYPE, 284 | COMPLEX_FLOAT_TYPE, 285 | COMPLEX_DOUBLE_TYPE, 286 | COMPLEX_LONG_DOUBLE_TYPE, 287 | BOOL_TYPE, 288 | INT8_TYPE, 289 | INT16_TYPE, 290 | INT32_TYPE, 291 | INT64_TYPE, 292 | INTPTR_TYPE, 293 | ENUM_TYPE, 294 | UNION_TYPE, 295 | STRUCT_TYPE, 296 | FUNCTION_TYPE, 297 | FUNCTION_PTR_TYPE, 298 | }; 299 | 300 | #define IS_CHAR_UNSIGNED (((char) -1) > 0) 301 | #define IS_COMPLEX(type) ((type) == COMPLEX_FLOAT_TYPE || (type) == COMPLEX_DOUBLE_TYPE) 302 | 303 | #define POINTER_BITS 2 304 | #define POINTER_MAX ((1 << POINTER_BITS) - 1) 305 | 306 | #define ALIGNOF(S) ((int) ((char*) &S.v - (char*) &S - 1)) 307 | 308 | /* Note: if adding a new member that is associated with a struct/union 309 | * definition then it needs to be copied over in ctype.c:set_defined for when 310 | * we create types based off of the declaration alone. 311 | * 312 | * Since this is used as a header for every ctype and cdata, and we create a 313 | * ton of them on the stack, we try and minimise its size. 314 | */ 315 | struct ctype { 316 | size_t base_size; /* size of the base type in bytes */ 317 | 318 | union { 319 | /* valid if is_bitfield */ 320 | struct { 321 | /* size of bitfield in bits */ 322 | unsigned bit_size : 7; 323 | /* offset within the current byte between 0-63 */ 324 | unsigned bit_offset : 6; 325 | }; 326 | /* Valid if is_array */ 327 | size_t array_size; 328 | /* Valid for is_variable_struct or is_variable_array. If 329 | * variable_size_known (only used for is_variable_struct) then this is 330 | * the total increment otherwise this is the per element increment. 331 | */ 332 | size_t variable_increment; 333 | }; 334 | size_t offset; 335 | unsigned align_mask : 4; /* as (align bytes - 1) eg 7 gives 8 byte alignment */ 336 | unsigned pointers : POINTER_BITS; /* number of dereferences to get to the base type including +1 for arrays */ 337 | unsigned const_mask : POINTER_MAX + 1; /* const pointer mask, LSB is current pointer, +1 for the whether the base type is const */ 338 | unsigned type : 5; /* value given by type enum above */ 339 | unsigned is_reference : 1; 340 | unsigned is_array : 1; 341 | unsigned is_defined : 1; 342 | unsigned is_null : 1; 343 | unsigned has_member_name : 1; 344 | unsigned calling_convention : 2; 345 | unsigned has_var_arg : 1; 346 | unsigned is_variable_array : 1; /* set for variable array types where we don't know the variable size yet */ 347 | unsigned is_variable_struct : 1; 348 | unsigned variable_size_known : 1; /* used for variable structs after we know the variable size */ 349 | unsigned is_bitfield : 1; 350 | unsigned has_bitfield : 1; 351 | unsigned is_jitted : 1; 352 | unsigned is_packed : 1; 353 | unsigned is_unsigned : 1; 354 | }; 355 | 356 | #ifdef _MSC_VER 357 | __declspec(align(16)) 358 | #endif 359 | struct cdata { 360 | const struct ctype type 361 | #ifdef __GNUC__ 362 | __attribute__ ((aligned(16))) 363 | #endif 364 | ; 365 | }; 366 | 367 | typedef void (*cfunction)(void); 368 | 369 | #ifdef HAVE_COMPLEX 370 | typedef double complex complex_double; 371 | typedef float complex complex_float; 372 | #else 373 | typedef struct { 374 | double real, imag; 375 | } complex_double; 376 | 377 | typedef struct { 378 | float real, imag; 379 | } complex_float; 380 | 381 | static double creal(complex_double c) { 382 | return c.real; 383 | } 384 | static float crealf(complex_float c) { 385 | return c.real; 386 | } 387 | 388 | static double cimag(complex_double c) { 389 | return c.imag; 390 | } 391 | static float cimagf(complex_float c) { 392 | return c.imag; 393 | } 394 | #endif 395 | 396 | #define CALLBACK_FUNC_USR_IDX 1 397 | 398 | void set_defined(lua_State* L, int ct_usr, struct ctype* ct); 399 | struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct); 400 | void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct); /* called from asm */ 401 | void push_callback(lua_State* L, cfunction f); 402 | void check_ctype(lua_State* L, int idx, struct ctype* ct); 403 | void* to_cdata(lua_State* L, int idx, struct ctype* ct); 404 | void* check_cdata(lua_State* L, int idx, struct ctype* ct); 405 | size_t ctype_size(lua_State* L, const struct ctype* ct); 406 | 407 | int parse_type(lua_State* L, struct parser* P, struct ctype* type); 408 | void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* type, struct token* name, struct parser* asmname); 409 | void push_type_name(lua_State* L, int usr, const struct ctype* ct); 410 | 411 | int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct); 412 | 413 | int ffi_cdef(lua_State* L); 414 | 415 | void push_func_ref(lua_State* L, cfunction func); 416 | void free_code(struct jit* jit, lua_State* L, cfunction func); 417 | int x86_return_size(lua_State* L, int usr, const struct ctype* ct); 418 | void compile_function(lua_State* L, cfunction f, int ct_usr, const struct ctype* ct); 419 | cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct); 420 | void compile_globals(struct jit* jit, lua_State* L); 421 | int get_extern(struct jit* jit, uint8_t* addr, int idx, int type); 422 | 423 | /* WARNING: assembly needs to be updated for prototype changes of these functions */ 424 | int check_bool(lua_State* L, int idx); 425 | double check_double(lua_State* L, int idx); 426 | double check_complex_imag(lua_State* L, int idx); 427 | float check_float(lua_State* L, int idx); 428 | uint64_t check_uint64(lua_State* L, int idx); 429 | int64_t check_int64(lua_State* L, int idx); 430 | int32_t check_int32(lua_State* L, int idx); 431 | uint32_t check_uint32(lua_State* L, int idx); 432 | uintptr_t check_uintptr(lua_State* L, int idx); 433 | int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* tt); 434 | /* these two will always push a value so that we can create structs/functions on the fly */ 435 | void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt); 436 | cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt); 437 | complex_double check_complex_double(lua_State* L, int idx); 438 | complex_float check_complex_float(lua_State* L, int idx); 439 | 440 | void unpack_varargs_stack(lua_State* L, int first, int last, char* to); 441 | void unpack_varargs_reg(lua_State* L, int first, int last, char* to); 442 | 443 | void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to); 444 | void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to); 445 | void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to); 446 | 447 | 448 | 449 | -------------------------------------------------------------------------------- /dynasm/dasm_x86.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM x86 encoding engine. 3 | ** Copyright (C) 2005-2011 Mike Pall. All rights reserved. 4 | ** Released under the MIT/X license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "x86" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. DASM_STOP must be 255. */ 19 | enum { 20 | DASM_DISP = 233, 21 | DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, 22 | DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, 23 | DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, 24 | DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP 25 | }; 26 | 27 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 28 | #define DASM_MAXSECPOS 25 29 | 30 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 31 | #define DASM_S_OK 0x00000000 32 | #define DASM_S_NOMEM 0x01000000 33 | #define DASM_S_PHASE 0x02000000 34 | #define DASM_S_MATCH_SEC 0x03000000 35 | #define DASM_S_RANGE_I 0x11000000 36 | #define DASM_S_RANGE_SEC 0x12000000 37 | #define DASM_S_RANGE_LG 0x13000000 38 | #define DASM_S_RANGE_PC 0x14000000 39 | #define DASM_S_RANGE_VREG 0x15000000 40 | #define DASM_S_UNDEF_L 0x21000000 41 | #define DASM_S_UNDEF_PC 0x22000000 42 | 43 | /* Macros to convert positions (8 bit section + 24 bit index). */ 44 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 45 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 46 | #define DASM_SEC2POS(sec) ((sec)<<24) 47 | #define DASM_POS2SEC(pos) ((pos)>>24) 48 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 49 | 50 | /* Action list type. */ 51 | typedef const unsigned char *dasm_ActList; 52 | 53 | /* Per-section structure. */ 54 | typedef struct dasm_Section { 55 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 56 | int *buf; /* True buffer pointer. */ 57 | size_t bsize; /* Buffer size in bytes. */ 58 | int pos; /* Biased buffer position. */ 59 | int epos; /* End of biased buffer position - max single put. */ 60 | int ofs; /* Byte offset into section. */ 61 | } dasm_Section; 62 | 63 | /* Core structure holding the DynASM encoding state. */ 64 | struct dasm_State { 65 | size_t psize; /* Allocated size of this structure. */ 66 | dasm_ActList actionlist; /* Current actionlist pointer. */ 67 | int *lglabels; /* Local/global chain/pos ptrs. */ 68 | size_t lgsize; 69 | int *pclabels; /* PC label chains/pos ptrs. */ 70 | size_t pcsize; 71 | void **globals; /* Array of globals (bias -10). */ 72 | dasm_Section *section; /* Pointer to active section. */ 73 | size_t codesize; /* Total size of all code sections. */ 74 | int maxsection; /* 0 <= sectionidx < maxsection. */ 75 | int status; /* Status code. */ 76 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 77 | }; 78 | 79 | /* The size of the core structure depends on the max. number of sections. */ 80 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 81 | 82 | 83 | /* Initialize DynASM state. */ 84 | void dasm_init(Dst_DECL, int maxsection) 85 | { 86 | dasm_State *D; 87 | size_t psz = 0; 88 | int i; 89 | Dst_REF = NULL; 90 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 91 | D = Dst_REF; 92 | D->psize = psz; 93 | D->lglabels = NULL; 94 | D->lgsize = 0; 95 | D->pclabels = NULL; 96 | D->pcsize = 0; 97 | D->globals = NULL; 98 | D->maxsection = maxsection; 99 | for (i = 0; i < maxsection; i++) { 100 | D->sections[i].buf = NULL; /* Need this for pass3. */ 101 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 102 | D->sections[i].bsize = 0; 103 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 104 | } 105 | } 106 | 107 | /* Free DynASM state. */ 108 | void dasm_free(Dst_DECL) 109 | { 110 | dasm_State *D = Dst_REF; 111 | int i; 112 | for (i = 0; i < D->maxsection; i++) 113 | if (D->sections[i].buf) 114 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 115 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 116 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 117 | DASM_M_FREE(Dst, D, D->psize); 118 | } 119 | 120 | /* Setup global label array. Must be called before dasm_setup(). */ 121 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 122 | { 123 | dasm_State *D = Dst_REF; 124 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 125 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 126 | } 127 | 128 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 129 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 130 | { 131 | dasm_State *D = Dst_REF; 132 | size_t osz = D->pcsize; 133 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 134 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 135 | } 136 | 137 | /* Setup encoder. */ 138 | void dasm_setup(Dst_DECL, const void *actionlist) 139 | { 140 | dasm_State *D = Dst_REF; 141 | int i; 142 | D->actionlist = (dasm_ActList)actionlist; 143 | D->status = DASM_S_OK; 144 | D->section = &D->sections[0]; 145 | memset((void *)D->lglabels, 0, D->lgsize); 146 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 147 | for (i = 0; i < D->maxsection; i++) { 148 | D->sections[i].pos = DASM_SEC2POS(i); 149 | D->sections[i].ofs = 0; 150 | } 151 | } 152 | 153 | 154 | #ifdef DASM_CHECKS 155 | #define CK(x, st) \ 156 | do { if (!(x)) { \ 157 | D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) 158 | #define CKPL(kind, st) \ 159 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 160 | D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) 161 | #else 162 | #define CK(x, st) ((void)0) 163 | #define CKPL(kind, st) ((void)0) 164 | #endif 165 | 166 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 167 | void dasm_put(Dst_DECL, int start, ...) 168 | { 169 | va_list ap; 170 | dasm_State *D = Dst_REF; 171 | dasm_ActList p = D->actionlist + start; 172 | dasm_Section *sec = D->section; 173 | int pos = sec->pos, ofs = sec->ofs, mrm = 4; 174 | int *b; 175 | 176 | if (pos >= sec->epos) { 177 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 178 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 179 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 180 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 181 | } 182 | 183 | b = sec->rbuf; 184 | b[pos++] = start; 185 | 186 | va_start(ap, start); 187 | while (1) { 188 | int action = *p++; 189 | if (action < DASM_DISP) { 190 | ofs++; 191 | } else if (action <= DASM_REL_A) { 192 | int n = va_arg(ap, int); 193 | b[pos++] = n; 194 | switch (action) { 195 | case DASM_DISP: 196 | if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; } 197 | case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; 198 | case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ 199 | case DASM_IMM_D: ofs += 4; break; 200 | case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; 201 | case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; 202 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; 203 | case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; 204 | case DASM_SPACE: p++; ofs += n; break; 205 | case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ 206 | case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG); 207 | if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue; 208 | } 209 | mrm = 4; 210 | } else { 211 | int *pl, n; 212 | switch (action) { 213 | case DASM_REL_LG: 214 | case DASM_IMM_LG: 215 | n = *p++; pl = D->lglabels + n; 216 | if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ 217 | pl -= 246; n = *pl; 218 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 219 | goto linkrel; 220 | case DASM_REL_PC: 221 | case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); 222 | putrel: 223 | n = *pl; 224 | if (n < 0) { /* Label exists. Get label pos and store it. */ 225 | b[pos] = -n; 226 | } else { 227 | linkrel: 228 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 229 | *pl = pos; 230 | } 231 | pos++; 232 | ofs += 4; /* Maximum offset needed. */ 233 | if (action == DASM_REL_LG || action == DASM_REL_PC) 234 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 235 | break; 236 | case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; 237 | case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); 238 | putlabel: 239 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 240 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } 241 | *pl = -pos; /* Label exists now. */ 242 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 243 | break; 244 | case DASM_ALIGN: 245 | ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ 246 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 247 | break; 248 | case DASM_EXTERN: p += 2; ofs += 4; break; 249 | case DASM_ESC: p++; ofs++; break; 250 | case DASM_MARK: mrm = p[-2]; break; 251 | case DASM_SECTION: 252 | n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; 253 | case DASM_STOP: goto stop; 254 | } 255 | } 256 | } 257 | stop: 258 | va_end(ap); 259 | sec->pos = pos; 260 | sec->ofs = ofs; 261 | } 262 | #undef CK 263 | 264 | /* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ 265 | int dasm_link(Dst_DECL, size_t *szp) 266 | { 267 | dasm_State *D = Dst_REF; 268 | int secnum; 269 | int ofs = 0; 270 | 271 | #ifdef DASM_CHECKS 272 | *szp = 0; 273 | if (D->status != DASM_S_OK) return D->status; 274 | { 275 | int pc; 276 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 277 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 278 | } 279 | #endif 280 | 281 | { /* Handle globals not defined in this translation unit. */ 282 | int idx; 283 | for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { 284 | int n = D->lglabels[idx]; 285 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 286 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 287 | } 288 | } 289 | 290 | /* Combine all code sections. No support for data sections (yet). */ 291 | for (secnum = 0; secnum < D->maxsection; secnum++) { 292 | dasm_Section *sec = D->sections + secnum; 293 | int *b = sec->rbuf; 294 | int pos = DASM_SEC2POS(secnum); 295 | int lastpos = sec->pos; 296 | 297 | while (pos != lastpos) { 298 | dasm_ActList p = D->actionlist + b[pos++]; 299 | while (1) { 300 | int op, action = *p++; 301 | switch (action) { 302 | case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; 303 | case DASM_REL_PC: op = p[-2]; rel_pc: { 304 | int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); 305 | if (shrink) { /* Shrinkable branch opcode? */ 306 | int lofs, lpos = b[pos]; 307 | if (lpos < 0) goto noshrink; /* Ext global? */ 308 | lofs = *DASM_POS2PTR(D, lpos); 309 | if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ 310 | int i; 311 | for (i = secnum; i < DASM_POS2SEC(lpos); i++) 312 | lofs += D->sections[i].ofs; 313 | } else { 314 | lofs -= ofs; /* Bkwd label: unfix offset. */ 315 | } 316 | lofs -= b[pos+1]; /* Short branch ok? */ 317 | if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ 318 | else { noshrink: shrink = 0; } /* No, cannot shrink op. */ 319 | } 320 | b[pos+1] = shrink; 321 | pos += 2; 322 | break; 323 | } 324 | case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; 325 | case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: 326 | case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: 327 | case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; 328 | case DASM_LABEL_LG: p++; 329 | case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ 330 | case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ 331 | case DASM_EXTERN: p += 2; break; 332 | case DASM_ESC: p++; break; 333 | case DASM_MARK: break; 334 | case DASM_SECTION: case DASM_STOP: goto stop; 335 | } 336 | } 337 | stop: (void)0; 338 | } 339 | ofs += sec->ofs; /* Next section starts right after current section. */ 340 | } 341 | 342 | D->codesize = ofs; /* Total size of all code sections */ 343 | *szp = ofs; 344 | return DASM_S_OK; 345 | } 346 | 347 | #define dasmb(x) *cp++ = (unsigned char)(x) 348 | #ifndef DASM_ALIGNED_WRITES 349 | #define dasmw(x) \ 350 | do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) 351 | #define dasmd(x) \ 352 | do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) 353 | #else 354 | #define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) 355 | #define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) 356 | #endif 357 | 358 | /* Pass 3: Encode sections. */ 359 | int dasm_encode(Dst_DECL, void *buffer) 360 | { 361 | dasm_State *D = Dst_REF; 362 | unsigned char *base = (unsigned char *)buffer; 363 | unsigned char *cp = base; 364 | int secnum; 365 | 366 | /* Encode all code sections. No support for data sections (yet). */ 367 | for (secnum = 0; secnum < D->maxsection; secnum++) { 368 | dasm_Section *sec = D->sections + secnum; 369 | int *b = sec->buf; 370 | int *endb = sec->rbuf + sec->pos; 371 | 372 | while (b != endb) { 373 | dasm_ActList p = D->actionlist + *b++; 374 | unsigned char *mark = NULL; 375 | while (1) { 376 | int action = *p++; 377 | int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; 378 | switch (action) { 379 | case DASM_DISP: if (!mark) mark = cp; { 380 | unsigned char *mm = mark; 381 | if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; 382 | if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; 383 | if (mrm != 5) { mm[-1] -= 0x80; break; } } 384 | if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; 385 | } 386 | case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; 387 | case DASM_IMM_DB: if (((n+128)&-256) == 0) { 388 | db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; 389 | } else mark = NULL; 390 | case DASM_IMM_D: wd: dasmd(n); break; 391 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; 392 | case DASM_IMM_W: dasmw(n); break; 393 | case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; } 394 | case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; 395 | b++; n = (int)(ptrdiff_t)D->globals[-n]; 396 | case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ 397 | case DASM_REL_PC: rel_pc: { 398 | int shrink = *b++; 399 | int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } 400 | n = *pb - ((int)(cp-base) + 4-shrink); 401 | if (shrink == 0) goto wd; 402 | if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; 403 | goto wb; 404 | } 405 | case DASM_IMM_LG: 406 | p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } 407 | case DASM_IMM_PC: { 408 | int *pb = DASM_POS2PTR(D, n); 409 | n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); 410 | goto wd; 411 | } 412 | case DASM_LABEL_LG: { 413 | int idx = *p++; 414 | if (idx >= 10) 415 | D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); 416 | break; 417 | } 418 | case DASM_LABEL_PC: case DASM_SETLABEL: break; 419 | case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } 420 | case DASM_ALIGN: 421 | n = *p++; 422 | while (((cp-base) & n)) *cp++ = 0x90; /* nop */ 423 | break; 424 | case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; 425 | case DASM_MARK: mark = cp; break; 426 | case DASM_ESC: action = *p++; 427 | default: *cp++ = action; break; 428 | case DASM_SECTION: case DASM_STOP: goto stop; 429 | } 430 | } 431 | stop: (void)0; 432 | } 433 | } 434 | 435 | if (base + D->codesize != cp) /* Check for phase errors. */ 436 | return DASM_S_PHASE; 437 | return DASM_S_OK; 438 | } 439 | 440 | /* Get PC label offset. */ 441 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 442 | { 443 | dasm_State *D = Dst_REF; 444 | if (pc*sizeof(int) < D->pcsize) { 445 | int pos = D->pclabels[pc]; 446 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 447 | if (pos > 0) return -1; /* Undefined. */ 448 | } 449 | return -2; /* Unused or out of range. */ 450 | } 451 | 452 | #ifdef DASM_CHECKS 453 | /* Optional sanity checker to call between isolated encoding steps. */ 454 | int dasm_checkstep(Dst_DECL, int secmatch) 455 | { 456 | dasm_State *D = Dst_REF; 457 | if (D->status == DASM_S_OK) { 458 | int i; 459 | for (i = 1; i <= 9; i++) { 460 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } 461 | D->lglabels[i] = 0; 462 | } 463 | } 464 | if (D->status == DASM_S_OK && secmatch >= 0 && 465 | D->section != &D->sections[secmatch]) 466 | D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); 467 | return D->status; 468 | } 469 | #endif 470 | 471 | -------------------------------------------------------------------------------- /call_arm.dasc: -------------------------------------------------------------------------------- 1 | /* vim: ts=4 sw=4 sts=4 et tw=78 2 | * Copyright (c) 2011 James R. McKaskill. See license in ffi.h 3 | */ 4 | |.arch arm 5 | |.actionlist build_actionlist 6 | |.globalnames globnames 7 | |.externnames extnames 8 | 9 | #define JUMP_SIZE 8 10 | #define MIN_BRANCH ((INT32_MIN) >> 8) 11 | #define MAX_BRANCH ((INT32_MAX) >> 8) 12 | #define BRANCH_OFF 4 13 | 14 | static void compile_extern_jump(struct jit* jit, lua_State* L, function_t func, uint8_t* code) 15 | { 16 | /* The jump code is the function pointer followed by a stub to call the 17 | * function pointer. The stub exists so we can jump to functions with an 18 | * offset greater than 32MB. 19 | * 20 | * Note we have to manually set this up since there are commands buffered 21 | * in the jit state. 22 | */ 23 | *(function_t*) code = func; 24 | /* ldr pc, [pc - 12] */ 25 | *(uint32_t*) &code[4] = 0xE51FF00CU; 26 | } 27 | 28 | |.define TOP, r4 29 | |.define L_ARG, r5 30 | |.define DATA, r6 31 | |.define DATA2, r7 32 | 33 | |.macro load32, reg, val 34 | | ldr reg, [pc] 35 | | b >5 36 | |.long val 37 | |5: 38 | |.endmacro 39 | 40 | |.macro lcall, func 41 | | mov r0, L_ARG 42 | | bl func 43 | |.endmacro 44 | 45 | void compile_globals(struct jit* jit, lua_State* L) 46 | { 47 | (void) jit; 48 | } 49 | 50 | function_t push_callback(struct jit* jit, lua_State* L, int fidx, int ct_usr, const struct ctype* ct) 51 | { 52 | struct jit* Dst = jit; 53 | int i, nargs, num_upvals, ref; 54 | const struct ctype* mt; 55 | 56 | int top = lua_gettop(L); 57 | 58 | ct_usr = lua_absindex(L, ct_usr); 59 | fidx = lua_absindex(L, fidx); 60 | nargs = (int) lua_rawlen(L, ct_usr); 61 | 62 | dasm_setup(Dst, build_actionlist); 63 | 64 | lua_newtable(L); 65 | lua_pushvalue(L, -1); 66 | ref = luaL_ref(L, LUA_REGISTRYINDEX); 67 | num_upvals = 0; 68 | 69 | if (ct->has_var_arg) { 70 | luaL_error(L, "can't create callbacks with varargs"); 71 | } 72 | 73 | /* prolog and get the upval table */ 74 | | mov r12, sp 75 | | push {r0, r1, r2, r3} // do this first so that r0-r3 is right before stack bound arguments 76 | | push {TOP, L_ARG, DATA, DATA2, r12, lr} 77 | | sub DATA, r12, #16 // points to r0 on stack 78 | | ldr L_ARG, [pc, #8] 79 | | ldr r2, [pc, #8] 80 | | ldr r1, [pc, #8] 81 | | b >1 82 | |.long L, ref, LUA_REGISTRYINDEX 83 | |1: 84 | | lcall extern lua_rawgeti 85 | 86 | /* get the lua function */ 87 | lua_pushvalue(L, fidx); 88 | lua_rawseti(L, -2, ++num_upvals); 89 | | mov r2, #num_upvals 90 | | mvn r1, #0 // -1 91 | | lcall extern lua_rawgeti 92 | 93 | for (i = 1; i <= nargs; i++) { 94 | lua_rawgeti(L, ct_usr, i); 95 | mt = (const struct ctype*) lua_touserdata(L, -1); 96 | 97 | if (mt->pointers) { 98 | lua_getuservalue(L, -1); 99 | lua_rawseti(L, -3, ++num_upvals); /* usr value */ 100 | lua_rawseti(L, -2, ++num_upvals); /* mt */ 101 | 102 | | mov r2, #num_upvals-1 // usr value 103 | | mvn r1, #i // -i-1, stack is upval table, func, i-1 args 104 | | lcall extern lua_rawgeti 105 | | load32 r2, mt 106 | | mvn r1, #0 // -1 107 | | lcall extern push_cdata 108 | | ldr r2, [DATA], #4 109 | | str r2, [r0] 110 | | mvn r1, #1 // -2 111 | | lcall extern lua_remove // remove the usr value 112 | 113 | } else { 114 | switch (mt->type) { 115 | case INT64_TYPE: 116 | case UINT64_TYPE: 117 | lua_rawseti(L, -2, ++num_upvals); /* mt */ 118 | | lcall extern lua_pushnil 119 | | load32 r2, mt 120 | | mvn r1, #0 // -1 121 | | lcall extern push_cdata 122 | | ldr r2, [DATA], #4 123 | | ldr r3, [DATA], #4 124 | | str r2, [r0] 125 | | str r3, [r0, #4] 126 | | mvn r1, #1 // -2 127 | | lcall extern lua_remove // remove the nil usr 128 | break; 129 | 130 | case UINTPTR_TYPE: 131 | lua_rawseti(L, -2, ++num_upvals); /* mt */ 132 | | lcall extern lua_pushnil 133 | | load32 r2, mt 134 | | mvn r1, #0 // -1 135 | | lcall extern push_cdata 136 | | ldr r2, [DATA], #4 137 | | str r2, [r0] 138 | | mvn r1, #1 // -2 139 | | lcall extern lua_remove // remove the nil usr 140 | break; 141 | 142 | case BOOL_TYPE: 143 | lua_pop(L, 1); 144 | | ldr r1, [DATA], #4 145 | | lcall extern lua_pushboolean 146 | break; 147 | 148 | case INT8_TYPE: 149 | lua_pop(L, 1); 150 | | ldr r1, [DATA], #4 151 | | mov r1, r1, lsl #24 152 | | mov r1, r1, asr #24 153 | | lcall extern push_int 154 | break; 155 | 156 | case UINT8_TYPE: 157 | lua_pop(L, 1); 158 | | ldr r1, [DATA], #4 159 | | and r1, r1, #0xFF 160 | | lcall extern push_uint 161 | break; 162 | 163 | case INT16_TYPE: 164 | lua_pop(L, 1); 165 | | ldr r1, [DATA], #4 166 | | mov r1, r1, lsl #16 167 | | mov r1, r1, asr #16 168 | | lcall extern push_int 169 | break; 170 | 171 | case UINT16_TYPE: 172 | lua_pop(L, 1); 173 | | ldr r1, [DATA], #4 174 | | mov r1, r1, lsl #16 175 | | mov r1, r1, lsr #16 176 | | lcall extern push_uint 177 | break; 178 | 179 | case ENUM_TYPE: 180 | case INT32_TYPE: 181 | lua_pop(L, 1); 182 | | ldr r1, [DATA], #4 183 | | lcall extern push_int 184 | break; 185 | 186 | case UINT32_TYPE: 187 | lua_pop(L, 1); 188 | | ldr r1, [DATA], #4 189 | | lcall extern push_uint 190 | break; 191 | 192 | case FLOAT_TYPE: 193 | lua_pop(L, 1); 194 | | ldr r1, [DATA], #4 195 | | lcall extern push_float 196 | break; 197 | 198 | case DOUBLE_TYPE: 199 | lua_pop(L, 1); 200 | | ldmia DATA!, {r1, r2} 201 | | lcall extern lua_pushnumber 202 | break; 203 | 204 | default: 205 | luaL_error(L, "NYI: callback arg type"); 206 | } 207 | } 208 | } 209 | 210 | lua_rawgeti(L, ct_usr, 0); 211 | mt = (const struct ctype*) lua_touserdata(L, -1); 212 | 213 | | mov r3, #0 214 | | mov r2, #((mt->pointers || mt->type != VOID_TYPE) ? 1 : 0) 215 | | mov r1, #nargs 216 | | lcall extern lua_callk 217 | 218 | if (mt->pointers) { 219 | lua_getuservalue(L, -1); 220 | lua_rawseti(L, -3, ++num_upvals); /* usr value */ 221 | lua_rawseti(L, -2, ++num_upvals); /* mt */ 222 | 223 | | mov r2, #num_upvals-1 // usr value 224 | | mvn r1, #1 // -2 stack is (upval table, ret val) 225 | | lcall extern lua_rawgeti 226 | | load32 r3, mt 227 | | mov r2, #0 // -1 - ct_usr 228 | | mvn r1, #1 // -2 - val 229 | | lcall extern to_typed_pointer 230 | | mov DATA, r0 231 | | mvn r1, #3 // -4 - remove 3 (upval table, ret val, usr value) 232 | | lcall extern lua_settop 233 | | mov r0, DATA 234 | } else { 235 | switch (mt->type) { 236 | case ENUM_TYPE: 237 | lua_getuservalue(L, -1); 238 | lua_rawseti(L, -3, ++num_upvals); /* usr value */ 239 | lua_rawseti(L, -2, ++num_upvals); /* mt */ 240 | 241 | | mov r2, #num_upvals-1 // usr value 242 | | mvn r1, #1 // -2 stack is (upval table, ret val) 243 | | lcall extern lua_rawgeti 244 | | load32 r3, mt 245 | | mvn r2, #0 // -1 - ct_usr 246 | | mvn r1, #1 // -2 - val 247 | | lcall extern to_enum 248 | | mov DATA, r0 249 | | mvn r1, #3 // -4 - remove 3 (upval table, ret val, usr value) 250 | | lcall extern lua_settop 251 | | mov r0, DATA 252 | break; 253 | 254 | case VOID_TYPE: 255 | | mvn r1, #1 // -2 256 | | lcall extern lua_settop 257 | lua_pop(L, 1); 258 | break; 259 | 260 | case BOOL_TYPE: 261 | case INT8_TYPE: 262 | case INT16_TYPE: 263 | case INT32_TYPE: 264 | | mvn r1, #0 // -1 265 | | lcall extern to_int32 266 | goto single; 267 | 268 | case UINT8_TYPE: 269 | case UINT16_TYPE: 270 | case UINT32_TYPE: 271 | | mvn r1, #0 // -1 272 | | lcall extern to_uint32 273 | goto single; 274 | 275 | case INT64_TYPE: 276 | | mvn r1, #0 // -1 277 | | lcall extern to_int64 278 | goto dual; 279 | 280 | case UINT64_TYPE: 281 | | mvn r1, #0 // -1 282 | | lcall extern to_uint64 283 | goto dual; 284 | 285 | case UINTPTR_TYPE: 286 | | mvn r1, #0 // -1 287 | | lcall extern to_uintptr 288 | goto single; 289 | 290 | case FLOAT_TYPE: 291 | | mvn r1, #0 // -1 292 | | lcall extern to_float 293 | goto single; 294 | 295 | case DOUBLE_TYPE: 296 | | mvn r1, #0 // -1 297 | | lcall extern to_double 298 | goto dual; 299 | 300 | single: 301 | | mov DATA, r0 302 | | mvn r1, #2 // -3 303 | | lcall extern lua_settop 304 | | mov r0, DATA 305 | lua_pop(L, 1); 306 | break; 307 | 308 | dual: 309 | | mov DATA, r0 310 | | mov DATA2, r1 311 | | mvn r1, #2 // -3 312 | | lcall extern lua_settop 313 | | mov r0, DATA 314 | | mov r1, DATA2 315 | lua_pop(L, 1); 316 | break; 317 | 318 | default: 319 | luaL_error(L, "NYI: callback return type"); 320 | } 321 | } 322 | 323 | | ldmia sp, {TOP, L_ARG, DATA, DATA2, sp, pc} 324 | 325 | lua_pop(L, 1); /* upval table - already in registry */ 326 | assert(lua_gettop(L) == top); 327 | 328 | { 329 | void* p; 330 | struct ctype ft; 331 | function_t func; 332 | 333 | func = compile(jit, L, NULL, ref); 334 | 335 | ft = *ct; 336 | ft.is_jitted = 1; 337 | p = push_cdata(L, ct_usr, &ft); 338 | *(function_t*) p = func; 339 | 340 | assert(lua_gettop(L) == top + 1); 341 | 342 | return func; 343 | } 344 | } 345 | 346 | void push_function(struct jit* jit, lua_State* L, function_t func, int ct_usr, const struct ctype* ct) 347 | { 348 | struct jit* Dst = jit; 349 | int i, nargs, num_upvals; 350 | const struct ctype* mt; 351 | void* p; 352 | 353 | int top = lua_gettop(L); 354 | 355 | ct_usr = lua_absindex(L, ct_usr); 356 | nargs = (int) lua_rawlen(L, ct_usr); 357 | 358 | p = push_cdata(L, ct_usr, ct); 359 | *(function_t*) p = func; 360 | num_upvals = 1; 361 | 362 | dasm_setup(Dst, build_actionlist); 363 | 364 | | mov r12, sp 365 | | push {r0} 366 | | push {TOP, L_ARG, DATA, DATA2, r11, r12, lr} 367 | | sub r11, r12, #4 368 | | mov L_ARG, r0 369 | | lcall extern lua_gettop 370 | | mov TOP, r0 371 | | cmp TOP, #nargs 372 | | // these should really be in globals - but for some reason dynasm breaks when you do that 373 | if (ct->has_var_arg) { 374 | | bge >1 375 | | load32 r1, "too few arguments" 376 | | lcall extern luaL_error 377 | |1: 378 | } else { 379 | | beq >1 380 | | load32 r1, "incorrect number of arguments" 381 | | lcall extern luaL_error 382 | |1: 383 | } 384 | 385 | /* reserve enough stack space for all of the arguments (8 bytes per 386 | * argument for double and maintains alignment). Add an extra 16 bytes so 387 | * that the pop {r0, r1, r2, r3} doesn't clean out our stack frame */ 388 | | sub sp, sp, TOP, lsl #3 389 | | sub sp, sp, #16 390 | | mov DATA, sp 391 | 392 | for (i = 1; i <= nargs; i++) { 393 | lua_rawgeti(L, ct_usr, i); 394 | mt = (const struct ctype*) lua_touserdata(L, -1); 395 | 396 | if (mt->pointers || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE) { 397 | lua_getuservalue(L, -1); 398 | num_upvals += 2; 399 | 400 | | ldr r3, [pc, #4] 401 | | ldr r2, [pc, #4] 402 | | b >1 403 | |.long mt, lua_upvalueindex(num_upvals) 404 | |1: 405 | | mov r1, #i 406 | | mov r0, L_ARG 407 | 408 | if (mt->pointers) { 409 | | bl extern to_typed_pointer 410 | } else if (mt->type == FUNCTION_PTR_TYPE) { 411 | | bl extern to_typed_function 412 | } else if (mt->type == ENUM_TYPE) { 413 | | bl extern to_enum 414 | } 415 | 416 | | str r0, [DATA], #4 417 | 418 | } else { 419 | lua_pop(L, 1); 420 | | mov r1, #i 421 | 422 | switch (mt->type) { 423 | case INT8_TYPE: 424 | | lcall extern to_int32 425 | | mov r0, r0, lsl #24 426 | | mov r0, r0, asr #24 427 | | str r0, [DATA], #4 428 | break; 429 | 430 | case INT16_TYPE: 431 | | lcall extern to_int32 432 | | mov r0, r0, lsl #16 433 | | mov r0, r0, asr #16 434 | | str r0, [DATA], #4 435 | break; 436 | 437 | case INT32_TYPE: 438 | | lcall extern to_int32 439 | | str r0, [DATA], #4 440 | break; 441 | 442 | case UINT8_TYPE: 443 | | lcall extern to_uint32 444 | | and r0, r0, #0xFF 445 | | str r0, [DATA], #4 446 | break; 447 | 448 | case UINT16_TYPE: 449 | | lcall extern to_uint32 450 | | mov r0, r0, lsl #16 451 | | mov r0, r0, lsr #16 452 | | str r0, [DATA], #4 453 | break; 454 | 455 | case UINT32_TYPE: 456 | | lcall extern to_uint32 457 | | str r0, [DATA], #4 458 | break; 459 | 460 | case INT64_TYPE: 461 | | lcall extern to_int64 462 | | str r0, [DATA], #4 463 | | str r1, [DATA], #4 464 | break; 465 | 466 | case UINT64_TYPE: 467 | | lcall extern to_uint64 468 | | str r0, [DATA], #4 469 | | str r1, [DATA], #4 470 | break; 471 | 472 | case DOUBLE_TYPE: 473 | | lcall extern to_double 474 | | str r0, [DATA], #4 475 | | str r1, [DATA], #4 476 | break; 477 | 478 | case UINTPTR_TYPE: 479 | | lcall extern to_uintptr 480 | | str r0, [DATA], #4 481 | break; 482 | 483 | case FLOAT_TYPE: 484 | | lcall extern to_float 485 | | str r0, [DATA], #4 486 | break; 487 | 488 | default: 489 | luaL_error(L, "NYI: call arg type"); 490 | } 491 | } 492 | } 493 | 494 | if (ct->has_var_arg) { 495 | | mov r3, DATA 496 | | mov r2, TOP 497 | | mov r1, #nargs+1 498 | | lcall extern unpack_varargs_stack 499 | } 500 | 501 | | load32 r0, &jit->last_errno 502 | | ldr r0, [r0] 503 | | bl extern SetLastError 504 | 505 | | pop {r0, r1, r2, r3} // this pop is balanced with the sub sp, #16 506 | | bl extern FUNCTION 507 | 508 | |.macro get_errno 509 | | bl extern GetLastError 510 | | load32 r1, &jit->last_errno 511 | | str r0, [r1] 512 | |.endmacro 513 | 514 | |.macro return 515 | | ldmdb r11, {TOP, L_ARG, DATA, r11, sp, pc} 516 | |.endmacro 517 | 518 | lua_rawgeti(L, ct_usr, 0); 519 | mt = (const struct ctype*) lua_touserdata(L, -1); 520 | 521 | if (mt->pointers) { 522 | lua_getuservalue(L, -1); 523 | num_upvals += 2; 524 | | mov DATA, r0 525 | | get_errno 526 | | ldr r2, [pc, #4] 527 | | ldr r1, [pc, #4] 528 | | b >1 529 | |.long mt, lua_upvalueindex(num_upvals) 530 | |1: 531 | | lcall extern push_cdata 532 | | str DATA, [r0] 533 | | mov r0, #1 534 | | return 535 | 536 | } else { 537 | switch (mt->type) { 538 | case INT64_TYPE: 539 | case UINT64_TYPE: 540 | num_upvals++; 541 | | mov DATA, r0 542 | | mov DATA2, r1 543 | | get_errno 544 | | lcall extern lua_pushnil 545 | | load32 r2, mt 546 | | mvn r1, #0 // -1 547 | | lcall extern push_cdata 548 | | str DATA, [r0] 549 | | str DATA2, [r0, #4] 550 | | mov r0, #1 551 | | return 552 | break; 553 | 554 | case UINTPTR_TYPE: 555 | num_upvals++; 556 | | mov DATA, r0 557 | | get_errno 558 | | lcall extern lua_pushnil 559 | | load32 r2, mt 560 | | mvn r1, #0 // -1 561 | | lcall extern push_cdata 562 | | str DATA, [r0] 563 | | mov r0, #1 564 | | return 565 | break; 566 | 567 | case VOID_TYPE: 568 | lua_pop(L, 1); 569 | | get_errno 570 | | mov r0, #0 571 | | return 572 | break; 573 | 574 | case BOOL_TYPE: 575 | lua_pop(L, 1); 576 | | mov DATA, r0 577 | | get_errno 578 | | mov r1, DATA 579 | | lcall extern lua_pushboolean 580 | | mov r0, #1 581 | | return 582 | break; 583 | 584 | case INT8_TYPE: 585 | case INT16_TYPE: 586 | case INT32_TYPE: 587 | case ENUM_TYPE: 588 | lua_pop(L, 1); 589 | | mov DATA, r0 590 | | get_errno 591 | | mov r1, DATA 592 | | lcall extern push_int 593 | | mov r0, #1 594 | | return 595 | break; 596 | 597 | case UINT8_TYPE: 598 | case UINT16_TYPE: 599 | case UINT32_TYPE: 600 | lua_pop(L, 1); 601 | | mov DATA, r0 602 | | get_errno 603 | | mov r1, DATA 604 | | lcall extern push_uint 605 | | mov r0, #1 606 | | return 607 | break; 608 | 609 | case FLOAT_TYPE: 610 | lua_pop(L, 1); 611 | | mov DATA, r0 612 | | get_errno 613 | | mov r1, DATA 614 | | lcall extern push_float 615 | | mov r0, #1 616 | | return 617 | break; 618 | 619 | case DOUBLE_TYPE: 620 | lua_pop(L, 1); 621 | | mov DATA, r0 622 | | mov DATA2, r1 623 | | get_errno 624 | | mov r2, DATA2 625 | | mov r1, DATA 626 | | lcall extern lua_pushnumber 627 | | mov r0, #1 628 | | return 629 | break; 630 | 631 | default: 632 | luaL_error(L, "NYI: call return type"); 633 | } 634 | } 635 | 636 | assert(lua_gettop(L) == top + num_upvals); 637 | lua_pushcclosure(L, (lua_CFunction) compile(jit, L, func, LUA_NOREF), num_upvals); 638 | } 639 | 640 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* vim: ts=4 sw=4 sts=4 et tw=78 2 | * Copyright (c) 2011 James R. McKaskill. See license in ffi.h 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | #else 14 | #include 15 | #endif 16 | 17 | #if __STDC_VERSION__+0 >= 199901L 18 | #include 19 | #define HAVE_COMPLEX 20 | #endif 21 | 22 | #ifdef __cplusplus 23 | # define EXTERN_C extern "C" 24 | #else 25 | # define EXTERN_C extern 26 | #endif 27 | 28 | #ifdef _WIN32 29 | #define EXPORT EXTERN_C __declspec(dllexport) 30 | #elif defined __GNUC__ 31 | #define EXPORT EXTERN_C __attribute__((visibility("default"))) 32 | #else 33 | #define EXPORT EXTERN_C 34 | #endif 35 | 36 | enum e8 { 37 | FOO8, 38 | BAR8, 39 | }; 40 | enum e16 { 41 | FOO16 = 1 << 8, 42 | BAR16, 43 | BIG16 = 1 << 14, 44 | }; 45 | enum e32 { 46 | FOO32 = 1 << 16, 47 | BAR32, 48 | BIG32 = 1 << 30, 49 | }; 50 | 51 | EXPORT bool have_complex(); 52 | 53 | bool have_complex() 54 | { 55 | #ifdef HAVE_COMPLEX 56 | return 1; 57 | #else 58 | return 0; 59 | #endif 60 | } 61 | 62 | EXPORT bool is_msvc; 63 | 64 | bool is_msvc = 65 | #ifdef _MSC_VER 66 | 1; 67 | #else 68 | 0; 69 | #endif 70 | 71 | EXPORT int test_pow(int v); 72 | int test_pow(int v) 73 | { return v * v; } 74 | 75 | #define ADD(TYPE, NAME) \ 76 | EXPORT TYPE NAME(TYPE a, TYPE b); \ 77 | TYPE NAME(TYPE a, TYPE b) { return a + b; } 78 | 79 | ADD(int8_t, add_i8) 80 | ADD(uint8_t, add_u8) 81 | ADD(int16_t, add_i16) 82 | ADD(uint16_t, add_u16) 83 | ADD(int32_t, add_i32) 84 | ADD(uint32_t, add_u32) 85 | ADD(int64_t, add_i64) 86 | ADD(uint64_t, add_u64) 87 | ADD(double, add_d) 88 | ADD(float, add_f) 89 | #ifdef HAVE_COMPLEX 90 | ADD(double complex, add_dc) 91 | ADD(float complex, add_fc) 92 | #endif 93 | 94 | EXPORT enum e8 inc_e8(enum e8 v); 95 | EXPORT enum e16 inc_e16(enum e16 v); 96 | EXPORT enum e32 inc_e32(enum e32 v); 97 | enum e8 inc_e8(enum e8 v) {return v+1;} 98 | enum e16 inc_e16(enum e16 v) {return v+1;} 99 | enum e32 inc_e32(enum e32 v) {return v+1;} 100 | 101 | EXPORT _Bool not_b(_Bool v); 102 | EXPORT _Bool not_b2(_Bool v); 103 | 104 | _Bool not_b(_Bool v) {return !v;} 105 | _Bool not_b2(_Bool v) {return !v;} 106 | 107 | #define PRINT(TYPE, NAME, FORMAT) \ 108 | EXPORT int NAME(char* buf, TYPE val); \ 109 | int NAME(char* buf, TYPE val) {return sprintf(buf, "%" FORMAT, val);} 110 | 111 | PRINT(int8_t, print_i8, PRId8) 112 | PRINT(uint8_t, print_u8, PRIu8) 113 | PRINT(int16_t, print_i16, PRId16) 114 | PRINT(uint16_t, print_u16, PRIu16) 115 | PRINT(int32_t, print_i32, PRId32) 116 | PRINT(uint32_t, print_u32, PRIu32) 117 | PRINT(int64_t, print_i64, PRId64) 118 | PRINT(uint64_t, print_u64, PRIu64) 119 | PRINT(double, print_d, "g") 120 | PRINT(float, print_f, "g") 121 | PRINT(const char*, print_s, "s") 122 | PRINT(void*, print_p, "p") 123 | PRINT(enum e8, print_e8, "d") 124 | PRINT(enum e16, print_e16, "d") 125 | PRINT(enum e32, print_e32, "d") 126 | 127 | #ifdef HAVE_COMPLEX 128 | EXPORT int print_dc(char* buf, double complex val); 129 | EXPORT int print_fc(char* buf, float complex val); 130 | int print_dc(char* buf, double complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));} 131 | int print_fc(char* buf, float complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));} 132 | #endif 133 | 134 | EXPORT int print_b(char* buf, _Bool val); 135 | EXPORT int print_b2(char* buf, _Bool val); 136 | int print_b(char* buf, _Bool val) {return sprintf(buf, "%s", val ? "true" : "false");} 137 | int print_b2(char* buf, _Bool val) {return sprintf(buf, "%s", val ? "true" : "false");} 138 | 139 | EXPORT bool (*ret_fp(bool (*val)(bool)))(bool); 140 | bool (*ret_fp(bool (*val)(bool)))(bool) 141 | {return val;} 142 | 143 | #define OFFSETOF(STRUCT, MEMBER) ((int) ((char*) &STRUCT.MEMBER - (char*) &S - 1)) 144 | 145 | #define ALIGN_UP(VALUE, ALIGNMENT, SUFFIX) \ 146 | struct align_##ALIGNMENT##_##SUFFIX { \ 147 | char pad; \ 148 | VALUE; \ 149 | }; \ 150 | EXPORT int print_align_##ALIGNMENT##_##SUFFIX(char* buf, struct align_##ALIGNMENT##_##SUFFIX* p); \ 151 | int print_align_##ALIGNMENT##_##SUFFIX(char* buf, struct align_##ALIGNMENT##_##SUFFIX* p) { \ 152 | struct {char ch; struct align_##ALIGNMENT##_##SUFFIX v;} s; \ 153 | int off = sprintf(buf, "size %d offset %d align %d value ", \ 154 | (int) sizeof(s.v), \ 155 | (int) (((char*) &p->v) - (char*) p), \ 156 | (int) (((char*) &s.v) - (char*) &s)); \ 157 | return print_##SUFFIX(buf+off, p->v); \ 158 | } 159 | 160 | #ifdef HAVE_COMPLEX 161 | #define COMPLEX_ALIGN(ALIGNMENT, ATTR) \ 162 | ALIGN_UP(ATTR(double complex), ALIGNMENT, dc) \ 163 | ALIGN_UP(ATTR(float complex), ALIGNMENT, fc) 164 | #else 165 | #define COMPLEX_ALIGN(ALIGNMENT, ATTR) 166 | #endif 167 | 168 | /* MSVC doesn't support __declspec(aligned(#)) on enums see C4329 */ 169 | #define ENUM_ALIGN2(ALIGNMENT, ATTR) \ 170 | ALIGN_UP(ATTR(enum e8), ALIGNMENT, e8) \ 171 | ALIGN_UP(ATTR(enum e16), ALIGNMENT, e16) \ 172 | ALIGN_UP(ATTR(enum e32), ALIGNMENT, e32) \ 173 | 174 | #ifdef _MSC_VER 175 | #define ENUM_ALIGN(ALIGNMENT, ATTR) 176 | #else 177 | #define ENUM_ALIGN(ALIGNMENT, ATTR) ENUM_ALIGN2(ALIGNMENT, ATTR) 178 | #endif 179 | 180 | #define ALIGN2(ALIGNMENT, ATTR) \ 181 | ALIGN_UP(ATTR(uint16_t), ALIGNMENT, u16) \ 182 | ALIGN_UP(ATTR(uint32_t), ALIGNMENT, u32) \ 183 | ALIGN_UP(ATTR(uint64_t), ALIGNMENT, u64) \ 184 | ALIGN_UP(ATTR(float), ALIGNMENT, f) \ 185 | ALIGN_UP(ATTR(double), ALIGNMENT, d) \ 186 | ALIGN_UP(ATTR(const char*), ALIGNMENT, s) \ 187 | ALIGN_UP(ATTR(void*), ALIGNMENT, p) \ 188 | ALIGN_UP(ATTR(_Bool), ALIGNMENT, b) \ 189 | ALIGN_UP(ATTR(_Bool), ALIGNMENT, b2) \ 190 | ENUM_ALIGN(ALIGNMENT, ATTR) \ 191 | COMPLEX_ALIGN(ALIGNMENT, ATTR) 192 | 193 | #define NO_ATTR(TYPE) TYPE v 194 | 195 | #ifdef _MSC_VER 196 | #define ALIGN_NO_ATTR(ALIGNMENT) \ 197 | ALIGN2(ALIGNMENT, NO_ATTR) \ 198 | ENUM_ALIGN2(ALIGNMENT, NO_ATTR) 199 | #else 200 | #define ALIGN_NO_ATTR(ALIGNMENT) \ 201 | ALIGN2(ALIGNMENT, NO_ATTR) 202 | #endif 203 | 204 | ALIGN_NO_ATTR(0) 205 | 206 | #pragma pack(push) 207 | #pragma pack(1) 208 | ALIGN_NO_ATTR(1) 209 | #pragma pack(2) 210 | ALIGN_NO_ATTR(2) 211 | #pragma pack(4) 212 | ALIGN_NO_ATTR(4) 213 | #pragma pack(8) 214 | ALIGN_NO_ATTR(8) 215 | #pragma pack(16) 216 | ALIGN_NO_ATTR(16) 217 | #pragma pack(pop) 218 | 219 | #ifdef _MSC_VER 220 | #define ATTR_(TYPE, ALIGN) __declspec(align(ALIGN)) TYPE v 221 | #else 222 | #define ATTR_(TYPE, ALIGN) TYPE v __attribute__((aligned(ALIGN))) 223 | #endif 224 | 225 | #define ATTR1(TYPE) ATTR_(TYPE, 1) 226 | #define ATTR2(TYPE) ATTR_(TYPE, 2) 227 | #define ATTR4(TYPE) ATTR_(TYPE, 4) 228 | #define ATTR8(TYPE) ATTR_(TYPE, 8) 229 | #define ATTR16(TYPE) ATTR_(TYPE, 16) 230 | 231 | #define ATTR_DEF(TYPE) TYPE v __attribute__((aligned)) 232 | 233 | ALIGN2(attr_1, ATTR1) 234 | ALIGN2(attr_2, ATTR2) 235 | ALIGN2(attr_4, ATTR4) 236 | ALIGN2(attr_8, ATTR8) 237 | ALIGN2(attr_16, ATTR16) 238 | 239 | #ifndef _MSC_VER 240 | ALIGN2(attr_def, ATTR_DEF) 241 | #endif 242 | 243 | #ifdef _MSC_VER 244 | #define alignof(type) __alignof(type) 245 | #else 246 | #define alignof(type) __alignof__(type) 247 | #endif 248 | 249 | EXPORT int max_alignment(); 250 | 251 | int max_alignment() 252 | { return alignof(struct align_attr_16_p); } 253 | 254 | /* bit_fields1.cpp */ 255 | /* compile with: /LD */ 256 | struct Date { 257 | unsigned short nWeekDay : 3; /* 0..7 (3 bits) */ 258 | unsigned short nMonthDay : 6; /* 0..31 (6 bits) */ 259 | unsigned short nMonth : 5; /* 0..12 (5 bits) */ 260 | unsigned short nYear : 8; /* 0..100 (8 bits) */ 261 | }; 262 | 263 | EXPORT int print_date(size_t* sz, size_t* align, char* buf, struct Date* d); 264 | 265 | int print_date(size_t* sz, size_t* align, char* buf, struct Date* d) { 266 | *sz = sizeof(struct Date); 267 | *align = alignof(struct Date); 268 | return sprintf(buf, "%d %d %d %d", d->nWeekDay, d->nMonthDay, d->nMonth, d->nYear); 269 | } 270 | 271 | /* bit_fields2.cpp */ 272 | /* compile with: /LD */ 273 | struct Date2 { 274 | unsigned nWeekDay : 3; /* 0..7 (3 bits) */ 275 | unsigned nMonthDay : 6; /* 0..31 (6 bits) */ 276 | unsigned : 0; /* Force alignment to next boundary. */ 277 | unsigned nMonth : 5; /* 0..12 (5 bits) */ 278 | unsigned nYear : 8; /* 0..100 (8 bits) */ 279 | }; 280 | 281 | EXPORT int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* d); 282 | 283 | int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* d) { 284 | *sz = sizeof(struct Date2); 285 | *align = alignof(struct Date2); 286 | return sprintf(buf, "%d %d %d %d", d->nWeekDay, d->nMonthDay, d->nMonth, d->nYear); 287 | } 288 | 289 | // Examples from SysV X86 ABI 290 | struct sysv1 { 291 | int j:5; 292 | int k:6; 293 | int m:7; 294 | }; 295 | 296 | EXPORT int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s); 297 | 298 | int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s) { 299 | *sz = sizeof(struct sysv1); 300 | *align = alignof(struct sysv1); 301 | return sprintf(buf, "%d %d %d", s->j, s->k, s->m); 302 | } 303 | 304 | struct sysv2 { 305 | short s:9; 306 | int j:9; 307 | char c; 308 | short t:9; 309 | short u:9; 310 | char d; 311 | }; 312 | 313 | EXPORT int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s); 314 | 315 | int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s) { 316 | *sz = sizeof(struct sysv2); 317 | *align = alignof(struct sysv2); 318 | return sprintf(buf, "%d %d %d %d %d %d", s->s, s->j, s->c, s->t, s->u, s->d); 319 | } 320 | 321 | struct sysv3 { 322 | char c; 323 | short s:8; 324 | }; 325 | 326 | EXPORT int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s); 327 | 328 | int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s) { 329 | *sz = sizeof(struct sysv3); 330 | *align = alignof(struct sysv3); 331 | return sprintf(buf, "%d %d", s->c, s->s); 332 | } 333 | 334 | union sysv4 { 335 | char c; 336 | short s:8; 337 | }; 338 | 339 | EXPORT int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s); 340 | 341 | int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s) { 342 | *sz = sizeof(union sysv4); 343 | *align = alignof(union sysv4); 344 | return sprintf(buf, "%d", s->s); 345 | } 346 | 347 | struct sysv5 { 348 | char c; 349 | int :0; 350 | char d; 351 | short :9; 352 | char e; 353 | char :0; 354 | }; 355 | 356 | EXPORT int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s); 357 | 358 | int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s) { 359 | *sz = sizeof(struct sysv5); 360 | *align = alignof(struct sysv5); 361 | return sprintf(buf, "%d %d %d", s->c, s->d, s->e); 362 | } 363 | 364 | struct sysv6 { 365 | char c; 366 | int :0; 367 | char d; 368 | int :9; 369 | char e; 370 | }; 371 | 372 | EXPORT int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s); 373 | 374 | int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s) { 375 | *sz = sizeof(struct sysv6); 376 | *align = alignof(struct sysv6); 377 | return sprintf(buf, "%d %d %d", s->c, s->d, s->e); 378 | } 379 | 380 | struct sysv7 { 381 | int j:9; 382 | short s:9; 383 | char c; 384 | short t:9; 385 | short u:9; 386 | }; 387 | 388 | EXPORT int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s); 389 | 390 | int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s) { 391 | *sz = sizeof(struct sysv7); 392 | *align = alignof(struct sysv7); 393 | return sprintf(buf, "%d %d %d %d %d", s->j, s->s, s->c, s->t, s->u); 394 | } 395 | 396 | /* Now some targeting bitfield tests */ 397 | 398 | /* Bitfield alignment */ 399 | #define BITALIGN(TNUM,BNUM) \ 400 | struct ba_##TNUM##_##BNUM { \ 401 | char a; \ 402 | uint##TNUM##_t b : BNUM; \ 403 | }; \ 404 | EXPORT int print_ba_##TNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct ba_##TNUM##_##BNUM* s); \ 405 | int print_ba_##TNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct ba_##TNUM##_##BNUM* s) { \ 406 | *sz = sizeof(struct ba_##TNUM##_##BNUM); \ 407 | *align = alignof(struct ba_##TNUM##_##BNUM); \ 408 | return sprintf(buf, "%d %d", (int) s->a, (int) s->b); \ 409 | } 410 | 411 | BITALIGN(8,7) 412 | BITALIGN(16,7) 413 | BITALIGN(16,15) 414 | BITALIGN(32,7) 415 | BITALIGN(32,15) 416 | BITALIGN(32,31) 417 | BITALIGN(64,7) 418 | BITALIGN(64,15) 419 | BITALIGN(64,31) 420 | BITALIGN(64,63) 421 | 422 | /* Do unsigned and signed coallesce */ 423 | #define BITCOALESCE(NUM) \ 424 | struct bc##NUM { \ 425 | uint##NUM##_t a : 3; \ 426 | int##NUM##_t b : 3; \ 427 | }; \ 428 | EXPORT int print_bc##NUM(size_t* sz, size_t* align, char* buf, struct bc##NUM* s); \ 429 | int print_bc##NUM(size_t* sz, size_t* align, char* buf, struct bc##NUM* s) { \ 430 | *sz = sizeof(struct bc##NUM); \ 431 | *align = alignof(struct bc##NUM); \ 432 | return sprintf(buf, "%d %d", (int) s->a, (int) s->b); \ 433 | } 434 | 435 | BITCOALESCE(8) 436 | BITCOALESCE(16) 437 | BITCOALESCE(32) 438 | BITCOALESCE(64) 439 | 440 | // Do different sizes coallesce 441 | struct bdsz { 442 | uint8_t a : 3; 443 | uint16_t b : 3; 444 | uint32_t c : 3; 445 | uint64_t d : 3; 446 | }; 447 | 448 | EXPORT int print_bdsz(size_t* sz, size_t* align, char* buf, struct bdsz* s); 449 | int print_bdsz(size_t* sz, size_t* align, char* buf, struct bdsz* s) { 450 | *sz = sizeof(struct bdsz); 451 | *align = alignof(struct bdsz); 452 | return sprintf(buf, "%d %d %d %d", (int) s->a, (int) s->b, (int) s->c, (int) s->d); 453 | } 454 | 455 | // Does coallesence upgrade the storage unit 456 | struct bcup { 457 | uint8_t a : 7; 458 | uint16_t b : 9; 459 | uint32_t c : 17; 460 | uint64_t d : 33; 461 | }; 462 | 463 | EXPORT int print_bcup(size_t* sz, size_t* align, char* buf, struct bcup* s); 464 | int print_bcup(size_t* sz, size_t* align, char* buf, struct bcup* s) { 465 | *sz = sizeof(struct bcup); 466 | *align = alignof(struct bcup); 467 | return sprintf(buf, "%d %d %d %"PRIu64, (int) s->a, (int) s->b, (int) s->c, (uint64_t) s->d); 468 | } 469 | 470 | // Is unaligned access allowed 471 | struct buna { 472 | uint32_t a : 31; 473 | uint32_t b : 31; 474 | }; 475 | 476 | EXPORT int print_buna(size_t* sz, size_t* align, char* buf, struct buna* s); 477 | int print_buna(size_t* sz, size_t* align, char* buf, struct buna* s) { 478 | *sz = sizeof(struct buna); 479 | *align = alignof(struct buna); 480 | return sprintf(buf, "%d %d", (int) s->a, (int) s->b); 481 | } 482 | 483 | /* What does a lone :0 do */ 484 | #define BITLONEZERO(NUM) \ 485 | struct blz##NUM { \ 486 | uint##NUM##_t a; \ 487 | uint##NUM##_t :0; \ 488 | uint##NUM##_t b; \ 489 | }; \ 490 | EXPORT int print_##blz##NUM(size_t* sz, size_t* align, char* buf, struct blz##NUM* s); \ 491 | int print_blz##NUM(size_t* sz, size_t* align, char* buf, struct blz##NUM* s) { \ 492 | *sz = sizeof(struct blz##NUM); \ 493 | *align = alignof(struct blz##NUM); \ 494 | return sprintf(buf, "%d %d", (int) s->a, (int) s->b); \ 495 | } 496 | 497 | BITLONEZERO(8) 498 | BITLONEZERO(16) 499 | BITLONEZERO(32) 500 | BITLONEZERO(64) 501 | 502 | /* What does a :0 or unnamed :# of the same or different type do */ 503 | #define BITZERO(NUM, ZNUM, BNUM) \ 504 | struct bz_##NUM##_##ZNUM##_##BNUM { \ 505 | uint8_t a; \ 506 | uint##NUM##_t b : 3; \ 507 | uint##ZNUM##_t :BNUM; \ 508 | uint##NUM##_t c : 3; \ 509 | }; \ 510 | EXPORT int print_bz_##NUM##_##ZNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct bz_##NUM##_##ZNUM##_##BNUM* s); \ 511 | int print_bz_##NUM##_##ZNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct bz_##NUM##_##ZNUM##_##BNUM* s) { \ 512 | *sz = sizeof(struct bz_##NUM##_##ZNUM##_##BNUM); \ 513 | *align = alignof(struct bz_##NUM##_##ZNUM##_##BNUM); \ 514 | return sprintf(buf, "%d %d %d", (int) s->a, (int) s->b, (int) s->c); \ 515 | } 516 | 517 | BITZERO(8,8,0) 518 | BITZERO(8,8,7) 519 | BITZERO(8,16,0) 520 | BITZERO(8,16,7) 521 | BITZERO(8,16,15) 522 | BITZERO(8,32,0) 523 | BITZERO(8,32,7) 524 | BITZERO(8,32,15) 525 | BITZERO(8,32,31) 526 | BITZERO(8,64,0) 527 | BITZERO(8,64,7) 528 | BITZERO(8,64,15) 529 | BITZERO(8,64,31) 530 | BITZERO(8,64,63) 531 | BITZERO(16,8,0) 532 | BITZERO(16,8,7) 533 | BITZERO(16,16,0) 534 | BITZERO(16,16,7) 535 | BITZERO(16,16,15) 536 | BITZERO(16,32,0) 537 | BITZERO(16,32,7) 538 | BITZERO(16,32,15) 539 | BITZERO(16,32,31) 540 | BITZERO(16,64,0) 541 | BITZERO(16,64,7) 542 | BITZERO(16,64,15) 543 | BITZERO(16,64,31) 544 | BITZERO(16,64,63) 545 | BITZERO(32,8,0) 546 | BITZERO(32,8,7) 547 | BITZERO(32,16,0) 548 | BITZERO(32,16,7) 549 | BITZERO(32,16,15) 550 | BITZERO(32,32,0) 551 | BITZERO(32,32,7) 552 | BITZERO(32,32,15) 553 | BITZERO(32,32,31) 554 | BITZERO(32,64,0) 555 | BITZERO(32,64,7) 556 | BITZERO(32,64,15) 557 | BITZERO(32,64,31) 558 | BITZERO(32,64,63) 559 | BITZERO(64,8,0) 560 | BITZERO(64,8,7) 561 | BITZERO(64,16,0) 562 | BITZERO(64,16,7) 563 | BITZERO(64,16,15) 564 | BITZERO(64,32,0) 565 | BITZERO(64,32,7) 566 | BITZERO(64,32,15) 567 | BITZERO(64,32,31) 568 | BITZERO(64,64,0) 569 | BITZERO(64,64,7) 570 | BITZERO(64,64,15) 571 | BITZERO(64,64,31) 572 | BITZERO(64,64,63) 573 | 574 | #define CALL(TYPE, SUFFIX) \ 575 | EXPORT TYPE call_##SUFFIX(TYPE (*func)(TYPE), TYPE arg); \ 576 | TYPE call_##SUFFIX(TYPE (*func)(TYPE), TYPE arg) { \ 577 | return func(arg); \ 578 | } 579 | 580 | CALL(int, i) 581 | CALL(float, f) 582 | CALL(double, d) 583 | CALL(const char*, s) 584 | CALL(_Bool, b) 585 | CALL(enum e8, e8) 586 | CALL(enum e16, e16) 587 | CALL(enum e32, e32) 588 | #ifdef HAVE_COMPLEX 589 | CALL(double complex, dc) 590 | CALL(float complex, fc) 591 | #endif 592 | 593 | struct fptr { 594 | #ifdef _MSC_VER 595 | int (__cdecl *p)(int); 596 | #else 597 | int (*p)(int); 598 | #endif 599 | }; 600 | 601 | EXPORT int call_fptr(struct fptr* s, int val); 602 | 603 | int call_fptr(struct fptr* s, int val) { 604 | return (s->p)(val); 605 | } 606 | 607 | EXPORT bool g_b; 608 | EXPORT int8_t g_i8; 609 | EXPORT int16_t g_i16; 610 | EXPORT int32_t g_i32; 611 | EXPORT int64_t g_i64; 612 | EXPORT uint8_t g_u8; 613 | EXPORT uint16_t g_u16; 614 | EXPORT uint32_t g_u32; 615 | EXPORT uint64_t g_u64; 616 | EXPORT float g_f; 617 | EXPORT double g_d; 618 | #ifdef HAVE_COMPLEX 619 | EXPORT double complex g_dc; 620 | EXPORT float complex g_fc; 621 | #endif 622 | EXPORT bool (*g_fp)(bool); 623 | EXPORT const char g_s[]; 624 | EXPORT const char* g_sp; 625 | EXPORT void* g_p; 626 | EXPORT enum e8 g_e8; 627 | EXPORT enum e16 g_e16; 628 | EXPORT enum e32 g_e32; 629 | EXPORT struct Date g_date; 630 | 631 | bool g_b = true; 632 | int8_t g_i8 = -8; 633 | int16_t g_i16 = -16; 634 | int32_t g_i32 = -32; 635 | int64_t g_i64 = -64; 636 | uint8_t g_u8 = 8; 637 | uint16_t g_u16 = 16; 638 | uint32_t g_u32 = 32; 639 | uint64_t g_u64 = 64; 640 | float g_f = 3; 641 | double g_d = 5; 642 | #ifdef HAVE_COMPLEX 643 | double complex g_dc = 7+8i; 644 | float complex g_fc = 6+9i; 645 | #endif 646 | bool (*g_fp)(bool) = ¬_b; 647 | void* g_p = (void*) ¬_b; 648 | const char g_s[] = "g_s"; 649 | const char* g_sp = "g_sp"; 650 | enum e8 g_e8 = FOO8; 651 | enum e16 g_e16 = FOO16; 652 | enum e32 g_e32 = FOO32; 653 | struct Date g_date = {1,2,3,4}; 654 | 655 | EXPORT void set_errno(int val); 656 | EXPORT int get_errno(void); 657 | 658 | void set_errno(int val) { 659 | #ifdef _WIN32 660 | SetLastError(val); 661 | #else 662 | errno = val; 663 | #endif 664 | } 665 | 666 | int get_errno(void) { 667 | #ifdef _WIN32 668 | return GetLastError(); 669 | #else 670 | return errno; 671 | #endif 672 | } 673 | 674 | EXPORT int va_list_size, va_list_align; 675 | int va_list_size = sizeof(va_list); 676 | int va_list_align = alignof(va_list); 677 | 678 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | -- vim: ts=4 sw=4 sts=4 et tw=78 2 | -- Copyright (c) 2011 James R. McKaskill. See license in ffi.h 3 | 4 | io.stdout:setvbuf('no') 5 | local ffi = require 'ffi' 6 | local dlls = {} 7 | 8 | dlls.__cdecl = ffi.load('test_cdecl') 9 | 10 | if ffi.arch == 'x86' and ffi.os == 'Windows' then 11 | dlls.__stdcall = ffi.load('test_stdcall') 12 | dlls.__fastcall = ffi.load('test_fastcall') 13 | end 14 | 15 | local function check(a, b) 16 | if a ~= b then 17 | print('check', a, b) 18 | end 19 | return _G.assert(a == b) 20 | end 21 | 22 | print('Running test') 23 | 24 | ffi.cdef [[ 25 | enum e8 { 26 | FOO8, 27 | BAR8, 28 | }; 29 | enum e16 { 30 | FOO16 = 1 << 8, 31 | BAR16, 32 | BIG16 = 1 << 14, 33 | }; 34 | enum e32 { 35 | FOO32 = 1 << 16, 36 | BAR32, 37 | BIG32 = 1 << 30, 38 | }; 39 | int max_alignment(); 40 | bool is_msvc, is_msvc2 __asm__("is_msvc"); 41 | bool have_complex(void); 42 | bool have_complex2() __asm__("have" /*foo*/ "\x5F" "complex"); // 5F is _ 43 | 44 | int8_t add_i8(int8_t a, int8_t b); 45 | uint8_t add_u8(uint8_t a, uint8_t b); 46 | int16_t add_i16(int16_t a, int16_t b); 47 | uint16_t add_i16(uint16_t a, uint16_t b); 48 | int32_t add_i32(int32_t a, int32_t b); 49 | uint32_t add_u32(uint32_t a, uint32_t b); 50 | int64_t add_i64(int64_t a, int64_t b); 51 | uint64_t add_u64(uint64_t a, uint64_t b); 52 | double add_d(double a, double b); 53 | float add_f(float a, float b); 54 | double complex add_dc(double complex a, double complex b); 55 | float complex add_fc(float complex a, float complex b); 56 | enum e8 inc_e8(enum e8); 57 | enum e16 inc_e16(enum e16); 58 | enum e32 inc_e32(enum e32); 59 | bool not_b(bool v); 60 | _Bool not_b2(_Bool v); 61 | typedef bool (*fp)(bool); 62 | fp ret_fp(fp v); 63 | bool (*ret_fp2(bool (*)(bool)))(bool) __asm("ret_fp"); 64 | 65 | int print_i8(char* buf, int8_t val); 66 | int print_u8(char* buf, uint8_t val); 67 | int print_i16(char* buf, int16_t val); 68 | int print_u16(char* buf, uint16_t val); 69 | int print_i32(char* buf, int32_t val); 70 | int print_u32(char* buf, uint32_t val); 71 | int print_i64(char* buf, int64_t val); 72 | int print_u64(char* buf, uint64_t val); 73 | int print_s(char* buf, const char* val); 74 | int print_b(char* buf, bool val); 75 | int print_b2(char* buf, _Bool val); 76 | int print_d(char* buf, double val); 77 | int print_f(char* buf, float val); 78 | int print_p(char* buf, void* val); 79 | int print_dc(char* buf, double complex val); 80 | int print_fc(char* buf, float complex val); 81 | int print_e8(char* buf, enum e8 val); 82 | int print_e16(char* buf, enum e16 val); 83 | int print_e32(char* buf, enum e32 val); 84 | int sprintf(char* buf, const char* format, ...); 85 | 86 | // Examples from MSDN 87 | 88 | // bit_fields1.cpp 89 | // compile with: /LD 90 | struct Date { 91 | unsigned short nWeekDay : 3; // 0..7 (3 bits) 92 | unsigned short nMonthDay : 6; // 0..31 (6 bits) 93 | unsigned short nMonth : 5; // 0..12 (5 bits) 94 | unsigned short nYear : 8; // 0..100 (8 bits) 95 | }; 96 | 97 | // bit_fields2.cpp 98 | // compile with: /LD 99 | struct Date2 { 100 | unsigned nWeekDay : 3; // 0..7 (3 bits) 101 | unsigned nMonthDay : 6; // 0..31 (6 bits) 102 | unsigned : 0; // Force alignment to next boundary. 103 | unsigned nMonth : 5; // 0..12 (5 bits) 104 | unsigned nYear : 8; // 0..100 (8 bits) 105 | }; 106 | 107 | // For checking the alignment of short bitfields 108 | struct Date3 { 109 | char pad; 110 | unsigned short nWeekDay : 3; // 0..7 (3 bits) 111 | unsigned short nMonthDay : 6; // 0..31 (6 bits) 112 | unsigned short nMonth : 5; // 0..12 (5 bits) 113 | unsigned short nYear : 8; // 0..100 (8 bits) 114 | }; 115 | 116 | // For checking the alignment and container of int64 bitfields 117 | struct bit64 { 118 | char pad; 119 | uint64_t a : 15; 120 | uint64_t b : 14; 121 | uint64_t c : 13; 122 | uint64_t d : 12; 123 | }; 124 | 125 | // Examples from SysV X86 ABI 126 | struct sysv1 { 127 | int j:5; 128 | int k:6; 129 | int m:7; 130 | }; 131 | 132 | struct sysv2 { 133 | short s:9; 134 | int j:9; 135 | char c; 136 | short t:9; 137 | short u:9; 138 | char d; 139 | }; 140 | 141 | struct sysv3 { 142 | char c; 143 | short s:8; 144 | }; 145 | 146 | union sysv4 { 147 | char c; 148 | short s:8; 149 | }; 150 | 151 | struct sysv5 { 152 | char c; 153 | int :0; 154 | char d; 155 | short :9; 156 | char e; 157 | char :0; 158 | }; 159 | 160 | struct sysv6 { 161 | char c; 162 | int :0; 163 | char d; 164 | int :9; 165 | char e; 166 | }; 167 | 168 | struct sysv7 { 169 | int j:9; 170 | short s:9; 171 | char c; 172 | short t:9; 173 | short u:9; 174 | }; 175 | 176 | int print_date(size_t* sz, size_t* align, char* buf, struct Date* s); 177 | int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* s); 178 | int print_date3(size_t* sz, size_t* align, char* buf, struct Date3* d); 179 | int print_bit64(size_t* sz, size_t* align, char* buf, struct bit64* d); 180 | int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s); 181 | int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s); 182 | int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s); 183 | int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s); 184 | int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s); 185 | int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s); 186 | int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s); 187 | 188 | struct fptr { 189 | int (__cdecl *p)(int); 190 | }; 191 | int call_fptr(struct fptr* s, int val); 192 | 193 | bool g_b; 194 | int8_t g_i8; 195 | int16_t g_i16; 196 | int32_t g_i32; 197 | int64_t g_i64; 198 | uint8_t g_u8; 199 | uint16_t g_u16; 200 | uint32_t g_u32; 201 | uint64_t g_u64; 202 | float g_f; 203 | double g_d; 204 | double complex g_dc; 205 | float complex g_fc; 206 | bool (*g_fp)(bool); 207 | const char g_s[]; 208 | const char* g_sp; 209 | void* g_p; 210 | enum e8 g_e8; 211 | enum e16 g_e16; 212 | enum e32 g_e32; 213 | struct Date g_date; 214 | 215 | void set_errno(int val); 216 | int get_errno(void); 217 | ]] 218 | 219 | local align = [[ 220 | struct align_ALIGN_SUFFIX { 221 | char pad; 222 | TYPE v; 223 | }; 224 | 225 | int print_align_ALIGN_SUFFIX(char* buf, struct align_ALIGN_SUFFIX* p); 226 | ]] 227 | 228 | local palign = [[ 229 | #pragma pack(push) 230 | #pragma pack(ALIGN) 231 | ]] .. align .. [[ 232 | #pragma pack(pop) 233 | ]] 234 | 235 | local bitfields = [[ 236 | struct bcTNUM { 237 | uintTNUM_t a : 3; 238 | intTNUM_t b : 3; 239 | }; 240 | struct blzTNUM { 241 | uintTNUM_t a; 242 | uintTNUM_t :0; 243 | uintTNUM_t b; 244 | }; 245 | int print_bcTNUM(size_t* sz, size_t* align, char* buf, struct bcTNUM* s); 246 | int print_blzTNUM(size_t* sz, size_t* align, char* buf, struct blzTNUM* s); 247 | ]] 248 | 249 | local bitalign = [[ 250 | struct ba_TNUM_BNUM { 251 | char a; 252 | uintTNUM_t b : BNUM; 253 | }; 254 | struct bu_TNUM_BNUM { 255 | char a; 256 | uintTNUM_t :BNUM; 257 | char b; 258 | }; 259 | int print_ba_TNUM_BNUM(size_t* sz, size_t* align, char* buf, struct ba_TNUM_BNUM* s); 260 | ]] 261 | 262 | local bitzero = [[ 263 | struct bz_TNUM_ZNUM_BNUM { 264 | uint8_t a; 265 | uintTNUM_t b : 3; 266 | uintZNUM_t :BNUM; 267 | uintTNUM_t c : 3; 268 | }; 269 | int print_bz_TNUM_ZNUM_BNUM(size_t* sz, size_t* align, char* buf, struct bz_TNUM_ZNUM_BNUM* s); 270 | ]] 271 | 272 | local i = ffi.C.i 273 | local test_values = { 274 | ['void*'] = ffi.new('char[3]'), 275 | ['const char*'] = 'foo', 276 | float = 3.4, 277 | double = 5.6, 278 | uint16_t = 65000, 279 | uint32_t = ffi.new('uint32_t', 700000056), 280 | uint64_t = 12345678901234, 281 | bool = true, 282 | _Bool = false, 283 | ['float complex'] = 3+4*i, 284 | ['double complex'] = 5+6*i, 285 | ['enum e8'] = ffi.C.FOO8, 286 | ['enum e16'] = ffi.C.FOO16, 287 | ['enum e32'] = ffi.C.FOO32, 288 | } 289 | 290 | local types = { 291 | b = 'bool', 292 | b2 = '_Bool', 293 | d = 'double', 294 | f = 'float', 295 | u64 = 'uint64_t', 296 | u32 = 'uint32_t', 297 | u16 = 'uint16_t', 298 | s = 'const char*', 299 | p = 'void*', 300 | e8 = 'enum e8', 301 | e16 = 'enum e16', 302 | e32 = 'enum e32', 303 | } 304 | 305 | local buf = ffi.new('char[256]') 306 | 307 | local function checkbuf(type, ret) 308 | local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '') 309 | check(ffi.string(buf), str) 310 | check(ret, #str) 311 | end 312 | 313 | local function checkalign(type, v, ret) 314 | --print(v) 315 | local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '') 316 | check(ffi.string(buf), ('size %d offset %d align %d value %s'):format(ffi.sizeof(v), ffi.offsetof(v, 'v'), ffi.alignof(v, 'v'), str)) 317 | check(ret, #str) 318 | end 319 | 320 | local u64 = ffi.typeof('uint64_t') 321 | local i64 = ffi.typeof('int64_t') 322 | 323 | local first = true 324 | 325 | for convention,c in pairs(dlls) do 326 | check(c.add_i8(1,1), 2) 327 | check(c.add_i8(256,1), 1) 328 | check(c.add_i8(127,1), -128) 329 | check(c.add_i8(-120,120), 0) 330 | check(c.add_u8(255,1), 0) 331 | check(c.add_u8(120,120), 240) 332 | check(c.add_i16(2000,4000), 6000) 333 | check(c.add_d(20, 12), 32) 334 | check(c.add_f(40, 32), 72) 335 | check(c.not_b(true), false) 336 | check(c.not_b2(false), true) 337 | check(c.inc_e8(c.FOO8), c.BAR8) 338 | check(c.inc_e8('FOO8'), c.BAR8) 339 | check(c.inc_e16(c.FOO16), c.BAR16) 340 | check(c.inc_e32(c.FOO32), c.BAR32) 341 | check(c.ret_fp(c.g_fp), c.g_fp) 342 | check(c.ret_fp2(c.g_fp), c.g_fp) 343 | 344 | if c.have_complex() then 345 | check(c.add_dc(3+4*i, 4+5*i), 7+9*i) 346 | check(c.add_fc(2+4*i, 6+8*i), 8+12*i) 347 | types.dc = 'double complex' 348 | types.fc = 'float complex' 349 | else 350 | types.dc = nil 351 | types.fc = nil 352 | end 353 | check((3+4*i).re, 3) 354 | check((3+4*i).im, 4) 355 | check(ffi.new('complex float', 2+8*i).re, 2) 356 | check(ffi.new('complex float', 5+6*i).im, 6) 357 | 358 | check(c.have_complex(), c.have_complex2()) 359 | check(c.is_msvc, c.is_msvc2) 360 | 361 | check(c.g_b, true) 362 | check(c.g_i8, -8) 363 | check(c.g_i16, -16) 364 | check(c.g_i32, -32) 365 | check(c.g_i64, i64(-64)) 366 | check(c.g_u8, 8) 367 | check(c.g_u16, 16) 368 | check(c.g_u32, 32) 369 | check(c.g_u64, u64(64)) 370 | check(c.g_f, 3) 371 | check(c.g_d, 5) 372 | if c.have_complex() then 373 | check(c.g_dc, 7 + 8*i) 374 | check(c.g_fc, 6 + 9*i) 375 | end 376 | check(ffi.cast('void*', c.g_fp), c.g_p) 377 | check(c.g_s, 'g_s') 378 | check(c.g_sp, 'g_sp') 379 | check(c.g_e8, c.FOO8) 380 | check(c.g_e16, c.FOO16) 381 | check(c.g_e32, c.FOO32) 382 | check(c.g_date.nWeekDay, 1) 383 | check(c.g_date.nMonthDay, 2) 384 | check(c.g_date.nMonth, 3) 385 | check(c.g_date.nYear, 4) 386 | 387 | c.g_b = false; check(c.g_b, false) 388 | c.g_i8 = -108; check(c.g_i8, -108) 389 | c.g_i16 = -1016; check(c.g_i16, -1016) 390 | c.g_i32 = -1032; check(c.g_i32, -1032) 391 | c.g_i64 = -1064; check(c.g_i64, i64(-1064)) 392 | c.g_u8 = 208; check(c.g_u8, 208) 393 | c.g_u16 = 2016; check(c.g_u16, 2016) 394 | c.g_u32 = 2032; check(c.g_u32, 2032) 395 | c.g_u64 = 2064; check(c.g_u64, u64(2064)) 396 | c.g_f = 13; check(c.g_f, 13) 397 | c.g_d = 15; check(c.g_d, 15) 398 | if c.have_complex() then 399 | c.g_dc = 17+18*i; check(c.g_dc, 17+18*i) 400 | c.g_fc = 16+19*i; check(c.g_fc, 16+19*i) 401 | end 402 | c.g_sp = 'foo'; check(c.g_sp, 'foo') 403 | c.g_e8 = c.BAR8; check(c.g_e8, c.BAR8) 404 | c.g_e16 = c.BAR16; check(c.g_e16, c.BAR16) 405 | c.g_e32 = c.BAR32; check(c.g_e32, c.BAR32) 406 | c.g_date.nWeekDay = 3; check(c.g_date.nWeekDay, 3) 407 | 408 | local align_attr = c.is_msvc and [[ 409 | struct align_attr_ALIGN_SUFFIX { 410 | char pad; 411 | __declspec(align(ALIGN)) TYPE v; 412 | }; 413 | 414 | int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p); 415 | ]] or [[ 416 | struct align_attr_ALIGN_SUFFIX { 417 | char pad; 418 | TYPE v __attribute__(aligned(ALIGN)); 419 | }; 420 | 421 | int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p); 422 | ]] 423 | 424 | for suffix, type in pairs(types) do 425 | local test = test_values[type] 426 | --print('checkbuf', suffix, type, buf, test) 427 | checkbuf(type, c['print_' .. suffix](buf, test)) 428 | 429 | if first then 430 | ffi.cdef(align:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', 0)) 431 | end 432 | 433 | local v = ffi.new('struct align_0_' .. suffix, {0, test}) 434 | checkalign(type, v, c['print_align_0_' .. suffix](buf, v)) 435 | 436 | for _,align in ipairs{1,2,4,8,16} do 437 | if align > c.max_alignment() then 438 | break 439 | end 440 | 441 | if first then 442 | ffi.cdef(palign:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align)) 443 | ffi.cdef(align_attr:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align)) 444 | end 445 | 446 | local v = ffi.new('struct align_' .. align .. '_' .. suffix, {0, test}) 447 | checkalign(type, v, c['print_align_' .. align .. '_' .. suffix](buf, v)) 448 | 449 | -- MSVC doesn't support aligned attributes on enums 450 | if not type:match('^enum e[0-9]*$') or not c.is_msvc then 451 | local v2 = ffi.new('struct align_attr_' .. align .. '_' .. suffix, {0, test}) 452 | checkalign(type, v2, c['print_align_attr_' .. align .. '_' .. suffix](buf, v2)) 453 | end 454 | end 455 | 456 | if not c.is_msvc then 457 | if first then 458 | local h = [[ 459 | struct align_attr_def_SUFFIX { 460 | char pad; 461 | TYPE v __attribute__(aligned); 462 | }; 463 | int print_align_attr_def_SUFFIX(char* buf, struct align_attr_def_SUFFIX* p); 464 | ]] 465 | ffi.cdef(h:gsub('SUFFIX', suffix):gsub('TYPE', type)) 466 | end 467 | 468 | local v = ffi.new('struct align_attr_def_' .. suffix, {0, test}) 469 | checkalign(type, v, c['print_align_attr_def_' .. suffix](buf, v)) 470 | end 471 | end 472 | 473 | local psz = ffi.new('size_t[1]') 474 | local palign = ffi.new('size_t[1]') 475 | local function check_align(type, test, ret) 476 | --print('check_align', type, test, ret, ffi.string(buf), psz[0], palign[0]) 477 | check(tonumber(palign[0]), ffi.alignof(type)) 478 | check(tonumber(psz[0]), ffi.sizeof(type)) 479 | check(ret, #test) 480 | check(test, ffi.string(buf)) 481 | end 482 | 483 | for _, tnum in ipairs{8, 16, 32, 64} do 484 | if first then 485 | ffi.cdef(bitfields:gsub('TNUM',tnum)) 486 | end 487 | 488 | check_align('struct bc'..tnum, '1 2', c['print_bc'..tnum](psz, palign, buf, {1,2})) 489 | check_align('struct blz'..tnum, '1 2', c['print_blz'..tnum](psz, palign, buf, {1,2})) 490 | 491 | for _, znum in ipairs{8, 16, 32, 64} do 492 | for _, bnum in ipairs{7, 15, 31, 63} do 493 | if bnum > znum then 494 | break 495 | end 496 | if first then 497 | ffi.cdef(bitzero:gsub('TNUM',tnum):gsub('ZNUM',znum):gsub('BNUM', bnum)) 498 | end 499 | check_align('struct bz_'..tnum..'_'..znum..'_'..bnum, '1 2 3', c['print_bz_'..tnum..'_'..znum..'_'..bnum](psz, palign, buf, {1,2,3})) 500 | end 501 | end 502 | 503 | for _, bnum in ipairs{7, 15, 31, 63} do 504 | if bnum > tnum then 505 | break 506 | end 507 | if first then 508 | ffi.cdef(bitalign:gsub('TNUM',tnum):gsub('BNUM',bnum)) 509 | end 510 | check_align('struct ba_'..tnum..'_'..bnum, '1 2', c['print_ba_'..tnum..'_'..bnum](psz, palign, buf, {1,2})) 511 | end 512 | end 513 | 514 | check_align('struct Date', '1 2 3 4', c.print_date(psz, palign, buf, {1,2,3,4})) 515 | check_align('struct Date2', '1 2 3 4', c.print_date2(psz, palign, buf, {1,2,3,4})) 516 | check_align('struct sysv1', '1 2 3', c.print_sysv1(psz, palign, buf, {1,2,3})) 517 | check_align('struct sysv2', '1 2 3 4 5 6', c.print_sysv2(psz, palign, buf, {1,2,3,4,5,6})) 518 | check_align('struct sysv3', '1 2', c.print_sysv3(psz, palign, buf, {1,2})) 519 | check_align('union sysv4', '1', c.print_sysv4(psz, palign, buf, {1})) 520 | check_align('struct sysv5', '1 2 3', c.print_sysv5(psz, palign, buf, {1,2,3})) 521 | check_align('struct sysv6', '1 2 3', c.print_sysv6(psz, palign, buf, {1,2,3})) 522 | check_align('struct sysv7', '1 2 3 4 5', c.print_sysv7(psz, palign, buf, {1,2,3,4,5})) 523 | 524 | local cbs = [[ 525 | typedef const char* (*__cdecl sfunc)(const char*); 526 | int call_i(int (*__cdecl func)(int), int arg); 527 | float call_f(float (*__cdecl func)(float), float arg); 528 | double call_d(double (*__cdecl func)(double), double arg); 529 | const char* call_s(sfunc func, const char* arg); 530 | _Bool call_b(_Bool (*__cdecl func)(_Bool), _Bool arg); 531 | double complex call_dc(double complex (*__cdecl func)(double complex), double complex arg); 532 | float complex call_fc(float complex (*__cdecl func)(float complex), float complex arg); 533 | enum e8 call_e8(enum e8 (*__cdecl func)(enum e8), enum e8 arg); 534 | enum e16 call_e16(enum e16 (*__cdecl func)(enum e16), enum e16 arg); 535 | enum e32 call_e32(enum e32 (*__cdecl func)(enum e32), enum e32 arg); 536 | ]] 537 | 538 | ffi.cdef(cbs:gsub('__cdecl', convention)) 539 | 540 | local u3 = ffi.new('uint64_t', 3) 541 | check(c.call_i(function(a) return 2*a end, 3), 6) 542 | assert(math.abs(c.call_d(function(a) return 2*a end, 3.2) - 6.4) < 0.0000000001) 543 | assert(math.abs(c.call_f(function(a) return 2*a end, 3.2) - 6.4) < 0.000001) 544 | check(ffi.string(c.call_s(function(s) return s + u3 end, 'foobar')), 'bar') 545 | check(c.call_b(function(v) return not v end, true), false) 546 | check(c.call_e8(function(v) return v + 1 end, c.FOO8), c.BAR8) 547 | check(c.call_e16(function(v) return v + 1 end, c.FOO16), c.BAR16) 548 | check(c.call_e32(function(v) return v + 1 end, c.FOO32), c.BAR32) 549 | 550 | if c.have_complex() then 551 | check(c.call_dc(function(v) return v + 2+3*i end, 4+6*i), 6+9*i) 552 | check(c.call_fc(function(v) return v + 1+2*i end, 7+4*i), 8+6*i) 553 | end 554 | 555 | local u2 = ffi.new('uint64_t', 2) 556 | local cb = ffi.new('sfunc', function(s) return s + u3 end) 557 | check(ffi.string(cb('foobar')), 'bar') 558 | check(ffi.string(c.call_s(cb, 'foobar')), 'bar') 559 | cb:set(function(s) return s + u2 end) 560 | check(ffi.string(c.call_s(cb, 'foobar')), 'obar') 561 | 562 | local fp = ffi.new('struct fptr') 563 | assert(fp.p == ffi.C.NULL) 564 | fp.p = function(a) return 2*a end 565 | assert(fp.p ~= ffi.C.NULL) 566 | check(c.call_fptr(fp, 4), 8) 567 | local suc, err = pcall(function() fp.p:set(function() end) end) 568 | assert(not suc) 569 | check(err:gsub('^.*: ',''), "can't set the function for a non-lua callback") 570 | 571 | check(c.call_fptr({function(a) return 3*a end}, 5), 15) 572 | 573 | local suc, err = pcall(c.call_s, function(s) error(ffi.string(s), 0) end, 'my error') 574 | check(suc, false) 575 | check(err, 'my error') 576 | 577 | check(ffi.errno(), c.get_errno()) 578 | c.set_errno(3) 579 | check(ffi.errno(), 3) 580 | check(c.get_errno(), 3) 581 | check(ffi.errno(4), 3) 582 | check(ffi.errno(), 4) 583 | check(c.get_errno(), 4) 584 | 585 | local gccattr = { 586 | __cdecl = 'int test_pow(int v) __attribute__((cdecl));', 587 | __stdcall = 'int test_pow(int v) __attribute__(stdcall);', 588 | __fastcall = '__attribute__(fastcall) int test_pow(int v);', 589 | } 590 | 591 | ffi.cdef(gccattr[convention]) 592 | check(c.test_pow(5), 25) 593 | 594 | ffi.cdef [[ 595 | int va_list_size, va_list_align; 596 | int vsnprintf(char* buf, size_t sz, const char* fmt, va_list ap); 597 | ]] 598 | ffi.new('va_list') 599 | assert(ffi.debug().functions.vsnprintf ~= nil) 600 | assert(ffi.istype('va_list', ffi.new('__builtin_va_list'))) 601 | assert(ffi.istype('va_list', ffi.new('__gnuc_va_list'))) 602 | check(ffi.sizeof('va_list'), c.va_list_size) 603 | check(ffi.alignof('va_list'), c.va_list_align) 604 | 605 | first = false 606 | end 607 | 608 | local c = ffi.C 609 | 610 | assert(c.sprintf(buf, "%g", 5.3) == 3 and ffi.string(buf) == '5.3') 611 | assert(c.sprintf(buf, "%d", false) == 1 and ffi.string(buf) == '0') 612 | assert(c.sprintf(buf, "%d%g", false, 6.7) == 4 and ffi.string(buf) == '06.7') 613 | 614 | assert(ffi.sizeof('uint32_t[?]', 32) == 32 * 4) 615 | assert(ffi.sizeof(ffi.new('uint32_t[?]', 32)) == 32 * 4) 616 | 617 | ffi.cdef [[ 618 | struct vls { 619 | struct { 620 | char a; 621 | struct { 622 | char b; 623 | char v[?]; 624 | } c; 625 | } d; 626 | }; 627 | struct vls2 { 628 | char pad; 629 | union { 630 | uint8_t a; 631 | uint16_t b; 632 | }; 633 | }; 634 | ]] 635 | 636 | assert(ffi.sizeof('struct vls', 3) == 5) 637 | assert(ffi.sizeof(ffi.new('struct vls', 4).d.c) == 5) 638 | assert(ffi.offsetof('struct vls2', 'a') == 2) 639 | assert(ffi.sizeof('struct vls2') == 4) 640 | 641 | ffi.cdef [[ static const int DUMMY = 8 << 2; ]] 642 | assert(ffi.C.DUMMY == 32) 643 | 644 | ffi.new('struct {const char* foo;}', {'foo'}) 645 | 646 | assert(not pcall(function() 647 | ffi.new('struct {char* foo;}', {'ff'}) 648 | end)) 649 | 650 | local mt = {} 651 | local vls = ffi.new(ffi.metatype('struct vls', mt), 1) 652 | 653 | assert(not pcall(function() return vls.key end)) 654 | 655 | mt.__index = function(vls, key) 656 | return function(vls, a, b) 657 | return 'in index ' .. key .. ' ' .. vls.d.a .. ' ' .. a .. ' ' .. b 658 | end 659 | end 660 | 661 | vls.d.a = 3 662 | check(vls:key('a', 'b'), 'in index key 3 a b') 663 | 664 | assert(not pcall(function() vls.k = 3 end)) 665 | 666 | mt.__newindex = function(vls, key, val) 667 | error('in newindex ' .. key .. ' ' .. vls.d.a .. ' ' .. val, 0) 668 | end 669 | 670 | vls.d.a = 4 671 | local suc, err = pcall(function() vls.key = 'val' end) 672 | assert(not suc) 673 | check(err, 'in newindex key 4 val') 674 | 675 | mt.__add = function(vls, a) return vls.d.a + a end 676 | mt.__sub = function(vls, a) return vls.d.a - a end 677 | mt.__mul = function(vls, a) return vls.d.a * a end 678 | mt.__div = function(vls, a) return vls.d.a / a end 679 | mt.__mod = function(vls, a) return vls.d.a % a end 680 | mt.__pow = function(vls, a) return vls.d.a ^ a end 681 | mt.__eq = function(vls, a) return u64(vls.d.a) == a end 682 | mt.__lt = function(vls, a) return u64(vls.d.a) < a end 683 | mt.__le = function(vls, a) return u64(vls.d.a) <= a end 684 | mt.__call = function(vls, a, b) return '__call', vls.d.a .. a .. (b or 'nil') end 685 | mt.__unm = function(vls) return -vls.d.a end 686 | mt.__concat = function(vls, a) return vls.d.a .. a end 687 | mt.__len = function(vls) return vls.d.a end 688 | mt.__tostring = function(vls) return 'string ' .. vls.d.a end 689 | 690 | vls.d.a = 5 691 | check(vls + 5, 10) 692 | check(vls - 5, 0) 693 | check(vls * 5, 25) 694 | check(vls / 5, 1) 695 | check(vls % 3, 2) 696 | check(vls ^ 3, 125) 697 | check(vls == u64(4), false) 698 | check(vls == u64(5), true) 699 | check(vls == u64(6), false) 700 | check(vls < u64(4), false) 701 | check(vls < u64(5), false) 702 | check(vls < u64(6), true) 703 | check(vls <= u64(4), false) 704 | check(vls <= u64(5), true) 705 | check(vls <= u64(6), true) 706 | check(-vls, -5) 707 | local a,b = vls('6') 708 | check(a, '__call') 709 | check(b, '56nil') 710 | check(tostring(vls), 'string 5') 711 | 712 | if _VERSION ~= 'Lua 5.1' then 713 | check(vls .. 'str', '5str') 714 | check(#vls, 5) 715 | end 716 | 717 | check(tostring(1+3*i), '1+3i') 718 | check(tostring((1+3*i)*(2+4*i)), '-10+10i') 719 | check(tostring((3+2*i)*(3-2*i)), '13') 720 | 721 | -- Should ignore unknown attributes 722 | ffi.cdef [[ 723 | typedef int ALenum; 724 | __attribute__((dllimport)) void __attribute__((__cdecl__)) alEnable( ALenum capability ); 725 | ]] 726 | 727 | check(ffi.sizeof('struct {char foo[alignof(uint64_t)];}'), ffi.alignof('uint64_t')) 728 | 729 | -- Long double is not supported yet but it should be parsed 730 | ffi.cdef('long double foo(long double val);') 731 | check(tostring(ffi.debug().functions.foo):match('ctype(%b<>)'), '') 732 | 733 | ffi.cdef [[ 734 | typedef int byte1 __attribute__(mode(QI)); 735 | typedef int byte2 __attribute__(mode(HI)); 736 | typedef int byte4 __attribute__(mode(SI)); 737 | typedef int byte8 __attribute__(mode(DI)); 738 | typedef unsigned ubyte8 __attribute__(mode(DI)); 739 | typedef int word __attribute__(mode(word)); 740 | typedef int pointer __attribute__(mode(pointer)); 741 | typedef int byte __attribute__(mode(byte)); 742 | typedef float float4 __attribute__(mode(SF)); 743 | typedef float float8 __attribute__(mode(DF)); 744 | ]] 745 | assert(ffi.istype('int8_t', ffi.new('byte1'))) 746 | assert(ffi.istype('int16_t', ffi.new('byte2'))) 747 | assert(ffi.istype('int32_t', ffi.new('byte4'))) 748 | assert(ffi.istype('int64_t', ffi.new('byte8'))) 749 | assert(ffi.istype('uint64_t', ffi.new('ubyte8'))) 750 | check(ffi.sizeof('void*'), ffi.sizeof('pointer')) 751 | check(ffi.alignof('void*'), ffi.alignof('pointer')) 752 | check(ffi.sizeof('void*'), ffi.sizeof('word')) 753 | check(ffi.alignof('void*'), ffi.alignof('word')) 754 | assert(ffi.istype('int8_t', ffi.new('byte'))) 755 | assert(ffi.istype('float', ffi.new('float4'))) 756 | assert(ffi.istype('double', ffi.new('float8'))) 757 | 758 | ffi.cdef('void register_foo(register int val);') 759 | check(tostring(ffi.debug().functions.register_foo):match('%b<>'), '') 760 | 761 | ffi.cdef [[ 762 | typedef struct __sFILE FILE; 763 | FILE *fopen(const char * , const char * ) __asm("_" "fopen" ); 764 | ]] 765 | 766 | assert(not ffi.istype('int', ffi.new('int*'))) 767 | assert(not ffi.istype('int[]', ffi.new('int*'))) 768 | assert(not ffi.istype('int[3]', ffi.new('int*'))) 769 | assert(not ffi.istype('int[3]', ffi.new('int[2]'))) 770 | assert(ffi.istype('const int[3]', ffi.new('const int[3]'))) 771 | assert(ffi.istype('int[3]', ffi.new('const int[3]'))) 772 | 773 | -- Crazy function pointer that takes an int and a function pointer and returns 774 | -- a function pointer. Type of &signal. 775 | check(tostring(ffi.typeof('void (*foo(int, void(*)(int)))(int)')):match('%b<>'), '') 776 | 777 | -- Make sure we pass all arguments to tonumber 778 | check(tonumber('FE', 16), 0xFE) 779 | 780 | -- Allow casts from pointer to numeric types 781 | ffi.cast('long', ffi.C.NULL) 782 | ffi.cast('int8_t', ffi.C.NULL) 783 | assert(not pcall(function() ffi.new('long', ffi.C.NULL) end)) 784 | 785 | -- ffi.new and ffi.cast allow unpacked struct/arrays 786 | assert(ffi.new('int[3]', 1)[0] == 1) 787 | assert(ffi.new('int[3]', {1})[0] == 1) 788 | assert(ffi.new('int[3]', 1, 2)[1] == 2) 789 | assert(ffi.new('int[3]', {1, 2})[1] == 2) 790 | 791 | ffi.cdef[[ 792 | struct var { 793 | char ch[?]; 794 | }; 795 | ]] 796 | local d = ffi.new('char[4]') 797 | local v = ffi.cast('struct var*', d) 798 | v.ch = {1,2,3,4} 799 | assert(v.ch[3] == 4) 800 | v.ch = "bar" 801 | assert(v.ch[3] == 0) 802 | assert(v.ch[2] == string.byte('r')) 803 | assert(d[1] == string.byte('a')) 804 | 805 | ffi.cast('char*', 1) 806 | 807 | -- 2 arg form of ffi.copy 808 | ffi.copy(d, 'bar') 809 | 810 | -- unsigned should be ignored for pointer rules 811 | ffi.cdef[[ 812 | int strncmp(const signed char *s1, const unsigned char *s2, size_t n); 813 | ]] 814 | assert(ffi.C.strncmp("two", "three", 3) ~= 0) 815 | 816 | ffi.fill(d, 3, 1) 817 | assert(d[2] == 1) 818 | ffi.fill(d, 3) 819 | assert(d[2] == 0) 820 | 821 | -- tests for __new 822 | ffi.cdef[[ 823 | struct newtest { 824 | int a; 825 | int b; 826 | int c; 827 | }; 828 | ]] 829 | 830 | local tp = ffi.metatype("struct newtest", {__new = 831 | function(tp, x, y, z) 832 | tp = ffi.new(tp) 833 | tp.a, tp.b, tp.c = x, y, z 834 | return tp 835 | end}) 836 | local v = tp(1, 2, 3) 837 | assert(v.a == 1 and v.b == 2 and v.c == 3) 838 | 839 | local tp = ffi.metatype("struct newtest", {__new = 840 | function(tp, x, y, z) 841 | tp = ffi.new(tp, {a = x, b = y, c = z}) 842 | return tp 843 | end}) 844 | local v = tp(1, 2, 3) 845 | assert(v.a == 1 and v.b == 2 and v.c == 3) 846 | 847 | -- tests for __pairs and __ipairs; not iterating just testing what is returned 848 | local tp = ffi.metatype("struct newtest", 849 | {__pairs = function(tp) return tp.a, tp.b end, __ipairs = function(tp) return tp.b, tp.c end} 850 | ) 851 | local v = tp(1, 2, 3) 852 | x, y = pairs(v) 853 | assert(x == 1 and y == 2) 854 | x, y = ipairs(v) 855 | assert(x == 2 and y == 3) 856 | 857 | -- test for pointer to struct having same metamethods 858 | local st = ffi.cdef "struct ptest {int a, b;};" 859 | local tp = ffi.metatype("struct ptest", {__index = function(s, k) return k end, __len = function(s) return 3 end}) 860 | 861 | local a = tp(1, 2) 862 | assert(a.banana == "banana") 863 | assert(#a == 3) 864 | local b = ffi.new("int[2]") 865 | local c = ffi.cast("struct ptest *", b) 866 | assert(c.banana == "banana") -- should have same methods 867 | assert(#c == 3) 868 | 869 | 870 | print('Test PASSED') 871 | 872 | -------------------------------------------------------------------------------- /dynasm/dasm_arm.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM ARM module. 3 | -- 4 | -- Copyright (C) 2005-2011 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | 8 | -- Module information: 9 | local _info = { 10 | arch = "arm", 11 | description = "DynASM ARM module", 12 | version = "1.3.0", 13 | vernum = 10300, 14 | release = "2011-05-05", 15 | author = "Mike Pall", 16 | license = "MIT", 17 | } 18 | 19 | -- Exported glue functions for the arch-specific module. 20 | local _M = { _info = _info } 21 | 22 | -- Cache library functions. 23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs 24 | local assert, setmetatable, rawget = assert, setmetatable, rawget 25 | local _s = string 26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char 27 | local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub 28 | local concat, sort, insert = table.concat, table.sort, table.insert 29 | 30 | -- Inherited tables and callbacks. 31 | local g_opt, g_arch 32 | local wline, werror, wfatal, wwarn 33 | 34 | -- Action name list. 35 | -- CHECK: Keep this in sync with the C code! 36 | local action_names = { 37 | "STOP", "SECTION", "ESC", "REL_EXT", 38 | "ALIGN", "REL_LG", "LABEL_LG", 39 | "REL_PC", "LABEL_PC", "LONG", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", 40 | } 41 | 42 | -- Maximum number of section buffer positions for dasm_put(). 43 | -- CHECK: Keep this in sync with the C code! 44 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. 45 | 46 | -- Action name -> action number. 47 | local map_action = {} 48 | for n,name in ipairs(action_names) do 49 | map_action[name] = n-1 50 | end 51 | 52 | -- Action list buffer. 53 | local actlist = {} 54 | 55 | -- Argument list for next dasm_put(). Start with offset 0 into action list. 56 | local actargs = { 0 } 57 | 58 | -- Current number of section buffer positions for dasm_put(). 59 | local secpos = 1 60 | 61 | ------------------------------------------------------------------------------ 62 | 63 | -- Return 8 digit hex number. 64 | local function tohex(x) 65 | return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. 66 | end 67 | 68 | -- Dump action names and numbers. 69 | local function dumpactions(out) 70 | out:write("DynASM encoding engine action codes:\n") 71 | for n,name in ipairs(action_names) do 72 | local num = map_action[name] 73 | out:write(format(" %-10s %02X %d\n", name, num, num)) 74 | end 75 | out:write("\n") 76 | end 77 | 78 | -- Write action list buffer as a huge static C array. 79 | local function writeactions(out, name) 80 | local nn = #actlist 81 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end 82 | out:write("static const unsigned int ", name, "[", nn, "] = {\n") 83 | for i = 1,nn-1 do 84 | assert(out:write("0x", tohex(actlist[i]), ",\n")) 85 | end 86 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) 87 | end 88 | 89 | ------------------------------------------------------------------------------ 90 | 91 | -- Add word to action list. 92 | local function wputxw(n) 93 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 94 | actlist[#actlist+1] = n 95 | end 96 | 97 | -- Add action to list with optional arg. Advance buffer pos, too. 98 | local function waction(action, val, a, num) 99 | local w = assert(map_action[action], "bad action name `"..action.."'") 100 | wputxw(w * 0x10000 + (val or 0)) 101 | if a then actargs[#actargs+1] = a end 102 | if a or num then secpos = secpos + (num or 1) end 103 | end 104 | 105 | -- Flush action list (intervening C code or buffer pos overflow). 106 | local function wflush(term) 107 | if #actlist == actargs[1] then return end -- Nothing to flush. 108 | if not term then waction("STOP") end -- Terminate action list. 109 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) 110 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). 111 | secpos = 1 -- The actionlist offset occupies a buffer position, too. 112 | end 113 | 114 | -- Put escaped word. 115 | local function wputw(n) 116 | if n <= 0x000fffff then waction("ESC") end 117 | wputxw(n) 118 | end 119 | 120 | -- Reserve position for word. 121 | local function wpos() 122 | local pos = #actlist+1 123 | actlist[pos] = "" 124 | return pos 125 | end 126 | 127 | -- Store word to reserved position. 128 | local function wputpos(pos, n) 129 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 130 | if n <= 0x000fffff then 131 | insert(actlist, pos+1, n) 132 | n = map_action.ESC * 0x10000 133 | end 134 | actlist[pos] = n 135 | end 136 | 137 | ------------------------------------------------------------------------------ 138 | 139 | -- Global label name -> global label number. With auto assignment on 1st use. 140 | local next_global = 20 141 | local map_global = setmetatable({}, { __index = function(t, name) 142 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end 143 | local n = next_global 144 | if n > 2047 then werror("too many global labels") end 145 | next_global = n + 1 146 | t[name] = n 147 | return n 148 | end}) 149 | 150 | -- Dump global labels. 151 | local function dumpglobals(out, lvl) 152 | local t = {} 153 | for name, n in pairs(map_global) do t[n] = name end 154 | out:write("Global labels:\n") 155 | for i=20,next_global-1 do 156 | out:write(format(" %s\n", t[i])) 157 | end 158 | out:write("\n") 159 | end 160 | 161 | -- Write global label enum. 162 | local function writeglobals(out, prefix) 163 | local t = {} 164 | for name, n in pairs(map_global) do t[n] = name end 165 | out:write("enum {\n") 166 | for i=20,next_global-1 do 167 | out:write(" ", prefix, t[i], ",\n") 168 | end 169 | out:write(" ", prefix, "_MAX\n};\n") 170 | end 171 | 172 | -- Write global label names. 173 | local function writeglobalnames(out, name) 174 | local t = {} 175 | for name, n in pairs(map_global) do t[n] = name end 176 | out:write("static const char *const ", name, "[] = {\n") 177 | for i=20,next_global-1 do 178 | out:write(" \"", t[i], "\",\n") 179 | end 180 | out:write(" (const char *)0\n};\n") 181 | end 182 | 183 | ------------------------------------------------------------------------------ 184 | 185 | -- Extern label name -> extern label number. With auto assignment on 1st use. 186 | local next_extern = 0 187 | local map_extern_ = {} 188 | local map_extern = setmetatable({}, { __index = function(t, name) 189 | -- No restrictions on the name for now. 190 | local n = next_extern 191 | if n > 2047 then werror("too many extern labels") end 192 | next_extern = n + 1 193 | t[name] = n 194 | map_extern_[n] = name 195 | return n 196 | end}) 197 | 198 | -- Dump extern labels. 199 | local function dumpexterns(out, lvl) 200 | out:write("Extern labels:\n") 201 | for i=0,next_extern-1 do 202 | out:write(format(" %s\n", map_extern_[i])) 203 | end 204 | out:write("\n") 205 | end 206 | 207 | -- Write extern label names. 208 | local function writeexternnames(out, name) 209 | out:write("static const char *const ", name, "[] = {\n") 210 | for i=0,next_extern-1 do 211 | out:write(" \"", map_extern_[i], "\",\n") 212 | end 213 | out:write(" (const char *)0\n};\n") 214 | end 215 | 216 | ------------------------------------------------------------------------------ 217 | 218 | -- Arch-specific maps. 219 | 220 | -- Ext. register name -> int. name. 221 | local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } 222 | 223 | -- Int. register name -> ext. name. 224 | local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } 225 | 226 | local map_type = {} -- Type name -> { ctype, reg } 227 | local ctypenum = 0 -- Type number (for Dt... macros). 228 | 229 | -- Reverse defines for registers. 230 | function _M.revdef(s) 231 | return map_reg_rev[s] or s 232 | end 233 | 234 | local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } 235 | 236 | local map_cond = { 237 | eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, 238 | hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, 239 | hs = 2, lo = 3, 240 | } 241 | 242 | ------------------------------------------------------------------------------ 243 | 244 | -- Template strings for ARM instructions. 245 | local map_op = { 246 | -- Basic data processing instructions. 247 | and_3 = "e0000000DNPs", 248 | eor_3 = "e0200000DNPs", 249 | sub_3 = "e0400000DNPs", 250 | rsb_3 = "e0600000DNPs", 251 | add_3 = "e0800000DNPs", 252 | adc_3 = "e0a00000DNPs", 253 | sbc_3 = "e0c00000DNPs", 254 | rsc_3 = "e0e00000DNPs", 255 | tst_2 = "e1100000NP", 256 | teq_2 = "e1300000NP", 257 | cmp_2 = "e1500000NP", 258 | cmn_2 = "e1700000NP", 259 | orr_3 = "e1800000DNPs", 260 | mov_2 = "e1a00000DPs", 261 | bic_3 = "e1c00000DNPs", 262 | mvn_2 = "e1e00000DPs", 263 | 264 | and_4 = "e0000000DNMps", 265 | eor_4 = "e0200000DNMps", 266 | sub_4 = "e0400000DNMps", 267 | rsb_4 = "e0600000DNMps", 268 | add_4 = "e0800000DNMps", 269 | adc_4 = "e0a00000DNMps", 270 | sbc_4 = "e0c00000DNMps", 271 | rsc_4 = "e0e00000DNMps", 272 | tst_3 = "e1100000NMp", 273 | teq_3 = "e1300000NMp", 274 | cmp_3 = "e1500000NMp", 275 | cmn_3 = "e1700000NMp", 276 | orr_4 = "e1800000DNMps", 277 | mov_3 = "e1a00000DMps", 278 | bic_4 = "e1c00000DNMps", 279 | mvn_3 = "e1e00000DMps", 280 | 281 | lsl_3 = "e1a00000DMws", 282 | lsr_3 = "e1a00020DMws", 283 | asr_3 = "e1a00040DMws", 284 | ror_3 = "e1a00060DMws", 285 | rrx_2 = "e1a00060DMs", 286 | 287 | -- Multiply and multiply-accumulate. 288 | mul_3 = "e0000090NMSs", 289 | mla_4 = "e0200090NMSDs", 290 | umaal_4 = "e0400090DNMSs", -- v6 291 | mls_4 = "e0600090DNMSs", -- v6T2 292 | umull_4 = "e0800090DNMSs", 293 | umlal_4 = "e0a00090DNMSs", 294 | smull_4 = "e0c00090DNMSs", 295 | smlal_4 = "e0e00090DNMSs", 296 | 297 | -- Halfword multiply and multiply-accumulate. 298 | smlabb_4 = "e1000080NMSD", -- v5TE 299 | smlatb_4 = "e10000a0NMSD", -- v5TE 300 | smlabt_4 = "e10000c0NMSD", -- v5TE 301 | smlatt_4 = "e10000e0NMSD", -- v5TE 302 | smlawb_4 = "e1200080NMSD", -- v5TE 303 | smulwb_3 = "e12000a0NMS", -- v5TE 304 | smlawt_4 = "e12000c0NMSD", -- v5TE 305 | smulwt_3 = "e12000e0NMS", -- v5TE 306 | smlalbb_4 = "e1400080NMSD", -- v5TE 307 | smlaltb_4 = "e14000a0NMSD", -- v5TE 308 | smlalbt_4 = "e14000c0NMSD", -- v5TE 309 | smlaltt_4 = "e14000e0NMSD", -- v5TE 310 | smulbb_3 = "e1600080NMS", -- v5TE 311 | smultb_3 = "e16000a0NMS", -- v5TE 312 | smulbt_3 = "e16000c0NMS", -- v5TE 313 | smultt_3 = "e16000e0NMS", -- v5TE 314 | 315 | -- Miscellaneous data processing instructions. 316 | clz_2 = "e16f0f10DM", -- v5T 317 | rev_2 = "e6bf0f30DM", -- v6 318 | rev16_2 = "e6bf0fb0DM", -- v6 319 | revsh_2 = "e6ff0fb0DM", -- v6 320 | sel_3 = "e6800fb0DNM", -- v6 321 | usad8_3 = "e780f010NMS", -- v6 322 | usada8_4 = "e7800010NMSD", -- v6 323 | rbit_2 = "e6ff0f30DM", -- v6T2 324 | movw_2 = "e3000000DW", -- v6T2 325 | movt_2 = "e3400000DW", -- v6T2 326 | -- Note: the X encodes width-1, not width. 327 | sbfx_4 = "e7a00050DMvX", -- v6T2 328 | ubfx_4 = "e7e00050DMvX", -- v6T2 329 | -- Note: the X encodes the msb field, not the width. 330 | bfc_3 = "e7c0001fDvX", -- v6T2 331 | bfi_4 = "e7c00010DMvX", -- v6T2 332 | 333 | -- Packing and unpacking instructions. 334 | pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 335 | pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 336 | sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 337 | sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 338 | sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 339 | sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 340 | sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 341 | sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 342 | uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 343 | uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 344 | uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 345 | uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 346 | uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 347 | uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 348 | 349 | -- Saturating instructions. 350 | qadd_3 = "e1000050DMN", -- v5TE 351 | qsub_3 = "e1200050DMN", -- v5TE 352 | qdadd_3 = "e1400050DMN", -- v5TE 353 | qdsub_3 = "e1600050DMN", -- v5TE 354 | -- Note: the X for ssat* encodes sat_imm-1, not sat_imm. 355 | ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 356 | usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 357 | ssat16_3 = "e6a00f30DXM", -- v6 358 | usat16_3 = "e6e00f30DXM", -- v6 359 | 360 | -- Parallel addition and subtraction. 361 | sadd16_3 = "e6100f10DNM", -- v6 362 | sasx_3 = "e6100f30DNM", -- v6 363 | ssax_3 = "e6100f50DNM", -- v6 364 | ssub16_3 = "e6100f70DNM", -- v6 365 | sadd8_3 = "e6100f90DNM", -- v6 366 | ssub8_3 = "e6100ff0DNM", -- v6 367 | qadd16_3 = "e6200f10DNM", -- v6 368 | qasx_3 = "e6200f30DNM", -- v6 369 | qsax_3 = "e6200f50DNM", -- v6 370 | qsub16_3 = "e6200f70DNM", -- v6 371 | qadd8_3 = "e6200f90DNM", -- v6 372 | qsub8_3 = "e6200ff0DNM", -- v6 373 | shadd16_3 = "e6300f10DNM", -- v6 374 | shasx_3 = "e6300f30DNM", -- v6 375 | shsax_3 = "e6300f50DNM", -- v6 376 | shsub16_3 = "e6300f70DNM", -- v6 377 | shadd8_3 = "e6300f90DNM", -- v6 378 | shsub8_3 = "e6300ff0DNM", -- v6 379 | uadd16_3 = "e6500f10DNM", -- v6 380 | uasx_3 = "e6500f30DNM", -- v6 381 | usax_3 = "e6500f50DNM", -- v6 382 | usub16_3 = "e6500f70DNM", -- v6 383 | uadd8_3 = "e6500f90DNM", -- v6 384 | usub8_3 = "e6500ff0DNM", -- v6 385 | uqadd16_3 = "e6600f10DNM", -- v6 386 | uqasx_3 = "e6600f30DNM", -- v6 387 | uqsax_3 = "e6600f50DNM", -- v6 388 | uqsub16_3 = "e6600f70DNM", -- v6 389 | uqadd8_3 = "e6600f90DNM", -- v6 390 | uqsub8_3 = "e6600ff0DNM", -- v6 391 | uhadd16_3 = "e6700f10DNM", -- v6 392 | uhasx_3 = "e6700f30DNM", -- v6 393 | uhsax_3 = "e6700f50DNM", -- v6 394 | uhsub16_3 = "e6700f70DNM", -- v6 395 | uhadd8_3 = "e6700f90DNM", -- v6 396 | uhsub8_3 = "e6700ff0DNM", -- v6 397 | 398 | -- Load/store instructions. 399 | str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", 400 | strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", 401 | ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", 402 | ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", 403 | strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", 404 | ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", 405 | ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE 406 | ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", 407 | strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE 408 | ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", 409 | 410 | ldm_2 = "e8900000nR", ldmia_2 = "e8900000nR", ldmfd_2 = "e8900000nR", 411 | ldmda_2 = "e8100000nR", ldmfa_2 = "e8100000nR", 412 | ldmdb_2 = "e9100000nR", ldmea_2 = "e9100000nR", 413 | ldmib_2 = "e9900000nR", ldmed_2 = "e9900000nR", 414 | stm_2 = "e8800000nR", stmia_2 = "e8800000nR", stmfd_2 = "e8800000nR", 415 | stmda_2 = "e8000000nR", stmfa_2 = "e8000000nR", 416 | stmdb_2 = "e9000000nR", stmea_2 = "e9000000nR", 417 | stmib_2 = "e9800000nR", stmed_2 = "e9800000nR", 418 | pop_1 = "e8bd0000R", push_1 = "e92d0000R", 419 | 420 | -- Branch instructions. 421 | b_1 = "ea000000B", 422 | bl_1 = "eb000000B", 423 | blx_1 = "e12fff30C", 424 | bx_1 = "e12fff10M", 425 | 426 | -- Miscellaneous instructions. 427 | nop_0 = "e1a00000", 428 | mrs_1 = "e10f0000D", 429 | bkpt_1 = "e1200070K", -- v5T 430 | svc_1 = "ef000000T", swi_1 = "ef000000T", 431 | ud_0 = "e7f001f0", 432 | 433 | -- NYI: Advanced SIMD and VFP instructions. 434 | 435 | -- NYI instructions, since I have no need for them right now: 436 | -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh 437 | -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe 438 | -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb 439 | -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 440 | } 441 | 442 | -- Add mnemonics for "s" variants. 443 | do 444 | local t = {} 445 | for k,v in pairs(map_op) do 446 | if sub(v, -1) == "s" then 447 | local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) 448 | t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 449 | end 450 | end 451 | for k,v in pairs(t) do 452 | map_op[k] = v 453 | end 454 | end 455 | 456 | ------------------------------------------------------------------------------ 457 | 458 | local function parse_gpr(expr) 459 | local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") 460 | local tp = map_type[tname or expr] 461 | if tp then 462 | local reg = ovreg or tp.reg 463 | if not reg then 464 | werror("type `"..(tname or expr).."' needs a register override") 465 | end 466 | expr = reg 467 | end 468 | local r = match(expr, "^r(1?[0-9])$") 469 | if r then 470 | r = tonumber(r) 471 | if r <= 15 then return r, tp end 472 | end 473 | werror("bad register name `"..expr.."'") 474 | end 475 | 476 | local function parse_gpr_pm(expr) 477 | local pm, expr2 = match(expr, "^([+-]?)(.*)$") 478 | return parse_gpr(expr2), (pm == "-") 479 | end 480 | 481 | local function parse_reglist(reglist) 482 | reglist = match(reglist, "^{%s*([^}]*)}$") 483 | if not reglist then werror("register list expected") end 484 | local rr = 0 485 | for p in gmatch(reglist..",", "%s*([^,]*),") do 486 | local rbit = 2^parse_gpr(gsub(p, "%s+$", "")) 487 | if ((rr - (rr % rbit)) / rbit) % 2 ~= 0 then 488 | werror("duplicate register `"..p.."'") 489 | end 490 | rr = rr + rbit 491 | end 492 | return rr 493 | end 494 | 495 | local function parse_imm(imm, bits, shift, scale, signed) 496 | imm = match(imm, "^#(.*)$") 497 | if not imm then werror("expected immediate operand") end 498 | local n = tonumber(imm) 499 | if n then 500 | if n % 2^scale == 0 then 501 | n = n / 2^scale 502 | if signed then 503 | if n >= 0 then 504 | if n < 2^(bits-1) then return n*2^shift end 505 | else 506 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end 507 | end 508 | else 509 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end 510 | end 511 | end 512 | werror("out of range immediate `"..imm.."'") 513 | else 514 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) 515 | return 0 516 | end 517 | end 518 | 519 | local function parse_imm12(imm) 520 | local n = tonumber(imm) 521 | if n then 522 | local m = n 523 | for i=0,-15,-1 do 524 | if m >= 0 and m <= 255 and n % 1 == 0 then return m + (i%16) * 256 end 525 | local t = m % 4 526 | m = (m - t) / 4 + t * 2^30 527 | end 528 | werror("out of range immediate `"..imm.."'") 529 | else 530 | waction("IMM12", 0, imm) 531 | return 0 532 | end 533 | end 534 | 535 | local function parse_imm16(imm) 536 | imm = match(imm, "^#(.*)$") 537 | if not imm then werror("expected immediate operand") end 538 | local n = tonumber(imm) 539 | if n then 540 | if n >= 0 and n <= 65535 and n % 1 == 0 then 541 | local t = n % 4096 542 | return (n - t) * 16 + t 543 | end 544 | werror("out of range immediate `"..imm.."'") 545 | else 546 | waction("IMM16", 32*16, imm) 547 | return 0 548 | end 549 | end 550 | 551 | local function parse_imm_load(imm, ext) 552 | local n = tonumber(imm) 553 | if n then 554 | if ext then 555 | if n >= -255 and n <= 255 then 556 | local up = 0x00800000 557 | if n < 0 then n = -n; up = 0 end 558 | return (n-(n%16))*16+(n%16) + up 559 | end 560 | else 561 | if n >= -4095 and n <= 4095 then 562 | if n >= 0 then return n+0x00800000 end 563 | return -n 564 | end 565 | end 566 | werror("out of range immediate `"..imm.."'") 567 | else 568 | waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), imm) 569 | return 0 570 | end 571 | end 572 | 573 | local function parse_shift(shift, gprok) 574 | if shift == "rrx" then 575 | return 3 * 32 576 | else 577 | local s, s2 = match(shift, "^(%S+)%s*(.*)$") 578 | s = map_shift[s] 579 | if not s then werror("expected shift operand") end 580 | if sub(s2, 1, 1) == "#" then 581 | return parse_imm(s2, 5, 7, 0, false) + s * 32 582 | else 583 | if not gprok then werror("expected immediate shift operand") end 584 | return parse_gpr(s2) * 256 + s * 32 + 16 585 | end 586 | end 587 | end 588 | 589 | local function parse_label(label, def) 590 | local prefix = sub(label, 1, 2) 591 | -- =>label (pc label reference) 592 | if prefix == "=>" then 593 | return "PC", 0, sub(label, 3) 594 | end 595 | -- ->name (global label reference) 596 | if prefix == "->" then 597 | return "LG", map_global[sub(label, 3)] 598 | end 599 | if def then 600 | -- [1-9] (local label definition) 601 | if match(label, "^[1-9]$") then 602 | return "LG", 10+tonumber(label) 603 | end 604 | else 605 | -- [<>][1-9] (local label reference) 606 | local dir, lnum = match(label, "^([<>])([1-9])$") 607 | if dir then -- Fwd: 1-9, Bkwd: 11-19. 608 | return "LG", lnum + (dir == ">" and 0 or 10) 609 | end 610 | -- extern label (extern label reference) 611 | local extname = match(label, "^extern%s+(%S+)$") 612 | if extname then 613 | return "EXT", map_extern[extname] 614 | end 615 | end 616 | werror("bad label `"..label.."'") 617 | end 618 | 619 | local function parse_load(params, nparams, n, op) 620 | local oplo = op % 256 621 | local ext, ldrd = (oplo ~= 0), (oplo == 208) 622 | local d 623 | if (ldrd or oplo == 240) then 624 | d = ((op - (op % 4096)) / 4096) % 16 625 | if d % 2 ~= 0 then werror("odd destination register") end 626 | end 627 | local pn = params[n] 628 | local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") 629 | local p2 = params[n+1] 630 | if not p1 then 631 | if not p2 then 632 | if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then 633 | local mode, n, s = parse_label(pn, false) 634 | waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) 635 | return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) 636 | end 637 | local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") 638 | if reg and tailr ~= "" then 639 | local d, tp = parse_gpr(reg) 640 | if tp then 641 | waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), 642 | format(tp.ctypefmt, tailr)) 643 | return op + d * 65536 + 0x01000000 + (ext and 0x00400000 or 0) 644 | end 645 | end 646 | end 647 | werror("expected address operand") 648 | end 649 | if wb == "!" then op = op + 0x00200000 end 650 | if p2 then 651 | if wb == "!" then werror("bad use of '!'") end 652 | local p3 = params[n+2] 653 | op = op + parse_gpr(p1) * 65536 654 | local imm = match(p2, "^#(.*)$") 655 | if imm then 656 | local m = parse_imm_load(imm, ext) 657 | if p3 then werror("too many parameters") end 658 | op = op + m + (ext and 0x00400000 or 0) 659 | else 660 | local m, neg = parse_gpr_pm(p2) 661 | if ldrd and (m == d or m-1 == d) then werror("register conflict") end 662 | op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) 663 | if p3 then op = op + parse_shift(p3) end 664 | end 665 | else 666 | local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") 667 | op = op + parse_gpr(p1a) * 65536 + 0x01000000 668 | if p2 ~= "" then 669 | local imm = match(p2, "^,%s*#(.*)$") 670 | if imm then 671 | local m = parse_imm_load(imm, ext) 672 | op = op + m + (ext and 0x00400000 or 0) 673 | else 674 | local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") 675 | local m, neg = parse_gpr_pm(p2a) 676 | if ldrd and (m == d or m-1 == d) then werror("register conflict") end 677 | op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) 678 | if p3 ~= "" then 679 | if ext then werror("too many parameters") end 680 | op = op + parse_shift(p3) 681 | end 682 | end 683 | else 684 | if wb == "!" then werror("bad use of '!'") end 685 | op = op + (ext and 0x00c00000 or 0x00800000) 686 | end 687 | end 688 | return op 689 | end 690 | 691 | ------------------------------------------------------------------------------ 692 | 693 | -- Handle opcodes defined with template strings. 694 | map_op[".template__"] = function(params, template, nparams) 695 | if not params then return sub(template, 9) end 696 | local op = tonumber(sub(template, 1, 8), 16) 697 | local n = 1 698 | 699 | -- Limit number of section buffer positions used by a single dasm_put(). 700 | -- A single opcode needs a maximum of 3 positions. 701 | if secpos+3 > maxsecpos then wflush() end 702 | local pos = wpos() 703 | 704 | -- Process each character. 705 | for p in gmatch(sub(template, 9), ".") do 706 | if p == "D" then 707 | op = op + parse_gpr(params[n]) * 4096; n = n + 1 708 | elseif p == "N" then 709 | op = op + parse_gpr(params[n]) * 65536; n = n + 1 710 | elseif p == "S" then 711 | op = op + parse_gpr(params[n]) * 256; n = n + 1 712 | elseif p == "M" then 713 | op = op + parse_gpr(params[n]); n = n + 1 714 | elseif p == "P" then 715 | local imm = match(params[n], "^#(.*)$") 716 | if imm then 717 | op = op + parse_imm12(imm) + 0x02000000 718 | else 719 | op = op + parse_gpr(params[n]) 720 | end 721 | n = n + 1 722 | elseif p == "p" then 723 | op = op + parse_shift(params[n], true); n = n + 1 724 | elseif p == "L" then 725 | op = parse_load(params, nparams, n, op) 726 | elseif p == "B" then 727 | local mode, n, s = parse_label(params[n], false) 728 | waction("REL_"..mode, n, s, 1) 729 | elseif p == "C" then -- blx gpr vs. blx label. 730 | local p = params[n] 731 | if match(p, "^([%w_]+):(r1?[0-9])$") or match(p, "^r(1?[0-9])$") then 732 | op = op + parse_gpr(p) 733 | else 734 | if op < 0xe0000000 then werror("unconditional instruction") end 735 | local mode, n, s = parse_label(p, false) 736 | waction("REL_"..mode, n, s, 1) 737 | op = 0xfa000000 738 | end 739 | elseif p == "n" then 740 | local r, wb = match(params[n], "^([^!]*)(!?)$") 741 | op = op + parse_gpr(r) * 65536 + (wb == "!" and 0x00200000 or 0) 742 | n = n + 1 743 | elseif p == "R" then 744 | op = op + parse_reglist(params[n]); n = n + 1 745 | elseif p == "W" then 746 | op = op + parse_imm16(params[n]); n = n + 1 747 | elseif p == "v" then 748 | op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1 749 | elseif p == "w" then 750 | local imm = match(params[n], "^#(.*)$") 751 | if imm then 752 | op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1 753 | else 754 | op = op + parse_gpr(params[n]) * 256 + 16 755 | end 756 | elseif p == "X" then 757 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 758 | elseif p == "K" then 759 | local imm = tonumber(match(params[n], "^#(.*)$")); n = n + 1 760 | if not imm or imm % 1 ~= 0 or imm < 0 or imm > 0xffff then 761 | werror("bad immediate operand") 762 | end 763 | local t = imm % 16 764 | op = op + (imm - t) * 16 + t 765 | elseif p == "T" then 766 | op = op + parse_imm(params[n], 24, 0, 0, false); n = n + 1 767 | elseif p == "s" then 768 | -- Ignored. 769 | else 770 | assert(false) 771 | end 772 | end 773 | wputpos(pos, op) 774 | end 775 | 776 | ------------------------------------------------------------------------------ 777 | 778 | -- Pseudo-opcode to mark the position where the action list is to be emitted. 779 | map_op[".actionlist_1"] = function(params) 780 | if not params then return "cvar" end 781 | local name = params[1] -- No syntax check. You get to keep the pieces. 782 | wline(function(out) writeactions(out, name) end) 783 | end 784 | 785 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. 786 | map_op[".globals_1"] = function(params) 787 | if not params then return "prefix" end 788 | local prefix = params[1] -- No syntax check. You get to keep the pieces. 789 | wline(function(out) writeglobals(out, prefix) end) 790 | end 791 | 792 | -- Pseudo-opcode to mark the position where the global names are to be emitted. 793 | map_op[".globalnames_1"] = function(params) 794 | if not params then return "cvar" end 795 | local name = params[1] -- No syntax check. You get to keep the pieces. 796 | wline(function(out) writeglobalnames(out, name) end) 797 | end 798 | 799 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. 800 | map_op[".externnames_1"] = function(params) 801 | if not params then return "cvar" end 802 | local name = params[1] -- No syntax check. You get to keep the pieces. 803 | wline(function(out) writeexternnames(out, name) end) 804 | end 805 | 806 | ------------------------------------------------------------------------------ 807 | 808 | -- Label pseudo-opcode (converted from trailing colon form). 809 | map_op[".label_1"] = function(params) 810 | if not params then return "[1-9] | ->global | =>pcexpr" end 811 | if secpos+1 > maxsecpos then wflush() end 812 | local mode, n, s = parse_label(params[1], true) 813 | if mode == "EXT" then werror("bad label definition") end 814 | waction("LABEL_"..mode, n, s, 1) 815 | end 816 | 817 | ------------------------------------------------------------------------------ 818 | 819 | -- Pseudo-opcodes for data storage. 820 | map_op[".long_*"] = function(params) 821 | if not params then return "imm..." end 822 | for _,p in ipairs(params) do 823 | local n = tonumber(p) 824 | if n then 825 | if n < 0 then n = n + 2^32 end 826 | wputw(n) 827 | if secpos+2 > maxsecpos then wflush() end 828 | else 829 | waction("LONG", 0, format("(uintptr_t)(%s)", p)) 830 | end 831 | end 832 | end 833 | 834 | -- Alignment pseudo-opcode. 835 | map_op[".align_1"] = function(params) 836 | if not params then return "numpow2" end 837 | if secpos+1 > maxsecpos then wflush() end 838 | local align = tonumber(params[1]) 839 | if align then 840 | local x = align 841 | -- Must be a power of 2 in the range (2 ... 256). 842 | for i=1,8 do 843 | x = x / 2 844 | if x == 1 then 845 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. 846 | return 847 | end 848 | end 849 | end 850 | werror("bad alignment") 851 | end 852 | 853 | ------------------------------------------------------------------------------ 854 | 855 | -- Pseudo-opcode for (primitive) type definitions (map to C types). 856 | map_op[".type_3"] = function(params, nparams) 857 | if not params then 858 | return nparams == 2 and "name, ctype" or "name, ctype, reg" 859 | end 860 | local name, ctype, reg = params[1], params[2], params[3] 861 | if not match(name, "^[%a_][%w_]*$") then 862 | werror("bad type name `"..name.."'") 863 | end 864 | local tp = map_type[name] 865 | if tp then 866 | werror("duplicate type `"..name.."'") 867 | end 868 | -- Add #type to defines. A bit unclean to put it in map_archdef. 869 | map_archdef["#"..name] = "sizeof("..ctype..")" 870 | -- Add new type and emit shortcut define. 871 | local num = ctypenum + 1 872 | map_type[name] = { 873 | ctype = ctype, 874 | ctypefmt = format("Dt%X(%%s)", num), 875 | reg = reg, 876 | } 877 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) 878 | ctypenum = num 879 | end 880 | map_op[".type_2"] = map_op[".type_3"] 881 | 882 | -- Dump type definitions. 883 | local function dumptypes(out, lvl) 884 | local t = {} 885 | for name in pairs(map_type) do t[#t+1] = name end 886 | sort(t) 887 | out:write("Type definitions:\n") 888 | for _,name in ipairs(t) do 889 | local tp = map_type[name] 890 | local reg = tp.reg or "" 891 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) 892 | end 893 | out:write("\n") 894 | end 895 | 896 | ------------------------------------------------------------------------------ 897 | 898 | -- Set the current section. 899 | function _M.section(num) 900 | waction("SECTION", num) 901 | wflush(true) -- SECTION is a terminal action. 902 | end 903 | 904 | ------------------------------------------------------------------------------ 905 | 906 | -- Dump architecture description. 907 | function _M.dumparch(out) 908 | out:write(format("DynASM %s version %s, released %s\n\n", 909 | _info.arch, _info.version, _info.release)) 910 | dumpactions(out) 911 | end 912 | 913 | -- Dump all user defined elements. 914 | function _M.dumpdef(out, lvl) 915 | dumptypes(out, lvl) 916 | dumpglobals(out, lvl) 917 | dumpexterns(out, lvl) 918 | end 919 | 920 | ------------------------------------------------------------------------------ 921 | 922 | -- Pass callbacks from/to the DynASM core. 923 | function _M.passcb(wl, we, wf, ww) 924 | wline, werror, wfatal, wwarn = wl, we, wf, ww 925 | return wflush 926 | end 927 | 928 | -- Setup the arch-specific module. 929 | function _M.setup(arch, opt) 930 | g_arch, g_opt = arch, opt 931 | end 932 | 933 | -- Merge the core maps and the arch-specific maps. 934 | function _M.mergemaps(map_coreop, map_def) 935 | setmetatable(map_op, { __index = function(t, k) 936 | local v = map_coreop[k] 937 | if v then return v end 938 | local cc = sub(k, -4, -3) 939 | local cv = map_cond[cc] 940 | if cv then 941 | local v = rawget(t, sub(k, 1, -5)..sub(k, -2)) 942 | if type(v) == "string" then return format("%x%s", cv, sub(v, 2)) end 943 | end 944 | end }) 945 | setmetatable(map_def, { __index = map_archdef }) 946 | return map_op, map_def 947 | end 948 | 949 | return _M 950 | 951 | ------------------------------------------------------------------------------ 952 | 953 | --------------------------------------------------------------------------------