├── tools ├── make │ ├── dynasm-disabled.mk │ ├── lua-system.mk │ ├── libdwarf-system.mk │ ├── dynasm-linux-x64.mk │ ├── dynasm-linux-x86.mk │ ├── dynasm.mk │ ├── lua-bundled.mk │ └── libdwarf-bundled.mk ├── ninja │ ├── dynasm-disabled.ninja │ ├── lua-system.ninja │ ├── libdwarf-system.ninja │ ├── dynasm-linux-x64.ninja │ ├── dynasm-linux-x86.ninja │ ├── dynasm.ninja │ ├── libdwarf-bundled.ninja │ └── lua-bundled.ninja ├── make-example-wrapper-script ├── run-tests ├── harness-testutil.c ├── harness-assert.lua └── harness.lua ├── .gitignore ├── libtest2.c ├── test ├── modload.lua ├── typeof-type.lua ├── sizeof.lua ├── reflect-function.lua ├── typeof-string.lua ├── modload-private.lua ├── lookup-types.lua ├── typeof-var.lua ├── modload-global.lua ├── struct-member-access.lua ├── lookup-function.lua ├── struct-array-member-access.lua ├── lookup-variable.lua ├── create-var-from-type.lua ├── gc-library-before-varfunc.lua ├── struct-anonymous.lua ├── struct-member-access-nested.lua ├── arrayvar.lua ├── struct-nested.lua ├── constvar.lua ├── array-nested-struct-access.lua ├── reflect-enum.lua ├── test-eol-alignof.lua ├── struct.lua ├── reflect-function-types.lua ├── test-eol-abi.lua ├── test-assertions.lua ├── intvar.lua ├── fltvar.lua ├── test-eol-type.lua ├── reflect-var.lua ├── offsetof.lua └── test-eol-sizeof.lua ├── .gitmodules ├── eol-lua.h ├── eol-fcall-dasm.c ├── examples ├── ui.lua ├── nanovg-noise.lua ├── upng-info.lua ├── nanovg-demo.lua ├── modularize.lua ├── imgui-util.c ├── build.ninja ├── nanovg-utils.c └── type-pp.lua ├── eol-fcall-x64.h ├── specials.gperf ├── dynasm ├── dasm_x64.lua ├── dasm_proto.h ├── dasm_ppc.h ├── dasm_mips.h └── dasm_arm.h ├── eol-fcall-ffi.h ├── .travis.yml ├── eol-fcall.h ├── LICENSE ├── eol-typecache.h ├── eol-util.c ├── eol-typecache.c ├── libtest.c ├── eol-trace.h ├── README.md ├── Makefile ├── eol-trace.c ├── eol-libdwarf.c ├── eol-fcall-x86.dasc ├── specials.inc ├── eol-libdwarf.h ├── eol-fcall-x64.c ├── eol-typing.h ├── eol-util.h └── eol-fcall-ffi.c /tools/make/dynasm-disabled.mk: -------------------------------------------------------------------------------- 1 | eol_fcall := ffi 2 | -------------------------------------------------------------------------------- /tools/ninja/dynasm-disabled.ninja: -------------------------------------------------------------------------------- 1 | eol_fcall = ffi 2 | -------------------------------------------------------------------------------- /tools/ninja/lua-system.ninja: -------------------------------------------------------------------------------- 1 | lua_exe = ${system_lua_bin} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .*.sw[op] 3 | .ninja_deps 4 | .ninja_log 5 | build.conf 6 | -------------------------------------------------------------------------------- /tools/make/lua-system.mk: -------------------------------------------------------------------------------- 1 | LUA := ${system_lua_bin} 2 | LUA_LIB := -llua -lm 3 | -------------------------------------------------------------------------------- /tools/make/libdwarf-system.mk: -------------------------------------------------------------------------------- 1 | LIBDWARF_LDLIBS := -ldwarf -lelf 2 | LIBDWARF := 3 | -------------------------------------------------------------------------------- /tools/ninja/libdwarf-system.ninja: -------------------------------------------------------------------------------- 1 | libdwarf_lib = -ldwarf 2 | libdwarf_dep = eol-libdwarf.h 3 | -------------------------------------------------------------------------------- /tools/make/dynasm-linux-x64.mk: -------------------------------------------------------------------------------- 1 | eol_fcall := x64 2 | eol_fcall_in := x86 3 | dynasm_flags := -D X64 4 | 5 | include tools/make/dynasm.mk 6 | -------------------------------------------------------------------------------- /tools/make/dynasm-linux-x86.mk: -------------------------------------------------------------------------------- 1 | eol_fcall := x86 2 | eol_fcall_in := x86 3 | dynasm_flags := -D X86 4 | 5 | include tools/ninja/dynasm.mk 6 | -------------------------------------------------------------------------------- /tools/ninja/dynasm-linux-x64.ninja: -------------------------------------------------------------------------------- 1 | eol_fcall = x64 2 | eol_fcall_in = x86 3 | dynasm_flags = -D X64 4 | 5 | include tools/ninja/dynasm.ninja 6 | -------------------------------------------------------------------------------- /tools/ninja/dynasm-linux-x86.ninja: -------------------------------------------------------------------------------- 1 | eol_fcall = x86 2 | eol_fcall_in = x86 3 | dynasm_flags = -D X86 4 | 5 | include tools/ninja/dynasm.ninja 6 | -------------------------------------------------------------------------------- /libtest2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libtest.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | extern int intvar; 9 | 10 | int 11 | add_intvar (int a) 12 | { 13 | return a + intvar; 14 | } 15 | -------------------------------------------------------------------------------- /test/modload.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- modload.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | assert(eol, "could not load 'eol' module") 11 | assert.Field(eol, "load") 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "examples/nanovg"] 2 | path = examples/nanovg 3 | url = git://github.com/memononen/nanovg 4 | [submodule "examples/upng"] 5 | path = examples/upng 6 | url = git://github.com/elanthis/upng 7 | [submodule "examples/cimgui"] 8 | path = examples/cimgui 9 | url = git://github.com/Extrawurst/cimgui 10 | -------------------------------------------------------------------------------- /test/typeof-type.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- typeof-type.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local T = eol.type(eol.load "libtest", "int32_t") 11 | assert.Not.Nil(T) 12 | assert.Equal(T, eol.typeof(T)) 13 | assert.Equal(4, eol.sizeof(eol.typeof(T))) 14 | -------------------------------------------------------------------------------- /eol-lua.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-lua.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_LUA_H 9 | #define EOL_LUA_H 10 | 11 | #if defined(EOL_LUA_BUNDLED) && EOL_LUA_BUNDLED 12 | # include "lua.h" 13 | # include "lauxlib.h" 14 | #else 15 | # include 16 | # include 17 | #endif 18 | 19 | #endif /* !EOL_LUA_H */ 20 | -------------------------------------------------------------------------------- /test/sizeof.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-sizeof.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | assert.Field(eol, "sizeof") 11 | 12 | local libtest = eol.load("libtest") 13 | 14 | assert.Equal(4, eol.sizeof(libtest.var_i32)) 15 | assert.Equal(4, eol.sizeof(libtest.var_i32.__type)) 16 | -------------------------------------------------------------------------------- /test/reflect-function.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-reflect-function.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | local func = libtest.add 11 | assert.Not.Nil(func) 12 | assert.Callable(func) 13 | assert.Equal("add", func.__name) 14 | assert.Equal(libtest, func.__library) 15 | -------------------------------------------------------------------------------- /test/typeof-string.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- typeof-string.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local test = eol.load "libtest" 11 | local T = eol.typeof "int32_t" 12 | assert.Not.Nil(T) 13 | assert.Equal(T, eol.typeof "int32_t") 14 | assert.Equal(4, T.sizeof) 15 | assert.Equal(4, eol.sizeof(T)) 16 | -------------------------------------------------------------------------------- /test/modload-private.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- modload-private.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | local libtest = eol.load("libtest") 11 | assert.Not.Nil(libtest) 12 | 13 | local libtest2 = nil 14 | assert.Error(function () libtest2 = eol.load("libtest2", false) end) 15 | assert.Nil(libtest2) 16 | -------------------------------------------------------------------------------- /eol-fcall-dasm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-fcall-dasm.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | static int 9 | function_call (lua_State *L) 10 | { 11 | EolFunction *ef = to_eol_function (L); 12 | CHECK_NOT_NULL (ef->fcall_jit_func); 13 | return (*ef->fcall_jit_func) (L); 14 | } 15 | 16 | 17 | static void 18 | fcall_jit_free (EolFunction *ef) 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /test/lookup-types.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-lookup-types.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local libtest = eol.load "libtest" 11 | 12 | local i32 = eol.type(libtest, "int32_t") 13 | assert.Not.Nil(i32) 14 | assert.Equal("int32_t", i32.name) 15 | assert.Equal(4, i32.sizeof) 16 | assert.False(i32.readonly) 17 | -------------------------------------------------------------------------------- /test/typeof-var.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- typeof-var.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | 11 | local V = eol.load("libtest").var_i32 12 | assert.Not.Nil(V) 13 | 14 | local T = eol.typeof(V) 15 | assert.Not.Nil(T) 16 | assert.Equal(V.__type, T) 17 | assert.Equal(eol.typeof "int32_t", T) 18 | assert.Equal(4, T.sizeof) 19 | -------------------------------------------------------------------------------- /test/modload-global.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- modload-global.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local libtest = eol.load("libtest", true) -- Request loading as global 11 | assert.Not.Nil(libtest) 12 | 13 | -- Loading a second library that uses a symbol defined in the first library. 14 | local libtest = eol.load("libtest2") 15 | assert.Not.Nil(libtest) 16 | -------------------------------------------------------------------------------- /test/struct-member-access.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- struct-member-access.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local max_pos = require("eol").load("libtest").max_pos 10 | assert.Not.Nil(max_pos) 11 | 12 | -- Indexed access 13 | assert.Equal(800, max_pos[1]) 14 | assert.Equal(600, max_pos[2]) 15 | 16 | -- Named access 17 | assert.Equal(800, max_pos.x) 18 | assert.Equal(600, max_pos.y) 19 | -------------------------------------------------------------------------------- /test/lookup-function.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-lookup-function.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | assert(libtest, "could not load libtest.so") 11 | 12 | local add = libtest.add 13 | assert.Not.Nil(add) 14 | assert.Userdata(add, "org.perezdecastro.eol.Function") 15 | assert.Callable(add) 16 | assert.Equal(libtest, add.__library) 17 | -------------------------------------------------------------------------------- /test/struct-array-member-access.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- struct-array-member-access.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local curve = require("eol").load("libtest").curve 10 | assert.Not.Nil(curve) 11 | assert.Fields(curve, "points", "tangential") 12 | assert.Equal(4, #curve.points) 13 | assert.Equal(1, curve.points[1].x) 14 | curve.points[2].y = 5 15 | assert.Equal(5, curve.points[2].y) 16 | -------------------------------------------------------------------------------- /test/lookup-variable.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-lookup-variable.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | assert(libtest, "could not load libtest.so") 11 | 12 | local intvar = libtest.intvar 13 | assert.Not.Nil(intvar) 14 | assert.Userdata(intvar, "org.perezdecastro.eol.Variable") 15 | assert.Not.Callable(intvar) 16 | assert.Equal(libtest, intvar.__library) 17 | -------------------------------------------------------------------------------- /examples/ui.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- ui.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local ig = require "modularize" { 10 | "imgui", prefix = "ig", type_prefix = "ImGui" 11 | } 12 | 13 | local W = 800 14 | local H = 600 15 | 16 | local toplevel = ig.TopLevel("Lua + Eol + ImGui", W, H) 17 | ig.MakeCurrent(toplevel) 18 | 19 | while not ig.Done(toplevel) do 20 | ig.FrameStart(toplevel) 21 | ig.FrameEnd(toplevel) 22 | end 23 | ig.Exit() 24 | -------------------------------------------------------------------------------- /test/create-var-from-type.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-create-var-from-type.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local libtest = eol.load "libtest" 11 | local int32_t = eol.type(libtest, "int32_t") 12 | 13 | local value = int32_t() 14 | assert.Equal(int32_t, eol.typeof(value)) 15 | assert.Equal(1, #value) 16 | assert.Equal(0, value.__value) 17 | 18 | value.__value = 42 19 | assert.Equal(42, value.__value) 20 | 21 | -------------------------------------------------------------------------------- /test/gc-library-before-varfunc.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- gc-library-before-varfunc.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | assert.Not.Nil(libtest) 11 | 12 | local variable = libtest.intvar 13 | 14 | -- Force early collection of the library 15 | libtest = nil 16 | collectgarbage() 17 | 18 | -- This should work and not crash. 19 | assert.Equal(42, variable.__value) 20 | variable = nil 21 | collectgarbage() 22 | -------------------------------------------------------------------------------- /test/struct-anonymous.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-anon-struct.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local anon_struct = require("eol").load("libtest").anon_struct 10 | assert.Not.Nil(anon_struct) 11 | assert.Equal("anon_struct", anon_struct.__name) 12 | local struct_type = anon_struct.__type 13 | assert.Equal(1, #struct_type) 14 | assert.Equal("member", struct_type[1].name) 15 | assert.Equal(121, anon_struct.member) 16 | assert.Equal(121, anon_struct[1]) 17 | -------------------------------------------------------------------------------- /eol-fcall-x64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-fcall-x64.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_FCALL_X64_H 9 | #define EOL_FCALL_X64_H 10 | 11 | #define EOL_FUNCTION_FCALL_FIELDS lua_CFunction fcall_jit_func 12 | #define EOL_FUNCTION_FCALL_INIT(ef) fcall_jit_compile (L, ef) 13 | #define EOL_FUNCTION_FCALL_FREE fcall_jit_free 14 | 15 | static void fcall_jit_compile (lua_State*, const EolFunction*); 16 | static void fcall_jit_free (EolFunction*); 17 | 18 | #endif /* !EOL_FCALL_X64_H */ 19 | -------------------------------------------------------------------------------- /specials.gperf: -------------------------------------------------------------------------------- 1 | %language=ANSI-C 2 | %struct-type 3 | %compare-strncmp 4 | %readonly-tables 5 | %enum 6 | %includes 7 | %define hash-function-name eol_special_hash 8 | %define lookup-function-name eol_special_lookup 9 | struct EolSpecial { 10 | const char *name; 11 | EolSpecialCode code; 12 | }; 13 | %% 14 | name, EOL_SPECIAL_NAME 15 | type, EOL_SPECIAL_TYPE 16 | value, EOL_SPECIAL_VALUE 17 | library, EOL_SPECIAL_LIBRARY 18 | sizeof, EOL_SPECIAL_SIZEOF 19 | readonly, EOL_SPECIAL_READONLY 20 | kind, EOL_SPECIAL_KIND 21 | pointerto, EOL_SPECIAL_POINTERTO 22 | arrayof, EOL_SPECIAL_ARRAYOF 23 | -------------------------------------------------------------------------------- /test/struct-member-access-nested.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- struct-member-access-nested.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local screen = require("eol").load("libtest").screen 10 | assert.Fields(screen, "tl", "br") 11 | assert.Not.Nil(screen.tl) 12 | assert.Not.Nil(screen.br) 13 | assert.Equal(10, screen.tl.x) 14 | assert.Equal(20, screen.tl.y) 15 | assert.Equal(50, screen.br.x) 16 | assert.Equal(80, screen.br.y) 17 | 18 | screen.tl.x = 15 19 | assert.Equal(15, screen.tl.x) 20 | -------------------------------------------------------------------------------- /test/arrayvar.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-arrayvar.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local intarray = require("eol").load("libtest").intarray 10 | 11 | local function check_items(a) 12 | for i, v in ipairs(a) do 13 | assert.Equal(v, intarray[i]) 14 | end 15 | end 16 | 17 | assert.Not.Nil(intarray) 18 | assert.Equal("intarray", intarray.__name) 19 | assert.Equal(5, #intarray) 20 | check_items { 1, 2, 3, 4, 5 } 21 | intarray[3] = 42 22 | check_items { 1, 2, 42, 4, 5 } 23 | -------------------------------------------------------------------------------- /test/struct-nested.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-struct-nested.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local Square = require("eol").load("libtest").screen.__type 10 | assert.Not.Nil(Square) 11 | assert.Equal(2, #Square) 12 | assert.Equal("tl", Square[1].name) 13 | assert.Equal(2, #Square[1].type) 14 | assert.Equal("x", Square[1].type[1].name) 15 | assert.Equal("y", Square[1].type[2].name) 16 | assert.Equal("br", Square[2].name) 17 | assert.Equal(Square[1].type, Square[2].type) 18 | -------------------------------------------------------------------------------- /test/constvar.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-intvar.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | local variable = libtest.const_int 11 | 12 | assert.Not.Nil(variable) 13 | assert.Not.Callable(variable) 14 | assert.Equal(42, variable.__value) 15 | assert.Equal(libtest, variable.__library) 16 | 17 | -- Read-only variables cannot be assigned to. 18 | assert.Error(function () variable.__value = 100 end) 19 | assert.Equal(42, variable.__value) 20 | -------------------------------------------------------------------------------- /tools/make-example-wrapper-script: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # Usage: $0 lua-binary script.lua objdir outfile 4 | # 5 | 6 | pushd "$(dirname "$1")" &> /dev/null 7 | luadir=$(pwd) 8 | popd &> /dev/null 9 | 10 | mkdir -p "$3" "$(dirname "$4")" 11 | curdir=$(pwd) 12 | 13 | pushd "$(dirname "$2")" &> /dev/null 14 | script="$(pwd)/$(basename "$2")" 15 | popd &> /dev/null 16 | 17 | pushd "$3" &> /dev/null 18 | objdir=$(pwd) 19 | popd &> /dev/null 20 | 21 | cat > "$4" < 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local triangle = require("eol").load("libtest").triangle 10 | assert.Not.Nil(triangle) 11 | assert.Equal(3, #triangle) 12 | assert.Equal(1, triangle[1].x) 13 | assert.Equal(1, triangle[1].y) 14 | assert.Equal(2, triangle[2].x) 15 | assert.Equal(3, triangle[2].y) 16 | assert.Equal(1, triangle[3].x) 17 | assert.Equal(3, triangle[3].y) 18 | 19 | triangle[2].x = 3 20 | assert.Equal(3, triangle[2].x) 21 | -------------------------------------------------------------------------------- /test/reflect-enum.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- reflect-enum.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | local libtest = eol.load("libtest") 11 | local Continent = eol.type(libtest, "Continent") 12 | 13 | assert.Not.Nil(Continent) 14 | assert.Equal(6, #Continent) 15 | 16 | local data = { 17 | "AFRICA", "EUROPE", "ASIA", "AMERICA", "ANTARCTICA", "AUSTRALIA" 18 | } 19 | 20 | for i, name in ipairs(data) do 21 | local entry = Continent[i] 22 | assert.Equal(name, entry.name) 23 | assert.Equal(i - 1, entry.value) 24 | end 25 | -------------------------------------------------------------------------------- /test/test-eol-alignof.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- test-eol-alignof.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | assert.Field(eol, "alignof") 11 | assert.Callable(eol.alignof) 12 | 13 | local libtest = eol.load("libtest") 14 | local u8type = eol.type(libtest, "uint8_t") 15 | 16 | assert.Equal(1, eol.alignof(u8type)) 17 | assert.Equal(1, eol.alignof(libtest.var_u8)) 18 | 19 | -- Values other than variables or typeinfos raise an error 20 | for _, value in ipairs { 1, 3.14, false, true, "str", { table=true } } do 21 | assert.Error(function () 22 | local _ = eol.alignof(value) 23 | end) 24 | end 25 | -------------------------------------------------------------------------------- /test/struct.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-anon-struct.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local origin = require("eol").load("libtest").origin 10 | assert.Not.Nil(origin) 11 | assert.Equal("origin", origin.__name) 12 | 13 | local struct_type = origin.__type 14 | assert.Equal("Point", struct_type.name) 15 | assert.Equal(2, #struct_type) 16 | 17 | local x_member = struct_type[1] 18 | local y_member = struct_type[2] 19 | assert.Equal("x", x_member.name) 20 | assert.Equal("y", y_member.name) 21 | assert.Equal(0, x_member.offset) 22 | assert.Equal(x_member.type, y_member.type) 23 | assert.True(x_member.offset < y_member.offset) 24 | -------------------------------------------------------------------------------- /eol-fcall-ffi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-fcall-ffi.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_FCALL_FFI_H 9 | #define EOL_FCALL_FFI_H 10 | 11 | #include 12 | 13 | #define EOL_FUNCTION_FCALL_FIELDS \ 14 | ffi_cif fcall_ffi_cif; \ 15 | ffi_type *fcall_ffi_return_type; \ 16 | ffi_type **fcall_ffi_param_types; \ 17 | size_t fcall_ffi_scratch_size 18 | 19 | #define EOL_FUNCTION_FCALL_INIT \ 20 | eol_fcall_ffi_init 21 | 22 | #define EOL_FUNCTION_FCALL_FREE \ 23 | eol_fcall_ffi_free 24 | 25 | static inline void eol_fcall_ffi_init (EolFunction *ef); 26 | static inline void eol_fcall_ffi_free (EolFunction *ef); 27 | 28 | #endif /* !EOL_FCALL_FFI_H */ 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | addons: 3 | apt: 4 | packages: 5 | - libelf-dev 6 | - glibc-dev 7 | - ninja-build 8 | - gperf 9 | sudo: false 10 | compiler: 11 | - clang 12 | - gcc 13 | env: 14 | matrix: 15 | - COVERAGE=true 16 | - COVERAGE=false 17 | install: 18 | - $COVERAGE && pip install --user cpp-coveralls || true 19 | script: 20 | - export PATH="${PATH}:${HOME}/.local/bin" 21 | - $COVERAGE && export CC="${CC} -fprofile-arcs -ftest-coverage -O0 -g" || true 22 | - ./configure --objdir=out --enable-checks --enable-bundled-lua --enable-bundled-libdwarf && ninja && ./run-tests --verbose --output=tap 23 | after_success: 24 | - $COVERAGE && coveralls --exclude out --exclude --gcov-options '\-lp' || true 25 | -------------------------------------------------------------------------------- /test/reflect-function-types.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- reflect-function-types.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | local func = libtest.add 11 | assert.Not.Nil(func) 12 | assert.Equal(2, #func) 13 | assert.Fields(func, "__name", "__type", "__library") 14 | assert.Equal("add", func.__name) 15 | assert.Equal(libtest, func.__library) 16 | 17 | local rettype = func.__type 18 | assert.Not.Nil(rettype) 19 | 20 | for i = 1, #func do 21 | local paramtype = func[i] 22 | assert.Not.Nil(paramtype) 23 | assert.Equal(rettype, paramtype) 24 | end 25 | 26 | assert.Error(function () 27 | -- Access an invalid function parameter index 28 | local paramtype = func[42] 29 | end) 30 | -------------------------------------------------------------------------------- /test/test-eol-abi.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- test-eol-abi.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | 11 | for _, flag in ipairs { "le", "be", "32bit", "64bit", "win", "fpu", "softfpu", "eabi" } do 12 | -- We cannot make assumptions about the machine where the test suite runs, 13 | -- so just call the function with the flags to check that no errors are 14 | -- raised and a boolean value is returned. 15 | assert.Boolean(eol.abi(flag)) 16 | end 17 | 18 | for _, flag in ipairs { 1, 3.14, false, true, { table=true }, "foobar" } do 19 | -- Check that an error is raised for non-string parameters and invalid 20 | -- string flags. 21 | assert.Error(function () 22 | local _ = eol.abi(flag) 23 | end) 24 | end 25 | -------------------------------------------------------------------------------- /tools/make/dynasm.mk: -------------------------------------------------------------------------------- 1 | BITOP_VERSION := 1.0.2 2 | BITOP_TARBALL := ${OUT}/downloads/LuaBitOp-${BITOP_VERSION}.tar.gz 3 | BITOP_PATH := ${OUT}/LuaBitOp-${BITOP_VERSION} 4 | 5 | ${BITOP_TARBALL}: URL = http://bitop.luajit.org/download/LuaBitOp-${BITOP_VERSION}.tar.gz 6 | ${BITOP_TARBALL}: 7 | ${RUN_FETCH_URL} 8 | 9 | ${BITOP_PATH}/bit.c: ${BITOP_TARBALL} 10 | ${RUN_UNTARGZ} 11 | $Q touch $@ 12 | 13 | ${OUT}/bit.so: ${BITOP_PATH}/bit.o 14 | ${OUT}/bit.so: CPPFLAGS += -DLUA_NUMBER_DOUBLE 15 | ${OUT}/bit.so: LDFLAGS += -shared 16 | 17 | clean-bit: 18 | $Q ${RM} ${OUT}/bit.so ${OUT}/bit.o 19 | 20 | .PHONY: clean-bit 21 | clean: clean-bit 22 | 23 | 24 | eol-fcall-${eol_fcall}.c: eol-fcall-${eol_fcall_in}.dasc | ${LUA} ${OUT}/bit.so 25 | $P 'DynASM(${jit_arch})' $< 26 | $Q LUA_CPATH=${OUT}/?.so ${LUA} dynasm/dynasm.lua ${dynasm_flags} -o $@ $< 27 | 28 | -------------------------------------------------------------------------------- /test/test-assertions.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- test-assertions.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | assert(type(assert) == "table", "assert is not a table") 10 | 11 | -- Check metatable 12 | local meta = getmetatable(assert) 13 | assert(meta ~= nil, "assert does not have a metatable") 14 | assert(meta.__call ~= nil, "assert metatable does not have __call") 15 | assert(type(meta.__call) == "function", "assert() is not callable") 16 | 17 | assert.True(true) 18 | assert.False(false) 19 | assert.Not.True(false) 20 | assert.Not.False(true) 21 | 22 | -- Try calling a function that raises an error 23 | assert.Error(function() error("meh") end) 24 | assert.Error("meh", function() error("meh") end) 25 | assert.Not.Error("meow", function() error("meh") end) 26 | -------------------------------------------------------------------------------- /test/intvar.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-intvar.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | 11 | function check_variable (variable, expected_value) 12 | assert.Not.Nil(variable) 13 | assert.Not.Callable(variable) 14 | assert.Equal(expected_value, variable.__value) 15 | assert.Equal(libtest, variable.__library) 16 | variable.__value = 100 17 | assert.Equal(100, variable.__value) 18 | end 19 | 20 | 21 | for _, width in ipairs { 8, 16, 32, 64 } do 22 | for _, signedness in ipairs { "i", "u" } do 23 | local variable_name = "var_" .. signedness .. tostring(width) 24 | local variable = libtest[variable_name] 25 | check_variable(variable, signedness == "i" and -width or width) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /tools/ninja/dynasm.ninja: -------------------------------------------------------------------------------- 1 | bitop_version = 1.0.2 2 | bitop_tarball = ${obj}/downloads/LuaBitOp-${bitop_version}.tar.gz 3 | bitop_path = ${obj}/LuaBitOp-${bitop_version} 4 | 5 | rule dynasm 6 | command = env LUA_CPATH=${obj}/?.so ${lua_exe} dynasm/dynasm.lua ${dynasm_flags} -o ${out} ${in} 7 | description = DynASM(${jit_arch}) ${in} -> ${out} 8 | 9 | build ${bitop_tarball} : urlfetch 10 | url = http://bitop.luajit.org/download/LuaBitOp-${bitop_version}.tar.gz 11 | 12 | build ${bitop_path}/bit.c : untargz ${bitop_tarball} 13 | 14 | build ${obj}/bit.o : cc ${bitop_path}/bit.c || eol-lua.h 15 | cppflags = ${cppflags} -DLUA_NUMBER_DOUBLE 16 | 17 | build ${obj}/bit.so : ld ${obj}/bit.o 18 | ldflags = ${ldflags} -shared 19 | 20 | build eol-fcall-${eol_fcall}.c : dynasm $ 21 | eol-fcall-${eol_fcall_in}.dasc | eol-fcall-dasm.c || ${lua_exe} ${obj}/bit.so 22 | -------------------------------------------------------------------------------- /test/fltvar.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-fltvar.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | 11 | for _, varname in ipairs { "var_flt", "var_dbl" } do 12 | local variable = libtest[varname] 13 | assert.Not.Nil(variable) 14 | assert.Not.Callable(variable) 15 | assert.Equal(1.0, variable.__value) 16 | assert.Equal(libtest, variable.__library) 17 | 18 | -- Set a floating point value. 19 | variable.__value = -42.5 20 | assert.Not.Equal(1.0, variable.__value) 21 | assert.Equal(-42.5, variable.__value) 22 | 23 | -- Set an integral value (must work for floating point values). 24 | variable.__value = 42 25 | assert.Not.Equal(1.0, variable.__value) 26 | assert.Not.Equal(-42.5, variable.__value) 27 | assert.Equal(42, variable.__value) 28 | end 29 | 30 | -------------------------------------------------------------------------------- /eol-fcall.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-fcall.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | /* 9 | * Select the appropriate implementation of eol_function_call() 10 | * depending on the target architecture and operating system. 11 | */ 12 | #if defined(EOL_FCALL_FFI) && EOL_FCALL_FFI > 0 13 | # ifdef EOL_FCALL_IMPLEMENT 14 | # include "eol-fcall-ffi.c" 15 | # else 16 | # include "eol-fcall-ffi.h" 17 | # endif 18 | #else 19 | # if defined(__x86_64__) || defined(__x86_64) || \ 20 | defined(__amd64__) || defined(__amd64) 21 | # ifdef EOL_FCALL_IMPLEMENT 22 | # include "eol-fcall-x64.c" 23 | # else 24 | # include "eol-fcall-x64.h" 25 | # endif 26 | # else 27 | # error No eol_fcall implementation chosen, you may want to configure with --enable-ffi 28 | # endif 29 | # ifdef EOL_FCALL_IMPLEMENT 30 | # include "eol-fcall-dasm.c" 31 | # endif 32 | #endif 33 | -------------------------------------------------------------------------------- /test/test-eol-type.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- test-eol-type.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | assert.Field(eol, "type") 11 | assert.Callable(eol.type) 12 | 13 | local libtest = eol.load("libtest") 14 | 15 | assert.Not.Nil(eol.type(libtest, "int")) -- Existing type 16 | assert.Nil(eol.type(libtest, "no no no")) -- Nonexistent type 17 | 18 | -- Values other than a library for the first parameter raise errors. 19 | for _, value in ipairs { 1, 3.14, false, true, "foo", { table=true } } do 20 | assert.Error(function () 21 | local _ = eol.type(value, "int") 22 | end) 23 | end 24 | 25 | -- Values other than a string for the second parameter raise errors. 26 | for _, value in ipairs { 1, 3.13, false, true, { table=true }, libtest } do 27 | assert.Error(function () 28 | local _ = eol.type(libtest, value) 29 | end) 30 | end 31 | -------------------------------------------------------------------------------- /test/reflect-var.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- libtest-reflect-var.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local libtest = require("eol").load("libtest") 10 | assert.Not.Nil(libtest) 11 | 12 | function check_variable(variable, expected_name, expected_readonly, 13 | expected_type, expected_type_sizeof) 14 | assert.Not.Nil(variable) 15 | assert.Equal(expected_name, variable.__name) 16 | assert.Equal(libtest, variable.__library) 17 | assert.Match(expected_type, variable.__type.name) 18 | assert.Equal(expected_readonly, variable.__type.readonly) 19 | if expected_type_sizeof ~= nil then 20 | assert.Equal(expected_type_sizeof, variable.__type.sizeof) 21 | end 22 | end 23 | 24 | check_variable(libtest.const_int, "const_int", true, "int%d+_t") 25 | check_variable(libtest.var_u16, "var_u16", false, "uint16_t", 2) 26 | check_variable(libtest.intvar, "intvar", false, "int%d+_t") 27 | -------------------------------------------------------------------------------- /test/offsetof.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- offsetof.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local Point = eol.type(eol.load "libtest", "Point") 11 | assert.Not.Nil(Point) 12 | 13 | -- First field always at offset 0; the offset of the second field must be 14 | -- at least the size of the first field (it can be more, because padding). 15 | assert.Equal(0, eol.offsetof(Point, 1)) 16 | assert.True(eol.offsetof(Point, 2) >= Point[1].type.sizeof) 17 | 18 | -- The information gotten by field name must be the same. 19 | assert.Equal(0, eol.offsetof(Point, "x")) 20 | assert.True(eol.offsetof(Point, "y") >= Point[1].type.sizeof) 21 | 22 | -- Offsets given by eol.offsetof() must match the ones given by indexing 23 | -- the EolTypeInfo userdatas. 24 | assert.Equal(Point[1].offset, eol.offsetof(Point, 1)) 25 | assert.Equal(Point[1].offset, eol.offsetof(Point, "x")) 26 | assert.Equal(Point[2].offset, eol.offsetof(Point, 2)) 27 | assert.Equal(Point[2].offset, eol.offsetof(Point, "y")) 28 | -------------------------------------------------------------------------------- /test/test-eol-sizeof.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- test-eol-sizeof.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | local libtest = eol.load("libtest") 11 | 12 | assert.Fields(eol, "sizeof") 13 | assert.Callable(eol.sizeof) 14 | 15 | assert.Equal(4, eol.sizeof(libtest.var_u32)) 16 | assert.Equal(4, eol.sizeof(libtest.var_u32.__type)) 17 | 18 | local inttype = libtest.intvar.__type 19 | assert.Equal(inttype.sizeof, eol.sizeof(inttype)) 20 | assert.Equal(inttype.sizeof, eol.sizeof(libtest.intvar)) 21 | 22 | -- For functions and "void", returns "nil" (it does not have a size) 23 | assert.Nil(eol.sizeof(libtest.add)) 24 | assert.Nil(eol.sizeof(libtest.voidptr.__type.type)) 25 | 26 | -- For other values, raises an error 27 | local error_values = { 28 | 1, 3.14, 29 | true, false, 30 | { table = true }, 31 | function () end, 32 | io.stdin, 33 | } 34 | 35 | for _, value in ipairs(error_values) do 36 | assert.Error(function () 37 | local _ = eol.sizeof(value) 38 | end) 39 | end 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 Adrián Pérez de Castro 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tools/run-tests: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # run-tests 4 | # Copyright (C) 2015 Adrian Perez 5 | # 6 | # Distributed under terms of the MIT license. 7 | # 8 | 9 | # Obtain the working directory and the directory where this scripts resides, 10 | # which then can be used to find the test harness and the needed binaries. 11 | curdir=$(pwd) 12 | cd "$(dirname "$0")/.." 13 | eoldir=$(pwd) 14 | 15 | if ! test -r build.conf 16 | then 17 | echo "build.conf not found. Have you run ./configure?" 1>&2 18 | exit 1 19 | fi 20 | 21 | luaexe=$(sed -e 's/^system_lua_bin[[:space:]]*=[[:space:]]*\(.*\)$/\1/p' -e 'd' build.conf) 22 | objdir=$(sed -e 's/^obj[[:space:]]*=[[:space:]]*\(.*\)$/\1/p' -e 'd' build.conf) 23 | cd "${objdir}" 24 | objdir=$(pwd) 25 | 26 | if test "x${luaexe}" = "x" 27 | then 28 | luaexe="${objdir}/lua" 29 | fi 30 | 31 | for file in libtest.so eol.so testutil.so "${luaexe}" 32 | do 33 | if ! test -r "${file}" 34 | then 35 | echo "File not found: ${file}" 1>&2 36 | echo "Have you run 'ninja' or 'make'?" 1>&2 37 | exit 1 38 | fi 39 | done 40 | 41 | export EOL_LUA_EXE="${luaexe}" 42 | export LUA_INIT="@${eoldir}/tools/harness-assert.lua" 43 | exec "${luaexe}" "${eoldir}/tools/harness.lua" "${eoldir}" "${curdir}" "$@" 44 | -------------------------------------------------------------------------------- /eol-typecache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-typecache.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_TYPECACHE_H 9 | #define EOL_TYPECACHE_H 10 | 11 | #include "eol-typing.h" 12 | #include 13 | #include 14 | 15 | 16 | typedef struct _EolTypeCacheEntry* EolTypeCache; 17 | typedef bool (*EolTypeCacheIter) (EolTypeCache*, 18 | const EolTypeInfo*, 19 | void *userdata); 20 | 21 | extern void eol_type_cache_init (EolTypeCache *cache); 22 | extern void eol_type_cache_free (EolTypeCache *cache); 23 | 24 | extern void eol_type_cache_add (EolTypeCache *cache, 25 | uint32_t offset, 26 | const EolTypeInfo *typeinfo); 27 | 28 | extern const EolTypeInfo* eol_type_cache_lookup (EolTypeCache *cache, 29 | uint32_t offset); 30 | 31 | extern void eol_type_cache_foreach (EolTypeCache *cache, 32 | EolTypeCacheIter callback, 33 | void *userdata); 34 | 35 | #endif /* !EOL_TYPECACHE_H */ 36 | -------------------------------------------------------------------------------- /examples/nanovg-noise.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- nanovg-noise.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require "eol" 10 | local nvg = require "modularize" { 11 | "nanovg", prefix = "nvg", type_prefix = "NVG" 12 | } 13 | local inttype = eol.type(nvg.__library, "long int") 14 | local ucharptr = eol.type(nvg.__library, "unsigned char"):pointerto() 15 | 16 | local W = 320 17 | local H = 240 18 | 19 | local window = nvg.Window("Noise", W, H) 20 | nvg.MakeCurrent(window) 21 | 22 | local vg = nvg.Create(false) 23 | local bits = inttype(W * H / 2) 24 | local bits_as_ptr = eol.cast(ucharptr, bits) 25 | local image = nvg.CreateImageRGBA(vg, W, H, 0, bits_as_ptr) 26 | local paint = nvg.ImagePattern(vg, 0, 0, W, H, 0.0, image, 1.0) 27 | 28 | while not nvg.Done(window) do 29 | 30 | -- Fill with random data 31 | local r = bits[1] + 1 32 | for i = 1, #bits do 33 | r = r * 1103515245 34 | bits[i] = r ~ (bits[i] >> 16) 35 | end 36 | 37 | nvg.UpdateImage(vg, image, bits_as_ptr) 38 | 39 | nvg.FrameStart(window, vg) 40 | nvg.BeginPath(vg) 41 | nvg.Rect(vg, 0, 0, W, H) 42 | nvg.FillPaint(vg, paint) 43 | nvg.Fill(vg) 44 | nvg.FrameEnd(window, vg) 45 | end 46 | nvg.DeleteImage(vg, image) 47 | nvg.Exit() 48 | -------------------------------------------------------------------------------- /examples/upng-info.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- upnginfo.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local upng = require "modularize" { "upng", prefix = "upng_" } 10 | 11 | local function enum_value_string(enum, value) 12 | for i = 1, #enum do 13 | local item = enum[i] 14 | if value == item.value then 15 | return item.name 16 | end 17 | end 18 | return tostring(value) .. " (no symbolic name?)" 19 | end 20 | 21 | local print_item_format = " %-10s %s\n" 22 | local function print_item(key, value) 23 | io.stdout:write(print_item_format:format(key, tostring(value))) 24 | end 25 | 26 | local function info(img) 27 | local fmt = upng.get_format(img) 28 | print_item("format", enum_value_string(upng.types.format, fmt)) 29 | print_item("channels", upng.get_components(img)) 30 | print_item("width", upng.get_width(img)) 31 | print_item("height", upng.get_height(img)) 32 | print_item("bpp", upng.get_bpp(img)) 33 | print_item("depth", upng.get_bitdepth(img)) 34 | end 35 | 36 | for _, path in ipairs(arg) do 37 | local img = upng.new_from_file(path) 38 | if img ~= nil then 39 | if upng.decode(img) == 0 then 40 | print("" .. path .. "") 41 | info(img) 42 | else 43 | io.stderr:write(path .. ": error ") 44 | local err = upng.get_error(img) 45 | io.stderr:write(enum_value_string(upng.types.error, err)) 46 | end 47 | upng.free(img) 48 | else 49 | io.stderr:write("Cannot open '" .. path .. "'\n") 50 | end 51 | end 52 | 53 | -------------------------------------------------------------------------------- /tools/ninja/libdwarf-bundled.ninja: -------------------------------------------------------------------------------- 1 | libdwarf_version = 20150507 2 | libdwarf_tarball = ${obj}/downloads/libdwarf-${libdwarf_version}.tar.gz 3 | libdwarf_path = ${obj}/libdwarf-${libdwarf_version} 4 | libdwarf_lib = ${libdwarf_path}/libdwarf/libdwarf.a 5 | libdwarf_dep = ${libdwarf_lib} 6 | cppflags = ${cppflags} -I${libdwarf_path}/libdwarf $ 7 | -DEOL_WORKAROUND_DWARF_PUBTYPE_DIE_OFFSET=1 $ 8 | -DEOL_LIBDWARF_BUNDLED=1 9 | 10 | 11 | rule libdwarf_configure 12 | command = cd ${libdwarf_path}/libdwarf $ 13 | && CC='${cc}' CFLAGS='-fPIC' ./configure --disable-shared 14 | description = libdwarf/configure 15 | 16 | rule libdwarf_make 17 | command = make -C ${libdwarf_path}/libdwarf 18 | description = libdwarf/make 19 | 20 | 21 | build ${libdwarf_lib} : libdwarf_make ${libdwarf_path}/libdwarf/Makefile 22 | build ${libdwarf_path}/libdwarf/Makefile $ 23 | ${libdwarf_path}/libdwarf/libdwarf.h $ 24 | : libdwarf_configure || ${libdwarf_path}/libdwarf/configure 25 | 26 | build ${libdwarf_path}/libdwarf/configure $ 27 | ${libdwarf_path}/libdwarf/dwarf.h $ 28 | : untargz ${libdwarf_tarball} 29 | 30 | build ${libdwarf_tarball} : urlfetch 31 | url = https://github.com/Distrotech/libdwarf/archive/${libdwarf_version}.tar.gz 32 | 33 | # A dependency on the libdwarf.h header is needed to force the bundled 34 | # libdwarf to be (at least) configured before building eol-module.o 35 | # 36 | build eol-libdwarf.h : phony | ${libdwarf_path}/libdwarf/libdwarf.h $ 37 | ${libdwarf_path}/libdwarf/dwarf.h 38 | -------------------------------------------------------------------------------- /eol-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-util.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "eol-util.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #if defined(__GLIBC__) && __GLIBC__ >= 2 14 | # ifndef EOL_CHECK_BACKTRACE 15 | # define EOL_CHECK_BACKTRACE 5 16 | # endif /* !EOL_CHECK_BACKTRACE */ 17 | # include 18 | #else 19 | # undef EOL_CHECK_BACKTRACE 20 | #endif /* __GLIBC__ */ 21 | 22 | 23 | void 24 | eol_runtime_check_failed (const char *file, 25 | unsigned line, 26 | const char *func, 27 | const char *fmt, 28 | ...) 29 | { 30 | #ifdef EOL_CHECK_BACKTRACE 31 | void *addresses[EOL_CHECK_BACKTRACE + 1]; 32 | size_t size = backtrace (addresses, LENGTH_OF (addresses)); 33 | char **names = backtrace_symbols (addresses, size); 34 | 35 | fprintf (stderr, "\nSTACK:\n"); 36 | for (size_t i = size; i > 1; i--) 37 | fprintf (stderr, "%2u | %s\n", (unsigned) (i - 2), names[i-1]); 38 | free (names); 39 | #endif /* EOL_CHECK_BACKTRACE */ 40 | 41 | fprintf (stderr, 42 | "\n=== CHECK FAILED === at " 43 | "%s(), %s:%u\n", 44 | func, file, line); 45 | 46 | va_list args; 47 | va_start (args, fmt); 48 | vfprintf (stderr, fmt, args); 49 | va_end (args); 50 | fputc ('\n', stderr); 51 | fflush (stderr); 52 | abort (); 53 | } 54 | 55 | 56 | void 57 | lauto_free (void *ptr) 58 | { 59 | void **location = ptr; 60 | if (*location) { 61 | free (*location); 62 | *location = NULL; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tools/make/lua-bundled.mk: -------------------------------------------------------------------------------- 1 | LUA_VERSION := 5.3.1 2 | LUA_TARBALL := ${OUT}/downloads/lua-${LUA_VERSION}.tar.gz 3 | LUA_SRCPATH := ${OUT}/lua-${LUA_VERSION} 4 | LUA_LIB := ${OUT}/liblua.a 5 | LUA := ${OUT}/lua 6 | CPPFLAGS += -I${LUA_SRCPATH}/src -DEOL_LUA_BUNDLED=1 -DLUA_USE_DLOPEN=1 7 | 8 | 9 | LUA_LIB_SRCS := lapi.c lauxlib.c lbaselib.c lbitlib.c lcode.c lcorolib.c \ 10 | lctype.c ldblib.c ldebug.c ldo.c ldump.c lfunc.c lgc.c \ 11 | linit.c liolib.c llex.c lmathlib.c lmem.c loadlib.c \ 12 | lobject.c lopcodes.c loslib.c lparser.c lstate.c ltm.c \ 13 | lstring.c lstrlib.c ltable.c ltablib.c lundump.c lvm.c \ 14 | lutf8lib.c lzio.c 15 | LUA_LIB_SRCS := $(addprefix ${LUA_SRCPATH}/src/,${LUA_LIB_SRCS}) 16 | LUA_LIB_OBJS := $(patsubst %.c,%.o,${LUA_LIB_SRCS}) 17 | 18 | LUA_SRCS := lua.c 19 | LUA_SRCS := $(addprefix ${LUA_SRCPATH}/src/,${LUA_SRCS}) 20 | LUA_OBJS := $(patsubst %.c,%.o,${LUA_SRCS}) 21 | 22 | LUA_HEADERS := lauxlib.h lualib.h lua.h 23 | LUA_HEADERS := $(addprefix ${LUA_SRCPATH}/src/,${LUA_HEADERS}) 24 | 25 | 26 | ${LUA_LIB}: ${LUA_LIB_OBJS} 27 | ${RUN_STATICLIB} 28 | 29 | ${LUA}: ${LUA_OBJS} ${LUA_LIB} 30 | ${LUA}: LDLIBS += -lm 31 | 32 | ${LUA_TARBALL}: 33 | ${RUN_FETCH_URL} 34 | 35 | ${LUA_TARBALL}: URL = http://www.lua.org/ftp/lua-${LUA_VERSION}.tar.gz 36 | ${LUA_LIB_SRCS} ${LUA_SRCS} ${LUA_HEADERS}: ${LUA_TARBALL} 37 | ${RUN_UNTARGZ} 38 | $Q touch ${LUA_LIB_SRCS} ${LUA_SRCS} 39 | 40 | 41 | eol-lua.h: ${LUA_HEADERS} 42 | 43 | 44 | clean-lua: 45 | $Q ${RM} ${LUA} ${LUA_LIB} ${LUA_LIB_OBJS} ${LUA_OBJS} 46 | 47 | .PHONY: clean-lua 48 | clean: clean-lua 49 | 50 | 51 | distclean-lua: clean-lua 52 | $Q ${RM} -r ${LUA_SRCPATH} 53 | $Q ${RM} ${LUA_TARBALL} 54 | 55 | .PHONY: distclean-lua 56 | distclean: distclean-lua 57 | -------------------------------------------------------------------------------- /examples/nanovg-demo.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- nanovg-demo.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local nvg = require "modularize" { 10 | "nanovg", prefix = "nvg", type_prefix = "NVG" 11 | } 12 | 13 | local W = 800 14 | local H = 600 15 | 16 | local grColor1 = nvg.RGBA(0, 160, 192, 255) 17 | local grColor2 = nvg.RGBA(0, 160, 192, 32) 18 | 19 | local function graph(vg, x, y, w, h, t) 20 | local samples = { 21 | 1 + math.sin(t * 1.23450 + math.cos(t * 0.33457) * 0.44) * 0.5, 22 | 1 + math.sin(t * 0.68363 + math.cos(t * 1.30000) * 1.55) * 0.5, 23 | 1 + math.sin(t * 1.16442 + math.cos(t * 0.33457) * 1.24) * 0.5, 24 | 1 + math.sin(t * 0.56345 + math.cos(t * 1.63000) * 0.14) * 0.5, 25 | 1 + math.sin(t * 1.62450 + math.cos(t * 0.25400) * 0.30) * 0.5, 26 | 1 + math.sin(t * 0.34500 + math.cos(t * 0.03000) * 0.60) * 0.5, 27 | } 28 | 29 | local dx = w / 5.0 30 | local sx = {} 31 | local sy = {} 32 | for i, sample in ipairs(samples) do 33 | sx[i] = x + i * dx 34 | sy[i] = y + h * sample * 0.8 35 | end 36 | 37 | local bg = nvg.LinearGradient(vg, x, y, x, y + h, grColor1, grColor2) 38 | nvg.BeginPath(vg) 39 | nvg.MoveTo(vg, 0, (y + h/2) * 0.75) 40 | for i = 2, #sx do 41 | nvg.BezierTo(vg, sx[i-1] + dx * 0.5, sy[i-1], sx[i] - dx * 0.5, 42 | sy[i], sx[i], sy[i]) 43 | end 44 | nvg.LineTo(vg, x + w, y + h) 45 | nvg.LineTo(vg, x, y + h) 46 | nvg.FillPaint(vg, bg) 47 | nvg.Fill(vg) 48 | end 49 | 50 | local window = nvg.Window("Lua + Eol + NanoVG", W, H) 51 | nvg.MakeCurrent(window) 52 | 53 | local vg = nvg.Create(true) 54 | 55 | while not nvg.Done(window) do 56 | nvg.FrameStart(window, vg) 57 | graph(vg, 0, H/2, W, H/2, nvg.Time()) 58 | graph(vg, 0, 0, W, H, nvg.Time()+5) 59 | graph(vg, 0, -H, W, H*4, nvg.Time()+1.618) 60 | nvg.FrameEnd(window, vg) 61 | end 62 | nvg.Exit() 63 | -------------------------------------------------------------------------------- /tools/make/libdwarf-bundled.mk: -------------------------------------------------------------------------------- 1 | LIBDWARF_VERSION := 20150507 2 | LIBDWARF_TARBALL := ${OUT}/downloads/libdwarf-${LIBDWARF_VERSION}.tar.gz 3 | LIBDWARF_SRCPATH := ${OUT}/libdwarf-${LIBDWARF_VERSION} 4 | LIBDWARF := ${LIBDWARF_SRCPATH}/libdwarf/libdwarf.a 5 | LIBDWARF_LDLIBS := -lelf 6 | CPPFLAGS += -I${LIBDWARF_SRCPATH}/libdwarf \ 7 | -DEOL_WORKAROUND_DWARF_PUBTYPE_DIE_OFFSET=1 \ 8 | -DEOL_LIBDWARF_BUNDLED=1 9 | 10 | ${LIBDWARF}: ${LIBDWARF_SRCPATH}/libdwarf/Makefile 11 | $Q ${MAKE} -s -C $(dir $<) 12 | $Q touch $@ 13 | 14 | ${LIBDWARF_SRCPATH}/libdwarf/Makefile \ 15 | ${LIBDWARF_SRCPATH}/libdwarf/libdwarf.h: ${LIBDWARF_SRCPATH}/libdwarf/configure 16 | $Q cd ${LIBDWARF_SRCPATH}/libdwarf && \ 17 | CC='${CC}' CFLAGS='-fPIC' ./configure --disable-shared 18 | 19 | ${LIBDWARF_SRCPATH}/libdwarf/configure \ 20 | ${LIBDWARF_SRCPATH}/libdwarf/dwarf.h: ${LIBDWARF_TARBALL} 21 | ${RUN_UNTARGZ} 22 | $Q touch ${LIBDWARF_SRCPATH}/libdwarf/configure \ 23 | ${LIBDWARF_SRCPATH}/libdwarf/dwarf.h 24 | 25 | .NOTPARALLEL: ${LIBDWARF_SRCPATH}/libdwarf/configure \ 26 | ${LIBDWARF_SRCPATH}/libdwarf/dwarf.h \ 27 | ${LIBDWARF_SRCPATH}/libdwarf/Makefile \ 28 | ${LIBDWARF_SRCPATH}/libdwarf/libdwarf.h 29 | 30 | ${LIBDWARF_TARBALL}: URL = https://github.com/Distrotech/libdwarf/archive/${LIBDWARF_VERSION}.tar.gz 31 | ${LIBDWARF_TARBALL}: 32 | ${RUN_FETCH_URL} 33 | 34 | eol-libdwarf.h: ${LIBDWARF_SRCPATH}/libdwarf/libdwarf.h \ 35 | ${LIBDWARF_SRCPATH}/libdwarf/dwarf.h 36 | 37 | libdwarf-clean: ${LIBDWARF_SRCPATH}/libdwarf/Makefile 38 | $Q ${MAKE} -s -C ${LIBDWARF_SRCPATH}/libdwarf clean 39 | 40 | .PHONY: libdwarf-clean 41 | clean: libdwarf-clean 42 | 43 | 44 | libdwarf-distclean: ${LIBDWARF_SRCPATH}/libdwarf/Makefile 45 | $Q ${RM} -r ${LIBDWARF_SRCPATH} 46 | $Q ${RM} ${LIBDWARF_TARBALL} 47 | 48 | .PHONY: libdwarf-distclean 49 | clean: libdwarf-distclean 50 | -------------------------------------------------------------------------------- /examples/modularize.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- modularize.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local eol = require("eol") 10 | local eol_load = eol.load 11 | local eol_type = eol.type 12 | local _setmetatable = setmetatable 13 | local _rawget = rawget 14 | local _rawset = rawset 15 | local _type = type 16 | 17 | -- 18 | -- Makes functions and types available (and memoized) in a table, 19 | -- Prefixes are added automatically when looking up items from the 20 | -- library, and different prefixes can be specified for functions 21 | -- and types. 22 | -- 23 | -- Usage example: 24 | -- 25 | -- png = require "modularize" { 26 | -- "libpng", prefix = "png_", type_prefix = "png_" 27 | -- } 28 | -- 29 | -- color = png.types.color_8() 30 | -- color.red = 255 31 | -- color.green = 127 32 | -- 33 | -- print(png.get_header_ver(nil)) 34 | -- 35 | local function modularize(lib) 36 | local type_prefix 37 | local func_prefix 38 | local library_name 39 | 40 | if _type(lib) == "table" then 41 | library_name = lib.library or lib[1] 42 | func_prefix = lib.function_prefix or lib.prefix or "" 43 | type_prefix = lib.type_prefix or lib.prefix or "" 44 | else 45 | library_name = lib 46 | func_prefix = "" 47 | type_prefix = "" 48 | end 49 | 50 | local library = eol_load(library_name) 51 | 52 | return _setmetatable({ __library = library, 53 | types = _setmetatable({ __library = library }, { 54 | __index = function (self, key) 55 | local t = _rawget(self, key) 56 | if t == nil then 57 | t = eol_type(library, type_prefix .. key) 58 | _rawset(self, key, t or false) 59 | end 60 | return t 61 | end, 62 | }), 63 | }, { 64 | __index = function (self, key) 65 | local f = _rawget(self, key) 66 | if f == nil then 67 | f = library[func_prefix .. key] 68 | _rawset(self, key, f or false) 69 | end 70 | return f 71 | end, 72 | }); 73 | end 74 | 75 | return modularize 76 | -------------------------------------------------------------------------------- /eol-typecache.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-typecache.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "eol-typecache.h" 9 | #include "eol-util.h" 10 | #include "uthash.h" 11 | 12 | 13 | typedef struct _EolTypeCacheEntry EolTypeCacheEntry; 14 | 15 | struct _EolTypeCacheEntry { 16 | uint32_t offset; 17 | const EolTypeInfo *typeinfo; 18 | UT_hash_handle hh; 19 | }; 20 | 21 | 22 | void 23 | eol_type_cache_init (EolTypeCache *cache) 24 | { 25 | CHECK_NOT_NULL (cache); 26 | *cache = NULL; 27 | } 28 | 29 | 30 | void 31 | eol_type_cache_free (EolTypeCache *cache) 32 | { 33 | CHECK_NOT_NULL (cache); 34 | 35 | EolTypeCacheEntry *entry, *tmp; 36 | HASH_ITER (hh, *cache, entry, tmp) { 37 | /* XXX: This leaks the EolTypeInfo. */ 38 | HASH_DEL (*cache, entry); 39 | free (entry); 40 | } 41 | } 42 | 43 | 44 | 45 | const EolTypeInfo* 46 | eol_type_cache_lookup (EolTypeCache *cache, 47 | uint32_t offset) 48 | { 49 | CHECK_NOT_NULL (cache); 50 | 51 | EolTypeCacheEntry *entry; 52 | HASH_FIND_INT (*cache, &offset, entry); 53 | return entry ? entry->typeinfo : NULL; 54 | } 55 | 56 | 57 | void 58 | eol_type_cache_add (EolTypeCache *cache, 59 | uint32_t offset, 60 | const EolTypeInfo *typeinfo) 61 | { 62 | CHECK_NOT_NULL (cache); 63 | CHECK_NOT_NULL (typeinfo); 64 | 65 | EolTypeCacheEntry *entry = malloc (sizeof (EolTypeCacheEntry)); 66 | entry->offset = offset; 67 | entry->typeinfo = typeinfo; 68 | 69 | HASH_ADD_INT (*cache, offset, entry); 70 | } 71 | 72 | 73 | void 74 | eol_type_cache_foreach (EolTypeCache *cache, 75 | EolTypeCacheIter callback, 76 | void *userdata) 77 | { 78 | CHECK_NOT_NULL (cache); 79 | CHECK_NOT_NULL (callback); 80 | 81 | EolTypeCacheEntry *entry, *tmp; 82 | HASH_ITER (hh, *cache, entry, tmp) { 83 | if (!(*callback) (cache, entry->typeinfo, userdata)) 84 | break; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /libtest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libtest.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include 9 | 10 | /* Simple integer variable, and a pointer to it. */ 11 | int intvar = 42; 12 | int *intptrvar = &intvar; 13 | int intarray[] = { 1, 2, 3, 4, 5 }; 14 | void *voidptr = &intarray[2]; 15 | 16 | /* Standard C99 integral typedefs. */ 17 | int8_t var_i8 = -8; 18 | uint8_t var_u8 = 8; 19 | int16_t var_i16 = -16; 20 | uint16_t var_u16 = 16; 21 | int32_t var_i32 = -32; 22 | uint32_t var_u32 = 32; 23 | int64_t var_i64 = -64; 24 | uint64_t var_u64 = 64; 25 | 26 | /* Floating point numbers. */ 27 | float var_flt = 1.0; 28 | double var_dbl = 1.0; 29 | 30 | /* Constant declaration. */ 31 | const int const_int = 42; 32 | 33 | /* Anynymous structure. */ 34 | struct { 35 | int member; 36 | } anon_struct = { 37 | .member = 121, 38 | }; 39 | 40 | /* Previously defined structure. */ 41 | struct Point { 42 | int x; 43 | int y; 44 | }; 45 | 46 | struct Point origin = { .x = 0, .y = 0 }; 47 | 48 | /* Structure typedef. */ 49 | typedef struct Point Point; 50 | Point max_pos = { .x = 800, .y = 600 }; 51 | 52 | typedef struct { 53 | Point tl; 54 | Point br; 55 | } Square; 56 | 57 | Square screen = { 58 | .tl.x = 10, .tl.y = 20, 59 | .br.x = 50, .br.y = 80, 60 | }; 61 | 62 | typedef struct { 63 | int tangential; 64 | Point points[4]; 65 | } Bezier; 66 | 67 | Bezier curve = { 68 | 0, 69 | { { 1, 2 }, 70 | { 3, 4 }, 71 | { 5, 6 }, 72 | { 1, 1 } } 73 | }; 74 | 75 | Point triangle[] = { 76 | { 1, 1 }, 77 | { 2, 3 }, 78 | { 1, 3 }, 79 | }; 80 | 81 | 82 | enum Continent { 83 | AFRICA, 84 | EUROPE, 85 | ASIA, 86 | AMERICA, 87 | ANTARCTICA, 88 | AUSTRALIA, 89 | }; 90 | 91 | enum Continent location = EUROPE; 92 | 93 | 94 | static int 95 | private_add (int a, int b) 96 | { 97 | return a + b; 98 | } 99 | 100 | 101 | int 102 | add (int a, int b) 103 | { 104 | return private_add (a, b); 105 | } 106 | 107 | 108 | int 109 | get_intvar (void) 110 | { 111 | return intvar; 112 | } 113 | -------------------------------------------------------------------------------- /dynasm/dasm_proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM encoding engine prototypes. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT 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 | -------------------------------------------------------------------------------- /eol-trace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-trace.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_TRACE_H 9 | #define EOL_TRACE_H 10 | 11 | #include 12 | 13 | #if defined(EOL_TRACE) && EOL_TRACE > 0 14 | # undef EOL_TRACE 15 | # define EOL_TRACE 1 16 | 17 | # define TRACE(...) \ 18 | do { \ 19 | if (eol_trace_enabled) \ 20 | eol_trace (__FILE__, __LINE__, __func__, __VA_ARGS__); \ 21 | } while (0) 22 | 23 | extern void eol_trace (const char* file, 24 | unsigned line, 25 | const char* func, 26 | const char* fmt, 27 | ...); 28 | 29 | /* 30 | * Reads the EOL_TRACE environment variable and, if present, configures the 31 | * tracing mechanism according to its value. The value of the variable must 32 | * be a sequence of characters, which enable printing of different items 33 | * along with each message passed to the TRACE() macro: 34 | * 35 | * 'S' - source file name. 36 | * 'L' - line in source file. 37 | * 'F' - function name. 38 | * 'A' - all of the above. 39 | * 40 | * The lowercase counterparts disable printing of the corresponding item. 41 | * Characters other than the above (either upper- or lowercase) are ignored. 42 | * 43 | * Also, if the '>' or ':' characters are found, the rest of the value of the 44 | * EOL_TRACE environment variable is taken as the name of a file to open for 45 | * writing (when using ':'), or appending messages (when using '>'). 46 | */ 47 | extern void eol_trace_setup (void); 48 | 49 | extern bool eol_trace_enabled; 50 | 51 | #else 52 | # undef EOL_TRACE 53 | # define EOL_TRACE 0 54 | # define eol_trace_setup( ) ((void)0) 55 | # define TRACE(...) ((void)0) 56 | #endif /* EOL_TRACE */ 57 | 58 | #define NORMAL "" 59 | #define WHITE "" 60 | 61 | #define RED "" 62 | #define GREEN "" 63 | #define BROWN "" 64 | #define FBLUE "" 65 | #define MAGENTA "" 66 | #define CYAN "" 67 | #define GREY "" 68 | 69 | #define BRED "" 70 | #define BGREEN "" 71 | #define YELLOW "" 72 | #define BLUE "" 73 | #define PINK "" 74 | #define BCYAN "" 75 | 76 | #define TODO "TODO: " 77 | 78 | #define TRACE_PTR(hint, t, ptr, fmt, ...) \ 79 | TRACE (">" #hint CYAN " " #t GREEN " %p" NORMAL fmt, (ptr), ##__VA_ARGS__) 80 | 81 | #endif /* !EOL_TRACE_H */ 82 | -------------------------------------------------------------------------------- /examples/imgui-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imgui-util.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | static void 14 | printGlfwError (int error, const char *desc) 15 | { 16 | fprintf (stderr, "GLFW error %d: %s\n", error, desc); 17 | fflush (stderr); 18 | } 19 | 20 | 21 | static void 22 | keyCallback (GLFWwindow *window, int key, int scancode, int action, int mods) 23 | { 24 | if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 25 | glfwSetWindowShouldClose (window, GL_TRUE); 26 | } 27 | 28 | 29 | GLFWwindow* 30 | igTopLevel (const char *window_name, 31 | unsigned window_width, 32 | unsigned window_height) 33 | { 34 | static bool initialized = false; 35 | if (!initialized) { 36 | if (!glfwInit()) 37 | return NULL; 38 | glfwSetErrorCallback (printGlfwError); 39 | glfwWindowHint (GLFW_CLIENT_API, GLFW_OPENGL_ES_API); 40 | glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 2); 41 | glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 0); 42 | initialized = true; 43 | } 44 | 45 | GLFWwindow *w = glfwCreateWindow (window_width, 46 | window_height, 47 | window_name, 48 | NULL, 49 | NULL); 50 | if (w) { 51 | glfwSetKeyCallback (w, keyCallback); 52 | } 53 | 54 | return w; 55 | } 56 | 57 | 58 | void 59 | igMakeCurrent (GLFWwindow *window) 60 | { 61 | glfwMakeContextCurrent (window); 62 | glfwSwapInterval (0); 63 | } 64 | 65 | 66 | float 67 | igTime (void) 68 | { 69 | return glfwGetTime (); 70 | } 71 | 72 | 73 | void 74 | igFrameStart (GLFWwindow *window) 75 | { 76 | int winWidth, winHeight, fbWidth, fbHeight; 77 | glfwGetWindowSize (window, &winWidth, &winHeight); 78 | glfwGetFramebufferSize (window, &fbWidth, &fbHeight); 79 | glViewport (0, 0, fbWidth, fbHeight); 80 | glClearColor(0, 0, 0, 0); 81 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 82 | glEnable(GL_BLEND); 83 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 84 | glEnable(GL_CULL_FACE); 85 | glDisable(GL_DEPTH_TEST); 86 | } 87 | 88 | 89 | void 90 | igFrameEnd (GLFWwindow *window) 91 | { 92 | glfwSwapBuffers (window); 93 | glfwPollEvents (); 94 | } 95 | 96 | 97 | bool 98 | igDone (GLFWwindow *window) 99 | { 100 | return !!glfwWindowShouldClose (window); 101 | } 102 | 103 | 104 | void 105 | igExit (void) 106 | { 107 | glfwTerminate (); 108 | } 109 | -------------------------------------------------------------------------------- /examples/build.ninja: -------------------------------------------------------------------------------- 1 | # This "modularize" module is used by some of the other examples. 2 | # Provide a link to it in the build output directory. 3 | rule hardlink 4 | command = ln -T ${in} ${out} 5 | description = ln ${in} -> ${out} 6 | 7 | build ${obj}/modularize.lua : hardlink examples/modularize.lua 8 | 9 | # NanoVG module. 10 | build ${obj}/nanovg.o : cc examples/nanovg/src/nanovg.c 11 | build ${obj}/nanovg-utils.o : cc examples/nanovg-utils.c 12 | build ${obj}/nanovg.so : ld ${obj}/nanovg.o ${obj}/nanovg-utils.o 13 | ldflags = ${ldflags} -shared 14 | libs = -lGLESv2 -lglfw 15 | 16 | # uPNG module. 17 | build ${obj}/upng.o : cc examples/upng/upng.c 18 | build ${obj}/upng.so : ld ${obj}/upng.o 19 | ldflags = ${ldflags} -shared 20 | 21 | # ImGUI module. 22 | build ${obj}/imgui-cimgui.o : cxx examples/cimgui/cimgui/cimgui.cpp 23 | build ${obj}/imgui-fontAtlas.o : cxx examples/cimgui/cimgui/fontAtlas.cpp 24 | build ${obj}/imgui-drawList.o : cxx examples/cimgui/cimgui/drawList.cpp 25 | build ${obj}/imgui-draw.o : cxx examples/cimgui/imgui/imgui_draw.cpp 26 | build ${obj}/imgui-demo.o : cxx examples/cimgui/imgui/imgui_demo.cpp 27 | build ${obj}/imgui.o : cxx examples/cimgui/imgui/imgui.cpp 28 | build ${obj}/imgui-util.o : cc examples/imgui-util.c 29 | build ${obj}/imgui.so : ld $ 30 | ${obj}/imgui-cimgui.o $ 31 | ${obj}/imgui-fontAtlas.o $ 32 | ${obj}/imgui-drawList.o $ 33 | ${obj}/imgui-draw.o $ 34 | ${obj}/imgui-demo.o $ 35 | ${obj}/imgui.o $ 36 | ${obj}/imgui-util.o 37 | ldflags = ${ldflags} -shared 38 | libs = -lGLESv2 -lglfw -lstdc++ 39 | 40 | # Makes a wrapper shell script which changes to the output directory 41 | # and runs Lua in there passing the wrapped script. This makes the 42 | # examples easier to run. 43 | rule wrap 44 | command = ./tools/make-example-wrapper-script ${lua_exe} ${in} ${obj} ${out} 45 | description = wrap-example ${in} 46 | 47 | build ${obj}/examples/type-pp : wrap examples/type-pp.lua 48 | build ${obj}/examples/nanovg-demo : wrap examples/nanovg-demo.lua 49 | build ${obj}/examples/nanovg-noise : wrap examples/nanovg-noise.lua 50 | build ${obj}/examples/upng-info : wrap examples/upng-info.lua 51 | 52 | build examples-wrapper-c : phony $ 53 | ${obj}/examples/type-pp $ 54 | ${obj}/examples/upng-info $ 55 | ${obj}/examples/nanovg-demo $ 56 | ${obj}/examples/nanovg-noise 57 | 58 | build examples-c : phony $ 59 | examples-wrapper-c $ 60 | ${obj}/nanovg.so $ 61 | ${obj}/upng.so $ 62 | ${obj}/modularize.lua 63 | 64 | 65 | build ${obj}/examples/ui : wrap examples/ui.lua 66 | 67 | build examples-wrapper-cxx : phony $ 68 | ${obj}/examples/ui 69 | 70 | build examples-cxx : phony $ 71 | examples-wrapper-cxx $ 72 | ${obj}/imgui.so $ 73 | ${obj}/modularize.lua 74 | 75 | 76 | build examples : phony examples-c examples-cxx 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Eöl - Fully automatic Lua↔C bridge using DWARF 2 | ============================================== 3 | 4 | Eöl (ELF Object Loader) ris is a fully automatic, run-time, fast foreign 5 | function interface for native C libraries. It allows using existing 6 | libraries directly from [Lua](http://www.lua.org). Eöl uses the 7 | [DWARF](http://dwarfstd.org/) debugging information generated by C 8 | compilers. 9 | 10 | Eöl is licensed under a [MIT-style](http://www.opensource.org/licenses/mit-license.php) 11 | license, see `LICENSE` for the full text. 12 | 13 | Change of name 14 | -------------- 15 | 16 | Eöl used to be called Eris, but the name was already used for the [Eris 17 | persistence system](http://permalink.gmane.org/gmane.comp.lang.lua.general/118048) 18 | for Lua. The change of name was done on 2015-08-01 to avoid module name clashes. 19 | 20 | 21 | Compatibility 22 | ------------- 23 | 24 | Eöl is tested and compatible with: 25 | 26 | * Lua 5.3.1 27 | * Lua 5.3.0 28 | 29 | 30 | Building 31 | -------- 32 | 33 | Building Eöl requires the following dependencies: 34 | 35 | * A reasonable POSIX-ish operating system. Development is done using 36 | GNU/Linux, other systems might work (YMMV). 37 | * `libdwarf`, version `20140805` (or newer). 38 | * `libelf`, version `0.161` (or newer). 39 | * [Ninja](http://martine.github.com/ninja/) (preferred), or GNU Make. 40 | * *(Optional)* GNU `readline`. 41 | 42 | Though GNU Auto*foo* is not used, care has been taken in following its 43 | conventions, so in order to build Eöl the following will work: 44 | 45 | ```sh 46 | ./configure 47 | make 48 | ``` 49 | 50 | Or, using Ninja to do the build (preferred): 51 | 52 | ```sh 53 | ./configure 54 | ninja 55 | ``` 56 | 57 | Once building has finished, it is possible to check that everything 58 | is working fine by running the test suite: 59 | 60 | ```sh 61 | ./run-tests 62 | ``` 63 | 64 | 65 | Usage 66 | ----- 67 | 68 | Once built, the `eol` module can be used from Lua: 69 | 70 | ```lua 71 | -- Find and load the readline library from the standard system directories. 72 | local libreadline = require("eol").load("libreadline") 73 | 74 | -- Obtain a handle to the readline() function, which allows calling it. 75 | local readline = libreadline.readline 76 | 77 | -- Read a line from standard input using readline() and echo it back. 78 | print(readline("input: ")) 79 | ``` 80 | 81 | For more examples, check the the `samples/` subdirectory. Documentation 82 | is available under the `doc/` subdirectory. Run your favourite Markdown 83 | processor on it to read the documentation in HTML. 84 | 85 | 86 | Examples 87 | -------- 88 | 89 | Usage examples can be found in the `examples/` subdirectory. 90 | 91 | Some of the examples use third-party code, which needs to be built 92 | from sources. The needed sources are referenced from the repository as Git 93 | submodules, and the exact needed version will be fetched automatically. 94 | Note that the examples can only be built with Ninja at the moment: 95 | 96 | ```sh 97 | git submodule update --recursive --init 98 | ninja examples 99 | ``` 100 | 101 | Additional dependencies for the examples: 102 | 103 | * OpenGL ES 2 (`libGLESv2` from Mesa will do). 104 | * GLFW3 105 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # Adrian Perez, 2015-04-17 10:59 4 | # 5 | 6 | # Handle V=(0|1) in the command line. This must be the first thing done! 7 | __verbose := 0 8 | ifeq ($(origin V),command line) 9 | ifneq ($(strip $V),0) 10 | __verbose := 1 11 | endif 12 | endif 13 | 14 | P := @: 15 | Q := 16 | ifeq (${__verbose},0) 17 | ifneq (${MAKE_TERMOUT},) 18 | P := @printf '%s %s ' 19 | Q := @ 20 | endif 21 | endif 22 | 23 | 24 | -include build.conf 25 | 26 | OUT := ${obj} 27 | PREFIX = ${prefix} 28 | LDLIBS = ${libs} 29 | CC = ${cc} 30 | LDFLAGS += -fPIC -Wl,-E -Wl,--as-needed 31 | 32 | 33 | define RUN_FETCH_URL 34 | $P Fetch ${URL} 35 | $Q mkdir -p $(dir $@) 36 | $Q curl -s -L -R -o '$@' '${URL}' 37 | endef 38 | 39 | define RUN_UNTARGZ 40 | $P UnTarGz $< 41 | $Q mkdir -p ${OUT} 42 | $Q tar -xzf $< -C ${OUT} 43 | endef 44 | 45 | define RUN_STATICLIB 46 | $P StaticLib $@ 47 | $Q mkdir -p $(dir $@) 48 | $Q ar cr $@ $^ 49 | endef 50 | 51 | # We want -Wall *before* the other CFLAGS, so we have to force its 52 | # expansion and then re-assign to the variable. 53 | EXPAND_CFLAGS := -fPIC -std=gnu99 -Wall ${CFLAGS} 54 | CFLAGS = ${EXPAND_CFLAGS} 55 | 56 | all: 57 | clean: 58 | distclean: clean 59 | .PHONY: distclean 60 | 61 | include tools/make/lua-${lua_build}.mk 62 | include tools/make/libdwarf-${libdwarf_build}.mk 63 | include tools/make/dynasm-${jit_arch}.mk 64 | 65 | # EOL module sources. 66 | EOL_MODULE_SRCS := eol-module.c eol-trace.c eol-util.c eol-typing.c \ 67 | eol-typecache.c eol-libdwarf.c 68 | EOL_MODULE_OBJS := $(patsubst %.c,${OUT}/%.o,${EOL_MODULE_SRCS}) 69 | 70 | # Testutil module source. 71 | TESTUTIL_MODULE_SRCS := tools/harness-testutil.c 72 | TESTUTIL_MODULE_OBJS := $(patsubst %.c,${OUT}/%.o,${TESTUTIL_MODULE_SRCS}) 73 | 74 | %.inc: %.gperf 75 | $P gperf $< 76 | $Q gperf -o $@ $< 77 | 78 | ${OUT}/%.o: ${OUT}/%.c 79 | $P Compile $@ 80 | $Q mkdir -p $(dir $@) 81 | $Q ${CC} ${CFLAGS} ${CPPFLAGS} -c -o $@ $< 82 | 83 | ${OUT}/%.o: %.c 84 | $P Compile $@ 85 | $Q mkdir -p $(dir $@) 86 | $Q ${CC} ${CFLAGS} ${CPPFLAGS} -c -o $@ $< 87 | 88 | ${OUT}/%: 89 | $P Link $@ 90 | $Q mkdir -p $(dir $@) 91 | $Q ${CC} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDLIBS} 92 | 93 | 94 | all: ${LUA} \ 95 | ${OUT}/eol.so \ 96 | ${OUT}/testutil.so \ 97 | ${OUT}/libtest2.so \ 98 | ${OUT}/libtest.so 99 | $(if ${MAKE_TERMOUT},$Q echo) 100 | 101 | clean: 102 | $Q ${RM} ${OUT}/lua ${LUA_OBJS} 103 | $Q ${RM} ${OUT}/eol.so ${EOL_MODULE_OBJS} 104 | $Q ${RM} ${OUT}/testutil.so ${TESTUTIL_MODULE_OBJS} 105 | $Q ${RM} ${OUT}/libtest.so ${OUT}/libtest.o 106 | $Q ${RM} ${OUT}/libtest2.so ${OUT}/libtest2.o 107 | 108 | eol-module.c: eol-lua.h eol-libdwarf.h specials.inc eol-fcall-${eol_fcall}.c 109 | tools/harness-testutil.c: eol-lua.h 110 | 111 | ${OUT}/eol.so: ${EOL_MODULE_OBJS} ${LIBDWARF} 112 | ${OUT}/eol.so: LDFLAGS += -shared 113 | ${OUT}/eol.so: LDLIBS += ${LIBDWARF_LDLIBS} 114 | 115 | ${OUT}/testutil.so: ${TESTUTIL_MODULE_OBJS} 116 | ${OUT}/testutil.so: LDFLAGS += -shared 117 | 118 | ${OUT}/libtest.so: ${OUT}/libtest.o 119 | ${OUT}/libtest.so: LDFLAGS += -shared 120 | 121 | ${OUT}/libtest2.so: ${OUT}/libtest2.o 122 | ${OUT}/libtest2.so: LDFLAGS += -shared 123 | 124 | build.conf: configure 125 | ./configure 126 | -------------------------------------------------------------------------------- /examples/nanovg-utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nanovg-utils.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #define GLFW_INCLUDE_ES2 9 | #include 10 | #include "nanovg/src/nanovg.h" 11 | 12 | #define NANOVG_GLES2_IMPLEMENTATION 13 | #include "nanovg/src/nanovg_gl.h" 14 | #include "nanovg/src/nanovg_gl_utils.h" 15 | 16 | #include 17 | 18 | 19 | static void 20 | printGlfwError (int error, const char *desc) 21 | { 22 | fprintf (stderr, "GLFW error %d: %s\n", error, desc); 23 | fflush (stderr); 24 | } 25 | 26 | 27 | static void 28 | keyCallback (GLFWwindow *window, int key, int scancode, int action, int mods) 29 | { 30 | if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 31 | glfwSetWindowShouldClose (window, GL_TRUE); 32 | } 33 | 34 | 35 | GLFWwindow* 36 | nvgWindow (const char *window_name, 37 | unsigned window_width, 38 | unsigned window_height) 39 | { 40 | static bool initialized = false; 41 | if (!initialized) { 42 | if (!glfwInit()) 43 | return NULL; 44 | glfwSetErrorCallback (printGlfwError); 45 | glfwWindowHint (GLFW_CLIENT_API, GLFW_OPENGL_ES_API); 46 | glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 2); 47 | glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 0); 48 | initialized = true; 49 | } 50 | 51 | GLFWwindow *w = glfwCreateWindow (window_width, 52 | window_height, 53 | window_name, 54 | NULL, 55 | NULL); 56 | if (w) { 57 | glfwSetKeyCallback (w, keyCallback); 58 | } 59 | 60 | return w; 61 | } 62 | 63 | 64 | void 65 | nvgMakeCurrent (GLFWwindow *window) 66 | { 67 | glfwMakeContextCurrent (window); 68 | glfwSwapInterval (0); 69 | } 70 | 71 | 72 | float 73 | nvgTime (void) 74 | { 75 | return glfwGetTime (); 76 | } 77 | 78 | 79 | void 80 | nvgFrameStart (GLFWwindow *window, NVGcontext *vg) 81 | { 82 | int winWidth, winHeight, fbWidth, fbHeight; 83 | glfwGetWindowSize (window, &winWidth, &winHeight); 84 | glfwGetFramebufferSize (window, &fbWidth, &fbHeight); 85 | glViewport (0, 0, fbWidth, fbHeight); 86 | glClearColor(0, 0, 0, 0); 87 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 88 | glEnable(GL_BLEND); 89 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 90 | glEnable(GL_CULL_FACE); 91 | glDisable(GL_DEPTH_TEST); 92 | nvgBeginFrame (vg, winWidth, winHeight, (float) fbWidth / (float) winWidth); 93 | } 94 | 95 | 96 | NVGcontext* 97 | nvgCreate (bool debug) 98 | { 99 | return nvgCreateGLES2 (NVG_ANTIALIAS | NVG_STENCIL_STROKES | 100 | (debug ? NVG_DEBUG : 0)); 101 | } 102 | 103 | 104 | void 105 | nvgDelete (NVGcontext *vg) 106 | { 107 | nvgDeleteGLES2 (vg); 108 | } 109 | 110 | 111 | void 112 | nvgFrameEnd (GLFWwindow *window, NVGcontext *vg) 113 | { 114 | nvgEndFrame (vg); 115 | glfwSwapBuffers (window); 116 | glfwPollEvents (); 117 | } 118 | 119 | 120 | bool 121 | nvgDone (GLFWwindow *window) 122 | { 123 | return !!glfwWindowShouldClose (window); 124 | } 125 | 126 | 127 | void 128 | nvgExit (void) 129 | { 130 | glfwTerminate (); 131 | } 132 | -------------------------------------------------------------------------------- /tools/harness-testutil.c: -------------------------------------------------------------------------------- 1 | /* 2 | * harness-testutil.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "../eol-lua.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | static int 23 | testutil_isatty (lua_State *L) 24 | { 25 | luaL_Stream *f = (luaL_Stream*) luaL_checkudata (L, 1, LUA_FILEHANDLE); 26 | lua_pushboolean (L, isatty (fileno (f->f))); 27 | return 1; 28 | } 29 | 30 | 31 | static int 32 | testutil_listdir (lua_State *L) 33 | { 34 | const char *path = luaL_checkstring (L, 1); 35 | DIR *d = opendir (path); 36 | if (d == NULL) { 37 | return luaL_error (L, "%s: %s", path, strerror (errno)); 38 | } 39 | 40 | int index = 0; 41 | struct dirent *de = NULL; 42 | 43 | lua_newtable (L); /* Stack: Table */ 44 | while ((de = readdir (d)) != NULL) { 45 | /* Skip "." and ".." entries. */ 46 | if (de->d_name[0] == '.' && 47 | (de->d_name[1] == '\0' || 48 | (de->d_name[1] == '.' && de->d_name[2] == '\0'))) { 49 | continue; 50 | } 51 | lua_pushstring (L, de->d_name); /* Stack: Table Filename */ 52 | lua_rawseti (L, -2, ++index); /* Stack: Table */ 53 | } 54 | closedir (d); 55 | 56 | return 1; 57 | } 58 | 59 | 60 | static int 61 | testutil_realpath (lua_State *L) 62 | { 63 | const char *path = luaL_checkstring (L, 1); 64 | char buffer[PATH_MAX]; 65 | if (realpath (path, buffer) == NULL) { 66 | return luaL_error (L, "%s: %s", path, strerror (errno)); 67 | } 68 | lua_pushstring (L, buffer); 69 | return 1; 70 | } 71 | 72 | 73 | static int 74 | testutil_isfile (lua_State *L) 75 | { 76 | struct stat sb; 77 | const char *path = luaL_checkstring (L, 1); 78 | if (stat (path, &sb) == 0) { 79 | lua_pushboolean (L, S_ISREG (sb.st_mode)); 80 | } else if (errno == ENOENT || errno == ENOTDIR) { 81 | lua_pushboolean (L, false); 82 | } else { 83 | return luaL_error (L, "%s: %s", path, strerror (errno)); 84 | } 85 | return 1; 86 | } 87 | 88 | 89 | static int 90 | testutil_isdir (lua_State *L) 91 | { 92 | struct stat sb; 93 | const char *path = luaL_checkstring (L, 1); 94 | if (stat (path, &sb) == 0) { 95 | lua_pushboolean (L, S_ISDIR (sb.st_mode)); 96 | } else if (errno == ENOENT || errno == ENOTDIR) { 97 | lua_pushboolean (L, false); 98 | } else { 99 | return luaL_error (L, "%s: %s", path, strerror (errno)); 100 | } 101 | return 1; 102 | } 103 | 104 | 105 | static int 106 | testutil_getcwd (lua_State *L) 107 | { 108 | char path[PATH_MAX]; 109 | if (getcwd (path, PATH_MAX) == NULL) 110 | return luaL_error (L, "getcwd(): %s", strerror (errno)); 111 | lua_pushstring (L, path); 112 | return 1; 113 | } 114 | 115 | 116 | static const luaL_Reg testutillib[] = { 117 | { "isatty", testutil_isatty }, 118 | { "listdir", testutil_listdir }, 119 | { "realpath", testutil_realpath }, 120 | { "isfile", testutil_isfile }, 121 | { "isdir", testutil_isdir }, 122 | { "getcwd", testutil_getcwd }, 123 | { NULL, NULL } 124 | }; 125 | 126 | 127 | LUAMOD_API int 128 | luaopen_testutil (lua_State *L) 129 | { 130 | luaL_newlib (L, testutillib); 131 | return 1; 132 | } 133 | -------------------------------------------------------------------------------- /eol-trace.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-trace.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "eol-trace.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #undef eol_trace_setup 17 | 18 | 19 | enum { 20 | TRACE_NONE = 0, 21 | TRACE_FILE = (1 << 1), 22 | TRACE_LINE = (1 << 2), 23 | TRACE_FUNC = (1 << 3), 24 | TRACE_ALL = (TRACE_FILE | TRACE_LINE | TRACE_FUNC) 25 | }; 26 | 27 | 28 | /* 29 | * These values are configured by eol_trace_setup(). 30 | */ 31 | bool eol_trace_enabled = false; 32 | static FILE* trace_output = NULL; 33 | static unsigned trace_items = TRACE_NONE; 34 | 35 | 36 | void 37 | eol_trace (const char *file, 38 | unsigned line, 39 | const char* func, 40 | const char* fmt, 41 | ...) 42 | { 43 | if (*fmt == '>') { 44 | fmt++; 45 | } else { 46 | bool insert_space = false; 47 | if (trace_items & TRACE_FILE) { 48 | fprintf (trace_output, "%s:", file); 49 | insert_space = true; 50 | } 51 | if (trace_items & TRACE_FUNC) { 52 | fprintf (trace_output, "%s:", func); 53 | insert_space = true; 54 | } 55 | if (trace_items & TRACE_LINE) { 56 | fprintf (trace_output, "%u:", line); 57 | insert_space = true; 58 | } 59 | if (insert_space) { 60 | fputc (' ', trace_output); 61 | } 62 | } 63 | 64 | va_list args; 65 | va_start (args, fmt); 66 | vfprintf (trace_output, fmt, args); 67 | va_end (args); 68 | 69 | fflush (trace_output); 70 | } 71 | 72 | 73 | void 74 | eol_trace_setup (void) 75 | { 76 | /* Tracing was already configured. */ 77 | if (trace_output != NULL) 78 | return; 79 | 80 | trace_output = stderr; 81 | const char *env_value = getenv ("EOL_TRACE"); 82 | 83 | /* Check for an empty environment variable. */ 84 | if (!env_value || !*env_value) 85 | return; 86 | 87 | bool file_append = false; 88 | 89 | /* Check flags. */ 90 | for (; *env_value; env_value++) { 91 | switch (*env_value) { 92 | case 'L': 93 | trace_items |= TRACE_LINE; 94 | break; 95 | case 'S': 96 | trace_items |= TRACE_FILE; 97 | break; 98 | case 'F': 99 | trace_items |= TRACE_FUNC; 100 | break; 101 | case 'A': 102 | trace_items |= TRACE_ALL; 103 | break; 104 | 105 | case 'l': 106 | trace_items &= ~TRACE_LINE; 107 | break; 108 | case 's': 109 | trace_items &= ~TRACE_FILE; 110 | break; 111 | case 'f': 112 | trace_items &= ~TRACE_FUNC; 113 | break; 114 | 115 | case '>': 116 | file_append = true; 117 | /* fall-through */ 118 | case ':': 119 | env_value++; 120 | trace_output = fopen (env_value, 121 | file_append ? "ab" : "wb"); 122 | if (!trace_output) { 123 | fprintf (stderr, 124 | "Could not open '%s' for %s (%s), using stderr\n", 125 | env_value, file_append ? "appending" : "writing", 126 | strerror (errno)); 127 | fflush (stderr); 128 | trace_output = stderr; 129 | } 130 | goto setup_done; 131 | break; 132 | } 133 | } 134 | 135 | setup_done: 136 | eol_trace_enabled = true; 137 | } 138 | -------------------------------------------------------------------------------- /examples/type-pp.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- type-pp.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local help = [[ 10 | Usage: %s file.so typename 11 | 12 | This script uses the type information exposed by the Eol module to pretty 13 | print C types. The output format can be (mostly) fed back to a C compiler, 14 | and it also has some additional annotations in comments. 15 | ]] 16 | 17 | if #arg ~= 2 then 18 | io.stderr:write(help:format(arg[0])) 19 | os.exit(1) 20 | end 21 | 22 | local function O(t) 23 | io.stdout:write(t) 24 | end 25 | 26 | 27 | local repr_type 28 | 29 | local types = { 30 | has = function (self, t) 31 | assert(t.name, "Type does not have a name") 32 | return self[t.kind .. ":" .. t.name] 33 | end, 34 | add = function (self, t) 35 | assert(t.name, "Type does not have a name") 36 | local key = t.kind .. ":" .. t.name 37 | local rep = self[key] 38 | if rep == nil then 39 | print("/* Type: " .. key .. " */") 40 | rep = repr_type(t, true) 41 | self[key] = rep 42 | table.insert(self, key) 43 | end 44 | return rep 45 | end 46 | } 47 | 48 | 49 | local reprs = {} 50 | 51 | repr_type = function (T, verbose) 52 | local r = reprs[T.kind] 53 | if r then 54 | return r(T, verbose) 55 | else 56 | return { T.name } 57 | end 58 | end 59 | 60 | 61 | reprs.enum = function (T, verbose) 62 | local r = { "enum ", T.name } 63 | if verbose or not T.name then 64 | table.insert(r, " ") 65 | table.insert(r, "{") 66 | table.insert(r, "\n") 67 | for i = 1, #T do 68 | local member = T[i] 69 | table.insert(r, member.name .. " = " .. tostring(member.value) .. ",") 70 | table.insert(r, "\n") 71 | end 72 | table.insert(r, "}") 73 | end 74 | return r 75 | end 76 | 77 | reprs.struct = function (T, verbose) 78 | local r = { T.kind .. " " } 79 | if T.name then 80 | table.insert(r, T.name .. " ") 81 | end 82 | if verbose or not T.name then 83 | table.insert(r, "{") 84 | table.insert(r, "\n") 85 | for i = 1, #T do 86 | local member = T[i] 87 | if member.type.kind == "array" then 88 | table.insert(r, repr_type(member.type.type)) 89 | table.insert(r, " " .. member.name .. "[" .. tostring(#member.type) .. "]") 90 | else 91 | table.insert(r, repr_type(member.type)) 92 | if member.name then 93 | table.insert(r, " " .. member.name) 94 | end 95 | end 96 | table.insert(r, ";") 97 | table.insert(r, "\n") 98 | end 99 | table.insert(r, "}") 100 | end 101 | return r 102 | end 103 | reprs.union = reprs.struct 104 | 105 | reprs.array = function (T, verbose) 106 | return { repr_type(T.type, verbose), "[" .. tostring(#T) .. "]" } 107 | end 108 | 109 | reprs.typedef = function (T, verbose) 110 | if T.type.name then 111 | types:add(T.type) 112 | return { T.name } 113 | else 114 | return { "typedef ", repr_type(T.type), " " .. T.name } 115 | end 116 | end 117 | 118 | reprs.pointer = function (T, verbose) 119 | return { repr_type(T.type), "*" } 120 | end 121 | 122 | 123 | local PP = { 124 | indent = 0, 125 | indent_pending = false, 126 | 127 | Print = function (self, v) 128 | if self.indent_pending then 129 | for i = 1, self.indent do 130 | io.stdout:write(" ") 131 | end 132 | self.indent_pending = false 133 | end 134 | if type(v) == "string" then 135 | if v == "\n" then 136 | self.indent_pending = true 137 | elseif v == "{" then 138 | self.indent = self.indent + 1 139 | elseif v == "}" then 140 | self.indent = self.indent - 1 141 | v = "\b\b\b\b}" 142 | end 143 | O(v) 144 | elseif type(v) == "table" then 145 | for _, vv in ipairs(v) do 146 | self:Print(vv) 147 | end 148 | end 149 | end, 150 | } 151 | 152 | 153 | local eol = require("eol") 154 | local T = eol.type(eol.load(arg[1]), arg[2]) 155 | types:add(T) 156 | 157 | for _, tkey in ipairs(types) do 158 | PP:Print(types[tkey], #types == 1) 159 | O(";\n\n") 160 | end 161 | 162 | -------------------------------------------------------------------------------- /eol-libdwarf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-libdwarf.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "eol-libdwarf.h" 9 | #include "eol-trace.h" 10 | 11 | #include 12 | #include 13 | 14 | 15 | #define DW_DEFINE_DEALLOC_FUNC(name, _, enumvalue) \ 16 | void dw_dealloc_ ## name (void *location) { \ 17 | dw_ ## name ## _t *dd = *((dw_ ## name ## _t**) location); \ 18 | if (dd->name) { \ 19 | dwarf_dealloc (dd->debug, dd->name, enumvalue); \ 20 | dd->name = NULL; \ 21 | } \ 22 | } 23 | 24 | DW_DEALLOC_TYPES (DW_DEFINE_DEALLOC_FUNC) 25 | 26 | #undef DW_DEFINE_DEALLOC_FUNC 27 | 28 | 29 | char* 30 | dw_die_repr (Dwarf_Debug dbg, Dwarf_Die die) 31 | { 32 | CHECK_NOT_NULL (dbg); 33 | CHECK_NOT_NULL (die); 34 | 35 | uint32_t len = 1 + 3 + 1 + 20 + 1 + 1 + 1; /* \0 */ 36 | 37 | dw_lerror_t err = { dbg }; 38 | dw_lstring_t name = { dbg, dw_die_name (die, &err.error) }; 39 | 40 | const char *stringrep = name.string; 41 | if (!stringrep) { 42 | /* try to get the DW_TAG_* name instead. */ 43 | Dwarf_Half tag; 44 | dw_lerror_t err = { dbg }; 45 | if (dwarf_tag (die, &tag, &err.error) == DW_DLV_OK) 46 | if (dwarf_get_TAG_name (tag, &stringrep) != DW_DLV_OK) 47 | stringrep = NULL; 48 | } 49 | 50 | if (!stringrep) stringrep = "?"; 51 | len += strlen (stringrep); 52 | 53 | char *result = calloc (len + 1, sizeof (char)); 54 | snprintf (result, len, "", 55 | (unsigned long) dw_die_offset_ (die), 56 | stringrep); 57 | return result; 58 | } 59 | 60 | 61 | char* 62 | dw_die_get_string_attr (Dwarf_Debug dbg, 63 | Dwarf_Die die, 64 | Dwarf_Half tag, 65 | Dwarf_Error *e) 66 | { 67 | CHECK_NOT_NULL (dbg); 68 | CHECK_NOT_NULL (die); 69 | 70 | char *result; 71 | dw_lattr_t value = { dbg }; 72 | if (dwarf_attr (die, tag, &value.attr, e) != DW_DLV_OK || 73 | dwarf_formstring (value.attr, &result, e) != DW_DLV_OK) 74 | return NULL; 75 | return result; 76 | } 77 | 78 | 79 | bool 80 | dw_die_get_uint_attr (Dwarf_Debug dbg, 81 | Dwarf_Die die, 82 | Dwarf_Half tag, 83 | Dwarf_Unsigned *out, 84 | Dwarf_Error *e) 85 | { 86 | CHECK_NOT_NULL (dbg); 87 | CHECK_NOT_NULL (die); 88 | CHECK_NOT_NULL (out); 89 | 90 | dw_lattr_t value = { dbg }; 91 | return dwarf_attr (die, tag, &value.attr, e) == DW_DLV_OK 92 | && dwarf_formudata (value.attr, out, e) == DW_DLV_OK; 93 | } 94 | 95 | 96 | bool 97 | dw_die_get_sint_attr (Dwarf_Debug dbg, 98 | Dwarf_Die die, 99 | Dwarf_Half tag, 100 | Dwarf_Signed *out, 101 | Dwarf_Error *e) 102 | { 103 | CHECK_NOT_NULL (dbg); 104 | CHECK_NOT_NULL (die); 105 | CHECK_NOT_NULL (out); 106 | 107 | dw_lattr_t value = { dbg }; 108 | return dwarf_attr (die, tag, &value.attr, e) == DW_DLV_OK 109 | && dwarf_formsdata (value.attr, out, e) == DW_DLV_OK; 110 | } 111 | 112 | 113 | bool 114 | dw_tue_array_get_n_items (Dwarf_Debug dbg, 115 | Dwarf_Die tue, 116 | Dwarf_Unsigned *out, 117 | Dwarf_Error *e) 118 | { 119 | CHECK_NOT_NULL (dbg); 120 | CHECK_NOT_NULL (tue); 121 | CHECK_NOT_NULL (out); 122 | 123 | dw_ldie_t child = { dbg }; 124 | if (dwarf_child (tue, &child.die, e) != DW_DLV_OK) 125 | return false; 126 | 127 | bool result = false; 128 | for (;;) { 129 | Dwarf_Half tag; 130 | if (dwarf_tag (child.die, &tag, e) != DW_DLV_OK) 131 | break; 132 | 133 | if ((result = (tag == DW_TAG_subrange_type) && 134 | dw_die_get_uint_attrb (child, DW_AT_count, out, e))) 135 | break; 136 | 137 | dw_ldie_t prev = child; 138 | if (dwarf_siblingof (dbg, prev.die, &child.die, e) != DW_DLV_OK) 139 | break; 140 | } 141 | return result; 142 | } 143 | -------------------------------------------------------------------------------- /eol-fcall-x86.dasc: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-fcall-x86.dasc 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "dynasm/dasm_proto.h" 9 | #include "dynasm/dasm_x86.h" 10 | #include "eol-fcall-x64.h" 11 | #include "eol-typing.h" 12 | #include "eol-util.h" 13 | #include "eol-lua.h" 14 | #include 15 | 16 | 17 | |.if X64 18 | |.arch x64 19 | ||#define DASM_X64 1 20 | |.else 21 | |.arch x86 22 | ||#define DASM_X64 0 23 | |.endif 24 | 25 | |.if X64 26 | |.define REG_A, rax 27 | |.else 28 | |.define REG_A, eax 29 | |.define RET_H, edx // Used for returning int64_t values 30 | |.define RET_L, eax 31 | |.endif 32 | 33 | 34 | | // These macros allow calling into C functions, and are used to generate 35 | | // calls from the assembler to the Lua C API. 36 | |.macro call_rrp, func, arg1, arg2, arg3 37 | | mov64 rdx, arg3 38 | | mov rsi, arg2 39 | | mov rdi, arg1 40 | | call func 41 | |.endmacro 42 | | 43 | |.macro call_rr, func, arg1, arg2 44 | | mov rsi, arg2 45 | | mov rdi, arg1 46 | | call func 47 | |.endmacro 48 | 49 | 50 | enum { 51 | #if DASM_X64 52 | FJ_REGS_INT = 6, /* rdi, rsi, rdx, rcx, r8, r9 */ 53 | FJ_REGS_FLT = 8, /* xmm0-xmm7 */ 54 | #else 55 | FJ_REGS_INT = 0, 56 | FJ_REGS_FLT = 0, 57 | #endif 58 | }; 59 | 60 | typedef struct { 61 | uint16_t ints; 62 | uint16_t floats; 63 | uint32_t stack_offset; 64 | } FjAllocation; 65 | 66 | 67 | static inline void 68 | fj_allocation_add_param (Dst_DECL, FjAllocation *alloc) 69 | { 70 | if (alloc->ints < FJ_REGS_INT) { 71 | switch (alloc->ints) { 72 | case 0: 73 | | mov rdi, REG_A 74 | break; 75 | case 1: 76 | | mov rsi, REG_A 77 | break; 78 | case 2: 79 | | mov rdx, REG_A 80 | break; 81 | case 3: 82 | | mov rcx, REG_A 83 | break; 84 | case 4: 85 | | mov r8, REG_A 86 | break; 87 | case 5: 88 | | mov r0, REG_A 89 | break; 90 | default: 91 | CHECK_UNREACHABLE (); 92 | } 93 | } else { 94 | |.if X64 95 | | mov [rsp + alloc->stack_offset], rax 96 | |.else 97 | | mov [rsp + alloc->stack_offset], eax 98 | |.endif 99 | #if DASM_X64 100 | alloc->stack_offset += 8; 101 | #else 102 | alloc->stack_offset += 4; 103 | #endif 104 | } 105 | alloc->ints++; 106 | } 107 | 108 | |.actionlist fj_function_trampoline 109 | 110 | 111 | static void 112 | fcall_jit_compile (lua_State *L, 113 | const EolFunction *ef) 114 | { 115 | /* 116 | * Builds a lua_CFunction trampoline which calls the 117 | * given EolFunction. 118 | */ 119 | dasm_State *dasm; 120 | dasm_init (&dasm, 0); 121 | dasm_setup (&dasm, fj_function_trampoline); 122 | FjAllocation alloc = { 0, }; 123 | dasm_State **Dst = &dasm; 124 | 125 | for (uint32_t i = 0; i < ef->n_param; i++) { 126 | const EolTypeInfo *typeinfo = ef->param_types[i]; 127 | switch (eol_typeinfo_type (typeinfo)) { 128 | case EOL_TYPE_BOOL: 129 | | call_rr extern lua_toboolean, L, i + 2 130 | | cmp REG_A, 0 131 | | setne al 132 | | movzx REG_A, al 133 | fj_allocation_add_param (Dst, &alloc); 134 | break; 135 | 136 | case EOL_TYPE_U8: 137 | | call_rr extern luaL_checkinteger, L, i + 2 138 | | movzx REG_A, al 139 | fj_allocation_add_param (Dst, &alloc); 140 | break; 141 | 142 | case EOL_TYPE_S8: 143 | | call_rr extern luaL_checkinteger, L, i + 2 144 | | movsx REG_A, al 145 | fj_allocation_add_param (Dst, &alloc); 146 | break; 147 | 148 | case EOL_TYPE_U16: 149 | | call_rr extern luaL_checkinteger, L, i + 2 150 | | movzx REG_A, ax 151 | fj_allocation_add_param (Dst, &alloc); 152 | break; 153 | 154 | case EOL_TYPE_S16: 155 | | call_rr extern luaL_checkinteger, L, i + 2 156 | | movsx REG_A, ax 157 | fj_allocation_add_param (Dst, &alloc); 158 | break; 159 | 160 | case EOL_TYPE_U32: 161 | | call_rr extern luaL_checkinteger, L, i + 2 162 | |.if not X64 163 | | movzx REG_A, eax 164 | |.endif 165 | fj_allocation_add_param (Dst, &alloc); 166 | break; 167 | 168 | case EOL_TYPE_S32: 169 | | call_rr extern luaL_checkinteger, L, i + 2 170 | |.if not X64 171 | | movsx REG_A, eax 172 | |.endif 173 | fj_allocation_add_param (Dst, &alloc); 174 | break; 175 | } 176 | } 177 | } 178 | 179 | /* vim: set ft=c: */ 180 | -------------------------------------------------------------------------------- /tools/harness-assert.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- harness-assert.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local Steps = {} 10 | local Chain = {} 11 | local ChainMeta = {} 12 | 13 | function ChainMeta:__index(key) 14 | local value = rawget(self, key) 15 | if value == nil then 16 | rawset(self, rawlen(self) + 1, Steps[key]) 17 | value = self 18 | end 19 | return value 20 | end 21 | 22 | 23 | function ChainMeta:__call(...) 24 | local i = rawlen(self) 25 | local s = rawget(self, i) 26 | local m, r = s:apply("", ...) 27 | i = i - 1 28 | while i > 0 do 29 | s = rawget(self, i) 30 | m, r = s:apply(m, r) 31 | i = i - 1 32 | end 33 | if not r then 34 | error(m .. " expected", 2) 35 | end 36 | end 37 | 38 | 39 | function Chain:make() 40 | return setmetatable({}, ChainMeta) 41 | end 42 | 43 | 44 | Steps.True = { 45 | message = "boolean 'true'", 46 | apply = function (self, _, value) 47 | return self.message, type(value) == "boolean" and value == true 48 | end 49 | } 50 | 51 | Steps.False = { 52 | message = "boolean 'false'", 53 | apply = function (self, _, value) 54 | return self.message, type(value) == "boolean" and value == false 55 | end 56 | } 57 | 58 | Steps.Truthy = { 59 | message = "truthy value", 60 | apply = function (self, _, value) 61 | local result = false 62 | if value then 63 | result = true 64 | end 65 | return self.message, result 66 | end 67 | } 68 | 69 | Steps.Falsey = { 70 | message = "falsey value", 71 | apply = function (self, _, value) 72 | local result = true 73 | if value then 74 | result = false 75 | end 76 | return self.message, result 77 | end 78 | } 79 | 80 | Steps.Not = { 81 | apply = function (self, message, value) 82 | return message .. " not", not value 83 | end 84 | } 85 | 86 | Steps.Error = { 87 | apply = function (self, _, func_or_error, func) 88 | local expected_error = nil 89 | if func ~= nil then 90 | expected_error = func_or_error 91 | else 92 | func = func_or_error 93 | end 94 | local success, actual_error = pcall(func) 95 | if success then 96 | return "error", false 97 | end 98 | if expected_error ~= nil then 99 | -- Errors returned by pcall() contain the file name and line 100 | -- number where the error was produced. After that, the strings 101 | -- must match, and before the error string there is always a 102 | -- colon and a space (": ") which can be easily checked for. 103 | local err = actual_error:sub(-#expected_error - 2) 104 | return "error '" .. expected_error .. "' (got '" .. 105 | actual_error .. "' instead)", ": " .. expected_error == err 106 | end 107 | return "error", true 108 | end 109 | } 110 | 111 | Steps.Callable = { 112 | message = "callable object", 113 | apply = function (self, _, obj) 114 | if type(obj) == "function" then 115 | return self.message, true 116 | end 117 | local meta = getmetatable(obj) 118 | if meta ~= nil and type(meta.__call) == "function" then 119 | return self.message, true 120 | end 121 | return self.message, false 122 | end 123 | } 124 | 125 | Steps.Fields = { 126 | apply = function (self, _, obj, ...) 127 | local fields = { ... } 128 | for i, key in ipairs(fields) do 129 | if obj[key] == nil then 130 | return "table field '" .. key .. "'", false 131 | end 132 | end 133 | return "table fields { " .. table.concat(fields, ", ") .. " }", true 134 | end 135 | } 136 | Steps.Field = Steps.Fields 137 | 138 | local function make_type_checker(typename) 139 | return { 140 | message = "value of type '" .. typename .. "'", 141 | apply = function (self, _, obj) 142 | return self.message, type(obj) == typename 143 | end 144 | } 145 | end 146 | 147 | local typenames = { 148 | -- Userdata is handled a bit differently, see below. 149 | "Nil", "Number", "String", "Boolean", 150 | "Table", "Function", "Thread", 151 | } 152 | for _, name in ipairs(typenames) do 153 | Steps[name] = make_type_checker(name:lower()) 154 | end 155 | make_type_checker = nil 156 | typenames = nil 157 | 158 | Steps.Userdata = { 159 | message = "value of type 'userdata'", 160 | apply = function (self, _, obj, udatatype) 161 | if udatatype == nil then 162 | return self.message, type(obj) == "userdata" 163 | else 164 | local m = getmetatable(obj) 165 | local r = m ~= nil and m.__name == udatatype 166 | return self.message .. " with metatable '" .. udatatype .. "'", r 167 | end 168 | end 169 | } 170 | 171 | Steps.Equal = { 172 | apply = function (self, _, expected, obj) 173 | return tostring(expected) .. " (got '" .. tostring(obj) .. "')", 174 | expected == obj 175 | end 176 | } 177 | 178 | Steps.Match = { 179 | apply = function (self, _, match_re, obj) 180 | local re = "^" .. match_re .. "$" 181 | return "string matching '" .. re .. "' (got '" .. tostring(obj) .. "')", 182 | type(obj) == "string" and obj:match(re) ~= nil 183 | end 184 | } 185 | 186 | 187 | _G.assert = setmetatable({}, { 188 | __index = function (table, key) 189 | return Chain:make()[key] 190 | end, 191 | __call = function (table, thing, message, ...) 192 | if not thing then 193 | if message == nil then 194 | message = "Assertion failed!" 195 | end 196 | error(message:format(...), 2) 197 | end 198 | end, 199 | }) 200 | return _G.assert 201 | -------------------------------------------------------------------------------- /specials.inc: -------------------------------------------------------------------------------- 1 | /* ANSI-C code produced by gperf version 3.0.4 */ 2 | /* Command-line: gperf --output=specials.inc specials.gperf */ 3 | /* Computed positions: -k'1' */ 4 | 5 | #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ 6 | && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ 7 | && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ 8 | && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ 9 | && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ 10 | && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ 11 | && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ 12 | && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ 13 | && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ 14 | && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ 15 | && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ 16 | && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ 17 | && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ 18 | && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ 19 | && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ 20 | && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ 21 | && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ 22 | && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ 23 | && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ 24 | && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ 25 | && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ 26 | && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ 27 | && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) 28 | /* The character set is not based on ISO-646. */ 29 | #error "gperf generated tables don't work with this execution character set. Please report a bug to ." 30 | #endif 31 | 32 | #line 9 "specials.gperf" 33 | struct EolSpecial { 34 | const char *name; 35 | EolSpecialCode code; 36 | }; 37 | #include 38 | /* maximum key range = 16, duplicates = 0 */ 39 | 40 | #ifdef __GNUC__ 41 | __inline 42 | #else 43 | #ifdef __cplusplus 44 | inline 45 | #endif 46 | #endif 47 | static unsigned int 48 | eol_special_hash (register const char *str, register unsigned int len) 49 | { 50 | static const unsigned char asso_values[] = 51 | { 52 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 53 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 54 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 55 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 56 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 57 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 58 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 59 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 60 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 61 | 20, 20, 20, 20, 20, 20, 20, 5, 20, 20, 62 | 20, 20, 20, 20, 20, 20, 20, 15, 0, 20, 63 | 10, 20, 0, 20, 0, 0, 0, 20, 0, 20, 64 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 65 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 66 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 67 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 68 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 69 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 70 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 71 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 72 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 73 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 74 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 75 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 76 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 77 | 20, 20, 20, 20, 20, 20 78 | }; 79 | return len + asso_values[(unsigned char)str[0]]; 80 | } 81 | 82 | #ifdef __GNUC__ 83 | __inline 84 | #if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ 85 | __attribute__ ((__gnu_inline__)) 86 | #endif 87 | #endif 88 | const struct EolSpecial * 89 | eol_special_lookup (register const char *str, register unsigned int len) 90 | { 91 | enum 92 | { 93 | TOTAL_KEYWORDS = 9, 94 | MIN_WORD_LENGTH = 4, 95 | MAX_WORD_LENGTH = 9, 96 | MIN_HASH_VALUE = 4, 97 | MAX_HASH_VALUE = 19 98 | }; 99 | 100 | static const struct EolSpecial wordlist[] = 101 | { 102 | {""}, {""}, {""}, {""}, 103 | #line 15 "specials.gperf" 104 | {"type", EOL_SPECIAL_TYPE}, 105 | #line 16 "specials.gperf" 106 | {"value", EOL_SPECIAL_VALUE}, 107 | #line 18 "specials.gperf" 108 | {"sizeof", EOL_SPECIAL_SIZEOF}, 109 | #line 17 "specials.gperf" 110 | {"library", EOL_SPECIAL_LIBRARY}, 111 | #line 19 "specials.gperf" 112 | {"readonly", EOL_SPECIAL_READONLY}, 113 | #line 21 "specials.gperf" 114 | {"pointerto", EOL_SPECIAL_POINTERTO}, 115 | {""}, {""}, 116 | #line 22 "specials.gperf" 117 | {"arrayof", EOL_SPECIAL_ARRAYOF}, 118 | {""}, 119 | #line 14 "specials.gperf" 120 | {"name", EOL_SPECIAL_NAME}, 121 | {""}, {""}, {""}, {""}, 122 | #line 20 "specials.gperf" 123 | {"kind", EOL_SPECIAL_KIND} 124 | }; 125 | 126 | if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) 127 | { 128 | register int key = eol_special_hash (str, len); 129 | 130 | if (key <= MAX_HASH_VALUE && key >= 0) 131 | { 132 | register const char *s = wordlist[key].name; 133 | 134 | if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') 135 | return &wordlist[key]; 136 | } 137 | } 138 | return 0; 139 | } 140 | -------------------------------------------------------------------------------- /tools/ninja/lua-bundled.ninja: -------------------------------------------------------------------------------- 1 | lua_version = 5.3.1 2 | lua_tarball = ${obj}/downloads/lua-${lua_version}.tar.gz 3 | lua_path = ${obj}/lua-${lua_version} 4 | lua_lib = ${obj}/liblua.a 5 | lua_exe = ${obj}/lua 6 | cppflags = ${cppflags} -I${lua_path}/src $ 7 | -DEOL_LUA_BUNDLED=1 -DLUA_USE_DLOPEN=1 8 | 9 | 10 | build ${lua_lib} : staticlib $ 11 | ${obj}/lua.lapi.o $ 12 | ${obj}/lua.lauxlib.o $ 13 | ${obj}/lua.lbaselib.o $ 14 | ${obj}/lua.lbitlib.o $ 15 | ${obj}/lua.lcode.o $ 16 | ${obj}/lua.lcorolib.o $ 17 | ${obj}/lua.lctype.o $ 18 | ${obj}/lua.ldblib.o $ 19 | ${obj}/lua.ldebug.o $ 20 | ${obj}/lua.ldo.o $ 21 | ${obj}/lua.ldump.o $ 22 | ${obj}/lua.lfunc.o $ 23 | ${obj}/lua.lgc.o $ 24 | ${obj}/lua.linit.o $ 25 | ${obj}/lua.liolib.o $ 26 | ${obj}/lua.llex.o $ 27 | ${obj}/lua.lmathlib.o $ 28 | ${obj}/lua.lmem.o $ 29 | ${obj}/lua.loadlib.o $ 30 | ${obj}/lua.lobject.o $ 31 | ${obj}/lua.lopcodes.o $ 32 | ${obj}/lua.loslib.o $ 33 | ${obj}/lua.lparser.o $ 34 | ${obj}/lua.lstate.o $ 35 | ${obj}/lua.lstring.o $ 36 | ${obj}/lua.lstrlib.o $ 37 | ${obj}/lua.ltable.o $ 38 | ${obj}/lua.ltablib.o $ 39 | ${obj}/lua.ltm.o $ 40 | ${obj}/lua.lundump.o $ 41 | ${obj}/lua.lutf8lib.o $ 42 | ${obj}/lua.lvm.o $ 43 | ${obj}/lua.lzio.o 44 | 45 | build ${lua_exe} : ld ${obj}/lua.lua.o ${lua_lib} 46 | libs = ${libs} -lm 47 | 48 | build ${obj}/lua.lapi.o : cc ${lua_path}/src/lapi.c 49 | build ${obj}/lua.lauxlib.o : cc ${lua_path}/src/lauxlib.c 50 | build ${obj}/lua.lbaselib.o : cc ${lua_path}/src/lbaselib.c 51 | build ${obj}/lua.lbitlib.o : cc ${lua_path}/src/lbitlib.c 52 | build ${obj}/lua.lcode.o : cc ${lua_path}/src/lcode.c 53 | build ${obj}/lua.lcorolib.o : cc ${lua_path}/src/lcorolib.c 54 | build ${obj}/lua.lctype.o : cc ${lua_path}/src/lctype.c 55 | build ${obj}/lua.ldblib.o : cc ${lua_path}/src/ldblib.c 56 | build ${obj}/lua.ldebug.o : cc ${lua_path}/src/ldebug.c 57 | build ${obj}/lua.ldo.o : cc ${lua_path}/src/ldo.c 58 | build ${obj}/lua.ldump.o : cc ${lua_path}/src/ldump.c 59 | build ${obj}/lua.lfunc.o : cc ${lua_path}/src/lfunc.c 60 | build ${obj}/lua.lgc.o : cc ${lua_path}/src/lgc.c 61 | build ${obj}/lua.linit.o : cc ${lua_path}/src/linit.c 62 | build ${obj}/lua.liolib.o : cc ${lua_path}/src/liolib.c 63 | build ${obj}/lua.llex.o : cc ${lua_path}/src/llex.c 64 | build ${obj}/lua.lmathlib.o : cc ${lua_path}/src/lmathlib.c 65 | build ${obj}/lua.lmem.o : cc ${lua_path}/src/lmem.c 66 | build ${obj}/lua.loadlib.o : cc ${lua_path}/src/loadlib.c 67 | build ${obj}/lua.lobject.o : cc ${lua_path}/src/lobject.c 68 | build ${obj}/lua.lopcodes.o : cc ${lua_path}/src/lopcodes.c 69 | build ${obj}/lua.loslib.o : cc ${lua_path}/src/loslib.c 70 | build ${obj}/lua.lparser.o : cc ${lua_path}/src/lparser.c 71 | build ${obj}/lua.lstate.o : cc ${lua_path}/src/lstate.c 72 | build ${obj}/lua.lstring.o : cc ${lua_path}/src/lstring.c 73 | build ${obj}/lua.lstrlib.o : cc ${lua_path}/src/lstrlib.c 74 | build ${obj}/lua.ltable.o : cc ${lua_path}/src/ltable.c 75 | build ${obj}/lua.ltablib.o : cc ${lua_path}/src/ltablib.c 76 | build ${obj}/lua.ltm.o : cc ${lua_path}/src/ltm.c 77 | build ${obj}/lua.lundump.o : cc ${lua_path}/src/lundump.c 78 | build ${obj}/lua.lutf8lib.o : cc ${lua_path}/src/lutf8lib.c 79 | build ${obj}/lua.lvm.o : cc ${lua_path}/src/lvm.c 80 | build ${obj}/lua.lzio.o : cc ${lua_path}/src/lzio.c 81 | build ${obj}/lua.lua.o : cc ${lua_path}/src/lua.c 82 | build ${obj}/lua.luac.o : cc ${lua_path}/src/luac.c 83 | 84 | build ${lua_path}/src/lapi.c $ 85 | ${lua_path}/src/lauxlib.c $ 86 | ${lua_path}/src/lbaselib.c $ 87 | ${lua_path}/src/lbitlib.c $ 88 | ${lua_path}/src/lcode.c $ 89 | ${lua_path}/src/lcorolib.c $ 90 | ${lua_path}/src/lctype.c $ 91 | ${lua_path}/src/ldblib.c $ 92 | ${lua_path}/src/ldebug.c $ 93 | ${lua_path}/src/ldo.c $ 94 | ${lua_path}/src/ldump.c $ 95 | ${lua_path}/src/lfunc.c $ 96 | ${lua_path}/src/lgc.c $ 97 | ${lua_path}/src/linit.c $ 98 | ${lua_path}/src/liolib.c $ 99 | ${lua_path}/src/llex.c $ 100 | ${lua_path}/src/lmathlib.c $ 101 | ${lua_path}/src/lmem.c $ 102 | ${lua_path}/src/loadlib.c $ 103 | ${lua_path}/src/lobject.c $ 104 | ${lua_path}/src/lopcodes.c $ 105 | ${lua_path}/src/loslib.c $ 106 | ${lua_path}/src/lparser.c $ 107 | ${lua_path}/src/lstate.c $ 108 | ${lua_path}/src/lstring.c $ 109 | ${lua_path}/src/lstrlib.c $ 110 | ${lua_path}/src/ltable.c $ 111 | ${lua_path}/src/ltablib.c $ 112 | ${lua_path}/src/ltm.c $ 113 | ${lua_path}/src/lundump.c $ 114 | ${lua_path}/src/lutf8lib.c $ 115 | ${lua_path}/src/lvm.c $ 116 | ${lua_path}/src/lzio.c $ 117 | ${lua_path}/src/lua.c $ 118 | ${lua_path}/src/luac.c $ 119 | ${lua_path}/src/lua.h $ 120 | ${lua_path}/src/lualib.h $ 121 | ${lua_path}/src/lauxlib.h $ 122 | : untargz ${lua_tarball} 123 | 124 | build ${lua_tarball} : urlfetch 125 | url = http://www.lua.org/ftp/lua-${lua_version}.tar.gz 126 | 127 | build eol-lua.h : phony | ${lua_path}/src/lauxlib.h $ 128 | ${lua_path}/src/lualib.h $ 129 | ${lua_path}/src/lua.h $ 130 | || ${lua_exe} 131 | -------------------------------------------------------------------------------- /eol-libdwarf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-libdwarf.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_LIBDWARF_H 9 | #define EOL_LIBDWARF_H 10 | 11 | #ifdef EOL_WORKAROUND_DWARF_PUBTYPE_DIE_OFFSET 12 | # if EOL_WORKAROUND_DWARF_PUBTYPE_DIE_OFFSET 13 | # define dwarf_pubtype_die_offset dwarf_pubtype_type_die_offset 14 | # endif 15 | #endif /* EOL_WORKAROUND_DWARF_PUBTYPE_DIE_OFFSET */ 16 | 17 | #if defined(EOL_LIBDWARF_BUNDLED) && EOL_LIBDWARF_BUNDLED 18 | # include "libdwarf.h" 19 | # include "dwarf.h" 20 | #else 21 | # if defined(EOL_LIBDWARF_LIBDWARF_H) && EOL_LIBDWARF_LIBDWARF_H 22 | # include 23 | # include 24 | # else 25 | # include 26 | # include 27 | # endif /* EOL_LIBDWARF_LIBDWARF_H */ 28 | #endif /* EOL_LIBDWARF_BUNDLED */ 29 | 30 | #include "eol-util.h" 31 | 32 | 33 | #define DW_TYPE_TAG_NAMES(F) \ 34 | F (base_type) \ 35 | F (typedef) \ 36 | F (const_type) \ 37 | F (array_type) \ 38 | F (pointer_type) \ 39 | F (union_type) \ 40 | F (enumeration_type) \ 41 | F (structure_type) 42 | 43 | #define DW_DEALLOC_TYPES(F) \ 44 | F (string, char*, DW_DLA_STRING) \ 45 | F (die, Dwarf_Die, DW_DLA_DIE) \ 46 | F (error, Dwarf_Error, DW_DLA_ERROR) \ 47 | F (attr, Dwarf_Attribute, DW_DLA_ATTR) 48 | 49 | 50 | #define DW_DECLARE_DW_DATA_T(name, ctype, _) \ 51 | typedef struct { \ 52 | Dwarf_Debug debug; \ 53 | ctype name; \ 54 | } dw_ ## name ## _t; 55 | DW_DEALLOC_TYPES (DW_DECLARE_DW_DATA_T) 56 | #undef DW_DECLARE_DW_DATA_T 57 | 58 | 59 | #define DW_DECLARE_DEALLOC_CALLBACK(name, _, __) \ 60 | extern void dw_dealloc_ ## name (void*); 61 | DW_DEALLOC_TYPES (DW_DECLARE_DEALLOC_CALLBACK) 62 | #undef DW_DECLARE_DEALLOC_CALLBACK 63 | 64 | /* Ugh. Those have to be defined one by one. */ 65 | #define dw_ldie_t LAUTO (dw_dealloc_die) dw_die_t 66 | #define dw_lstring_t LAUTO (dw_dealloc_string) dw_string_t 67 | #define dw_lerror_t LAUTO (dw_dealloc_die) dw_error_t 68 | #define dw_lattr_t LAUTO (dw_dealloc_attr) dw_attr_t 69 | 70 | 71 | static inline unsigned 72 | dw_die_offset (Dwarf_Die die, Dwarf_Error *e) 73 | { 74 | CHECK_NOT_NULL (die); 75 | Dwarf_Off offset; 76 | return dwarf_dieoffset (die, &offset, e) == DW_DLV_OK 77 | ? (unsigned) offset : (unsigned) DW_DLV_BADOFFSET; 78 | } 79 | 80 | 81 | static inline unsigned 82 | dw_die_offset_ (Dwarf_Die die) 83 | { 84 | CHECK_NOT_NULL (die); 85 | return dw_die_offset (die, NULL); 86 | } 87 | 88 | 89 | extern char* dw_die_repr (Dwarf_Debug dbg, Dwarf_Die die); 90 | static inline char* dw_die_reprb (const dw_die_t dd) 91 | { return dw_die_repr (dd.debug, dd.die); } 92 | 93 | 94 | extern char* dw_die_get_string_attr (Dwarf_Debug dbg, 95 | Dwarf_Die die, 96 | Dwarf_Half tag, 97 | Dwarf_Error *e); 98 | static inline char* 99 | dw_die_get_string_attrb (const dw_die_t dd, 100 | Dwarf_Half tag, 101 | Dwarf_Error *e) 102 | { return dw_die_get_string_attr (dd.debug, dd.die, tag, e); } 103 | 104 | 105 | extern bool dw_die_get_uint_attr (Dwarf_Debug dbg, 106 | Dwarf_Die die, 107 | Dwarf_Half tag, 108 | Dwarf_Unsigned *out, 109 | Dwarf_Error *e); 110 | static inline bool 111 | dw_die_get_uint_attrb (const dw_die_t dd, 112 | Dwarf_Half tag, 113 | Dwarf_Unsigned *out, 114 | Dwarf_Error *e) 115 | { return dw_die_get_uint_attr (dd.debug, dd.die, tag, out, e); } 116 | 117 | 118 | extern bool dw_die_get_sint_attr (Dwarf_Debug dbg, 119 | Dwarf_Die die, 120 | Dwarf_Half tag, 121 | Dwarf_Signed *out, 122 | Dwarf_Error *e); 123 | static inline bool 124 | dw_die_get_sint_attrb (const dw_die_t dd, 125 | Dwarf_Half tag, 126 | Dwarf_Signed *out, 127 | Dwarf_Error *e) 128 | { return dw_die_get_sint_attr (dd.debug, dd.die, tag, out, e); } 129 | 130 | 131 | extern bool 132 | dw_tue_array_get_n_items (Dwarf_Debug dbg, 133 | Dwarf_Die tue, 134 | Dwarf_Unsigned *out, 135 | Dwarf_Error *e); 136 | 137 | 138 | static inline char* 139 | dw_die_name (Dwarf_Die die, 140 | Dwarf_Error *e) 141 | { 142 | CHECK_NOT_NULL (die); 143 | 144 | char *name; 145 | if (dwarf_diename (die, &name, e) != DW_DLV_OK) 146 | name = NULL; 147 | return name; 148 | } 149 | 150 | 151 | static inline const char* 152 | dw_errmsg (Dwarf_Error e) 153 | { 154 | return e ? dwarf_errmsg (e) : "no libdwarf error"; 155 | } 156 | 157 | 158 | #if EOL_TRACE 159 | # define DW_TRACE_DIE(fmt, dbg, die, ...) \ 160 | do { \ 161 | LMEM char *die_repr = dw_die_repr ((dbg), (die)); \ 162 | TRACE (BROWN "%s" NORMAL " " fmt, \ 163 | die_repr, ##__VA_ARGS__); \ 164 | } while (0) 165 | # define DW_TRACE_DIE_ERROR(fmt, dbg, die, err, ...) \ 166 | do { \ 167 | LMEM char *die_repr = dw_die_repr ((dbg), (die)); \ 168 | TRACE (BROWN "%s " NORMAL "{" RED "%s" NORMAL \ 169 | "} " fmt, die_repr, dw_errmsg (err), \ 170 | ##__VA_ARGS__); \ 171 | } while (0); 172 | #else 173 | # define DW_TRACE_DIE(...) ((void) 0) 174 | # define DW_TRACE_DIE_ERROR(...) ((void) 0) 175 | #endif 176 | 177 | #endif /* !EOL_LIBDWARF_H */ 178 | -------------------------------------------------------------------------------- /eol-fcall-x64.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** This file has been pre-processed with DynASM. 3 | ** http://luajit.org/dynasm.html 4 | ** DynASM version 1.3.0, DynASM x64 version 1.3.0 5 | ** DO NOT EDIT! The original file is in "eol-fcall-x86.dasc". 6 | */ 7 | 8 | #line 1 "eol-fcall-x86.dasc" 9 | /* 10 | * eol-fcall-x86.dasc 11 | * Copyright (C) 2015 Adrian Perez 12 | * 13 | * Distributed under terms of the MIT license. 14 | */ 15 | 16 | #include "dynasm/dasm_proto.h" 17 | #include "dynasm/dasm_x86.h" 18 | #include "eol-fcall-x64.h" 19 | #include "eol-typing.h" 20 | #include "eol-util.h" 21 | #include "eol-lua.h" 22 | #include 23 | 24 | 25 | //|.if X64 26 | //|.arch x64 27 | #if DASM_VERSION != 10300 28 | #error "Version mismatch between DynASM and included encoding engine" 29 | #endif 30 | #line 19 "eol-fcall-x86.dasc" 31 | #define DASM_X64 1 32 | //|.else 33 | //|.arch x86 34 | #line 23 "eol-fcall-x86.dasc" 35 | //|.endif 36 | 37 | //|.if X64 38 | //|.define REG_A, rax 39 | //|.else 40 | //|.define REG_A, eax 41 | //|.define RET_H, edx // Used for returning int64_t values 42 | //|.define RET_L, eax 43 | //|.endif 44 | 45 | 46 | //| // These macros allow calling into C functions, and are used to generate 47 | //| // calls from the assembler to the Lua C API. 48 | //|.macro call_rrp, func, arg1, arg2, arg3 49 | //| mov64 rdx, arg3 50 | //| mov rsi, arg2 51 | //| mov rdi, arg1 52 | //| call func 53 | //|.endmacro 54 | //| 55 | //|.macro call_rr, func, arg1, arg2 56 | //| mov rsi, arg2 57 | //| mov rdi, arg1 58 | //| call func 59 | //|.endmacro 60 | 61 | 62 | enum { 63 | #if DASM_X64 64 | FJ_REGS_INT = 6, /* rdi, rsi, rdx, rcx, r8, r9 */ 65 | FJ_REGS_FLT = 8, /* xmm0-xmm7 */ 66 | #else 67 | FJ_REGS_INT = 0, 68 | FJ_REGS_FLT = 0, 69 | #endif 70 | }; 71 | 72 | typedef struct { 73 | uint16_t ints; 74 | uint16_t floats; 75 | uint32_t stack_offset; 76 | } FjAllocation; 77 | 78 | 79 | static inline void 80 | fj_allocation_add_param (Dst_DECL, FjAllocation *alloc) 81 | { 82 | if (alloc->ints < FJ_REGS_INT) { 83 | switch (alloc->ints) { 84 | case 0: 85 | //| mov rdi, REG_A 86 | dasm_put(Dst, 0); 87 | #line 74 "eol-fcall-x86.dasc" 88 | break; 89 | case 1: 90 | //| mov rsi, REG_A 91 | dasm_put(Dst, 4); 92 | #line 77 "eol-fcall-x86.dasc" 93 | break; 94 | case 2: 95 | //| mov rdx, REG_A 96 | dasm_put(Dst, 8); 97 | #line 80 "eol-fcall-x86.dasc" 98 | break; 99 | case 3: 100 | //| mov rcx, REG_A 101 | dasm_put(Dst, 12); 102 | #line 83 "eol-fcall-x86.dasc" 103 | break; 104 | case 4: 105 | //| mov r8, REG_A 106 | dasm_put(Dst, 16); 107 | #line 86 "eol-fcall-x86.dasc" 108 | break; 109 | case 5: 110 | //| mov r0, REG_A 111 | dasm_put(Dst, 20); 112 | #line 89 "eol-fcall-x86.dasc" 113 | break; 114 | default: 115 | CHECK_UNREACHABLE (); 116 | } 117 | } else { 118 | //|.if X64 119 | //| mov [rsp + alloc->stack_offset], rax 120 | //|.else 121 | //| mov [rsp + alloc->stack_offset], eax 122 | //|.endif 123 | dasm_put(Dst, 24, alloc->stack_offset); 124 | #line 99 "eol-fcall-x86.dasc" 125 | #if DASM_X64 126 | alloc->stack_offset += 8; 127 | #else 128 | alloc->stack_offset += 4; 129 | #endif 130 | } 131 | alloc->ints++; 132 | } 133 | 134 | //|.actionlist fj_function_trampoline 135 | static const unsigned char fj_function_trampoline[137] = { 136 | 72.0,137.0,199.0,255,72.0,137.0,198.0,255,72.0,137.0,194.0,255,72.0,137.0, 137 | 193.0,255,73.0,137.0,192.0,255,72.0,137.0,192.0,255,72.0,137.0,132.0,253, 138 | 36.0,233,255,72.0,199.0,198.0,237,72.0,199.0,199.0,237,232,251,1,0,72.0,131.0, 139 | 252,248.0,0,15.0,149.0,208.0,72.0,15.0,182.0,192.0,255,72.0,199.0,198.0,237, 140 | 72.0,199.0,199.0,237,232,251,1,1,72.0,15.0,182.0,192.0,255,72.0,199.0,198.0, 141 | 237,72.0,199.0,199.0,237,232,251,1,1,72.0,15.0,190.0,192.0,255,72.0,199.0, 142 | 198.0,237,72.0,199.0,199.0,237,232,251,1,1,72.0,15.0,183.0,192.0,255,72.0, 143 | 199.0,198.0,237,72.0,199.0,199.0,237,232,251,1,1,72.0,15.0,191.0,192.0,255, 144 | 72.0,199.0,198.0,237,72.0,199.0,199.0,237,232,251,1,1,255 145 | }; 146 | 147 | #line 109 "eol-fcall-x86.dasc" 148 | 149 | 150 | static void 151 | fcall_jit_compile (lua_State *L, 152 | const EolFunction *ef) 153 | { 154 | /* 155 | * Builds a lua_CFunction trampoline which calls the 156 | * given EolFunction. 157 | */ 158 | dasm_State *dasm; 159 | dasm_init (&dasm, 0); 160 | dasm_setup (&dasm, fj_function_trampoline); 161 | FjAllocation alloc = { 0, }; 162 | dasm_State **Dst = &dasm; 163 | 164 | for (uint32_t i = 0; i < ef->n_param; i++) { 165 | const EolTypeInfo *typeinfo = ef->param_types[i]; 166 | switch (eol_typeinfo_type (typeinfo)) { 167 | case EOL_TYPE_BOOL: 168 | //| call_rr extern lua_toboolean, L, i + 2 169 | //| cmp REG_A, 0 170 | //| setne al 171 | //| movzx REG_A, al 172 | dasm_put(Dst, 31, i + 2, L); 173 | #line 133 "eol-fcall-x86.dasc" 174 | fj_allocation_add_param (Dst, &alloc); 175 | break; 176 | 177 | case EOL_TYPE_U8: 178 | //| call_rr extern luaL_checkinteger, L, i + 2 179 | //| movzx REG_A, al 180 | dasm_put(Dst, 56, i + 2, L); 181 | #line 139 "eol-fcall-x86.dasc" 182 | fj_allocation_add_param (Dst, &alloc); 183 | break; 184 | 185 | case EOL_TYPE_S8: 186 | //| call_rr extern luaL_checkinteger, L, i + 2 187 | //| movsx REG_A, al 188 | dasm_put(Dst, 73, i + 2, L); 189 | #line 145 "eol-fcall-x86.dasc" 190 | fj_allocation_add_param (Dst, &alloc); 191 | break; 192 | 193 | case EOL_TYPE_U16: 194 | //| call_rr extern luaL_checkinteger, L, i + 2 195 | //| movzx REG_A, ax 196 | dasm_put(Dst, 90, i + 2, L); 197 | #line 151 "eol-fcall-x86.dasc" 198 | fj_allocation_add_param (Dst, &alloc); 199 | break; 200 | 201 | case EOL_TYPE_S16: 202 | //| call_rr extern luaL_checkinteger, L, i + 2 203 | //| movsx REG_A, ax 204 | dasm_put(Dst, 107, i + 2, L); 205 | #line 157 "eol-fcall-x86.dasc" 206 | fj_allocation_add_param (Dst, &alloc); 207 | break; 208 | 209 | case EOL_TYPE_U32: 210 | //| call_rr extern luaL_checkinteger, L, i + 2 211 | //|.if not X64 212 | //| movzx REG_A, eax 213 | //|.endif 214 | dasm_put(Dst, 124, i + 2, L); 215 | #line 165 "eol-fcall-x86.dasc" 216 | fj_allocation_add_param (Dst, &alloc); 217 | break; 218 | 219 | case EOL_TYPE_S32: 220 | //| call_rr extern luaL_checkinteger, L, i + 2 221 | //|.if not X64 222 | //| movsx REG_A, eax 223 | //|.endif 224 | dasm_put(Dst, 124, i + 2, L); 225 | #line 173 "eol-fcall-x86.dasc" 226 | fj_allocation_add_param (Dst, &alloc); 227 | break; 228 | } 229 | } 230 | } 231 | 232 | /* vim: set ft=c: */ 233 | -------------------------------------------------------------------------------- /eol-typing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-typing.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_TYPING_H 9 | #define EOL_TYPING_H 10 | 11 | #include 12 | #include 13 | 14 | 15 | #define INTEGER_S_TYPES(F) \ 16 | F (S8, s8, int8_t ) \ 17 | F (S16, s16, int16_t ) \ 18 | F (S32, s32, int32_t ) \ 19 | F (S64, s64, int64_t ) 20 | 21 | #define INTEGER_U_TYPES(F) \ 22 | F (U8, u8, uint8_t ) \ 23 | F (U16, u16, uint16_t) \ 24 | F (U32, u32, uint32_t) \ 25 | F (U64, u64, uint64_t) 26 | 27 | #define INTEGER_TYPES(F) \ 28 | INTEGER_S_TYPES (F) \ 29 | INTEGER_U_TYPES (F) 30 | 31 | #define FLOAT_TYPES(F) \ 32 | F (DOUBLE, double, double) \ 33 | F (FLOAT, float, float) 34 | 35 | #define BASE_TYPES(F) \ 36 | INTEGER_TYPES (F) \ 37 | FLOAT_TYPES (F) \ 38 | F (BOOL, bool, bool) \ 39 | F (POINTER, pointer, void*) 40 | 41 | #define SYNTHETIC_TYPES(F) \ 42 | F (TYPEDEF, typedef, typedef) \ 43 | F (CONST, const, const) 44 | 45 | #define COMPOUND_TYPES(F) \ 46 | F (STRUCT, struct, struct) \ 47 | F (UNION, union, union) \ 48 | F (ARRAY, array, array) 49 | 50 | #define CONST_TYPES(F) \ 51 | INTEGER_TYPES (F) \ 52 | FLOAT_TYPES (F) \ 53 | F (BOOL, bool, bool) \ 54 | F (VOID, void, void) 55 | 56 | #define ALL_TYPES(F) \ 57 | BASE_TYPES (F) \ 58 | SYNTHETIC_TYPES (F) \ 59 | COMPOUND_TYPES (F) \ 60 | F (ENUM, enum, enum) \ 61 | F (VOID, void, void) 62 | 63 | 64 | typedef enum { 65 | #define TYPE_ENUM_ENTRY(suffix, name, ctype) EOL_TYPE_ ## suffix, 66 | ALL_TYPES (TYPE_ENUM_ENTRY) 67 | #undef TYPE_ENUM_ENTRY 68 | } EolType; 69 | 70 | 71 | extern const char* eol_type_name (EolType type); 72 | 73 | #define TYPE_CASE_TRUE(suffix, name, ctype) \ 74 | case EOL_TYPE_ ## suffix : return true; 75 | 76 | #define DECLARE_EOL_TYPE_IS(suffix, check) \ 77 | static inline bool eol_type_is_ ## check (EolType type) { \ 78 | switch (type) { \ 79 | SYNTHETIC_TYPES (TYPE_CASE_TRUE) \ 80 | default: return false; \ 81 | } \ 82 | } 83 | 84 | DECLARE_EOL_TYPE_IS (BASE, base) 85 | DECLARE_EOL_TYPE_IS (SYNTHETIC, synthetic) 86 | DECLARE_EOL_TYPE_IS (COMPOUND, compound) 87 | 88 | #undef DECLARE_EOL_TYPE_IS 89 | #undef TYPE_CASE_TRUE 90 | 91 | 92 | typedef struct _EolTypeInfo EolTypeInfo; 93 | 94 | #define DECL_CONST_TYPEINFO_ITEM(suffix, name, ctype) \ 95 | extern const EolTypeInfo *eol_typeinfo_ ## name; 96 | 97 | CONST_TYPES (DECL_CONST_TYPEINFO_ITEM) 98 | extern const EolTypeInfo *eol_typeinfo_pointer; 99 | 100 | #undef DECL_CONST_TYPEINFO_ITEM 101 | 102 | 103 | typedef struct { 104 | const char *name; 105 | union { 106 | int64_t value; /* EOL_TYPE_ENUM */ 107 | struct { 108 | uint32_t offset; /* EOL_TYPE_{UNION,STRUCT} */ 109 | const EolTypeInfo *typeinfo; /* ditto. */ 110 | }; 111 | }; 112 | } EolTypeInfoMember; 113 | 114 | 115 | extern EolTypeInfo* eol_typeinfo_new_const (const EolTypeInfo *base); 116 | extern EolTypeInfo* eol_typeinfo_new_pointer (const EolTypeInfo *base); 117 | extern EolTypeInfo* eol_typeinfo_new_typedef (const EolTypeInfo *base, 118 | const char *name); 119 | extern EolTypeInfo* eol_typeinfo_new_array (const EolTypeInfo *base, 120 | uint64_t n_items); 121 | extern EolTypeInfo* eol_typeinfo_new_struct (const char *name, 122 | uint32_t size, 123 | uint32_t n_members); 124 | extern EolTypeInfo* eol_typeinfo_new_enum (const char *name, 125 | uint32_t size, 126 | uint32_t n_members); 127 | extern EolTypeInfo* eol_typeinfo_new_union (const char *name, 128 | uint32_t size, 129 | uint32_t n_members); 130 | 131 | extern void eol_typeinfo_free (EolTypeInfo *typeinfo); 132 | 133 | extern const EolTypeInfo* eol_typeinfo_base (const EolTypeInfo *typeinfo); 134 | 135 | extern const char* eol_typeinfo_name (const EolTypeInfo *typeinfo); 136 | extern EolType eol_typeinfo_type (const EolTypeInfo *typeinfo); 137 | extern bool eol_typeinfo_equal (const EolTypeInfo *a, 138 | const EolTypeInfo *b); 139 | extern uint32_t eol_typeinfo_sizeof (const EolTypeInfo *typeinfo); 140 | extern int8_t eol_typeinfo_alignment (const EolTypeInfo *typeinfo); 141 | extern uint64_t eol_typeinfo_array_n_items (const EolTypeInfo* typeinfo); 142 | extern bool eol_typeinfo_struct_is_opaque (const EolTypeInfo *typeinfo); 143 | extern uint32_t eol_typeinfo_compound_n_members (const EolTypeInfo *typeinfo); 144 | extern bool eol_typeinfo_is_cstring (const EolTypeInfo *typeinfo); 145 | 146 | extern bool eol_typeinfo_is_readonly (const EolTypeInfo *typeinfo); 147 | extern const EolTypeInfo* eol_typeinfo_get_compound (const EolTypeInfo *typeinfo); 148 | extern const EolTypeInfo* eol_typeinfo_get_non_synthetic (const EolTypeInfo *typeinfo); 149 | 150 | 151 | extern EolTypeInfoMember* 152 | eol_typeinfo_compound_named_member (EolTypeInfo *typeinfo, 153 | const char *name); 154 | extern EolTypeInfoMember* 155 | eol_typeinfo_compound_member (EolTypeInfo *typeinfo, 156 | uint32_t index); 157 | 158 | extern const EolTypeInfoMember* 159 | eol_typeinfo_compound_const_named_member (const EolTypeInfo *typeinfo, 160 | const char *name); 161 | extern const EolTypeInfoMember* 162 | eol_typeinfo_compound_const_member (const EolTypeInfo *typeinfo, 163 | uint32_t index); 164 | 165 | 166 | #define EOL_TYPEINFO_COMPOUND_FOREACH_CONST_MEMBER(itername, typeinfo) \ 167 | itername = eol_typeinfo_compound_const_member (typeinfo, 0); \ 168 | for (uint32_t itername ## _i = 0, itername ## _n_members = \ 169 | eol_typeinfo_compound_n_members (typeinfo); \ 170 | itername ## _i < itername ## _n_members; \ 171 | itername = eol_typeinfo_compound_const_member (typeinfo, itername ## _i++)) 172 | 173 | #define EOL_TYPEINFO_COMPOUND_FOREACH_MEMBER(itername, typeinfo) \ 174 | itername = eol_typeinfo_compound_const_member (typeinfo, 0); \ 175 | for (uint32_t itername ## _i = 0, itername ## _n_members = \ 176 | eol_typeinfo_compound_n_members (typeinfo); \ 177 | itername ## _i < itername ## _n_members; \ 178 | itername = eol_typeinfo_compound_const_member (typeinfo, itername ## _i++)) 179 | 180 | 181 | #define DECLARE_TYPEINFO_IS_TYPE(suffix, name, ctype) \ 182 | static inline bool eol_typeinfo_is_ ## name (const EolTypeInfo *typeinfo) { \ 183 | typeinfo = eol_typeinfo_get_non_synthetic (typeinfo); \ 184 | return eol_typeinfo_type (typeinfo) == EOL_TYPE_ ## suffix; } 185 | 186 | ALL_TYPES (DECLARE_TYPEINFO_IS_TYPE) 187 | 188 | #undef DECLARE_TYPEINFO_IS_TYPE 189 | 190 | 191 | #define DECLARE_EOL_TYPEINFO_IS(check) \ 192 | static inline bool eol_typeinfo_is_ ## check (const EolTypeInfo *typeinfo) { \ 193 | typeinfo = eol_typeinfo_get_non_synthetic (typeinfo); \ 194 | return eol_type_is_ ## check (eol_typeinfo_type (typeinfo)); } 195 | 196 | DECLARE_EOL_TYPEINFO_IS (base) 197 | DECLARE_EOL_TYPEINFO_IS (synthetic) 198 | DECLARE_EOL_TYPEINFO_IS (compound) 199 | 200 | #undef DECLARE_EOL_TYPEINFO_IS 201 | 202 | #endif /* !EOL_TYPING_H */ 203 | -------------------------------------------------------------------------------- /eol-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-util.h 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef EOL_UTIL_H 9 | #define EOL_UTIL_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #define LENGTH_OF(array) \ 17 | (sizeof (array) / sizeof (array[0])) 18 | 19 | /* 20 | * Debug checks. 21 | */ 22 | #if defined(EOL_RUNTIME_CHECKS) && EOL_RUNTIME_CHECKS > 0 23 | 24 | # define CHECK_FAILED(...) \ 25 | eol_runtime_check_failed (__FILE__, __LINE__, __func__, __VA_ARGS__) 26 | 27 | # define CHECK_UNREACHABLE( ) CHECK_FAILED ("Unreachable code\n") 28 | 29 | # define CHECK(expression) \ 30 | do { \ 31 | if (!(expression)) \ 32 | CHECK_FAILED ("expression: %s\n", #expression); \ 33 | } while (0) 34 | 35 | # define CHECK_NUMERIC_OP(op, expect, expr, type, fmt) \ 36 | do { \ 37 | type eval_expect = (expect); \ 38 | type eval_expr = (expr); \ 39 | if (!(eval_expr op eval_expect)) \ 40 | CHECK_FAILED ("expression: %s\n" \ 41 | "expected: " #op " %" fmt "\n" \ 42 | "value: %" fmt "\n", \ 43 | #expr, eval_expect, eval_expr); \ 44 | } while (0) 45 | 46 | # define CHECK_NOT_NULL(expression) \ 47 | do { \ 48 | if ((expression) == NULL) \ 49 | CHECK_FAILED ("expression: " #expression "\n" \ 50 | "expected: non-NULL\n"); \ 51 | } while (0) 52 | 53 | # define CHECK_NOT_ZERO(expression) \ 54 | do { \ 55 | if ((expression) == 0) \ 56 | CHECK_FAILED ("expression: " #expression "\n" \ 57 | "expected: non-zero\n"); \ 58 | } while (0) 59 | 60 | # define CHECK_STR_EQ(expected, expression) \ 61 | do { \ 62 | const char *eval_expected = (expected); \ 63 | const char *eval_expression = (expression); \ 64 | if (strcmp (eval_expected, eval_expression) != 0) \ 65 | CHECK_FAILED ("expression: %s\n" \ 66 | "expected: '%s'\n" \ 67 | "value: '%s'\n", \ 68 | #expression, \ 69 | eval_expected, \ 70 | eval_expression); \ 71 | } while (0); 72 | 73 | extern void eol_runtime_check_failed (const char *file, 74 | unsigned line, 75 | const char *func, 76 | const char *fmt, 77 | ...); 78 | #else /* !EOL_DEBUG_CHECKS */ 79 | # undef EOL_RUNTIME_CHECKS 80 | # define EOL_RUNTIME_CHECKS 0 81 | # define CHECK(e) ((void) 0) 82 | # define CHECK_UNREACHABLE( ) ((void) 0) 83 | # define CHECK_NUMERIC_OP(o, e, x, t, f) ((void) 0) 84 | # define CHECK_NOT_NULL(e) ((void) 0) 85 | # define CHECK_NOT_ZERO(e) ((void) 0) 86 | # define CHECK_STR_EQ(e, x) ((void) 0) 87 | #endif /* EOL_DEBUG_CHECKS */ 88 | 89 | #define CHECK_I8_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, int8_t, PRIi8) 90 | #define CHECK_U8_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, uint8_t, PRIu8) 91 | #define CHECK_I16_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, int16_t, PRIi16) 92 | #define CHECK_U16_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, uint16_t, PRIu16) 93 | #define CHECK_I32_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, int32_t, PRIi32) 94 | #define CHECK_U32_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, uint32_t, PRIu32) 95 | #define CHECK_INT_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, int, "i") 96 | #define CHECK_UINT_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, unsigned, "u") 97 | #define CHECK_SIZE_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, size_t, PRIuMAX) 98 | #define CHECK_SSIZE_EQ(e, x) CHECK_NUMERIC_OP (==, e, x, ssize_t, PRIiMAX) 99 | 100 | #define CHECK_I8_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, int8_t, PRIi8) 101 | #define CHECK_U8_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, uint8_t, PRIu8) 102 | #define CHECK_I16_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, int16_t, PRIi16) 103 | #define CHECK_U16_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, uint16_t, PRIu16) 104 | #define CHECK_I32_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, int32_t, PRIi32) 105 | #define CHECK_U32_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, uint32_t, PRIu32) 106 | #define CHECK_INT_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, int, "i") 107 | #define CHECK_UINT_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, unsigned, "u") 108 | #define CHECK_SIZE_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, size_t, PRIuMAX) 109 | #define CHECK_SSIZE_NE(e, x) CHECK_NUMERIC_OP (!=, e, x, ssize_t, PRIiMAX) 110 | 111 | #define CHECK_I8_LT(e, x) CHECK_NUMERIC_OP (< , e, x, int8_t, PRIi8) 112 | #define CHECK_U8_LT(e, x) CHECK_NUMERIC_OP (< , e, x, uint8_t, PRIu8) 113 | #define CHECK_I16_LT(e, x) CHECK_NUMERIC_OP (< , e, x, int16_t, PRIi16) 114 | #define CHECK_U16_LT(e, x) CHECK_NUMERIC_OP (< , e, x, uint16_t, PRIu16) 115 | #define CHECK_I32_LT(e, x) CHECK_NUMERIC_OP (< , e, x, int32_t, PRIi32) 116 | #define CHECK_U32_LT(e, x) CHECK_NUMERIC_OP (< , e, x, uint32_t, PRIu32) 117 | #define CHECK_INT_LT(e, x) CHECK_NUMERIC_OP (< , e, x, int, "i") 118 | #define CHECK_UINT_LT(e, x) CHECK_NUMERIC_OP (< , e, x, unsigned, "u") 119 | #define CHECK_SIZE_LT(e, x) CHECK_NUMERIC_OP (< , e, x, size_t, PRIuMAX) 120 | #define CHECK_SSIZE_LT(e, x) CHECK_NUMERIC_OP (< , e, x, ssize_t, PRIiMAX) 121 | 122 | 123 | /* 124 | * Helper macros to create reference-counted structure types. First, the 125 | * REF_COUNTER macro adds a member in a struct for the reference counter: 126 | * 127 | * struct BigData { 128 | * REF_COUNTER; 129 | * // Other members. 130 | * } 131 | * 132 | * Then, functions to manage the reference counter can be created using 133 | * REF_COUNTER_FUNCTIONS, which receives as parameters the name of the 134 | * struct type and a prefix for the created functions: 135 | * 136 | * void big_data_free (struct BigData *data); 137 | * REF_COUNTER_FUNCTIONS (struct BigData, big_data) 138 | * 139 | * The functions declared by the above macro expansion will have the 140 | * following signatures: 141 | * 142 | * struct BigData* big_data_ref (struct BigData*); 143 | * void big_data_unref (struct BigData*); 144 | * 145 | * Optionally, the REF_COUNTER_FUNCTIONS accepts an additional parameter 146 | * which can be used to specify the storage class of the functions, so: 147 | * 148 | * REF_COUNTER_FUNCTIONS(struct BigData, big_data, static inline) 149 | * 150 | * will create the functions as: 151 | * 152 | * static inline struct BigData* big_data_ref (struct BigData*); 153 | * static inline void big_data_unref (struct BigData*); 154 | * 155 | * Note that the macro expects a big_data_free() function to be already 156 | * declared (or defined). That will be the function which gets called 157 | * when the reference counter hits 0 in order to free the struct BigData. 158 | * 159 | * Last, but not least, the REF_COUNTER_DECLARE_FUNCTIONS macro can be 160 | * used to only declare (but not define) the reference counting functions. 161 | * Like REF_COUNTER_FUNCTIONS, it accepts an optional parameter which can 162 | * be used to specify the storage class. This is typically used to declare 163 | * the functions in a header: 164 | * 165 | * REF_COUNTER_DECLARE_FUNCTIONS (struct BigData, big_data, extern) 166 | */ 167 | #ifndef REF_COUNTER_TYPE 168 | #define REF_COUNTER_TYPE unsigned int 169 | #endif /* !REF_COUNTER_TYPE */ 170 | 171 | #ifndef REF_COUNTER_NAME 172 | #define REF_COUNTER_NAME ref_counter 173 | #endif /* !REF_COUNTER_NAME */ 174 | 175 | #define REF_COUNTER \ 176 | REF_COUNTER_TYPE REF_COUNTER_NAME 177 | 178 | #define REF_COUNTER_FUNCTIONS(type, prefix, ...) \ 179 | __VA_ARGS__ type* prefix ## _ref (type* obj) { \ 180 | obj->REF_COUNTER_NAME++; return obj; \ 181 | } \ 182 | __VA_ARGS__ bool prefix ## _unref (type* obj) { \ 183 | if (--obj->REF_COUNTER_NAME == 0) { \ 184 | prefix ## _free (obj); \ 185 | return true; \ 186 | } \ 187 | return false; \ 188 | } 189 | 190 | #define REF_COUNTER_DECLARE_FUNCTIONS(type, prefix, ...) \ 191 | __VA_ARGS__ bool prefix ## _unref (type*); \ 192 | __VA_ARGS__ type* prefix ## _ref (type*) 193 | 194 | 195 | /* 196 | * Semi-automatic C memory cleanup using GCC/Clang's "cleanup" attribute. 197 | */ 198 | #define LAUTO(clean) __attribute__((cleanup(clean))) 199 | #define LMEM LAUTO(lauto_free) 200 | 201 | extern void lauto_free (void*); 202 | 203 | 204 | /* 205 | * Miscellaneous utilities. 206 | */ 207 | static inline bool 208 | string_equal (const char *a, 209 | const char *b) 210 | { 211 | return (a == b) || (a && b && strcmp (a, b) == 0); 212 | } 213 | 214 | #endif /* !EOL_UTIL_H */ 215 | -------------------------------------------------------------------------------- /eol-fcall-ffi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * eol-fcall-ffi.c 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "eol-fcall-ffi.h" 9 | 10 | 11 | /* 12 | * Counts the number of ffi_type items needed to represent a particular 13 | * struct. Note that this is particularly tricky because libffi has no 14 | * awareness of array types, so embedded, fixed-size arrays like the 15 | * following: 16 | * 17 | * struct Foo { void* userdata;, int values[2] }; 18 | * 19 | * has to be repsented like it was: 20 | * 21 | * struct Foo { 22 | * void* userdata; // elements[0] = &ffi_type_pointer 23 | * int values_0; // elements[1] = &ffi_type_sint 24 | * int values_1; // elements[2] = &ffi_type_sint 25 | * }; 26 | * 27 | * Note that while "struct Foo" has 2 members, we have to tell libffi 28 | * that it does have 3 elements. Otherwise libffi will not calculate the 29 | * correct size of the type. 30 | */ 31 | static inline uint32_t 32 | eol_ffi_struct_type_count_items (const EolTypeInfo *typeinfo) 33 | { 34 | typeinfo = eol_typeinfo_get_non_synthetic (typeinfo); 35 | uint32_t result = 0; 36 | 37 | const EolTypeInfoMember *member; 38 | EOL_TYPEINFO_COMPOUND_FOREACH_CONST_MEMBER (member, typeinfo) { 39 | const EolTypeInfo *T = 40 | eol_typeinfo_get_non_synthetic (member->typeinfo); 41 | 42 | if (eol_typeinfo_is_array (T)) { 43 | result += eol_typeinfo_array_n_items (T); 44 | } else { 45 | result++; 46 | } 47 | } 48 | return result; 49 | } 50 | 51 | 52 | static ffi_type* eol_ffi_get_type (const EolTypeInfo*); 53 | 54 | 55 | static inline ffi_type* 56 | eol_ffi_get_struct_type (const EolTypeInfo *typeinfo) 57 | { 58 | CHECK_NOT_NULL (typeinfo); 59 | CHECK_UINT_EQ (EOL_TYPE_STRUCT, eol_typeinfo_type (typeinfo)); 60 | 61 | uint32_t n_items = eol_ffi_struct_type_count_items (typeinfo); 62 | ffi_type *type = calloc (1, sizeof (ffi_type) + 63 | sizeof (ffi_type*) * (n_items + 1)); 64 | type->elements = (void*) &type[1]; 65 | type->type = FFI_TYPE_STRUCT; 66 | 67 | const EolTypeInfoMember *member; 68 | uint32_t element_index = 0; 69 | 70 | EOL_TYPEINFO_COMPOUND_FOREACH_CONST_MEMBER (member, typeinfo) { 71 | const EolTypeInfo *member_typeinfo = 72 | eol_typeinfo_get_non_synthetic (member->typeinfo); 73 | 74 | if (eol_typeinfo_is_array (member_typeinfo)) { 75 | ffi_type *item_type = 76 | eol_ffi_get_type (eol_typeinfo_base (member_typeinfo)); 77 | uint32_t n = eol_typeinfo_array_n_items (member_typeinfo); 78 | 79 | CHECK_UINT_LT (n_items, element_index + n); 80 | while (n--) { 81 | type->elements[element_index++] = item_type; 82 | CHECK_UINT_LT (n_items, element_index); 83 | } 84 | } else { 85 | type->elements[element_index++] = 86 | eol_ffi_get_type (member_typeinfo); 87 | } 88 | } 89 | CHECK_UINT_EQ (n_items, element_index); 90 | CHECK (type->elements[n_items] == NULL); 91 | 92 | return type; 93 | } 94 | 95 | 96 | static inline ffi_type* 97 | eol_ffi_get_array_type (const EolTypeInfo *typeinfo) 98 | { 99 | CHECK_NOT_NULL (typeinfo); 100 | CHECK_UINT_EQ (EOL_TYPE_ARRAY, eol_typeinfo_type (typeinfo)); 101 | 102 | ffi_type *base = eol_ffi_get_type (eol_typeinfo_base (typeinfo)); 103 | uint32_t n_items = eol_typeinfo_array_n_items (typeinfo); 104 | ffi_type* type = calloc (1, sizeof (ffi_type) + 105 | sizeof (ffi_type*) * (n_items + 1)); 106 | type->elements = (void*) &type[1]; 107 | type->type = FFI_TYPE_STRUCT; 108 | 109 | for (uint32_t i = 0; i < n_items; i++) { 110 | type->elements[i] = base; 111 | } 112 | CHECK (type->elements[n_items] == NULL); 113 | 114 | return type; 115 | } 116 | 117 | 118 | /* 119 | * As libffi does not know about unions, choose the biggest of the union 120 | * members to make sure it passes around a value big enough to hold any 121 | * of the possible values the union can hold. 122 | */ 123 | static inline ffi_type* 124 | eol_ffi_get_union_type (const EolTypeInfo *typeinfo) 125 | { 126 | CHECK_NOT_NULL (typeinfo); 127 | CHECK_UINT_EQ (EOL_TYPE_UNION, eol_typeinfo_type (typeinfo)); 128 | 129 | const EolTypeInfo *biggest_typeinfo = NULL; 130 | const EolTypeInfoMember *member; 131 | uint32_t biggest_size = 0; 132 | 133 | EOL_TYPEINFO_COMPOUND_FOREACH_CONST_MEMBER (member, typeinfo) { 134 | const uint32_t member_size = eol_typeinfo_sizeof (member->typeinfo); 135 | if (member_size > biggest_size) { 136 | biggest_typeinfo = member->typeinfo; 137 | biggest_size = member_size; 138 | } 139 | } 140 | 141 | return eol_ffi_get_type (biggest_typeinfo); 142 | } 143 | 144 | 145 | static ffi_type* 146 | eol_ffi_get_type (const EolTypeInfo *typeinfo) 147 | { 148 | CHECK_NOT_NULL (typeinfo); 149 | 150 | typeinfo = eol_typeinfo_get_non_synthetic (typeinfo); 151 | 152 | switch (eol_typeinfo_type (typeinfo)) { 153 | case EOL_TYPE_VOID: return &ffi_type_void; 154 | case EOL_TYPE_BOOL: return &ffi_type_uint8; 155 | case EOL_TYPE_S8: return &ffi_type_sint8; 156 | case EOL_TYPE_U8: return &ffi_type_uint8; 157 | case EOL_TYPE_S16: return &ffi_type_sint16; 158 | case EOL_TYPE_U16: return &ffi_type_uint16; 159 | case EOL_TYPE_S32: return &ffi_type_sint32; 160 | case EOL_TYPE_U32: return &ffi_type_uint32; 161 | case EOL_TYPE_S64: return &ffi_type_sint64; 162 | case EOL_TYPE_U64: return &ffi_type_uint64; 163 | case EOL_TYPE_FLOAT: return &ffi_type_float; 164 | case EOL_TYPE_DOUBLE: return &ffi_type_double; 165 | case EOL_TYPE_POINTER: return &ffi_type_pointer; 166 | case EOL_TYPE_STRUCT: return eol_ffi_get_struct_type (typeinfo); 167 | case EOL_TYPE_ARRAY: return eol_ffi_get_array_type (typeinfo); 168 | case EOL_TYPE_UNION: return eol_ffi_get_union_type (typeinfo); 169 | 170 | case EOL_TYPE_ENUM: 171 | /* Enums are passed as integers of the corresponding width. */ 172 | switch (eol_typeinfo_sizeof (typeinfo)) { 173 | case 1: return &ffi_type_sint8; 174 | case 2: return &ffi_type_sint16; 175 | case 4: return &ffi_type_sint32; 176 | case 8: return &ffi_type_sint64; 177 | } 178 | /* fall-through */ 179 | 180 | case EOL_TYPE_TYPEDEF: 181 | case EOL_TYPE_CONST: 182 | CHECK_UNREACHABLE (); 183 | 184 | default: 185 | TRACE (RED "Unsupported type: " NORMAL "%s\n", 186 | eol_typeinfo_name (typeinfo)); 187 | abort (); /* TODO: Handle a bit more gracefully. */ 188 | } 189 | } 190 | 191 | 192 | static void 193 | eol_fcall_ffi_map_types (EolFunction *ef) 194 | { 195 | CHECK_NOT_NULL (ef); 196 | 197 | if (ef->return_typeinfo) { 198 | ef->fcall_ffi_scratch_size = eol_typeinfo_sizeof (ef->return_typeinfo); 199 | ef->fcall_ffi_return_type = eol_ffi_get_type (ef->return_typeinfo); 200 | } else { 201 | ef->fcall_ffi_scratch_size = 0; 202 | ef->fcall_ffi_return_type = &ffi_type_void; 203 | } 204 | 205 | if (ef->n_param > 0) { 206 | ef->fcall_ffi_param_types = calloc (ef->n_param, sizeof (ffi_type*)); 207 | for (uint32_t i = 0; i < ef->n_param; i++) { 208 | ef->fcall_ffi_scratch_size += 209 | eol_typeinfo_sizeof (ef->param_types[i]); 210 | ef->fcall_ffi_param_types[i] = 211 | eol_ffi_get_type (ef->param_types[i]); 212 | } 213 | } 214 | 215 | ffi_status status = ffi_prep_cif (&ef->fcall_ffi_cif, 216 | FFI_DEFAULT_ABI, 217 | ef->n_param, 218 | ef->fcall_ffi_return_type, 219 | ef->fcall_ffi_param_types); 220 | if (status != FFI_OK) { 221 | TRACE ("%s(): cannot map typeinfos to FFI types\n", 222 | ef->name ? ef->name : "?"); 223 | /* TODO: Report instead of aborting. */ 224 | abort (); 225 | } 226 | } 227 | 228 | 229 | static int 230 | function_call (lua_State *L) 231 | { 232 | EolFunction *ef = to_eol_function (L); 233 | 234 | if (lua_gettop (L) - 1 != ef->n_param) { 235 | return luaL_error (L, "wrong number of parameters" 236 | " (given=%d, expected=%d)", 237 | lua_gettop (L) - 1, 238 | ef->n_param); 239 | } 240 | TRACE (BLUE "%s()" NORMAL ": FFI call address=%p\n", ef->name, ef->address); 241 | 242 | if (!ef->fcall_ffi_return_type) 243 | eol_fcall_ffi_map_types (ef); 244 | 245 | uintptr_t scratch[ef->fcall_ffi_scratch_size / sizeof (uintptr_t) + 1]; 246 | void *params[ef->n_param]; 247 | 248 | TRACE (FBLUE "%s()" NORMAL ": FFI scratch buffer size=%lu (requested=%lu)\n", 249 | ef->name, sizeof (scratch), ef->fcall_ffi_scratch_size); 250 | 251 | uintptr_t addr = (uintptr_t) scratch; 252 | if (ef->return_typeinfo) { 253 | addr += eol_typeinfo_sizeof (ef->return_typeinfo); 254 | } 255 | 256 | /* 257 | * Convert function arguments in C types. 258 | */ 259 | for (uint32_t i = 0; i < ef->n_param; i++) { 260 | params[i] = (void*) addr; 261 | TRACE (FBLUE "%s()" NORMAL ": Parameter %" PRIu32 ", type %s\n", 262 | ef->name, i, eol_typeinfo_name (ef->param_types[i])); 263 | cvalue_get (L, i + 2, ef->param_types[i], (void*) addr); 264 | addr += eol_typeinfo_sizeof (ef->param_types[i]); 265 | } 266 | 267 | TRACE (FBLUE "%s()" NORMAL ": Invoking ... ", ef->name); 268 | ffi_call (&ef->fcall_ffi_cif, ef->address, scratch, params); 269 | TRACE (">" BLUE "done\n" NORMAL); 270 | 271 | if (ef->return_typeinfo) { 272 | return cvalue_push (L, ef->return_typeinfo, scratch, 273 | VARIABLE_PUSH_COPY); 274 | } else { 275 | return 0; 276 | } 277 | } 278 | 279 | 280 | static inline void 281 | eol_fcall_ffi_init (EolFunction *ef) 282 | { 283 | /* 284 | * Zero ffi_type pointers, to mark FFI types to be filled-in 285 | * later on lazily, on the first call to the function. 286 | */ 287 | CHECK_NOT_NULL (ef); 288 | ef->fcall_ffi_return_type = NULL; 289 | ef->fcall_ffi_param_types = NULL; 290 | } 291 | 292 | 293 | static void 294 | eol_ffi_free_elements (ffi_type *type) 295 | { 296 | CHECK_NOT_NULL (type); 297 | 298 | if (type->type != FFI_TYPE_STRUCT) 299 | return; 300 | for (size_t i = 0; type->elements[i]; i++) 301 | eol_ffi_free_elements (type->elements[i]); 302 | free (type); 303 | } 304 | 305 | 306 | static inline void 307 | eol_fcall_ffi_free (EolFunction *ef) 308 | { 309 | CHECK_NOT_NULL (ef); 310 | 311 | if (!ef->fcall_ffi_return_type) 312 | return; 313 | 314 | eol_ffi_free_elements (ef->fcall_ffi_return_type); 315 | for (uint32_t i = 0; i < ef->n_param; i++) 316 | eol_ffi_free_elements (ef->fcall_ffi_param_types[i]); 317 | free (ef->fcall_ffi_param_types); 318 | } 319 | -------------------------------------------------------------------------------- /tools/harness.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- harness.lua 4 | -- Copyright (C) 2015 Adrian Perez 5 | -- 6 | -- Distributed under terms of the MIT license. 7 | -- 8 | 9 | local tu = require "testutil" 10 | 11 | 12 | local usage = [[ 13 | Usage: harness.lua [options] 14 | This script assumes that it is being run from the build output directory. 15 | Options: 16 | 17 | --output=FORMAT Output format (default: auto). 18 | --verbose Print additional messages. 19 | --list List names of all test cases. 20 | --commands Print commands used to run the test cases. 21 | --debug Run test case under a debugger. 22 | --debugger=CMD Use CMD as debugger command (default: gdb --args). 23 | --help Display this help message. 24 | 25 | Output formats: 26 | 27 | uterm UTF-8 terminal supporting ANSI color codes. 28 | tap Test Anything Protocol (http://www.testanything.org) 29 | auto Use "uterm" when outputting to a terminal, "tap" otherwise. 30 | 31 | ]] 32 | 33 | 34 | local function die(fmt, ...) 35 | io.stderr:write(fmt:format(...)) 36 | os.exit(1) 37 | end 38 | 39 | 40 | if #arg < 2 then 41 | die(usage) 42 | end 43 | 44 | 45 | local tests = {} 46 | local options = { 47 | debugger = "gdb --args", 48 | output = "auto", 49 | commands = false, 50 | verbose = false, 51 | debug = false, 52 | list = false, 53 | } 54 | 55 | 56 | local function printf(fmt, ...) 57 | io.stdout:write(fmt:format(...)) 58 | end 59 | 60 | local function verbose(fmt, ...) 61 | if options.verbose then 62 | io.stdout:write(fmt:format(...)) 63 | end 64 | end 65 | 66 | 67 | for i = 3, #arg do 68 | local opt = arg[i] 69 | if opt == "-h" or opt == "--help" then 70 | io.stdout:write(usage) 71 | os.exit(0) 72 | end 73 | 74 | -- Try a flag with value first. If there is no match, then try for a 75 | -- boolean flag. If neither matches, assume the option is a test name. 76 | 77 | local name, value = opt:match("^%-%-(%w[%w%-]*)=(.+)$") 78 | if name == nil then 79 | name = opt:match("^%-%-(%w[%w%-]*)$") 80 | end 81 | 82 | if name == nil then 83 | -- Test name. 84 | tests[#tests + 1] = opt 85 | elseif options[name] == nil then 86 | -- Flag looks like an option, but it is an unrecognized one. 87 | io.stderr:write("Invalid command line option: " .. opt .. "\n") 88 | io.stderr:write(usage) 89 | os.exit(1) 90 | elseif value == nil then 91 | -- Boolean flag. 92 | options[name] = not options[name] 93 | else 94 | -- Flag with value 95 | options[name] = value 96 | end 97 | end 98 | 99 | 100 | local LUA_EXE = os.getenv("EOL_LUA_EXE") 101 | if LUA_EXE == nil then 102 | die("Environment variable LUA_EXE is undefined") 103 | end 104 | 105 | 106 | local object = { 107 | clone = function (self, t) 108 | local clone = {} 109 | setmetatable(clone, { __index = self }) 110 | if type(t) == "table" then 111 | for k, v in pairs(t) do 112 | clone[k] = v 113 | end 114 | end 115 | return clone 116 | end; 117 | 118 | prototype = function(self) 119 | local meta = getmetatable(self) 120 | return meta and meta.__index or nil 121 | end; 122 | 123 | extends = function (self, obj) 124 | local meta = getmetatable(self) 125 | while true do 126 | if not (meta and meta.__index) then 127 | return false 128 | end 129 | if meta.__index == obj then 130 | return true 131 | end 132 | meta = getmetatable(meta.__index) 133 | end 134 | end; 135 | } 136 | 137 | 138 | local BaseOutput = object:clone() 139 | 140 | function BaseOutput:setup(tests) 141 | self.succeeded = {} 142 | self.failed = {} 143 | self.skipped = {} 144 | end 145 | 146 | function BaseOutput:start(test) 147 | -- No-op 148 | end 149 | 150 | function BaseOutput:finish(test) 151 | if test.status == "success" then 152 | self.succeeded[#self.succeeded + 1] = test 153 | elseif test.status == "failure" then 154 | self.failed[#self.failed + 1] = test 155 | elseif test.status == "skip" then 156 | self.skipped[#self.skipped + 1] = test 157 | else 158 | assert(false, "invalid status") 159 | end 160 | end 161 | 162 | function BaseOutput:report() 163 | -- No-op 164 | end 165 | 166 | 167 | local TAPOutput = BaseOutput:clone { 168 | success = "ok %u - %s\n", 169 | skip = "ok %u - # SKIP %s\n", 170 | failure = "not ok %u - %s\n", 171 | } 172 | 173 | function TAPOutput:setup(tests) 174 | self:prototype().setup(self, tests) 175 | self.counter = 0 176 | printf("1..%u\n", #tests) 177 | end 178 | 179 | function TAPOutput:start(test) 180 | self:prototype().start(self, test) 181 | end 182 | 183 | function TAPOutput:finish(test) 184 | self:prototype().finish(self, test) 185 | self.counter = self.counter + 1 186 | if test.status == "success" then 187 | printf(self.success, self.counter, test.name) 188 | if options.verbose and test.output ~= nil and #test.output > 0 then 189 | printf("# %s\n", test.output:gsub("\n", "\n# ")) 190 | end 191 | elseif test.status == "failure" then 192 | printf(self.failure, self.counter, test.name) 193 | if test.signal then 194 | verbose("# Exited due to signal %s, output:\n", test.exitcode) 195 | else 196 | verbose("# Exited with code %i, output:\n", test.exitcode) 197 | end 198 | -- Output of failed tests is always written. 199 | if test.output ~= nil and #test.output > 0 then 200 | printf("# %s\n", test.output:gsub("\n", "\n# ")) 201 | else 202 | verbose("# (no output)\n") 203 | end 204 | elseif test.status == "skip" then 205 | printf(self.skip, self.counter, test.name) 206 | else 207 | assert(false, "invalid status") 208 | end 209 | end 210 | 211 | 212 | local CSI_data = { 213 | -- Formats for character attributes. 214 | F_normal = "[%um%s", 215 | F_bold = "[1;%um%s", 216 | 217 | -- Formats for cursor movement. 218 | M_up = "[%uA", 219 | M_down = "[%uB", 220 | M_right = "[%uC", 221 | M_left = "[%uD", 222 | M_column = "[%uG", 223 | 224 | -- Color constants. 225 | C_black = 30, 226 | C_red = 31, 227 | C_green = 32, 228 | C_brown = 33, 229 | C_blue = 34, 230 | C_magenta = 35, 231 | C_cyan = 36, 232 | C_white = 37, 233 | 234 | -- Actions which do not require parameters. 235 | erase = "", 236 | eraseline = "", 237 | savepos = "", 238 | restorepos = "", 239 | } 240 | 241 | local CSI = setmetatable({}, { __index = CSI_data }) 242 | for k, v in pairs(CSI_data) do 243 | local function make_movement_func(format, move) 244 | return function (n) 245 | return format:format(n) 246 | end 247 | end 248 | 249 | if k:sub(0, 2) == "C_" then 250 | k = k:sub(3) 251 | CSI[k] = function (txt) 252 | return CSI_data.F_normal:format(v, txt) 253 | end 254 | CSI[k .. "bg"] = function (txt) 255 | return CSI_data.F_normal:format(v + 10, txt) 256 | end 257 | CSI["bold" .. k] = function (txt) 258 | return CSI_data.F_bold:format(v, txt) 259 | end 260 | CSI["bold" .. k .. "bg"] = function (txt) 261 | return CSI_data.F_bold:format(v + 10, txt) 262 | end 263 | elseif k:sub(0, 2) == "M_" then 264 | k = k:sub(3) 265 | CSI[k] = make_movement_func(v, k) 266 | end 267 | end 268 | 269 | 270 | local Utf8TermOutput = BaseOutput:clone { 271 | dot_success = CSI.boldgreen "●", 272 | dot_failure = CSI.boldred "◼", 273 | dot_skip = CSI.boldbrown "✱", 274 | dot_pending = CSI.boldcyan "◌", 275 | } 276 | 277 | function Utf8TermOutput:setup(tests) 278 | self:prototype().setup(self, tests) 279 | self.counter = 0 280 | self.total = #tests 281 | end 282 | 283 | function Utf8TermOutput:start(test) 284 | self:prototype().start(self, test) 285 | self.counter = self.counter + 1 286 | local progress = CSI.boldblue(("[%u/%u]"):format(self.counter, self.total)) 287 | printf("%s%s %s %s%s", CSI.column(2), self.dot_pending, 288 | test.name, progress, CSI.erase) 289 | io.stdout:flush() 290 | end 291 | 292 | function Utf8TermOutput:finish(test) 293 | self:prototype().finish(self, test) 294 | local statusdot = self["dot_" .. test.status] 295 | printf("%s%s%s%s%s", CSI.savepos, CSI.column(2), 296 | statusdot, CSI.restorepos, CSI.erase) 297 | if test.status ~= "success" then 298 | printf("\n") 299 | if test.status == "failure" and test.output ~= nil and #test.output > 0 then 300 | printf("%s", CSI.white(test.output)) 301 | end 302 | end 303 | io.stdout:flush() 304 | end 305 | 306 | function Utf8TermOutput:report() 307 | self:prototype().report(self) 308 | if #self.failed > 0 or #self.skipped > 0 then 309 | printf("\n") 310 | else 311 | printf("%s%s", CSI.column(1), CSI.erase) 312 | end 313 | if options.verbose and #self.failed > 0 then 314 | printf("Failed tests:\n") 315 | for _, test in ipairs(self.failed) do 316 | printf(" %s\n", CSI.red(test.name)) 317 | end 318 | printf("\n") 319 | end 320 | printf(" %s %u %s %u %s %u\n", 321 | self.dot_success, #self.succeeded, 322 | self.dot_skip, #self.skipped, 323 | self.dot_failure, #self.failed) 324 | end 325 | 326 | 327 | -- Pick the output format 328 | local outputs = { tap = TAPOutput, uterm = Utf8TermOutput } 329 | local supports_uterm = { "xterm", "uxterm", "screen", "st", "tmux" } 330 | function detect_uterm() 331 | if not tu.isatty(io.stdout) then 332 | return false 333 | end 334 | 335 | local term = os.getenv("TERM") 336 | if term == nil or #term == 0 then 337 | return false 338 | end 339 | 340 | for _, t in ipairs(supports_uterm) do 341 | if term == t then 342 | return true 343 | end 344 | if term:sub(0, #t + 1) == t .. "-" then 345 | return true 346 | end 347 | end 348 | return false 349 | end 350 | 351 | if options.output == "auto" then 352 | options.output = detect_uterm() and "uterm" or "tap" 353 | end 354 | 355 | local output = outputs[options.output] 356 | if output == nil then 357 | io.stderr:write("Invalid output format: " .. options.output .. "\n") 358 | os.exit(2) 359 | end 360 | 361 | 362 | local Test = object:clone { 363 | status = "skip", -- Values: "skip", "success", "failure" 364 | skip = false, -- Set to "true" for skipped tests 365 | signal = false, -- Set to "true" 366 | 367 | command = function (self) 368 | return "'" .. LUA_EXE .. "' '" .. self.file .. "'" 369 | end, 370 | 371 | run = function (self) 372 | assert(not self.skip, "Test should have been skipped") 373 | 374 | local fd = io.popen(self:command() .. " 2>&1") 375 | self.output = fd:read("*a") 376 | local success, reason, exitcode = fd:close() 377 | 378 | -- TODO: Support "expected-to-fail" tests, which invert 379 | -- the final resulting status. 380 | self.status = success and "success" or "failure" 381 | self.signal = reason == "signal" 382 | self.exitcode = exitcode 383 | end, 384 | } 385 | 386 | 387 | local scan_tests = options.list or #tests == 0 388 | if scan_tests then 389 | -- No test names given in the command line: scan the tests directory. 390 | for i, filename in ipairs(tu.listdir(arg[1] .. "/test")) do 391 | local testname = filename:match("^([%w%-]+)%.lua$") 392 | if testname then 393 | -- Got a valid test file name, pick it. 394 | filename = tu.realpath(arg[1] .. "/test/" .. filename) 395 | tests[#tests + 1] = Test:clone { name = testname, file = filename } 396 | end 397 | end 398 | else 399 | -- Test names given in the command line: validate that files exist. 400 | local valid = {} 401 | for i, testname in ipairs(tests) do 402 | local filename = arg[1] .. "/test/" .. testname .. ".lua" 403 | if tu.isfile(filename) then 404 | filename = tu.realpath(filename) 405 | valid[#valid + 1] = Test:clone { name = testname, file = filename } 406 | else 407 | io.stderr:write("Invalid test: " .. testname .. " (skipping)\n") 408 | end 409 | end 410 | tests = valid 411 | end 412 | 413 | 414 | table.sort(tests, function (a, b) return a.name < b.name end) 415 | 416 | if options.list then 417 | for _, test in ipairs(tests) do 418 | print(test.name) 419 | end 420 | elseif options.debug then 421 | if #tests > 1 then 422 | die("Running a debugger supports only a single test case.\n"); 423 | end 424 | local command = options.debugger .. " " .. tests[1]:command() 425 | verbose("LUA_INIT='%s'\n", os.getenv("LUA_INIT") or "") 426 | printf("Debug command: %s\n", command) 427 | os.execute(command) 428 | elseif options.commands then 429 | local lua_init = os.getenv("LUA_INIT") 430 | local cwd = tu.getcwd() 431 | if lua_init then 432 | lua_init = "LUA_INIT='" .. lua_init .. "' " 433 | else 434 | lua_init = "" 435 | end 436 | lua_init = "cd '" .. cwd .. "' && " .. lua_init 437 | for _, test in ipairs(tests) do 438 | if not test.skip or not scan_tests then 439 | print(lua_init .. test:command()) 440 | end 441 | end 442 | else 443 | output:setup(tests) 444 | for _, test in ipairs(tests) do 445 | output:start(test) 446 | -- When test names are given in the command line (i.e. not 447 | -- scanned from the tests directory), tests are always run. 448 | if not test.skip or not scan_tests then 449 | test:run() 450 | end 451 | output:finish(test) 452 | end 453 | output:report() 454 | if #output.failed > 0 then 455 | os.exit(1) 456 | end 457 | end 458 | -------------------------------------------------------------------------------- /dynasm/dasm_ppc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM PPC encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT 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 | /* Bkwd rel or global. */ 206 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 207 | pl += 10; n = *pl; 208 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 209 | goto linkrel; 210 | case DASM_REL_PC: 211 | pl = D->pclabels + n; CKPL(pc, PC); 212 | putrel: 213 | n = *pl; 214 | if (n < 0) { /* Label exists. Get label pos and store it. */ 215 | b[pos] = -n; 216 | } else { 217 | linkrel: 218 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 219 | *pl = pos; 220 | } 221 | pos++; 222 | break; 223 | case DASM_LABEL_LG: 224 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 225 | case DASM_LABEL_PC: 226 | pl = D->pclabels + n; CKPL(pc, PC); 227 | putlabel: 228 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 229 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 230 | } 231 | *pl = -pos; /* Label exists now. */ 232 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 233 | break; 234 | case DASM_IMM: 235 | #ifdef DASM_CHECKS 236 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 237 | #endif 238 | n >>= ((ins>>10)&31); 239 | #ifdef DASM_CHECKS 240 | if (ins & 0x8000) 241 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 242 | else 243 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 244 | #endif 245 | b[pos++] = n; 246 | break; 247 | } 248 | } 249 | } 250 | stop: 251 | va_end(ap); 252 | sec->pos = pos; 253 | sec->ofs = ofs; 254 | } 255 | #undef CK 256 | 257 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 258 | int dasm_link(Dst_DECL, size_t *szp) 259 | { 260 | dasm_State *D = Dst_REF; 261 | int secnum; 262 | int ofs = 0; 263 | 264 | #ifdef DASM_CHECKS 265 | *szp = 0; 266 | if (D->status != DASM_S_OK) return D->status; 267 | { 268 | int pc; 269 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 270 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 271 | } 272 | #endif 273 | 274 | { /* Handle globals not defined in this translation unit. */ 275 | int idx; 276 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 277 | int n = D->lglabels[idx]; 278 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 279 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 280 | } 281 | } 282 | 283 | /* Combine all code sections. No support for data sections (yet). */ 284 | for (secnum = 0; secnum < D->maxsection; secnum++) { 285 | dasm_Section *sec = D->sections + secnum; 286 | int *b = sec->rbuf; 287 | int pos = DASM_SEC2POS(secnum); 288 | int lastpos = sec->pos; 289 | 290 | while (pos != lastpos) { 291 | dasm_ActList p = D->actionlist + b[pos++]; 292 | while (1) { 293 | unsigned int ins = *p++; 294 | unsigned int action = (ins >> 16); 295 | switch (action) { 296 | case DASM_STOP: case DASM_SECTION: goto stop; 297 | case DASM_ESC: p++; break; 298 | case DASM_REL_EXT: break; 299 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 300 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 301 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 302 | case DASM_IMM: pos++; break; 303 | } 304 | } 305 | stop: (void)0; 306 | } 307 | ofs += sec->ofs; /* Next section starts right after current section. */ 308 | } 309 | 310 | D->codesize = ofs; /* Total size of all code sections */ 311 | *szp = ofs; 312 | return DASM_S_OK; 313 | } 314 | 315 | #ifdef DASM_CHECKS 316 | #define CK(x, st) \ 317 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 318 | #else 319 | #define CK(x, st) ((void)0) 320 | #endif 321 | 322 | /* Pass 3: Encode sections. */ 323 | int dasm_encode(Dst_DECL, void *buffer) 324 | { 325 | dasm_State *D = Dst_REF; 326 | char *base = (char *)buffer; 327 | unsigned int *cp = (unsigned int *)buffer; 328 | int secnum; 329 | 330 | /* Encode all code sections. No support for data sections (yet). */ 331 | for (secnum = 0; secnum < D->maxsection; secnum++) { 332 | dasm_Section *sec = D->sections + secnum; 333 | int *b = sec->buf; 334 | int *endb = sec->rbuf + sec->pos; 335 | 336 | while (b != endb) { 337 | dasm_ActList p = D->actionlist + *b++; 338 | while (1) { 339 | unsigned int ins = *p++; 340 | unsigned int action = (ins >> 16); 341 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 342 | switch (action) { 343 | case DASM_STOP: case DASM_SECTION: goto stop; 344 | case DASM_ESC: *cp++ = *p++; break; 345 | case DASM_REL_EXT: 346 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; 347 | goto patchrel; 348 | case DASM_ALIGN: 349 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; 350 | break; 351 | case DASM_REL_LG: 352 | CK(n >= 0, UNDEF_LG); 353 | case DASM_REL_PC: 354 | CK(n >= 0, UNDEF_PC); 355 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); 356 | patchrel: 357 | CK((n & 3) == 0 && 358 | (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> 359 | ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); 360 | cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); 361 | break; 362 | case DASM_LABEL_LG: 363 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 364 | break; 365 | case DASM_LABEL_PC: break; 366 | case DASM_IMM: 367 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); 368 | break; 369 | default: *cp++ = ins; break; 370 | } 371 | } 372 | stop: (void)0; 373 | } 374 | } 375 | 376 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 377 | return DASM_S_PHASE; 378 | return DASM_S_OK; 379 | } 380 | #undef CK 381 | 382 | /* Get PC label offset. */ 383 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 384 | { 385 | dasm_State *D = Dst_REF; 386 | if (pc*sizeof(int) < D->pcsize) { 387 | int pos = D->pclabels[pc]; 388 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 389 | if (pos > 0) return -1; /* Undefined. */ 390 | } 391 | return -2; /* Unused or out of range. */ 392 | } 393 | 394 | #ifdef DASM_CHECKS 395 | /* Optional sanity checker to call between isolated encoding steps. */ 396 | int dasm_checkstep(Dst_DECL, int secmatch) 397 | { 398 | dasm_State *D = Dst_REF; 399 | if (D->status == DASM_S_OK) { 400 | int i; 401 | for (i = 1; i <= 9; i++) { 402 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 403 | D->lglabels[i] = 0; 404 | } 405 | } 406 | if (D->status == DASM_S_OK && secmatch >= 0 && 407 | D->section != &D->sections[secmatch]) 408 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 409 | return D->status; 410 | } 411 | #endif 412 | 413 | -------------------------------------------------------------------------------- /dynasm/dasm_mips.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM MIPS encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "mips" 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) - 0xff00; 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 | /* Bkwd rel or global. */ 206 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 207 | pl += 10; n = *pl; 208 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 209 | goto linkrel; 210 | case DASM_REL_PC: 211 | pl = D->pclabels + n; CKPL(pc, PC); 212 | putrel: 213 | n = *pl; 214 | if (n < 0) { /* Label exists. Get label pos and store it. */ 215 | b[pos] = -n; 216 | } else { 217 | linkrel: 218 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 219 | *pl = pos; 220 | } 221 | pos++; 222 | break; 223 | case DASM_LABEL_LG: 224 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 225 | case DASM_LABEL_PC: 226 | pl = D->pclabels + n; CKPL(pc, PC); 227 | putlabel: 228 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 229 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 230 | } 231 | *pl = -pos; /* Label exists now. */ 232 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 233 | break; 234 | case DASM_IMM: 235 | #ifdef DASM_CHECKS 236 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 237 | #endif 238 | n >>= ((ins>>10)&31); 239 | #ifdef DASM_CHECKS 240 | if (ins & 0x8000) 241 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 242 | else 243 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 244 | #endif 245 | b[pos++] = n; 246 | break; 247 | } 248 | } 249 | } 250 | stop: 251 | va_end(ap); 252 | sec->pos = pos; 253 | sec->ofs = ofs; 254 | } 255 | #undef CK 256 | 257 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 258 | int dasm_link(Dst_DECL, size_t *szp) 259 | { 260 | dasm_State *D = Dst_REF; 261 | int secnum; 262 | int ofs = 0; 263 | 264 | #ifdef DASM_CHECKS 265 | *szp = 0; 266 | if (D->status != DASM_S_OK) return D->status; 267 | { 268 | int pc; 269 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 270 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 271 | } 272 | #endif 273 | 274 | { /* Handle globals not defined in this translation unit. */ 275 | int idx; 276 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 277 | int n = D->lglabels[idx]; 278 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 279 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 280 | } 281 | } 282 | 283 | /* Combine all code sections. No support for data sections (yet). */ 284 | for (secnum = 0; secnum < D->maxsection; secnum++) { 285 | dasm_Section *sec = D->sections + secnum; 286 | int *b = sec->rbuf; 287 | int pos = DASM_SEC2POS(secnum); 288 | int lastpos = sec->pos; 289 | 290 | while (pos != lastpos) { 291 | dasm_ActList p = D->actionlist + b[pos++]; 292 | while (1) { 293 | unsigned int ins = *p++; 294 | unsigned int action = (ins >> 16) - 0xff00; 295 | switch (action) { 296 | case DASM_STOP: case DASM_SECTION: goto stop; 297 | case DASM_ESC: p++; break; 298 | case DASM_REL_EXT: break; 299 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 300 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 301 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 302 | case DASM_IMM: pos++; break; 303 | } 304 | } 305 | stop: (void)0; 306 | } 307 | ofs += sec->ofs; /* Next section starts right after current section. */ 308 | } 309 | 310 | D->codesize = ofs; /* Total size of all code sections */ 311 | *szp = ofs; 312 | return DASM_S_OK; 313 | } 314 | 315 | #ifdef DASM_CHECKS 316 | #define CK(x, st) \ 317 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 318 | #else 319 | #define CK(x, st) ((void)0) 320 | #endif 321 | 322 | /* Pass 3: Encode sections. */ 323 | int dasm_encode(Dst_DECL, void *buffer) 324 | { 325 | dasm_State *D = Dst_REF; 326 | char *base = (char *)buffer; 327 | unsigned int *cp = (unsigned int *)buffer; 328 | int secnum; 329 | 330 | /* Encode all code sections. No support for data sections (yet). */ 331 | for (secnum = 0; secnum < D->maxsection; secnum++) { 332 | dasm_Section *sec = D->sections + secnum; 333 | int *b = sec->buf; 334 | int *endb = sec->rbuf + sec->pos; 335 | 336 | while (b != endb) { 337 | dasm_ActList p = D->actionlist + *b++; 338 | while (1) { 339 | unsigned int ins = *p++; 340 | unsigned int action = (ins >> 16) - 0xff00; 341 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 342 | switch (action) { 343 | case DASM_STOP: case DASM_SECTION: goto stop; 344 | case DASM_ESC: *cp++ = *p++; break; 345 | case DASM_REL_EXT: 346 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); 347 | goto patchrel; 348 | case DASM_ALIGN: 349 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; 350 | break; 351 | case DASM_REL_LG: 352 | CK(n >= 0, UNDEF_LG); 353 | case DASM_REL_PC: 354 | CK(n >= 0, UNDEF_PC); 355 | n = *DASM_POS2PTR(D, n); 356 | if (ins & 2048) 357 | n = n - (int)((char *)cp - base); 358 | else 359 | n = (n + (int)base) & 0x0fffffff; 360 | patchrel: 361 | CK((n & 3) == 0 && 362 | ((n + ((ins & 2048) ? 0x00020000 : 0)) >> 363 | ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); 364 | cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); 365 | break; 366 | case DASM_LABEL_LG: 367 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 368 | break; 369 | case DASM_LABEL_PC: break; 370 | case DASM_IMM: 371 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); 372 | break; 373 | default: *cp++ = ins; break; 374 | } 375 | } 376 | stop: (void)0; 377 | } 378 | } 379 | 380 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 381 | return DASM_S_PHASE; 382 | return DASM_S_OK; 383 | } 384 | #undef CK 385 | 386 | /* Get PC label offset. */ 387 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 388 | { 389 | dasm_State *D = Dst_REF; 390 | if (pc*sizeof(int) < D->pcsize) { 391 | int pos = D->pclabels[pc]; 392 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 393 | if (pos > 0) return -1; /* Undefined. */ 394 | } 395 | return -2; /* Unused or out of range. */ 396 | } 397 | 398 | #ifdef DASM_CHECKS 399 | /* Optional sanity checker to call between isolated encoding steps. */ 400 | int dasm_checkstep(Dst_DECL, int secmatch) 401 | { 402 | dasm_State *D = Dst_REF; 403 | if (D->status == DASM_S_OK) { 404 | int i; 405 | for (i = 1; i <= 9; i++) { 406 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 407 | D->lglabels[i] = 0; 408 | } 409 | } 410 | if (D->status == DASM_S_OK && secmatch >= 0 && 411 | D->section != &D->sections[secmatch]) 412 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 413 | return D->status; 414 | } 415 | #endif 416 | 417 | -------------------------------------------------------------------------------- /dynasm/dasm_arm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM ARM encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT 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_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, 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 | /* Bkwd rel or global. */ 215 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 216 | pl += 10; n = *pl; 217 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 218 | goto linkrel; 219 | case DASM_REL_PC: 220 | pl = D->pclabels + n; CKPL(pc, PC); 221 | putrel: 222 | n = *pl; 223 | if (n < 0) { /* Label exists. Get label pos and store it. */ 224 | b[pos] = -n; 225 | } else { 226 | linkrel: 227 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 228 | *pl = pos; 229 | } 230 | pos++; 231 | break; 232 | case DASM_LABEL_LG: 233 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 234 | case DASM_LABEL_PC: 235 | pl = D->pclabels + n; CKPL(pc, PC); 236 | putlabel: 237 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 238 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 239 | } 240 | *pl = -pos; /* Label exists now. */ 241 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 242 | break; 243 | case DASM_IMM: 244 | case DASM_IMM16: 245 | #ifdef DASM_CHECKS 246 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 247 | if ((ins & 0x8000)) 248 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 249 | else 250 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 251 | #endif 252 | b[pos++] = n; 253 | break; 254 | case DASM_IMMV8: 255 | CK((n & 3) == 0, RANGE_I); 256 | n >>= 2; 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_IMM: case DASM_IMM12: case DASM_IMM16: 323 | case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: 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 if ((ins & 0x2000) == 0) { 385 | CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); 386 | goto patchimml; 387 | } else { 388 | CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); 389 | n >>= 2; 390 | goto patchimml; 391 | } 392 | break; 393 | case DASM_LABEL_LG: 394 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 395 | break; 396 | case DASM_LABEL_PC: break; 397 | case DASM_IMM: 398 | cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); 399 | break; 400 | case DASM_IMM12: 401 | cp[-1] |= dasm_imm12((unsigned int)n); 402 | break; 403 | case DASM_IMM16: 404 | cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); 405 | break; 406 | case DASM_IMML8: patchimml8: 407 | cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : 408 | ((-n & 0x0f) | ((-n & 0xf0) << 4)); 409 | break; 410 | case DASM_IMML12: case DASM_IMMV8: patchimml: 411 | cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); 412 | break; 413 | default: *cp++ = ins; break; 414 | } 415 | } 416 | stop: (void)0; 417 | } 418 | } 419 | 420 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 421 | return DASM_S_PHASE; 422 | return DASM_S_OK; 423 | } 424 | #undef CK 425 | 426 | /* Get PC label offset. */ 427 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 428 | { 429 | dasm_State *D = Dst_REF; 430 | if (pc*sizeof(int) < D->pcsize) { 431 | int pos = D->pclabels[pc]; 432 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 433 | if (pos > 0) return -1; /* Undefined. */ 434 | } 435 | return -2; /* Unused or out of range. */ 436 | } 437 | 438 | #ifdef DASM_CHECKS 439 | /* Optional sanity checker to call between isolated encoding steps. */ 440 | int dasm_checkstep(Dst_DECL, int secmatch) 441 | { 442 | dasm_State *D = Dst_REF; 443 | if (D->status == DASM_S_OK) { 444 | int i; 445 | for (i = 1; i <= 9; i++) { 446 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 447 | D->lglabels[i] = 0; 448 | } 449 | } 450 | if (D->status == DASM_S_OK && secmatch >= 0 && 451 | D->section != &D->sections[secmatch]) 452 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 453 | return D->status; 454 | } 455 | #endif 456 | 457 | --------------------------------------------------------------------------------