├── .gitignore ├── .gitmodules ├── Makefile ├── dynasm ├── dasm_x64.lua ├── dasm_proto.h ├── dasm_ppc.h ├── dasm_mips.h ├── dasm_arm.h ├── dasm_x86.h ├── dasm_mips.lua ├── dynasm.lua └── dasm_arm.lua ├── test.lua ├── README.md ├── lvm_jit.c ├── lvm_x64.dasc └── lvm_x64.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.dSYM 3 | *.o -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lua"] 2 | path = lua 3 | url = git@github.com:lua/lua.git 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY : macosx linux clean 2 | 3 | macosx: 4 | clang -Wall -g -O2 -shared -undefined dynamic_lookup -o lvmjit.so lvm_jit.c -Ilua/ 5 | 6 | linux: 7 | gcc -Wall -g -O2 -fPIC -shared -o lvmjit.so lvm_jit.c -Ilua/ 8 | 9 | lvmjit: 10 | cd dynasm && luajit dynasm.lua -o ../lvm_x64.h ../lvm_x64.dasc 11 | 12 | test: 13 | ../lua/lua-5.4.0/src/lua test.lua -------------------------------------------------------------------------------- /dynasm/dasm_x64.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM x64 module. 3 | -- 4 | -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | -- This module just sets 64 bit mode for the combined x86/x64 module. 8 | -- All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | x64 = true -- Using a global is an ugly, but effective solution. 12 | return require("dasm_x86") 13 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | local lvmjit = require "lvmjit.core" 2 | 3 | local function foo(a, b) 4 | local sum = a + b 5 | local d = 1 6 | for i=1,400000000 do 7 | sum = sum + d 8 | end 9 | return sum 10 | end 11 | 12 | local cfoo = lvmjit.compile(foo) 13 | 14 | local b = os.clock() 15 | local v = foo(11.2, 22) 16 | local e = os.clock() 17 | local c1 = e - b 18 | print("origin lua cost time:", c1) 19 | 20 | local b = os.clock() 21 | local v2 = cfoo(11.2, 22) 22 | local e = os.clock() 23 | local c2 = e - b 24 | print("lvmjit lua cost time:", c2) 25 | 26 | assert(v == v2) 27 | local p = (c1-c2)/c1 * 100 28 | print(string.format("result:%s\nup:%.2f%%", v, p)) 29 | -- print(v, type(v), v(11, 22)) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lvmjit 2 | 3 | compilation lua fucntion during execution of lua program at run time. 4 | 5 | ### tutorail 6 | ~~~.lua 7 | local lvmjit = require "lvmjit.core" 8 | 9 | local function func(...) 10 | -- do something.. 11 | end 12 | 13 | local cfunc = lvmjit.compile(func) 14 | cfunc(...) 15 | ~~~ 16 | 17 | ### benchmark 18 | test lua case in `test.lua` in my `3 GHz Intel Core i7` CPU 19 | 20 | ~~~.lua 21 | local function foo(a, b) 22 | local sum = a + b 23 | local d = 1 24 | for i=1,400000000 do 25 | sum = sum + d 26 | end 27 | return sum 28 | end 29 | ~~~ 30 | 31 | | type | cost | up | 32 | |:----:|:-----:|:---:| 33 | | origin lua5.4 | `2.63411s` | `0%` | 34 | | lvmjit lua5.4 | `1.950952s` | `25.94%` | 35 | 36 | ### support opcode 37 | 38 | | opcode | status | 39 | |:------:|:-------:| 40 | | `OP_MOVE` | YES | 41 | | `OP_LOADI` | YES | 42 | | `OP_RETURN0` | YES | 43 | | `OP_RETURN1` | YES | 44 | | `OP_RETURN` | YES | 45 | | `OP_ADD` | YES | 46 | | `OP_FORPREP` | YES | 47 | | `OP_FORLOOP` | YES | 48 | | `OP_LOADK` | YES | 49 | | `OTHER OPCODE` | NO | 50 | 51 | ### linux platform 52 | 53 | instead `LUAI_FUNC` macro `extern` of `__attribute__((visibility("internal"))) extern` in `luaconf.h`. 54 | -------------------------------------------------------------------------------- /dynasm/dasm_proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM encoding engine prototypes. 3 | ** Copyright (C) 2005-2017 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 | -------------------------------------------------------------------------------- /lvm_jit.c: -------------------------------------------------------------------------------- 1 | #include "dynasm/dasm_proto.h" 2 | #include "dynasm/dasm_x86.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "lua.h" 11 | #include "lauxlib.h" 12 | #include "lualib.h" 13 | 14 | #include "lgc.h" 15 | #include "ldo.h" 16 | #include "lvm.h" 17 | #include "lfunc.h" 18 | #include "ldebug.h" 19 | #include "lstate.h" 20 | #include "lobject.h" 21 | #include "lopcodes.h" 22 | #include "lopnames.h" 23 | 24 | 25 | struct lvmjit_context { 26 | dasm_State* ds; 27 | unsigned int maxpc; 28 | }; 29 | 30 | typedef void (*jitcode_func)(lua_State *L, CallInfo *ci); 31 | 32 | struct lvmjit_compile { 33 | Proto* p; 34 | jitcode_func jitcodes; 35 | }; 36 | 37 | // ------------------------------------------------------------------------- // 38 | // ---------------------- copy static func from lvm.c ---------------------- // 39 | // ------------------------------------------------------------------------- // 40 | 41 | /* 42 | ** Execute a step of a float numerical for loop, returning 43 | ** true iff the loop must continue. (The integer case is 44 | ** written online with opcode OP_FORLOOP, for performance.) 45 | */ 46 | static int _lvmjit_floatforloop (StkId ra) { 47 | lua_Number step = fltvalue(s2v(ra + 2)); 48 | lua_Number limit = fltvalue(s2v(ra + 1)); 49 | lua_Number idx = fltvalue(s2v(ra)); /* internal index */ 50 | idx = luai_numadd(L, idx, step); /* increment index */ 51 | if (luai_numlt(0, step) ? luai_numle(idx, limit) 52 | : luai_numle(limit, idx)) { 53 | chgfltvalue(s2v(ra), idx); /* update internal index */ 54 | setfltvalue(s2v(ra + 3), idx); /* and control variable */ 55 | return 1; /* jump back */ 56 | } 57 | else 58 | return 0; /* finish the loop */ 59 | } 60 | 61 | /* 62 | ** Try to convert a 'for' limit to an integer, preserving the semantics 63 | ** of the loop. Return true if the loop must not run; otherwise, '*p' 64 | ** gets the integer limit. 65 | ** (The following explanation assumes a positive step; it is valid for 66 | ** negative steps mutatis mutandis.) 67 | ** If the limit is an integer or can be converted to an integer, 68 | ** rounding down, that is the limit. 69 | ** Otherwise, check whether the limit can be converted to a float. If 70 | ** the float is too large, clip it to LUA_MAXINTEGER. If the float 71 | ** is too negative, the loop should not run, because any initial 72 | ** integer value is greater than such limit; so, the function returns 73 | ** true to signal that. (For this latter case, no integer limit would be 74 | ** correct; even a limit of LUA_MININTEGER would run the loop once for 75 | ** an initial value equal to LUA_MININTEGER.) 76 | */ 77 | static int _lvmjit_forlimit (lua_State *L, lua_Integer init, const TValue *lim, 78 | lua_Integer *p, lua_Integer step) { 79 | if (!luaV_tointeger(lim, p, (step < 0 ? F2Iceil : F2Ifloor))) { 80 | /* not coercible to in integer */ 81 | lua_Number flim; /* try to convert to float */ 82 | if (!tonumber(lim, &flim)) /* cannot convert to float? */ 83 | luaG_forerror(L, lim, "limit"); 84 | /* else 'flim' is a float out of integer bounds */ 85 | if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ 86 | if (step < 0) return 1; /* initial value must be less than it */ 87 | *p = LUA_MAXINTEGER; /* truncate */ 88 | } 89 | else { /* it is less than min integer */ 90 | if (step > 0) return 1; /* initial value must be greater than it */ 91 | *p = LUA_MININTEGER; /* truncate */ 92 | } 93 | } 94 | return (step > 0 ? init > *p : init < *p); /* not to run? */ 95 | } 96 | 97 | /* 98 | ** Prepare a numerical for loop (opcode OP_FORPREP). 99 | ** Return true to skip the loop. Otherwise, 100 | ** after preparation, stack will be as follows: 101 | ** ra : internal index (safe copy of the control variable) 102 | ** ra + 1 : loop counter (integer loops) or limit (float loops) 103 | ** ra + 2 : step 104 | ** ra + 3 : control variable 105 | */ 106 | static int _lvmjit_forprep (lua_State *L, StkId ra) { 107 | TValue *pinit = s2v(ra); 108 | TValue *plimit = s2v(ra + 1); 109 | TValue *pstep = s2v(ra + 2); 110 | if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */ 111 | lua_Integer init = ivalue(pinit); 112 | lua_Integer step = ivalue(pstep); 113 | lua_Integer limit; 114 | if (step == 0) 115 | luaG_runerror(L, "'for' step is zero"); 116 | setivalue(s2v(ra + 3), init); /* control variable */ 117 | if (_lvmjit_forlimit(L, init, plimit, &limit, step)) 118 | return 1; /* skip the loop */ 119 | else { /* prepare loop counter */ 120 | lua_Unsigned count; 121 | if (step > 0) { /* ascending loop? */ 122 | count = l_castS2U(limit) - l_castS2U(init); 123 | if (step != 1) /* avoid division in the too common case */ 124 | count /= l_castS2U(step); 125 | } 126 | else { /* step < 0; descending loop */ 127 | count = l_castS2U(init) - l_castS2U(limit); 128 | /* 'step+1' avoids negating 'mininteger' */ 129 | count /= l_castS2U(-(step + 1)) + 1u; 130 | } 131 | /* store the counter in place of the limit (which won't be 132 | needed anymore */ 133 | setivalue(plimit, l_castU2S(count)); 134 | } 135 | } 136 | else { /* try making all values floats */ 137 | lua_Number init; lua_Number limit; lua_Number step; 138 | if (unlikely(!tonumber(plimit, &limit))) 139 | luaG_forerror(L, plimit, "limit"); 140 | if (unlikely(!tonumber(pstep, &step))) 141 | luaG_forerror(L, pstep, "step"); 142 | if (unlikely(!tonumber(pinit, &init))) 143 | luaG_forerror(L, pinit, "initial value"); 144 | if (step == 0) 145 | luaG_runerror(L, "'for' step is zero"); 146 | if (luai_numlt(0, step) ? luai_numlt(limit, init) 147 | : luai_numlt(init, limit)) 148 | return 1; /* skip the loop */ 149 | else { 150 | /* make sure internal values are all floats */ 151 | setfltvalue(plimit, limit); 152 | setfltvalue(pstep, step); 153 | setfltvalue(s2v(ra), init); /* internal index */ 154 | setfltvalue(s2v(ra + 3), init); /* control variable */ 155 | } 156 | } 157 | return 0; 158 | } 159 | 160 | // ------------------------------------------------------------------------- // 161 | // ------------------------------------------------------------------------- // 162 | // ------------------------------------------------------------------------- // 163 | 164 | #define Dst &(C->ds) 165 | #define maxpc C->maxpc 166 | #include "lvm_x64.h" 167 | 168 | 169 | static inline struct lvmjit_compile* 170 | _to_cpl(lua_State* L, int idx) { 171 | luaL_checktype(L, idx, LUA_TUSERDATA); 172 | struct lvmjit_compile* p = lua_touserdata(L, idx); 173 | if(p) { 174 | return p; 175 | }else { 176 | luaL_error(L, "invalid lvmjit_compile"); 177 | } 178 | return NULL; 179 | } 180 | 181 | 182 | static int 183 | _gen_compile(lua_State* L, struct lvmjit_context* C, void** out_codes) { 184 | size_t size; 185 | if(dasm_link(Dst, &size) != DASM_S_OK) { 186 | return 1; 187 | } 188 | 189 | char *mem = (char*)mmap(NULL, size + sizeof(size_t), 190 | PROT_READ | PROT_WRITE, 191 | MAP_ANON | MAP_PRIVATE, -1, 0); 192 | if(mem == MAP_FAILED) { 193 | return 2; 194 | } 195 | 196 | *(size_t*)mem = size; 197 | void *ret = mem + sizeof(size_t); 198 | dasm_encode(Dst, ret); 199 | if(mprotect(mem, size, PROT_EXEC | PROT_READ)){ 200 | return 3; 201 | } 202 | *out_codes = ret; 203 | return 0; 204 | } 205 | 206 | #define _lvmjit_next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) 207 | static int 208 | _lvmjit_compile_call(lua_State* L) { 209 | int nresults = L->ci->nresults; 210 | struct lvmjit_compile* cpl = _to_cpl(L, 1); 211 | Proto* p = cpl->p; 212 | int narg = lua_gettop(L)-1; 213 | StkId func = L->top-narg-1; 214 | int nfixparams = p->numparams; 215 | int fsize = p->maxstacksize; /* frame size */ 216 | CallInfo *ci = _lvmjit_next_ci(L); 217 | checkstackp(L, fsize, func); 218 | ci->nresults = nresults; 219 | ci->u.l.savedpc = p->code; /* starting point */ 220 | ci->callstatus = 0; 221 | ci->top = func + 1 + fsize; 222 | ci->func = func; 223 | L->ci = ci; 224 | for (; narg < nfixparams; narg++) { 225 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ 226 | } 227 | lua_assert(ci->top <= L->stack_last); 228 | // luaV_execute(L, ci); /* run the function */ 229 | cpl->jitcodes(L, ci); 230 | int rc = lua_gettop(L); 231 | return rc; 232 | } 233 | 234 | static int 235 | _lvmjit_compile_gc(lua_State* L) { 236 | struct lvmjit_compile* cpl = _to_cpl(L, 1); 237 | void *mem = (char*)cpl->jitcodes - sizeof(size_t); 238 | munmap(mem, *(size_t*)mem); 239 | return 0; 240 | } 241 | 242 | struct compile_resolve_args { 243 | struct lvmjit_context* C; 244 | Proto* p; 245 | }; 246 | static int 247 | _lvmjit_compile_resolve(lua_State* L) { 248 | struct compile_resolve_args* args = (struct compile_resolve_args*)lua_touserdata(L, 1); 249 | _resolve_compile(L, args->C, args->p); 250 | return 0; 251 | } 252 | 253 | static int 254 | _lvmjit_compile(lua_State* L) { 255 | struct lvmjit_context ctx = {0}; 256 | luaL_checktype(L, 1, LUA_TFUNCTION); 257 | if(lua_iscfunction(L, 1)) { 258 | luaL_error(L, "need lua function"); 259 | } 260 | 261 | // init compile 262 | dasm_init(&(ctx.ds), 1); 263 | dasm_setupglobal(&(ctx.ds), labels, LVMJIT_CODE__MAX); 264 | dasm_setup(&(ctx.ds), actions); 265 | 266 | // resolve compile 267 | struct GCObject* o = (struct GCObject*)lua_topointer(L, 1); 268 | Proto* p = gco2lcl(o)->p; 269 | struct compile_resolve_args args = { 270 | .C = &ctx, 271 | .p = p, 272 | }; 273 | lua_pushcfunction(L, _lvmjit_compile_resolve); 274 | lua_pushlightuserdata(L, &args); 275 | int r = lua_pcall(L, 1, 0, 0); 276 | if(r!=LUA_OK) { 277 | dasm_free(&(ctx.ds)); 278 | luaL_error(L, "compile resolve error:[%d] %s", r, lua_tostring(L, -1)); 279 | } 280 | 281 | // gen compile 282 | void* out_codes = NULL; 283 | int err = _gen_compile(L, &ctx, &out_codes); 284 | if(err) { 285 | dasm_free(&(ctx.ds)); 286 | luaL_error(L, "gen compile error: [%d]", err); 287 | } 288 | 289 | struct lvmjit_compile* cpl = (struct lvmjit_compile*)lua_newuserdatauv(L, sizeof(*cpl), 1); 290 | cpl->p = p; 291 | cpl->jitcodes = (jitcode_func)out_codes; 292 | lua_pushvalue(L, 2); 293 | lua_setiuservalue(L, -2, 1); 294 | if(luaL_newmetatable(L, "__LVMJIT_COMPILE_METATABLE__")) { 295 | lua_pushcfunction(L, _lvmjit_compile_gc); 296 | lua_setfield(L, -2, "__gc"); 297 | lua_pushcfunction(L, _lvmjit_compile_call); 298 | lua_setfield(L, -2, "__call"); 299 | } 300 | lua_setmetatable(L, -2); 301 | 302 | // free compile 303 | dasm_free(&(ctx.ds)); 304 | return 1; 305 | } 306 | 307 | int 308 | luaopen_lvmjit_core(lua_State* L) { 309 | luaL_checkversion(L); 310 | luaL_Reg l[] = { 311 | {"compile", _lvmjit_compile}, 312 | {NULL, NULL}, 313 | }; 314 | 315 | luaL_newlib(L, l); 316 | return 1; 317 | } 318 | -------------------------------------------------------------------------------- /dynasm/dasm_ppc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM PPC encoding engine. 3 | ** Copyright (C) 2005-2017 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-2017 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-2017 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 | -------------------------------------------------------------------------------- /lvm_x64.dasc: -------------------------------------------------------------------------------- 1 | |.arch x64 2 | |.actionlist actions 3 | 4 | |.globals LVMJIT_CODE_ 5 | static void* labels[LVMJIT_CODE__MAX]; 6 | 7 | |.macro callee_save 8 | | push rbp 9 | | push rbx 10 | | push r12 11 | | push r13 12 | | push r14 13 | | push r15 14 | |.endmacro 15 | 16 | |.macro callee_restore 17 | | pop r15 18 | | pop r14 19 | | pop r13 20 | | pop r12 21 | | pop rbx 22 | | pop rbp 23 | | ret 24 | |.endmacro 25 | 26 | |.type LS, lua_State, rdi 27 | |.type CI, CallInfo, rsi 28 | |.type PC, Instruction, rbx 29 | |.define TRAP, r10d 30 | |.type BASE, StackValue, r11 31 | |.type RA, StackValue, r12 32 | |.type RB, StackValue, r13 33 | |.type RC, StackValue, r14 34 | |.define TMP32, r14w 35 | |.define TMP64, r14 36 | |.define TMP2_64, r15 37 | |.define TMP_NUM1, xmm0 38 | |.define TMP_NUM2, xmm1 39 | |.define TMP_NUM3, xmm2 40 | 41 | |.macro _caller_save 42 | | push LS 43 | | push CI 44 | | push r10 45 | | push BASE 46 | |.endmacro 47 | 48 | |.macro _caller_restore 49 | | pop BASE 50 | | pop r10 51 | | pop CI 52 | | pop LS 53 | |.endmacro 54 | 55 | |.macro _lvmjit_floatforloop, ra 56 | | _caller_save 57 | | mov rsi, ra 58 | | mov64 rax, (uintptr_t)_lvmjit_floatforloop 59 | | call rax 60 | | _caller_restore 61 | |.endmacro 62 | 63 | |.macro call_lvmjit_forprep, ra 64 | | _caller_save 65 | | mov rsi, ra 66 | | mov64 rax, (uintptr_t)_lvmjit_forprep 67 | | call rax 68 | | _caller_restore 69 | |.endmacro 70 | 71 | |.macro call_luaT_trybinTM, p1, p2, res, event 72 | | _caller_save 73 | | mov rsi, p1 74 | | mov rdx, p2 75 | | mov rcx, res 76 | | mov r8, event 77 | | mov64 rax, (uintptr_t)luaT_trybinTM 78 | | call rax 79 | | _caller_restore 80 | |.endmacro 81 | 82 | |.macro call_luaD_hookcall 83 | | _caller_save 84 | | mov64 rax, (uintptr_t)luaD_hookcall 85 | | call rax 86 | | _caller_restore 87 | |.endmacro 88 | 89 | |.macro call_luaG_traceexec 90 | | _caller_save 91 | | mov rsi, PC 92 | | mov64 rax, (uintptr_t)luaG_traceexec 93 | | call rax 94 | | _caller_restore 95 | |.endmacro 96 | 97 | |.macro call_luaD_poscall, nres 98 | | _caller_save 99 | | mov rdx, nres 100 | | mov64 rax, (uintptr_t)luaD_poscall 101 | | call rax 102 | | _caller_restore 103 | |.endmacro 104 | 105 | |.macro call_luaF_close, status 106 | | _caller_save 107 | | mov rsi, BASE 108 | | mov rdx, status 109 | | mov64 rax, (uintptr_t)luaF_close 110 | | call rax 111 | | _caller_restore 112 | |.endmacro 113 | 114 | #define STACKVALUE_SZ sizeof(StackValue) 115 | #define STACKVALUE_POW 4 116 | |.macro inc_stackid, R1 117 | | add R1, STACKVALUE_SZ 118 | |.endmacro 119 | 120 | |.macro dec_stackid, R1 121 | | sub R1, STACKVALUE_SZ 122 | |.endmacro 123 | 124 | |.macro cnt_stackid, R1, R2 125 | | sub R1, R2 126 | | shr R1, STACKVALUE_POW 127 | |.endmacro 128 | 129 | |.macro sub_stackid, R1, VR2 130 | | shl VR2, STACKVALUE_POW 131 | | sub R1, VR2 132 | |.endmacro 133 | 134 | |.macro add_stackid, R1, VR2 135 | | shl VR2, STACKVALUE_POW 136 | | add R1, VR2 137 | |.endmacro 138 | 139 | static int 140 | _do_compile(lua_State* L, struct lvmjit_context* C, Proto* p) { 141 | if(sizeof(Value) != 8 || STACKVALUE_SZ != 1<k; 147 | 148 | |.macro savestate 149 | | savepc 150 | | mov rax, LS->top 151 | | mov CI->top, rax 152 | |.endmacro 153 | 154 | |.macro Protect, exp 155 | | savestate 156 | | exp 157 | | updatetrap 158 | |.endmacro 159 | 160 | |.macro savepc 161 | | mov CI->u.l.savedpc, PC 162 | |.endmacro 163 | 164 | |.macro updatetrap 165 | | mov TRAP, CI->u.l.trap 166 | |.endmacro 167 | 168 | |.macro updatebase 169 | | mov BASE, CI->func 170 | | inc_stackid, BASE 171 | |.endmacro 172 | 173 | |.macro updatestack 174 | | cmp TRAP, 0 175 | | je >1 176 | | updatebase 177 | | getRA, RA 178 | |1: 179 | |.endmacro 180 | 181 | |.macro incpc 182 | | add PC, sizeof(Instruction) 183 | |.endmacro 184 | 185 | |.macro addpc, V 186 | | add PC, V*sizeof(Instruction) 187 | |.endmacro 188 | 189 | |.macro subpc, V 190 | | sub PC, V*sizeof(Instruction) 191 | |.endmacro 192 | 193 | |.macro getRV, O1 194 | | add O1, (int)(ptrdiff_t)&(((StackValue *)0)->val) 195 | |.endmacro 196 | 197 | |.macro getRA_I, TR1, IV 198 | | mov TR1, BASE 199 | | add TR1, GETARG_A(IV)*STACKVALUE_SZ 200 | |.endmacro 201 | 202 | |.macro getRA, TR1 203 | | mov TR1, BASE 204 | | add TR1, GETARG_A(i)*STACKVALUE_SZ 205 | |.endmacro 206 | 207 | |.macro getRB, TR1 208 | | mov TR1, BASE 209 | | add TR1, GETARG_B(i)*STACKVALUE_SZ 210 | |.endmacro 211 | 212 | |.macro getRC, TR1 213 | | mov TR1, BASE 214 | | add TR1, GETARG_C(i)*STACKVALUE_SZ 215 | |.endmacro 216 | 217 | |.macro ivalue, O1, R1 218 | | mov R1, O1->val.value_.i 219 | |.endmacro 220 | 221 | |.macro setobj2s, O1, O2 222 | | mov rax, O2->value_.gc 223 | | mov O1->val.value_.gc, rax 224 | | mov al, O2->tt_ 225 | | mov byte O1->val.tt_, al 226 | |.endmacro 227 | 228 | |.macro setobjs2s, O1, O2 229 | | mov rax, O2->val.value_.gc 230 | | mov O1->val.value_.gc, rax 231 | | mov al, O2->val.tt_ 232 | | mov byte O1->val.tt_, al 233 | |.endmacro 234 | 235 | |.macro setivalue, O1, v 236 | | mov qword O1->val.value_.i, v 237 | | mov byte O1->val.tt_, LUA_VNUMINT 238 | |.endmacro 239 | 240 | |.macro setnilvalue, O1 241 | | mov byte O1->val.tt_, LUA_VNIL 242 | |.endmacro 243 | 244 | |.macro setfltvalue, O1, RNUM1 245 | | movd rax, RNUM1 246 | | mov qword O1->val.value_.n, rax 247 | | mov byte O1->val.tt_, LUA_VNUMFLT 248 | |.endmacro 249 | 250 | |.macro cmptype, O1, V 251 | | cmp byte O1->val.tt_, V 252 | |.endmacro 253 | 254 | |.macro ttisinteger, O1 255 | | cmptype, O1, LUA_VNUMINT 256 | |.endmacro 257 | 258 | |.macro ttisfloat, O1 259 | | cmptype, O1, LUA_VNUMFLT 260 | |.endmacro 261 | 262 | |.macro l_addi, O1, O2 263 | | add O1, O2 264 | |.endmacro 265 | 266 | |.macro luai_numadd, RNUM1, RNUM2 267 | | addsd RNUM1, RNUM2 268 | |.endmacro 269 | 270 | |.macro tonumberns, O1, RT_RET1, RT_NUMR1 271 | | xor RT_RET1, RT_RET1 272 | | ttisfloat, O1 273 | | jne >1 274 | | mov RT_RET1, 1 275 | | movd RT_NUMR1, qword O1->val.value_.n 276 | | jmp >2 277 | |1: 278 | | ttisinteger, O1 279 | | jne >2 280 | | mov RT_RET1, 1 281 | | cvtsi2sd RT_NUMR1, qword O1->val.value_.i 282 | |2: 283 | |.endmacro 284 | 285 | |.macro op_arithf_aux, O1, O2, fop 286 | | tonumberns, O1, rax, TMP_NUM1 287 | | cmp rax, 0 288 | | je >1 289 | | tonumberns, O2, rax, TMP_NUM2 290 | | cmp rax, 0 291 | | je >1 292 | | incpc 293 | | fop, TMP_NUM1, TMP_NUM2 294 | | setfltvalue, RA, TMP_NUM1 295 | | jmp =>(label_op_mmbin_end) 296 | |1: 297 | |.endmacro 298 | 299 | |.macro op_arith_aux, O1, O2, iop, fop 300 | | ttisinteger, O1 301 | | jne >1 302 | | ttisinteger, O2 303 | | jne >1 304 | | mov O1, O1->val.value_.i 305 | | mov O2, O2->val.value_.i 306 | | incpc 307 | | iop, O1, O2 308 | | setivalue, RA, O1 309 | | jmp =>(label_op_mmbin_end) 310 | |1: 311 | | op_arithf_aux, O1, O2, fop 312 | |2: 313 | |.endmacro 314 | 315 | |.macro op_arith, iop, fop 316 | | getRB, RB 317 | | getRC, RC 318 | | op_arith_aux, RB, RC, iop, fop 319 | |.endmacro 320 | 321 | |.macro vmfetch 322 | | cmp TRAP, 0 323 | | je >1 324 | | call_luaG_traceexec 325 | | mov TRAP, eax 326 | | updatebase 327 | |1: 328 | | incpc 329 | | getRA RA 330 | |.endmacro 331 | 332 | //---------------------- lvmjit compile begin ---------------------- 333 | | mov PC, CI->u.l.savedpc 334 | | mov TRAP, LS->hookmask 335 | | cmp TRAP, 0 336 | | je >1 337 | || if(p->is_vararg) { 338 | | mov TRAP, 0 339 | || } else { 340 | | cmp PC, p->code 341 | | jne >2 342 | | call_luaD_hookcall 343 | | 2: 344 | | mov dword CI->u.l.trap, 1 345 | || } 346 | | 1: 347 | | updatebase 348 | 349 | unsigned int* op_labels = calloc(p->sizecode, sizeof(unsigned int)); 350 | #define set_labels(i) (\ 351 | assert(i>=0 && isizecode), \ 352 | dasm_growpc(Dst, ++maxpc), \ 353 | op_labels[i] = maxpc, maxpc-1 ) 354 | 355 | #define get_labels(i) (\ 356 | assert(i>=0 && isizecode),\ 357 | assert(op_labels[i]), \ 358 | (op_labels[i]-1) ) 359 | 360 | int idx = 0; 361 | for(idx=0; idx< p->sizecode; idx++) { 362 | Instruction i = p->code[idx]; 363 | int op = GET_OPCODE(i); 364 | | 365 | | vmfetch 366 | | 367 | switch(op) { 368 | case OP_MOVE: { 369 | | 370 | | getRB, RB 371 | | setobjs2s, RA, RB 372 | | 373 | } break; 374 | 375 | case OP_LOADI: { 376 | lua_Integer b = GETARG_sBx(i); 377 | | 378 | | setivalue, RA, b 379 | | 380 | } break; 381 | 382 | case OP_RETURN0: { 383 | | 384 | | cmp TRAP, 0 385 | | je >1 386 | | mov LS->top, RA 387 | | savepc 388 | | call_luaD_poscall, 0 389 | | jmp >2 390 | |1: 391 | | mov TMP32, CI->nresults 392 | | mov rax, CI->previous 393 | | mov qword LS->ci, rax 394 | | mov RA, BASE 395 | | dec_stackid, RA 396 | | mov LS->top, RA 397 | | 398 | |3: 399 | | cmp TMP32, 0 400 | | jle >4 401 | | dec TMP32 402 | | setnilvalue, RA 403 | | inc_stackid, RA 404 | | jmp >3 405 | |4: 406 | | mov LS->top, RA 407 | |2: 408 | | 409 | | callee_restore 410 | | 411 | } break; 412 | 413 | case OP_RETURN1: { 414 | | 415 | | cmp TRAP, 0 416 | | je >1 417 | | mov rax, RA 418 | | inc rax 419 | | mov LS->top, rax 420 | | savepc 421 | | call_luaD_poscall, 1 422 | | jmp >5 423 | |1: 424 | | mov TMP32, CI->nresults 425 | | mov rax, CI->previous 426 | | mov LS->ci, rax 427 | | cmp TMP32, 0 428 | | jne >2 429 | | mov rax, BASE 430 | | dec_stackid, rax 431 | | mov LS->top, rax 432 | | jmp >5 433 | |2: 434 | | mov RB, BASE 435 | | dec_stackid, RB 436 | | setobjs2s, RB, RA 437 | | mov LS->top, BASE 438 | | mov RA, BASE 439 | |3: 440 | | dec TMP32 441 | | cmp TMP32, 0 442 | | jle >4 443 | | setnilvalue, RA 444 | | inc_stackid, RA 445 | | jmp >3 446 | |4: 447 | | mov LS->top, RA 448 | |5: 449 | | 450 | | callee_restore 451 | | 452 | } break; 453 | 454 | case OP_RETURN: { 455 | int n = GETARG_B(i) - 1; /* number of results */ 456 | int nparams1 = GETARG_C(i); 457 | if(n<0) { /* not fixed? */ 458 | | mov RB, LS->top 459 | | cnt_stackid, RB, RA 460 | } else { 461 | | mov RB, n 462 | } 463 | | savepc 464 | if(TESTARG_k(i)) { /* may there be open upvalues? */ 465 | | mov rax, CI->top 466 | | cmp LS->top, rax 467 | | ja >1 468 | | mov LS->top, rax 469 | |1: 470 | | call_luaF_close, LUA_OK 471 | | updatetrap 472 | | updatestack 473 | } 474 | if (nparams1) { /* vararg function? */ 475 | | xor TMP64, TMP64 476 | | mov TMP32, CI->u.l.nextraargs 477 | | add TMP32, nparams1 478 | | mov rax, CI->func 479 | | sub_stackid, rax, TMP64 480 | | mov CI->func, rax 481 | } 482 | | mov rax, RA 483 | | mov TMP2_64, RB 484 | | add_stackid, rax, TMP2_64 485 | | mov LS->top, rax 486 | | call_luaD_poscall, RB 487 | | 488 | | callee_restore 489 | } break; 490 | 491 | case OP_ADD: { 492 | unsigned int label_op_mmbin_end = set_labels(idx); 493 | | 494 | | op_arith, l_addi, luai_numadd 495 | | 496 | } break; 497 | 498 | case OP_MMBIN: { 499 | assert(idx-1>=0 && idx-1sizecode); 500 | Instruction pi = p->code[idx-1]; 501 | lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR); 502 | TMS tm = (TMS)GETARG_C(i); 503 | unsigned int label_op_mmbin_end = get_labels(idx-1); 504 | 505 | |.macro do_op_mmbin 506 | | getRV RA 507 | | getRV RB 508 | | call_luaT_trybinTM, RA, RB, RC, tm 509 | |.endmacro 510 | 511 | | 512 | | getRB, RB 513 | | getRA_I, RC, pi 514 | | Protect, do_op_mmbin 515 | |=>(label_op_mmbin_end): 516 | | 517 | } break; 518 | 519 | case OP_FORPREP: { 520 | unsigned int n = GETARG_Bx(i) + 1; 521 | unsigned int label_op_forperp_end = set_labels(idx); 522 | unsigned int label_op_forloop_end = set_labels(idx+n); 523 | 524 | | 525 | | savestate 526 | | call_lvmjit_forprep, RA 527 | | cmp eax, 0 528 | | je >1 529 | | addpc, n 530 | | jmp =>(label_op_forloop_end) 531 | |1: 532 | | =>(label_op_forperp_end): 533 | | 534 | } break; 535 | 536 | case OP_FORLOOP: { 537 | int back = GETARG_Bx(i); 538 | unsigned int label_op_forperp_end = get_labels(idx-back); 539 | unsigned int label_op_forloop_end = get_labels(idx); 540 | 541 | |.define loopcount, TMP64 542 | |.define loopstep, TMP2_64 543 | |.define loopidx, rcx 544 | 545 | |.macro ivalue_s2v_by_ra, V, R1 546 | | mov RB, RA 547 | | add RB, V*STACKVALUE_SZ 548 | | ivalue, RB, R1 549 | |.endmacro 550 | 551 | | 552 | | mov RB, RA 553 | | add, RB, 2*STACKVALUE_SZ 554 | | ttisinteger, RB 555 | | jne >1 556 | | ivalue_s2v_by_ra, 1, loopcount 557 | | cmp, loopcount, 0 558 | | jna >2 559 | | ivalue_s2v_by_ra, 2, loopstep 560 | | ivalue, RA, loopidx 561 | | dec loopcount 562 | | mov RB, RA 563 | | add, RB, 1*STACKVALUE_SZ 564 | | mov qword RB->val.value_.i, loopcount 565 | | add loopidx, loopstep 566 | | mov qword RA->val.value_.i, loopidx 567 | | add, RB, 2*STACKVALUE_SZ 568 | | setivalue, RB, loopidx 569 | | subpc, back 570 | | updatetrap 571 | | jmp =>(label_op_forperp_end) 572 | | 573 | |1: 574 | | _lvmjit_floatforloop, RA 575 | | cmp eax, 0 576 | | je >2 577 | | subpc, back 578 | | updatetrap 579 | | jmp =>(label_op_forperp_end) 580 | |2: 581 | | updatetrap 582 | | =>(label_op_forloop_end): 583 | | 584 | } break; 585 | 586 | case OP_LOADK: { 587 | TValue *rb = k + GETARG_Bx(i); 588 | | 589 | | setobj2s, RA, rb 590 | | 591 | } break; 592 | 593 | default: { 594 | free(op_labels); 595 | luaL_error(L, "Invalid opcode[%d]:%s", op, opnames[op]); 596 | } break; 597 | } 598 | } 599 | 600 | free(op_labels); 601 | return 0; 602 | } 603 | 604 | static int 605 | _resolve_compile(lua_State* L, struct lvmjit_context* C, Proto* p) { 606 | | callee_save 607 | | 608 | || _do_compile(L, C, p); 609 | | 610 | | callee_restore 611 | return 0; 612 | } -------------------------------------------------------------------------------- /dynasm/dasm_x86.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM x86 encoding engine. 3 | ** Copyright (C) 2005-2017 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 "x86" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. DASM_STOP must be 255. */ 19 | enum { 20 | DASM_DISP = 233, 21 | DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, 22 | DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, 23 | DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, 24 | DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP 25 | }; 26 | 27 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 28 | #define DASM_MAXSECPOS 25 29 | 30 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 31 | #define DASM_S_OK 0x00000000 32 | #define DASM_S_NOMEM 0x01000000 33 | #define DASM_S_PHASE 0x02000000 34 | #define DASM_S_MATCH_SEC 0x03000000 35 | #define DASM_S_RANGE_I 0x11000000 36 | #define DASM_S_RANGE_SEC 0x12000000 37 | #define DASM_S_RANGE_LG 0x13000000 38 | #define DASM_S_RANGE_PC 0x14000000 39 | #define DASM_S_RANGE_VREG 0x15000000 40 | #define DASM_S_UNDEF_L 0x21000000 41 | #define DASM_S_UNDEF_PC 0x22000000 42 | 43 | /* Macros to convert positions (8 bit section + 24 bit index). */ 44 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 45 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 46 | #define DASM_SEC2POS(sec) ((sec)<<24) 47 | #define DASM_POS2SEC(pos) ((pos)>>24) 48 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 49 | 50 | /* Action list type. */ 51 | typedef const unsigned char *dasm_ActList; 52 | 53 | /* Per-section structure. */ 54 | typedef struct dasm_Section { 55 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 56 | int *buf; /* True buffer pointer. */ 57 | size_t bsize; /* Buffer size in bytes. */ 58 | int pos; /* Biased buffer position. */ 59 | int epos; /* End of biased buffer position - max single put. */ 60 | int ofs; /* Byte offset into section. */ 61 | } dasm_Section; 62 | 63 | /* Core structure holding the DynASM encoding state. */ 64 | struct dasm_State { 65 | size_t psize; /* Allocated size of this structure. */ 66 | dasm_ActList actionlist; /* Current actionlist pointer. */ 67 | int *lglabels; /* Local/global chain/pos ptrs. */ 68 | size_t lgsize; 69 | int *pclabels; /* PC label chains/pos ptrs. */ 70 | size_t pcsize; 71 | void **globals; /* Array of globals (bias -10). */ 72 | dasm_Section *section; /* Pointer to active section. */ 73 | size_t codesize; /* Total size of all code sections. */ 74 | int maxsection; /* 0 <= sectionidx < maxsection. */ 75 | int status; /* Status code. */ 76 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 77 | }; 78 | 79 | /* The size of the core structure depends on the max. number of sections. */ 80 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 81 | 82 | 83 | /* Initialize DynASM state. */ 84 | void dasm_init(Dst_DECL, int maxsection) 85 | { 86 | dasm_State *D; 87 | size_t psz = 0; 88 | int i; 89 | Dst_REF = NULL; 90 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 91 | D = Dst_REF; 92 | D->psize = psz; 93 | D->lglabels = NULL; 94 | D->lgsize = 0; 95 | D->pclabels = NULL; 96 | D->pcsize = 0; 97 | D->globals = NULL; 98 | D->maxsection = maxsection; 99 | for (i = 0; i < maxsection; i++) { 100 | D->sections[i].buf = NULL; /* Need this for pass3. */ 101 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 102 | D->sections[i].bsize = 0; 103 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 104 | } 105 | } 106 | 107 | /* Free DynASM state. */ 108 | void dasm_free(Dst_DECL) 109 | { 110 | dasm_State *D = Dst_REF; 111 | int i; 112 | for (i = 0; i < D->maxsection; i++) 113 | if (D->sections[i].buf) 114 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 115 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 116 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 117 | DASM_M_FREE(Dst, D, D->psize); 118 | } 119 | 120 | /* Setup global label array. Must be called before dasm_setup(). */ 121 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 122 | { 123 | dasm_State *D = Dst_REF; 124 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 125 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 126 | } 127 | 128 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 129 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 130 | { 131 | dasm_State *D = Dst_REF; 132 | size_t osz = D->pcsize; 133 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 134 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 135 | } 136 | 137 | /* Setup encoder. */ 138 | void dasm_setup(Dst_DECL, const void *actionlist) 139 | { 140 | dasm_State *D = Dst_REF; 141 | int i; 142 | D->actionlist = (dasm_ActList)actionlist; 143 | D->status = DASM_S_OK; 144 | D->section = &D->sections[0]; 145 | memset((void *)D->lglabels, 0, D->lgsize); 146 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 147 | for (i = 0; i < D->maxsection; i++) { 148 | D->sections[i].pos = DASM_SEC2POS(i); 149 | D->sections[i].ofs = 0; 150 | } 151 | } 152 | 153 | 154 | #ifdef DASM_CHECKS 155 | #define CK(x, st) \ 156 | do { if (!(x)) { \ 157 | D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) 158 | #define CKPL(kind, st) \ 159 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 160 | D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) 161 | #else 162 | #define CK(x, st) ((void)0) 163 | #define CKPL(kind, st) ((void)0) 164 | #endif 165 | 166 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 167 | void dasm_put(Dst_DECL, int start, ...) 168 | { 169 | va_list ap; 170 | dasm_State *D = Dst_REF; 171 | dasm_ActList p = D->actionlist + start; 172 | dasm_Section *sec = D->section; 173 | int pos = sec->pos, ofs = sec->ofs, mrm = 4; 174 | int *b; 175 | 176 | if (pos >= sec->epos) { 177 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 178 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 179 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 180 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 181 | } 182 | 183 | b = sec->rbuf; 184 | b[pos++] = start; 185 | 186 | va_start(ap, start); 187 | while (1) { 188 | int action = *p++; 189 | if (action < DASM_DISP) { 190 | ofs++; 191 | } else if (action <= DASM_REL_A) { 192 | int n = va_arg(ap, int); 193 | b[pos++] = n; 194 | switch (action) { 195 | case DASM_DISP: 196 | if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; } 197 | case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; 198 | case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ 199 | case DASM_IMM_D: ofs += 4; break; 200 | case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; 201 | case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; 202 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; 203 | case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; 204 | case DASM_SPACE: p++; ofs += n; break; 205 | case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ 206 | case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG); 207 | if (*p++ == 1 && *p == DASM_DISP) mrm = n; 208 | continue; 209 | } 210 | mrm = 4; 211 | } else { 212 | int *pl, n; 213 | switch (action) { 214 | case DASM_REL_LG: 215 | case DASM_IMM_LG: 216 | n = *p++; pl = D->lglabels + n; 217 | /* Bkwd rel or global. */ 218 | if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 219 | pl -= 246; n = *pl; 220 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 221 | goto linkrel; 222 | case DASM_REL_PC: 223 | case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); 224 | putrel: 225 | n = *pl; 226 | if (n < 0) { /* Label exists. Get label pos and store it. */ 227 | b[pos] = -n; 228 | } else { 229 | linkrel: 230 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 231 | *pl = pos; 232 | } 233 | pos++; 234 | ofs += 4; /* Maximum offset needed. */ 235 | if (action == DASM_REL_LG || action == DASM_REL_PC) 236 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 237 | break; 238 | case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; 239 | case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); 240 | putlabel: 241 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 242 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } 243 | *pl = -pos; /* Label exists now. */ 244 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 245 | break; 246 | case DASM_ALIGN: 247 | ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ 248 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 249 | break; 250 | case DASM_EXTERN: p += 2; ofs += 4; break; 251 | case DASM_ESC: p++; ofs++; break; 252 | case DASM_MARK: mrm = p[-2]; break; 253 | case DASM_SECTION: 254 | n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; 255 | case DASM_STOP: goto stop; 256 | } 257 | } 258 | } 259 | stop: 260 | va_end(ap); 261 | sec->pos = pos; 262 | sec->ofs = ofs; 263 | } 264 | #undef CK 265 | 266 | /* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ 267 | int dasm_link(Dst_DECL, size_t *szp) 268 | { 269 | dasm_State *D = Dst_REF; 270 | int secnum; 271 | int ofs = 0; 272 | 273 | #ifdef DASM_CHECKS 274 | *szp = 0; 275 | if (D->status != DASM_S_OK) return D->status; 276 | { 277 | int pc; 278 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 279 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 280 | } 281 | #endif 282 | 283 | { /* Handle globals not defined in this translation unit. */ 284 | int idx; 285 | for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { 286 | int n = D->lglabels[idx]; 287 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 288 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 289 | } 290 | } 291 | 292 | /* Combine all code sections. No support for data sections (yet). */ 293 | for (secnum = 0; secnum < D->maxsection; secnum++) { 294 | dasm_Section *sec = D->sections + secnum; 295 | int *b = sec->rbuf; 296 | int pos = DASM_SEC2POS(secnum); 297 | int lastpos = sec->pos; 298 | 299 | while (pos != lastpos) { 300 | dasm_ActList p = D->actionlist + b[pos++]; 301 | while (1) { 302 | int op, action = *p++; 303 | switch (action) { 304 | case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; 305 | case DASM_REL_PC: op = p[-2]; rel_pc: { 306 | int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); 307 | if (shrink) { /* Shrinkable branch opcode? */ 308 | int lofs, lpos = b[pos]; 309 | if (lpos < 0) goto noshrink; /* Ext global? */ 310 | lofs = *DASM_POS2PTR(D, lpos); 311 | if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ 312 | int i; 313 | for (i = secnum; i < DASM_POS2SEC(lpos); i++) 314 | lofs += D->sections[i].ofs; 315 | } else { 316 | lofs -= ofs; /* Bkwd label: unfix offset. */ 317 | } 318 | lofs -= b[pos+1]; /* Short branch ok? */ 319 | if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ 320 | else { noshrink: shrink = 0; } /* No, cannot shrink op. */ 321 | } 322 | b[pos+1] = shrink; 323 | pos += 2; 324 | break; 325 | } 326 | case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; 327 | case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: 328 | case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: 329 | case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; 330 | case DASM_LABEL_LG: p++; 331 | case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ 332 | case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ 333 | case DASM_EXTERN: p += 2; break; 334 | case DASM_ESC: p++; break; 335 | case DASM_MARK: break; 336 | case DASM_SECTION: case DASM_STOP: goto stop; 337 | } 338 | } 339 | stop: (void)0; 340 | } 341 | ofs += sec->ofs; /* Next section starts right after current section. */ 342 | } 343 | 344 | D->codesize = ofs; /* Total size of all code sections */ 345 | *szp = ofs; 346 | return DASM_S_OK; 347 | } 348 | 349 | #define dasmb(x) *cp++ = (unsigned char)(x) 350 | #ifndef DASM_ALIGNED_WRITES 351 | #define dasmw(x) \ 352 | do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) 353 | #define dasmd(x) \ 354 | do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) 355 | #else 356 | #define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) 357 | #define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) 358 | #endif 359 | 360 | /* Pass 3: Encode sections. */ 361 | int dasm_encode(Dst_DECL, void *buffer) 362 | { 363 | dasm_State *D = Dst_REF; 364 | unsigned char *base = (unsigned char *)buffer; 365 | unsigned char *cp = base; 366 | int secnum; 367 | 368 | /* Encode all code sections. No support for data sections (yet). */ 369 | for (secnum = 0; secnum < D->maxsection; secnum++) { 370 | dasm_Section *sec = D->sections + secnum; 371 | int *b = sec->buf; 372 | int *endb = sec->rbuf + sec->pos; 373 | 374 | while (b != endb) { 375 | dasm_ActList p = D->actionlist + *b++; 376 | unsigned char *mark = NULL; 377 | while (1) { 378 | int action = *p++; 379 | int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; 380 | switch (action) { 381 | case DASM_DISP: if (!mark) mark = cp; { 382 | unsigned char *mm = mark; 383 | if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; 384 | if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; 385 | if (mrm != 5) { mm[-1] -= 0x80; break; } } 386 | if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; 387 | } 388 | case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; 389 | case DASM_IMM_DB: if (((n+128)&-256) == 0) { 390 | db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; 391 | } else mark = NULL; 392 | case DASM_IMM_D: wd: dasmd(n); break; 393 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; 394 | case DASM_IMM_W: dasmw(n); break; 395 | case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; } 396 | case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; 397 | b++; n = (int)(ptrdiff_t)D->globals[-n]; 398 | case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ 399 | case DASM_REL_PC: rel_pc: { 400 | int shrink = *b++; 401 | int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } 402 | n = *pb - ((int)(cp-base) + 4-shrink); 403 | if (shrink == 0) goto wd; 404 | if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; 405 | goto wb; 406 | } 407 | case DASM_IMM_LG: 408 | p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } 409 | case DASM_IMM_PC: { 410 | int *pb = DASM_POS2PTR(D, n); 411 | n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); 412 | goto wd; 413 | } 414 | case DASM_LABEL_LG: { 415 | int idx = *p++; 416 | if (idx >= 10) 417 | D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); 418 | break; 419 | } 420 | case DASM_LABEL_PC: case DASM_SETLABEL: break; 421 | case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } 422 | case DASM_ALIGN: 423 | n = *p++; 424 | while (((cp-base) & n)) *cp++ = 0x90; /* nop */ 425 | break; 426 | case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; 427 | case DASM_MARK: mark = cp; break; 428 | case DASM_ESC: action = *p++; 429 | default: *cp++ = action; break; 430 | case DASM_SECTION: case DASM_STOP: goto stop; 431 | } 432 | } 433 | stop: (void)0; 434 | } 435 | } 436 | 437 | if (base + D->codesize != cp) /* Check for phase errors. */ 438 | return DASM_S_PHASE; 439 | return DASM_S_OK; 440 | } 441 | 442 | /* Get PC label offset. */ 443 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 444 | { 445 | dasm_State *D = Dst_REF; 446 | if (pc*sizeof(int) < D->pcsize) { 447 | int pos = D->pclabels[pc]; 448 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 449 | if (pos > 0) return -1; /* Undefined. */ 450 | } 451 | return -2; /* Unused or out of range. */ 452 | } 453 | 454 | #ifdef DASM_CHECKS 455 | /* Optional sanity checker to call between isolated encoding steps. */ 456 | int dasm_checkstep(Dst_DECL, int secmatch) 457 | { 458 | dasm_State *D = Dst_REF; 459 | if (D->status == DASM_S_OK) { 460 | int i; 461 | for (i = 1; i <= 9; i++) { 462 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } 463 | D->lglabels[i] = 0; 464 | } 465 | } 466 | if (D->status == DASM_S_OK && secmatch >= 0 && 467 | D->section != &D->sections[secmatch]) 468 | D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); 469 | return D->status; 470 | } 471 | #endif 472 | 473 | -------------------------------------------------------------------------------- /lvm_x64.h: -------------------------------------------------------------------------------- 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 "../lvm_x64.dasc". 6 | */ 7 | 8 | #line 1 "../lvm_x64.dasc" 9 | //|.arch x64 10 | #if DASM_VERSION != 10300 11 | #error "Version mismatch between DynASM and included encoding engine" 12 | #endif 13 | #line 2 "../lvm_x64.dasc" 14 | //|.actionlist actions 15 | static const unsigned char actions[1213] = { 16 | 72,139,158,233,68,139,151,233,65,131,252,250,0,15,132,244,247,255,65,186, 17 | 0,0,0,0,255,72,129,252,251,239,15,133,244,248,87,86,65,82,65,83,72,184,237, 18 | 237,252,255,208,65,91,65,90,94,95,248,2,199,134,233,1,0,0,0,255,248,1,76, 19 | 139,158,233,73,129,195,239,255,65,131,252,250,0,15,132,244,247,87,86,65,82, 20 | 65,83,72,137,222,72,184,237,237,252,255,208,65,91,65,90,94,95,65,137,194, 21 | 76,139,158,233,73,129,195,239,248,1,72,129,195,239,77,137,220,73,129,196, 22 | 239,255,77,137,221,73,129,197,239,73,139,133,233,73,137,132,253,36,233,65, 23 | 138,133,233,65,136,132,253,36,233,255,73,199,132,253,36,233,237,65,198,132, 24 | 253,36,233,235,255,65,131,252,250,0,15,132,244,247,76,137,167,233,72,137, 25 | 158,233,87,86,65,82,65,83,72,199,194,0,0,0,0,72,184,237,237,252,255,208,65, 26 | 91,65,90,94,95,252,233,244,248,248,1,102,68,139,182,233,72,139,134,233,72, 27 | 137,135,233,77,137,220,73,129,252,236,239,76,137,167,233,248,3,102,65,131, 28 | 252,254,0,15,142,244,250,102,65,252,255,206,65,198,132,253,36,233,235,73, 29 | 129,196,239,255,252,233,244,249,248,4,76,137,167,233,248,2,65,95,65,94,65, 30 | 93,65,92,91,93,195,255,65,131,252,250,0,15,132,244,247,76,137,224,72,252, 31 | 255,192,72,137,135,233,72,137,158,233,87,86,65,82,65,83,72,199,194,1,0,0, 32 | 0,72,184,237,237,252,255,208,65,91,65,90,94,95,252,233,244,251,248,1,102, 33 | 68,139,182,233,72,139,134,233,72,137,135,233,102,65,131,252,254,0,15,133, 34 | 244,248,76,137,216,72,129,232,239,72,137,135,233,252,233,244,251,248,2,77, 35 | 137,221,73,129,252,237,239,255,73,139,132,253,36,233,73,137,133,233,65,138, 36 | 132,253,36,233,65,136,133,233,76,137,159,233,77,137,220,248,3,102,65,252, 37 | 255,206,102,65,131,252,254,0,15,142,244,250,65,198,132,253,36,233,235,73, 38 | 129,196,239,252,233,244,249,248,4,76,137,167,233,248,5,65,95,65,94,65,93, 39 | 65,92,91,93,195,255,76,139,175,233,77,41,229,73,193,252,237,235,255,73,199, 40 | 197,237,255,72,137,158,233,255,72,139,134,233,72,57,135,233,15,135,244,247, 41 | 72,137,135,233,248,1,87,86,65,82,65,83,76,137,222,72,199,194,237,72,184,237, 42 | 237,252,255,208,65,91,65,90,94,95,68,139,150,233,65,131,252,250,0,15,132, 43 | 244,247,76,139,158,233,73,129,195,239,77,137,220,73,129,196,239,248,1,255, 44 | 77,49,252,246,102,68,139,182,233,102,65,129,198,238,72,139,134,233,73,193, 45 | 230,235,76,41,252,240,72,137,134,233,255,76,137,224,77,137,252,239,73,193, 46 | 231,235,76,1,252,248,72,137,135,233,87,86,65,82,65,83,76,137,252,234,72,184, 47 | 237,237,252,255,208,65,91,65,90,94,95,65,95,65,94,65,93,65,92,91,93,195,255, 48 | 77,137,221,73,129,197,239,77,137,222,73,129,198,239,65,128,189,233,235,15, 49 | 133,244,247,65,128,190,233,235,15,133,244,247,77,139,173,233,77,139,182,233, 50 | 72,129,195,239,77,1,252,245,77,137,172,253,36,233,65,198,132,253,36,233,235, 51 | 252,233,245,248,1,72,49,192,65,128,189,233,235,255,15,133,244,247,72,199, 52 | 192,1,0,0,0,102,73,15,110,133,233,252,233,244,248,248,1,65,128,189,233,235, 53 | 15,133,244,248,72,199,192,1,0,0,0,252,242,73,15,42,133,233,248,2,72,131,252, 54 | 248,0,15,132,244,247,72,49,192,65,128,190,233,235,15,133,244,247,72,199,192, 55 | 1,0,0,0,102,73,15,110,142,233,252,233,244,248,248,1,255,65,128,190,233,235, 56 | 15,133,244,248,72,199,192,1,0,0,0,252,242,73,15,42,142,233,248,2,72,131,252, 57 | 248,0,15,132,244,247,72,129,195,239,252,242,15,88,193,102,72,15,126,192,73, 58 | 137,132,253,36,233,65,198,132,253,36,233,235,252,233,245,248,1,248,2,255, 59 | 77,137,221,73,129,197,239,77,137,222,73,129,198,239,72,137,158,233,72,139, 60 | 135,233,72,137,134,233,73,129,196,239,73,129,197,239,87,86,65,82,65,83,76, 61 | 137,230,76,137,252,234,76,137,252,241,73,199,192,237,72,184,237,237,252,255, 62 | 208,65,91,65,90,94,95,68,139,150,233,249,255,72,137,158,233,72,139,135,233, 63 | 72,137,134,233,87,86,65,82,65,83,76,137,230,72,184,237,237,252,255,208,65, 64 | 91,65,90,94,95,131,252,248,0,15,132,244,247,72,129,195,239,252,233,245,248, 65 | 1,249,255,77,137,229,73,129,197,239,65,128,189,233,235,15,133,244,247,77, 66 | 137,229,73,129,197,239,77,139,181,233,73,131,252,254,0,15,134,244,248,77, 67 | 137,229,73,129,197,239,77,139,189,233,73,139,140,253,36,233,73,252,255,206, 68 | 77,137,229,73,129,197,239,77,137,181,233,76,1,252,249,73,137,140,253,36,233, 69 | 73,129,197,239,73,137,141,233,65,198,133,233,235,72,129,252,235,239,255,68, 70 | 139,150,233,252,233,245,248,1,87,86,65,82,65,83,76,137,230,72,184,237,237, 71 | 252,255,208,65,91,65,90,94,95,131,252,248,0,15,132,244,248,72,129,252,235, 72 | 239,68,139,150,233,252,233,245,248,2,68,139,150,233,249,255,72,199,192,237, 73 | 73,137,132,253,36,233,176,235,65,136,132,253,36,233,255,85,83,65,84,65,85, 74 | 65,86,65,87,255 75 | }; 76 | 77 | #line 3 "../lvm_x64.dasc" 78 | 79 | //|.globals LVMJIT_CODE_ 80 | enum { 81 | LVMJIT_CODE__MAX 82 | }; 83 | #line 5 "../lvm_x64.dasc" 84 | static void* labels[LVMJIT_CODE__MAX]; 85 | 86 | //|.macro callee_save 87 | //| push rbp 88 | //| push rbx 89 | //| push r12 90 | //| push r13 91 | //| push r14 92 | //| push r15 93 | //|.endmacro 94 | 95 | //|.macro callee_restore 96 | //| pop r15 97 | //| pop r14 98 | //| pop r13 99 | //| pop r12 100 | //| pop rbx 101 | //| pop rbp 102 | //| ret 103 | //|.endmacro 104 | 105 | //|.type LS, lua_State, rdi 106 | #define Dt1(_V) (int)(ptrdiff_t)&(((lua_State *)0)_V) 107 | #line 27 "../lvm_x64.dasc" 108 | //|.type CI, CallInfo, rsi 109 | #define Dt2(_V) (int)(ptrdiff_t)&(((CallInfo *)0)_V) 110 | #line 28 "../lvm_x64.dasc" 111 | //|.type PC, Instruction, rbx 112 | #define Dt3(_V) (int)(ptrdiff_t)&(((Instruction *)0)_V) 113 | #line 29 "../lvm_x64.dasc" 114 | //|.define TRAP, r10d 115 | //|.type BASE, StackValue, r11 116 | #define Dt4(_V) (int)(ptrdiff_t)&(((StackValue *)0)_V) 117 | #line 31 "../lvm_x64.dasc" 118 | //|.type RA, StackValue, r12 119 | #define Dt5(_V) (int)(ptrdiff_t)&(((StackValue *)0)_V) 120 | #line 32 "../lvm_x64.dasc" 121 | //|.type RB, StackValue, r13 122 | #define Dt6(_V) (int)(ptrdiff_t)&(((StackValue *)0)_V) 123 | #line 33 "../lvm_x64.dasc" 124 | //|.type RC, StackValue, r14 125 | #define Dt7(_V) (int)(ptrdiff_t)&(((StackValue *)0)_V) 126 | #line 34 "../lvm_x64.dasc" 127 | //|.define TMP32, r14w 128 | //|.define TMP64, r14 129 | //|.define TMP2_64, r15 130 | //|.define TMP_NUM1, xmm0 131 | //|.define TMP_NUM2, xmm1 132 | //|.define TMP_NUM3, xmm2 133 | 134 | //|.macro _caller_save 135 | //| push LS 136 | //| push CI 137 | //| push r10 138 | //| push BASE 139 | //|.endmacro 140 | 141 | //|.macro _caller_restore 142 | //| pop BASE 143 | //| pop r10 144 | //| pop CI 145 | //| pop LS 146 | //|.endmacro 147 | 148 | //|.macro _lvmjit_floatforloop, ra 149 | //| _caller_save 150 | //| mov rsi, ra 151 | //| mov64 rax, (uintptr_t)_lvmjit_floatforloop 152 | //| call rax 153 | //| _caller_restore 154 | //|.endmacro 155 | 156 | //|.macro call_lvmjit_forprep, ra 157 | //| _caller_save 158 | //| mov rsi, ra 159 | //| mov64 rax, (uintptr_t)_lvmjit_forprep 160 | //| call rax 161 | //| _caller_restore 162 | //|.endmacro 163 | 164 | //|.macro call_luaT_trybinTM, p1, p2, res, event 165 | //| _caller_save 166 | //| mov rsi, p1 167 | //| mov rdx, p2 168 | //| mov rcx, res 169 | //| mov r8, event 170 | //| mov64 rax, (uintptr_t)luaT_trybinTM 171 | //| call rax 172 | //| _caller_restore 173 | //|.endmacro 174 | 175 | //|.macro call_luaD_hookcall 176 | //| _caller_save 177 | //| mov64 rax, (uintptr_t)luaD_hookcall 178 | //| call rax 179 | //| _caller_restore 180 | //|.endmacro 181 | 182 | //|.macro call_luaG_traceexec 183 | //| _caller_save 184 | //| mov rsi, PC 185 | //| mov64 rax, (uintptr_t)luaG_traceexec 186 | //| call rax 187 | //| _caller_restore 188 | //|.endmacro 189 | 190 | //|.macro call_luaD_poscall, nres 191 | //| _caller_save 192 | //| mov rdx, nres 193 | //| mov64 rax, (uintptr_t)luaD_poscall 194 | //| call rax 195 | //| _caller_restore 196 | //|.endmacro 197 | 198 | //|.macro call_luaF_close, status 199 | //| _caller_save 200 | //| mov rsi, BASE 201 | //| mov rdx, status 202 | //| mov64 rax, (uintptr_t)luaF_close 203 | //| call rax 204 | //| _caller_restore 205 | //|.endmacro 206 | 207 | #define STACKVALUE_SZ sizeof(StackValue) 208 | #define STACKVALUE_POW 4 209 | //|.macro inc_stackid, R1 210 | //| add R1, STACKVALUE_SZ 211 | //|.endmacro 212 | 213 | //|.macro dec_stackid, R1 214 | //| sub R1, STACKVALUE_SZ 215 | //|.endmacro 216 | 217 | //|.macro cnt_stackid, R1, R2 218 | //| sub R1, R2 219 | //| shr R1, STACKVALUE_POW 220 | //|.endmacro 221 | 222 | //|.macro sub_stackid, R1, VR2 223 | //| shl VR2, STACKVALUE_POW 224 | //| sub R1, VR2 225 | //|.endmacro 226 | 227 | //|.macro add_stackid, R1, VR2 228 | //| shl VR2, STACKVALUE_POW 229 | //| add R1, VR2 230 | //|.endmacro 231 | 232 | static int 233 | _do_compile(lua_State* L, struct lvmjit_context* C, Proto* p) { 234 | if(sizeof(Value) != 8 || STACKVALUE_SZ != 1<k; 240 | 241 | //|.macro savestate 242 | //| savepc 243 | //| mov rax, LS->top 244 | //| mov CI->top, rax 245 | //|.endmacro 246 | 247 | //|.macro Protect, exp 248 | //| savestate 249 | //| exp 250 | //| updatetrap 251 | //|.endmacro 252 | 253 | //|.macro savepc 254 | //| mov CI->u.l.savedpc, PC 255 | //|.endmacro 256 | 257 | //|.macro updatetrap 258 | //| mov TRAP, CI->u.l.trap 259 | //|.endmacro 260 | 261 | //|.macro updatebase 262 | //| mov BASE, CI->func 263 | //| inc_stackid, BASE 264 | //|.endmacro 265 | 266 | //|.macro updatestack 267 | //| cmp TRAP, 0 268 | //| je >1 269 | //| updatebase 270 | //| getRA, RA 271 | //|1: 272 | //|.endmacro 273 | 274 | //|.macro incpc 275 | //| add PC, sizeof(Instruction) 276 | //|.endmacro 277 | 278 | //|.macro addpc, V 279 | //| add PC, V*sizeof(Instruction) 280 | //|.endmacro 281 | 282 | //|.macro subpc, V 283 | //| sub PC, V*sizeof(Instruction) 284 | //|.endmacro 285 | 286 | //|.macro getRV, O1 287 | //| add O1, (int)(ptrdiff_t)&(((StackValue *)0)->val) 288 | //|.endmacro 289 | 290 | //|.macro getRA_I, TR1, IV 291 | //| mov TR1, BASE 292 | //| add TR1, GETARG_A(IV)*STACKVALUE_SZ 293 | //|.endmacro 294 | 295 | //|.macro getRA, TR1 296 | //| mov TR1, BASE 297 | //| add TR1, GETARG_A(i)*STACKVALUE_SZ 298 | //|.endmacro 299 | 300 | //|.macro getRB, TR1 301 | //| mov TR1, BASE 302 | //| add TR1, GETARG_B(i)*STACKVALUE_SZ 303 | //|.endmacro 304 | 305 | //|.macro getRC, TR1 306 | //| mov TR1, BASE 307 | //| add TR1, GETARG_C(i)*STACKVALUE_SZ 308 | //|.endmacro 309 | 310 | //|.macro ivalue, O1, R1 311 | //| mov R1, O1->val.value_.i 312 | //|.endmacro 313 | 314 | //|.macro setobj2s, O1, O2 315 | //| mov rax, O2->value_.gc 316 | //| mov O1->val.value_.gc, rax 317 | //| mov al, O2->tt_ 318 | //| mov byte O1->val.tt_, al 319 | //|.endmacro 320 | 321 | //|.macro setobjs2s, O1, O2 322 | //| mov rax, O2->val.value_.gc 323 | //| mov O1->val.value_.gc, rax 324 | //| mov al, O2->val.tt_ 325 | //| mov byte O1->val.tt_, al 326 | //|.endmacro 327 | 328 | //|.macro setivalue, O1, v 329 | //| mov qword O1->val.value_.i, v 330 | //| mov byte O1->val.tt_, LUA_VNUMINT 331 | //|.endmacro 332 | 333 | //|.macro setnilvalue, O1 334 | //| mov byte O1->val.tt_, LUA_VNIL 335 | //|.endmacro 336 | 337 | //|.macro setfltvalue, O1, RNUM1 338 | //| movd rax, RNUM1 339 | //| mov qword O1->val.value_.n, rax 340 | //| mov byte O1->val.tt_, LUA_VNUMFLT 341 | //|.endmacro 342 | 343 | //|.macro cmptype, O1, V 344 | //| cmp byte O1->val.tt_, V 345 | //|.endmacro 346 | 347 | //|.macro ttisinteger, O1 348 | //| cmptype, O1, LUA_VNUMINT 349 | //|.endmacro 350 | 351 | //|.macro ttisfloat, O1 352 | //| cmptype, O1, LUA_VNUMFLT 353 | //|.endmacro 354 | 355 | //|.macro l_addi, O1, O2 356 | //| add O1, O2 357 | //|.endmacro 358 | 359 | //|.macro luai_numadd, RNUM1, RNUM2 360 | //| addsd RNUM1, RNUM2 361 | //|.endmacro 362 | 363 | //|.macro tonumberns, O1, RT_RET1, RT_NUMR1 364 | //| xor RT_RET1, RT_RET1 365 | //| ttisfloat, O1 366 | //| jne >1 367 | //| mov RT_RET1, 1 368 | //| movd RT_NUMR1, qword O1->val.value_.n 369 | //| jmp >2 370 | //|1: 371 | //| ttisinteger, O1 372 | //| jne >2 373 | //| mov RT_RET1, 1 374 | //| cvtsi2sd RT_NUMR1, qword O1->val.value_.i 375 | //|2: 376 | //|.endmacro 377 | 378 | //|.macro op_arithf_aux, O1, O2, fop 379 | //| tonumberns, O1, rax, TMP_NUM1 380 | //| cmp rax, 0 381 | //| je >1 382 | //| tonumberns, O2, rax, TMP_NUM2 383 | //| cmp rax, 0 384 | //| je >1 385 | //| incpc 386 | //| fop, TMP_NUM1, TMP_NUM2 387 | //| setfltvalue, RA, TMP_NUM1 388 | //| jmp =>(label_op_mmbin_end) 389 | //|1: 390 | //|.endmacro 391 | 392 | //|.macro op_arith_aux, O1, O2, iop, fop 393 | //| ttisinteger, O1 394 | //| jne >1 395 | //| ttisinteger, O2 396 | //| jne >1 397 | //| mov O1, O1->val.value_.i 398 | //| mov O2, O2->val.value_.i 399 | //| incpc 400 | //| iop, O1, O2 401 | //| setivalue, RA, O1 402 | //| jmp =>(label_op_mmbin_end) 403 | //|1: 404 | //| op_arithf_aux, O1, O2, fop 405 | //|2: 406 | //|.endmacro 407 | 408 | //|.macro op_arith, iop, fop 409 | //| getRB, RB 410 | //| getRC, RC 411 | //| op_arith_aux, RB, RC, iop, fop 412 | //|.endmacro 413 | 414 | //|.macro vmfetch 415 | //| cmp TRAP, 0 416 | //| je >1 417 | //| call_luaG_traceexec 418 | //| mov TRAP, eax 419 | //| updatebase 420 | //|1: 421 | //| incpc 422 | //| getRA RA 423 | //|.endmacro 424 | 425 | //---------------------- lvmjit compile begin ---------------------- 426 | //| mov PC, CI->u.l.savedpc 427 | //| mov TRAP, LS->hookmask 428 | //| cmp TRAP, 0 429 | //| je >1 430 | dasm_put(Dst, 0, Dt2(->u.l.savedpc), Dt1(->hookmask)); 431 | if(p->is_vararg) { 432 | #line 338 "../lvm_x64.dasc" 433 | //| mov TRAP, 0 434 | dasm_put(Dst, 18); 435 | } else { 436 | #line 340 "../lvm_x64.dasc" 437 | //| cmp PC, p->code 438 | //| jne >2 439 | //| call_luaD_hookcall 440 | //| 2: 441 | //| mov dword CI->u.l.trap, 1 442 | dasm_put(Dst, 25, p->code, (unsigned int)((uintptr_t)luaD_hookcall), (unsigned int)(((uintptr_t)luaD_hookcall)>>32), Dt2(->u.l.trap)); 443 | } 444 | #line 346 "../lvm_x64.dasc" 445 | //| 1: 446 | //| updatebase 447 | dasm_put(Dst, 63, Dt2(->func), STACKVALUE_SZ); 448 | #line 348 "../lvm_x64.dasc" 449 | 450 | unsigned int* op_labels = calloc(p->sizecode, sizeof(unsigned int)); 451 | #define set_labels(i) (\ 452 | assert(i>=0 && isizecode), \ 453 | dasm_growpc(Dst, ++maxpc), \ 454 | op_labels[i] = maxpc, maxpc-1 ) 455 | 456 | #define get_labels(i) (\ 457 | assert(i>=0 && isizecode),\ 458 | assert(op_labels[i]), \ 459 | (op_labels[i]-1) ) 460 | 461 | int idx = 0; 462 | for(idx=0; idx< p->sizecode; idx++) { 463 | Instruction i = p->code[idx]; 464 | int op = GET_OPCODE(i); 465 | //| 466 | //| vmfetch 467 | //| 468 | dasm_put(Dst, 74, (unsigned int)((uintptr_t)luaG_traceexec), (unsigned int)(((uintptr_t)luaG_traceexec)>>32), Dt2(->func), STACKVALUE_SZ, sizeof(Instruction), GETARG_A(i)*STACKVALUE_SZ); 469 | #line 367 "../lvm_x64.dasc" 470 | switch(op) { 471 | case OP_MOVE: { 472 | //| 473 | //| getRB, RB 474 | //| setobjs2s, RA, RB 475 | //| 476 | dasm_put(Dst, 130, GETARG_B(i)*STACKVALUE_SZ, Dt6(->val.value_.gc), Dt5(->val.value_.gc), Dt6(->val.tt_), Dt5(->val.tt_)); 477 | #line 373 "../lvm_x64.dasc" 478 | } break; 479 | 480 | case OP_LOADI: { 481 | lua_Integer b = GETARG_sBx(i); 482 | //| 483 | //| setivalue, RA, b 484 | //| 485 | dasm_put(Dst, 158, Dt5(->val.value_.i), b, Dt5(->val.tt_), LUA_VNUMINT); 486 | #line 380 "../lvm_x64.dasc" 487 | } break; 488 | 489 | case OP_RETURN0: { 490 | //| 491 | //| cmp TRAP, 0 492 | //| je >1 493 | //| mov LS->top, RA 494 | //| savepc 495 | //| call_luaD_poscall, 0 496 | //| jmp >2 497 | //|1: 498 | //| mov TMP32, CI->nresults 499 | //| mov rax, CI->previous 500 | //| mov qword LS->ci, rax 501 | //| mov RA, BASE 502 | //| dec_stackid, RA 503 | //| mov LS->top, RA 504 | //| 505 | //|3: 506 | //| cmp TMP32, 0 507 | //| jle >4 508 | //| dec TMP32 509 | //| setnilvalue, RA 510 | //| inc_stackid, RA 511 | //| jmp >3 512 | dasm_put(Dst, 173, Dt1(->top), Dt2(->u.l.savedpc), (unsigned int)((uintptr_t)luaD_poscall), (unsigned int)(((uintptr_t)luaD_poscall)>>32), Dt2(->nresults), Dt2(->previous), Dt1(->ci), STACKVALUE_SZ, Dt1(->top), Dt5(->val.tt_), LUA_VNIL, STACKVALUE_SZ); 513 | #line 405 "../lvm_x64.dasc" 514 | //|4: 515 | //| mov LS->top, RA 516 | //|2: 517 | //| 518 | //| callee_restore 519 | //| 520 | dasm_put(Dst, 276, Dt1(->top)); 521 | #line 411 "../lvm_x64.dasc" 522 | } break; 523 | 524 | case OP_RETURN1: { 525 | //| 526 | //| cmp TRAP, 0 527 | //| je >1 528 | //| mov rax, RA 529 | //| inc rax 530 | //| mov LS->top, rax 531 | //| savepc 532 | //| call_luaD_poscall, 1 533 | //| jmp >5 534 | //|1: 535 | //| mov TMP32, CI->nresults 536 | //| mov rax, CI->previous 537 | //| mov LS->ci, rax 538 | //| cmp TMP32, 0 539 | //| jne >2 540 | //| mov rax, BASE 541 | //| dec_stackid, rax 542 | //| mov LS->top, rax 543 | //| jmp >5 544 | //|2: 545 | //| mov RB, BASE 546 | //| dec_stackid, RB 547 | //| setobjs2s, RB, RA 548 | dasm_put(Dst, 300, Dt1(->top), Dt2(->u.l.savedpc), (unsigned int)((uintptr_t)luaD_poscall), (unsigned int)(((uintptr_t)luaD_poscall)>>32), Dt2(->nresults), Dt2(->previous), Dt1(->ci), STACKVALUE_SZ, Dt1(->top), STACKVALUE_SZ); 549 | #line 437 "../lvm_x64.dasc" 550 | //| mov LS->top, BASE 551 | //| mov RA, BASE 552 | //|3: 553 | //| dec TMP32 554 | //| cmp TMP32, 0 555 | //| jle >4 556 | //| setnilvalue, RA 557 | //| inc_stackid, RA 558 | //| jmp >3 559 | //|4: 560 | //| mov LS->top, RA 561 | //|5: 562 | //| 563 | //| callee_restore 564 | //| 565 | dasm_put(Dst, 405, Dt5(->val.value_.gc), Dt6(->val.value_.gc), Dt5(->val.tt_), Dt6(->val.tt_), Dt1(->top), Dt5(->val.tt_), LUA_VNIL, STACKVALUE_SZ, Dt1(->top)); 566 | #line 452 "../lvm_x64.dasc" 567 | } break; 568 | 569 | case OP_RETURN: { 570 | int n = GETARG_B(i) - 1; /* number of results */ 571 | int nparams1 = GETARG_C(i); 572 | if(n<0) { /* not fixed? */ 573 | //| mov RB, LS->top 574 | //| cnt_stackid, RB, RA 575 | dasm_put(Dst, 484, Dt1(->top), STACKVALUE_POW); 576 | #line 460 "../lvm_x64.dasc" 577 | } else { 578 | //| mov RB, n 579 | dasm_put(Dst, 497, n); 580 | #line 462 "../lvm_x64.dasc" 581 | } 582 | //| savepc 583 | dasm_put(Dst, 502, Dt2(->u.l.savedpc)); 584 | #line 464 "../lvm_x64.dasc" 585 | if(TESTARG_k(i)) { /* may there be open upvalues? */ 586 | //| mov rax, CI->top 587 | //| cmp LS->top, rax 588 | //| ja >1 589 | //| mov LS->top, rax 590 | //|1: 591 | //| call_luaF_close, LUA_OK 592 | //| updatetrap 593 | //| updatestack 594 | dasm_put(Dst, 507, Dt2(->top), Dt1(->top), Dt1(->top), LUA_OK, (unsigned int)((uintptr_t)luaF_close), (unsigned int)(((uintptr_t)luaF_close)>>32), Dt2(->u.l.trap), Dt2(->func), STACKVALUE_SZ, GETARG_A(i)*STACKVALUE_SZ); 595 | #line 473 "../lvm_x64.dasc" 596 | } 597 | if (nparams1) { /* vararg function? */ 598 | //| xor TMP64, TMP64 599 | //| mov TMP32, CI->u.l.nextraargs 600 | //| add TMP32, nparams1 601 | //| mov rax, CI->func 602 | //| sub_stackid, rax, TMP64 603 | //| mov CI->func, rax 604 | dasm_put(Dst, 582, Dt2(->u.l.nextraargs), nparams1, Dt2(->func), STACKVALUE_POW, Dt2(->func)); 605 | #line 481 "../lvm_x64.dasc" 606 | } 607 | //| mov rax, RA 608 | //| mov TMP2_64, RB 609 | //| add_stackid, rax, TMP2_64 610 | //| mov LS->top, rax 611 | //| call_luaD_poscall, RB 612 | //| 613 | //| callee_restore 614 | dasm_put(Dst, 613, STACKVALUE_POW, Dt1(->top), (unsigned int)((uintptr_t)luaD_poscall), (unsigned int)(((uintptr_t)luaD_poscall)>>32)); 615 | #line 489 "../lvm_x64.dasc" 616 | } break; 617 | 618 | case OP_ADD: { 619 | unsigned int label_op_mmbin_end = set_labels(idx); 620 | //| 621 | //| op_arith, l_addi, luai_numadd 622 | dasm_put(Dst, 667, GETARG_B(i)*STACKVALUE_SZ, GETARG_C(i)*STACKVALUE_SZ, Dt6(->val.tt_), LUA_VNUMINT, Dt7(->val.tt_), LUA_VNUMINT, Dt6(->val.value_.i), Dt7(->val.value_.i), sizeof(Instruction), Dt5(->val.value_.i), Dt5(->val.tt_), LUA_VNUMINT, (label_op_mmbin_end), Dt6(->val.tt_), LUA_VNUMFLT); 623 | dasm_put(Dst, 742, Dt6(->val.value_.n), Dt6(->val.tt_), LUA_VNUMINT, Dt6(->val.value_.i), Dt7(->val.tt_), LUA_VNUMFLT, Dt7(->val.value_.n)); 624 | #line 495 "../lvm_x64.dasc" 625 | //| 626 | dasm_put(Dst, 831, Dt7(->val.tt_), LUA_VNUMINT, Dt7(->val.value_.i), sizeof(Instruction), Dt5(->val.value_.n), Dt5(->val.tt_), LUA_VNUMFLT, (label_op_mmbin_end)); 627 | #line 496 "../lvm_x64.dasc" 628 | } break; 629 | 630 | case OP_MMBIN: { 631 | assert(idx-1>=0 && idx-1sizecode); 632 | Instruction pi = p->code[idx-1]; 633 | lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR); 634 | TMS tm = (TMS)GETARG_C(i); 635 | unsigned int label_op_mmbin_end = get_labels(idx-1); 636 | 637 | //|.macro do_op_mmbin 638 | //| getRV RA 639 | //| getRV RB 640 | //| call_luaT_trybinTM, RA, RB, RC, tm 641 | //|.endmacro 642 | 643 | //| 644 | //| getRB, RB 645 | //| getRA_I, RC, pi 646 | //| Protect, do_op_mmbin 647 | //|=>(label_op_mmbin_end): 648 | //| 649 | dasm_put(Dst, 900, GETARG_B(i)*STACKVALUE_SZ, GETARG_A(pi)*STACKVALUE_SZ, Dt2(->u.l.savedpc), Dt1(->top), Dt2(->top), (int)(ptrdiff_t)&(((StackValue *)0)->val), (int)(ptrdiff_t)&(((StackValue *)0)->val), tm, (unsigned int)((uintptr_t)luaT_trybinTM), (unsigned int)(((uintptr_t)luaT_trybinTM)>>32), Dt2(->u.l.trap), (label_op_mmbin_end)); 650 | #line 517 "../lvm_x64.dasc" 651 | } break; 652 | 653 | case OP_FORPREP: { 654 | unsigned int n = GETARG_Bx(i) + 1; 655 | unsigned int label_op_forperp_end = set_labels(idx); 656 | unsigned int label_op_forloop_end = set_labels(idx+n); 657 | 658 | //| 659 | //| savestate 660 | //| call_lvmjit_forprep, RA 661 | //| cmp eax, 0 662 | //| je >1 663 | //| addpc, n 664 | //| jmp =>(label_op_forloop_end) 665 | //|1: 666 | //| =>(label_op_forperp_end): 667 | //| 668 | dasm_put(Dst, 974, Dt2(->u.l.savedpc), Dt1(->top), Dt2(->top), (unsigned int)((uintptr_t)_lvmjit_forprep), (unsigned int)(((uintptr_t)_lvmjit_forprep)>>32), n*sizeof(Instruction), (label_op_forloop_end), (label_op_forperp_end)); 669 | #line 534 "../lvm_x64.dasc" 670 | } break; 671 | 672 | case OP_FORLOOP: { 673 | int back = GETARG_Bx(i); 674 | unsigned int label_op_forperp_end = get_labels(idx-back); 675 | unsigned int label_op_forloop_end = get_labels(idx); 676 | 677 | //|.define loopcount, TMP64 678 | //|.define loopstep, TMP2_64 679 | //|.define loopidx, rcx 680 | 681 | //|.macro ivalue_s2v_by_ra, V, R1 682 | //| mov RB, RA 683 | //| add RB, V*STACKVALUE_SZ 684 | //| ivalue, RB, R1 685 | //|.endmacro 686 | 687 | //| 688 | //| mov RB, RA 689 | //| add, RB, 2*STACKVALUE_SZ 690 | //| ttisinteger, RB 691 | //| jne >1 692 | //| ivalue_s2v_by_ra, 1, loopcount 693 | //| cmp, loopcount, 0 694 | //| jna >2 695 | //| ivalue_s2v_by_ra, 2, loopstep 696 | //| ivalue, RA, loopidx 697 | //| dec loopcount 698 | //| mov RB, RA 699 | //| add, RB, 1*STACKVALUE_SZ 700 | //| mov qword RB->val.value_.i, loopcount 701 | //| add loopidx, loopstep 702 | //| mov qword RA->val.value_.i, loopidx 703 | //| add, RB, 2*STACKVALUE_SZ 704 | //| setivalue, RB, loopidx 705 | //| subpc, back 706 | //| updatetrap 707 | dasm_put(Dst, 1027, 2*STACKVALUE_SZ, Dt6(->val.tt_), LUA_VNUMINT, 1*STACKVALUE_SZ, Dt6(->val.value_.i), 2*STACKVALUE_SZ, Dt6(->val.value_.i), Dt5(->val.value_.i), 1*STACKVALUE_SZ, Dt6(->val.value_.i), Dt5(->val.value_.i), 2*STACKVALUE_SZ, Dt6(->val.value_.i), Dt6(->val.tt_), LUA_VNUMINT, back*sizeof(Instruction)); 708 | #line 571 "../lvm_x64.dasc" 709 | //| jmp =>(label_op_forperp_end) 710 | //| 711 | //|1: 712 | //| _lvmjit_floatforloop, RA 713 | //| cmp eax, 0 714 | //| je >2 715 | //| subpc, back 716 | //| updatetrap 717 | //| jmp =>(label_op_forperp_end) 718 | //|2: 719 | //| updatetrap 720 | //| =>(label_op_forloop_end): 721 | //| 722 | dasm_put(Dst, 1124, Dt2(->u.l.trap), (label_op_forperp_end), (unsigned int)((uintptr_t)_lvmjit_floatforloop), (unsigned int)(((uintptr_t)_lvmjit_floatforloop)>>32), back*sizeof(Instruction), Dt2(->u.l.trap), (label_op_forperp_end), Dt2(->u.l.trap), (label_op_forloop_end)); 723 | #line 584 "../lvm_x64.dasc" 724 | } break; 725 | 726 | case OP_LOADK: { 727 | TValue *rb = k + GETARG_Bx(i); 728 | //| 729 | //| setobj2s, RA, rb 730 | //| 731 | dasm_put(Dst, 1183, rb->value_.gc, Dt5(->val.value_.gc), rb->tt_, Dt5(->val.tt_)); 732 | #line 591 "../lvm_x64.dasc" 733 | } break; 734 | 735 | default: { 736 | free(op_labels); 737 | luaL_error(L, "Invalid opcode[%d]:%s", op, opnames[op]); 738 | } break; 739 | } 740 | } 741 | 742 | free(op_labels); 743 | return 0; 744 | } 745 | 746 | static int 747 | _resolve_compile(lua_State* L, struct lvmjit_context* C, Proto* p) { 748 | //| callee_save 749 | //| 750 | dasm_put(Dst, 1202); 751 | _do_compile(L, C, p); 752 | #line 609 "../lvm_x64.dasc" 753 | //| 754 | //| callee_restore 755 | dasm_put(Dst, 288); 756 | #line 611 "../lvm_x64.dasc" 757 | return 0; 758 | } 759 | -------------------------------------------------------------------------------- /dynasm/dasm_mips.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM MIPS module. 3 | -- 4 | -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | 8 | -- Module information: 9 | local _info = { 10 | arch = "mips", 11 | description = "DynASM MIPS module", 12 | version = "1.3.0", 13 | vernum = 10300, 14 | release = "2012-01-23", 15 | author = "Mike Pall", 16 | license = "MIT", 17 | } 18 | 19 | -- Exported glue functions for the arch-specific module. 20 | local _M = { _info = _info } 21 | 22 | -- Cache library functions. 23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs 24 | local assert, setmetatable = assert, setmetatable 25 | local _s = string 26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char 27 | local match, gmatch = _s.match, _s.gmatch 28 | local concat, sort = table.concat, table.sort 29 | local bit = bit or require("bit") 30 | local band, shl, sar, tohex = bit.band, bit.lshift, bit.arshift, bit.tohex 31 | 32 | -- Inherited tables and callbacks. 33 | local g_opt, g_arch 34 | local wline, werror, wfatal, wwarn 35 | 36 | -- Action name list. 37 | -- CHECK: Keep this in sync with the C code! 38 | local action_names = { 39 | "STOP", "SECTION", "ESC", "REL_EXT", 40 | "ALIGN", "REL_LG", "LABEL_LG", 41 | "REL_PC", "LABEL_PC", "IMM", 42 | } 43 | 44 | -- Maximum number of section buffer positions for dasm_put(). 45 | -- CHECK: Keep this in sync with the C code! 46 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. 47 | 48 | -- Action name -> action number. 49 | local map_action = {} 50 | for n,name in ipairs(action_names) do 51 | map_action[name] = n-1 52 | end 53 | 54 | -- Action list buffer. 55 | local actlist = {} 56 | 57 | -- Argument list for next dasm_put(). Start with offset 0 into action list. 58 | local actargs = { 0 } 59 | 60 | -- Current number of section buffer positions for dasm_put(). 61 | local secpos = 1 62 | 63 | ------------------------------------------------------------------------------ 64 | 65 | -- Dump action names and numbers. 66 | local function dumpactions(out) 67 | out:write("DynASM encoding engine action codes:\n") 68 | for n,name in ipairs(action_names) do 69 | local num = map_action[name] 70 | out:write(format(" %-10s %02X %d\n", name, num, num)) 71 | end 72 | out:write("\n") 73 | end 74 | 75 | -- Write action list buffer as a huge static C array. 76 | local function writeactions(out, name) 77 | local nn = #actlist 78 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end 79 | out:write("static const unsigned int ", name, "[", nn, "] = {\n") 80 | for i = 1,nn-1 do 81 | assert(out:write("0x", tohex(actlist[i]), ",\n")) 82 | end 83 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) 84 | end 85 | 86 | ------------------------------------------------------------------------------ 87 | 88 | -- Add word to action list. 89 | local function wputxw(n) 90 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 91 | actlist[#actlist+1] = n 92 | end 93 | 94 | -- Add action to list with optional arg. Advance buffer pos, too. 95 | local function waction(action, val, a, num) 96 | local w = assert(map_action[action], "bad action name `"..action.."'") 97 | wputxw(0xff000000 + w * 0x10000 + (val or 0)) 98 | if a then actargs[#actargs+1] = a end 99 | if a or num then secpos = secpos + (num or 1) end 100 | end 101 | 102 | -- Flush action list (intervening C code or buffer pos overflow). 103 | local function wflush(term) 104 | if #actlist == actargs[1] then return end -- Nothing to flush. 105 | if not term then waction("STOP") end -- Terminate action list. 106 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) 107 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). 108 | secpos = 1 -- The actionlist offset occupies a buffer position, too. 109 | end 110 | 111 | -- Put escaped word. 112 | local function wputw(n) 113 | if n >= 0xff000000 then waction("ESC") end 114 | wputxw(n) 115 | end 116 | 117 | -- Reserve position for word. 118 | local function wpos() 119 | local pos = #actlist+1 120 | actlist[pos] = "" 121 | return pos 122 | end 123 | 124 | -- Store word to reserved position. 125 | local function wputpos(pos, n) 126 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 127 | actlist[pos] = n 128 | end 129 | 130 | ------------------------------------------------------------------------------ 131 | 132 | -- Global label name -> global label number. With auto assignment on 1st use. 133 | local next_global = 20 134 | local map_global = setmetatable({}, { __index = function(t, name) 135 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end 136 | local n = next_global 137 | if n > 2047 then werror("too many global labels") end 138 | next_global = n + 1 139 | t[name] = n 140 | return n 141 | end}) 142 | 143 | -- Dump global labels. 144 | local function dumpglobals(out, lvl) 145 | local t = {} 146 | for name, n in pairs(map_global) do t[n] = name end 147 | out:write("Global labels:\n") 148 | for i=20,next_global-1 do 149 | out:write(format(" %s\n", t[i])) 150 | end 151 | out:write("\n") 152 | end 153 | 154 | -- Write global label enum. 155 | local function writeglobals(out, prefix) 156 | local t = {} 157 | for name, n in pairs(map_global) do t[n] = name end 158 | out:write("enum {\n") 159 | for i=20,next_global-1 do 160 | out:write(" ", prefix, t[i], ",\n") 161 | end 162 | out:write(" ", prefix, "_MAX\n};\n") 163 | end 164 | 165 | -- Write global label names. 166 | local function writeglobalnames(out, name) 167 | local t = {} 168 | for name, n in pairs(map_global) do t[n] = name end 169 | out:write("static const char *const ", name, "[] = {\n") 170 | for i=20,next_global-1 do 171 | out:write(" \"", t[i], "\",\n") 172 | end 173 | out:write(" (const char *)0\n};\n") 174 | end 175 | 176 | ------------------------------------------------------------------------------ 177 | 178 | -- Extern label name -> extern label number. With auto assignment on 1st use. 179 | local next_extern = 0 180 | local map_extern_ = {} 181 | local map_extern = setmetatable({}, { __index = function(t, name) 182 | -- No restrictions on the name for now. 183 | local n = next_extern 184 | if n > 2047 then werror("too many extern labels") end 185 | next_extern = n + 1 186 | t[name] = n 187 | map_extern_[n] = name 188 | return n 189 | end}) 190 | 191 | -- Dump extern labels. 192 | local function dumpexterns(out, lvl) 193 | out:write("Extern labels:\n") 194 | for i=0,next_extern-1 do 195 | out:write(format(" %s\n", map_extern_[i])) 196 | end 197 | out:write("\n") 198 | end 199 | 200 | -- Write extern label names. 201 | local function writeexternnames(out, name) 202 | out:write("static const char *const ", name, "[] = {\n") 203 | for i=0,next_extern-1 do 204 | out:write(" \"", map_extern_[i], "\",\n") 205 | end 206 | out:write(" (const char *)0\n};\n") 207 | end 208 | 209 | ------------------------------------------------------------------------------ 210 | 211 | -- Arch-specific maps. 212 | local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. 213 | 214 | local map_type = {} -- Type name -> { ctype, reg } 215 | local ctypenum = 0 -- Type number (for Dt... macros). 216 | 217 | -- Reverse defines for registers. 218 | function _M.revdef(s) 219 | if s == "r29" then return "sp" 220 | elseif s == "r31" then return "ra" end 221 | return s 222 | end 223 | 224 | ------------------------------------------------------------------------------ 225 | 226 | -- Template strings for MIPS instructions. 227 | local map_op = { 228 | -- First-level opcodes. 229 | j_1 = "08000000J", 230 | jal_1 = "0c000000J", 231 | b_1 = "10000000B", 232 | beqz_2 = "10000000SB", 233 | beq_3 = "10000000STB", 234 | bnez_2 = "14000000SB", 235 | bne_3 = "14000000STB", 236 | blez_2 = "18000000SB", 237 | bgtz_2 = "1c000000SB", 238 | addi_3 = "20000000TSI", 239 | li_2 = "24000000TI", 240 | addiu_3 = "24000000TSI", 241 | slti_3 = "28000000TSI", 242 | sltiu_3 = "2c000000TSI", 243 | andi_3 = "30000000TSU", 244 | lu_2 = "34000000TU", 245 | ori_3 = "34000000TSU", 246 | xori_3 = "38000000TSU", 247 | lui_2 = "3c000000TU", 248 | beqzl_2 = "50000000SB", 249 | beql_3 = "50000000STB", 250 | bnezl_2 = "54000000SB", 251 | bnel_3 = "54000000STB", 252 | blezl_2 = "58000000SB", 253 | bgtzl_2 = "5c000000SB", 254 | lb_2 = "80000000TO", 255 | lh_2 = "84000000TO", 256 | lwl_2 = "88000000TO", 257 | lw_2 = "8c000000TO", 258 | lbu_2 = "90000000TO", 259 | lhu_2 = "94000000TO", 260 | lwr_2 = "98000000TO", 261 | sb_2 = "a0000000TO", 262 | sh_2 = "a4000000TO", 263 | swl_2 = "a8000000TO", 264 | sw_2 = "ac000000TO", 265 | swr_2 = "b8000000TO", 266 | cache_2 = "bc000000NO", 267 | ll_2 = "c0000000TO", 268 | lwc1_2 = "c4000000HO", 269 | pref_2 = "cc000000NO", 270 | ldc1_2 = "d4000000HO", 271 | sc_2 = "e0000000TO", 272 | swc1_2 = "e4000000HO", 273 | sdc1_2 = "f4000000HO", 274 | 275 | -- Opcode SPECIAL. 276 | nop_0 = "00000000", 277 | sll_3 = "00000000DTA", 278 | movf_2 = "00000001DS", 279 | movf_3 = "00000001DSC", 280 | movt_2 = "00010001DS", 281 | movt_3 = "00010001DSC", 282 | srl_3 = "00000002DTA", 283 | rotr_3 = "00200002DTA", 284 | sra_3 = "00000003DTA", 285 | sllv_3 = "00000004DTS", 286 | srlv_3 = "00000006DTS", 287 | rotrv_3 = "00000046DTS", 288 | srav_3 = "00000007DTS", 289 | jr_1 = "00000008S", 290 | jalr_1 = "0000f809S", 291 | jalr_2 = "00000009DS", 292 | movz_3 = "0000000aDST", 293 | movn_3 = "0000000bDST", 294 | syscall_0 = "0000000c", 295 | syscall_1 = "0000000cY", 296 | break_0 = "0000000d", 297 | break_1 = "0000000dY", 298 | sync_0 = "0000000f", 299 | mfhi_1 = "00000010D", 300 | mthi_1 = "00000011S", 301 | mflo_1 = "00000012D", 302 | mtlo_1 = "00000013S", 303 | mult_2 = "00000018ST", 304 | multu_2 = "00000019ST", 305 | div_2 = "0000001aST", 306 | divu_2 = "0000001bST", 307 | add_3 = "00000020DST", 308 | move_2 = "00000021DS", 309 | addu_3 = "00000021DST", 310 | sub_3 = "00000022DST", 311 | negu_2 = "00000023DT", 312 | subu_3 = "00000023DST", 313 | and_3 = "00000024DST", 314 | or_3 = "00000025DST", 315 | xor_3 = "00000026DST", 316 | not_2 = "00000027DS", 317 | nor_3 = "00000027DST", 318 | slt_3 = "0000002aDST", 319 | sltu_3 = "0000002bDST", 320 | tge_2 = "00000030ST", 321 | tge_3 = "00000030STZ", 322 | tgeu_2 = "00000031ST", 323 | tgeu_3 = "00000031STZ", 324 | tlt_2 = "00000032ST", 325 | tlt_3 = "00000032STZ", 326 | tltu_2 = "00000033ST", 327 | tltu_3 = "00000033STZ", 328 | teq_2 = "00000034ST", 329 | teq_3 = "00000034STZ", 330 | tne_2 = "00000036ST", 331 | tne_3 = "00000036STZ", 332 | 333 | -- Opcode REGIMM. 334 | bltz_2 = "04000000SB", 335 | bgez_2 = "04010000SB", 336 | bltzl_2 = "04020000SB", 337 | bgezl_2 = "04030000SB", 338 | tgei_2 = "04080000SI", 339 | tgeiu_2 = "04090000SI", 340 | tlti_2 = "040a0000SI", 341 | tltiu_2 = "040b0000SI", 342 | teqi_2 = "040c0000SI", 343 | tnei_2 = "040e0000SI", 344 | bltzal_2 = "04100000SB", 345 | bal_1 = "04110000B", 346 | bgezal_2 = "04110000SB", 347 | bltzall_2 = "04120000SB", 348 | bgezall_2 = "04130000SB", 349 | synci_1 = "041f0000O", 350 | 351 | -- Opcode SPECIAL2. 352 | madd_2 = "70000000ST", 353 | maddu_2 = "70000001ST", 354 | mul_3 = "70000002DST", 355 | msub_2 = "70000004ST", 356 | msubu_2 = "70000005ST", 357 | clz_2 = "70000020DS=", 358 | clo_2 = "70000021DS=", 359 | sdbbp_0 = "7000003f", 360 | sdbbp_1 = "7000003fY", 361 | 362 | -- Opcode SPECIAL3. 363 | ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 364 | ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 365 | wsbh_2 = "7c0000a0DT", 366 | seb_2 = "7c000420DT", 367 | seh_2 = "7c000620DT", 368 | rdhwr_2 = "7c00003bTD", 369 | 370 | -- Opcode COP0. 371 | mfc0_2 = "40000000TD", 372 | mfc0_3 = "40000000TDW", 373 | mtc0_2 = "40800000TD", 374 | mtc0_3 = "40800000TDW", 375 | rdpgpr_2 = "41400000DT", 376 | di_0 = "41606000", 377 | di_1 = "41606000T", 378 | ei_0 = "41606020", 379 | ei_1 = "41606020T", 380 | wrpgpr_2 = "41c00000DT", 381 | tlbr_0 = "42000001", 382 | tlbwi_0 = "42000002", 383 | tlbwr_0 = "42000006", 384 | tlbp_0 = "42000008", 385 | eret_0 = "42000018", 386 | deret_0 = "4200001f", 387 | wait_0 = "42000020", 388 | 389 | -- Opcode COP1. 390 | mfc1_2 = "44000000TG", 391 | cfc1_2 = "44400000TG", 392 | mfhc1_2 = "44600000TG", 393 | mtc1_2 = "44800000TG", 394 | ctc1_2 = "44c00000TG", 395 | mthc1_2 = "44e00000TG", 396 | 397 | bc1f_1 = "45000000B", 398 | bc1f_2 = "45000000CB", 399 | bc1t_1 = "45010000B", 400 | bc1t_2 = "45010000CB", 401 | bc1fl_1 = "45020000B", 402 | bc1fl_2 = "45020000CB", 403 | bc1tl_1 = "45030000B", 404 | bc1tl_2 = "45030000CB", 405 | 406 | ["add.s_3"] = "46000000FGH", 407 | ["sub.s_3"] = "46000001FGH", 408 | ["mul.s_3"] = "46000002FGH", 409 | ["div.s_3"] = "46000003FGH", 410 | ["sqrt.s_2"] = "46000004FG", 411 | ["abs.s_2"] = "46000005FG", 412 | ["mov.s_2"] = "46000006FG", 413 | ["neg.s_2"] = "46000007FG", 414 | ["round.l.s_2"] = "46000008FG", 415 | ["trunc.l.s_2"] = "46000009FG", 416 | ["ceil.l.s_2"] = "4600000aFG", 417 | ["floor.l.s_2"] = "4600000bFG", 418 | ["round.w.s_2"] = "4600000cFG", 419 | ["trunc.w.s_2"] = "4600000dFG", 420 | ["ceil.w.s_2"] = "4600000eFG", 421 | ["floor.w.s_2"] = "4600000fFG", 422 | ["movf.s_2"] = "46000011FG", 423 | ["movf.s_3"] = "46000011FGC", 424 | ["movt.s_2"] = "46010011FG", 425 | ["movt.s_3"] = "46010011FGC", 426 | ["movz.s_3"] = "46000012FGT", 427 | ["movn.s_3"] = "46000013FGT", 428 | ["recip.s_2"] = "46000015FG", 429 | ["rsqrt.s_2"] = "46000016FG", 430 | ["cvt.d.s_2"] = "46000021FG", 431 | ["cvt.w.s_2"] = "46000024FG", 432 | ["cvt.l.s_2"] = "46000025FG", 433 | ["cvt.ps.s_3"] = "46000026FGH", 434 | ["c.f.s_2"] = "46000030GH", 435 | ["c.f.s_3"] = "46000030VGH", 436 | ["c.un.s_2"] = "46000031GH", 437 | ["c.un.s_3"] = "46000031VGH", 438 | ["c.eq.s_2"] = "46000032GH", 439 | ["c.eq.s_3"] = "46000032VGH", 440 | ["c.ueq.s_2"] = "46000033GH", 441 | ["c.ueq.s_3"] = "46000033VGH", 442 | ["c.olt.s_2"] = "46000034GH", 443 | ["c.olt.s_3"] = "46000034VGH", 444 | ["c.ult.s_2"] = "46000035GH", 445 | ["c.ult.s_3"] = "46000035VGH", 446 | ["c.ole.s_2"] = "46000036GH", 447 | ["c.ole.s_3"] = "46000036VGH", 448 | ["c.ule.s_2"] = "46000037GH", 449 | ["c.ule.s_3"] = "46000037VGH", 450 | ["c.sf.s_2"] = "46000038GH", 451 | ["c.sf.s_3"] = "46000038VGH", 452 | ["c.ngle.s_2"] = "46000039GH", 453 | ["c.ngle.s_3"] = "46000039VGH", 454 | ["c.seq.s_2"] = "4600003aGH", 455 | ["c.seq.s_3"] = "4600003aVGH", 456 | ["c.ngl.s_2"] = "4600003bGH", 457 | ["c.ngl.s_3"] = "4600003bVGH", 458 | ["c.lt.s_2"] = "4600003cGH", 459 | ["c.lt.s_3"] = "4600003cVGH", 460 | ["c.nge.s_2"] = "4600003dGH", 461 | ["c.nge.s_3"] = "4600003dVGH", 462 | ["c.le.s_2"] = "4600003eGH", 463 | ["c.le.s_3"] = "4600003eVGH", 464 | ["c.ngt.s_2"] = "4600003fGH", 465 | ["c.ngt.s_3"] = "4600003fVGH", 466 | 467 | ["add.d_3"] = "46200000FGH", 468 | ["sub.d_3"] = "46200001FGH", 469 | ["mul.d_3"] = "46200002FGH", 470 | ["div.d_3"] = "46200003FGH", 471 | ["sqrt.d_2"] = "46200004FG", 472 | ["abs.d_2"] = "46200005FG", 473 | ["mov.d_2"] = "46200006FG", 474 | ["neg.d_2"] = "46200007FG", 475 | ["round.l.d_2"] = "46200008FG", 476 | ["trunc.l.d_2"] = "46200009FG", 477 | ["ceil.l.d_2"] = "4620000aFG", 478 | ["floor.l.d_2"] = "4620000bFG", 479 | ["round.w.d_2"] = "4620000cFG", 480 | ["trunc.w.d_2"] = "4620000dFG", 481 | ["ceil.w.d_2"] = "4620000eFG", 482 | ["floor.w.d_2"] = "4620000fFG", 483 | ["movf.d_2"] = "46200011FG", 484 | ["movf.d_3"] = "46200011FGC", 485 | ["movt.d_2"] = "46210011FG", 486 | ["movt.d_3"] = "46210011FGC", 487 | ["movz.d_3"] = "46200012FGT", 488 | ["movn.d_3"] = "46200013FGT", 489 | ["recip.d_2"] = "46200015FG", 490 | ["rsqrt.d_2"] = "46200016FG", 491 | ["cvt.s.d_2"] = "46200020FG", 492 | ["cvt.w.d_2"] = "46200024FG", 493 | ["cvt.l.d_2"] = "46200025FG", 494 | ["c.f.d_2"] = "46200030GH", 495 | ["c.f.d_3"] = "46200030VGH", 496 | ["c.un.d_2"] = "46200031GH", 497 | ["c.un.d_3"] = "46200031VGH", 498 | ["c.eq.d_2"] = "46200032GH", 499 | ["c.eq.d_3"] = "46200032VGH", 500 | ["c.ueq.d_2"] = "46200033GH", 501 | ["c.ueq.d_3"] = "46200033VGH", 502 | ["c.olt.d_2"] = "46200034GH", 503 | ["c.olt.d_3"] = "46200034VGH", 504 | ["c.ult.d_2"] = "46200035GH", 505 | ["c.ult.d_3"] = "46200035VGH", 506 | ["c.ole.d_2"] = "46200036GH", 507 | ["c.ole.d_3"] = "46200036VGH", 508 | ["c.ule.d_2"] = "46200037GH", 509 | ["c.ule.d_3"] = "46200037VGH", 510 | ["c.sf.d_2"] = "46200038GH", 511 | ["c.sf.d_3"] = "46200038VGH", 512 | ["c.ngle.d_2"] = "46200039GH", 513 | ["c.ngle.d_3"] = "46200039VGH", 514 | ["c.seq.d_2"] = "4620003aGH", 515 | ["c.seq.d_3"] = "4620003aVGH", 516 | ["c.ngl.d_2"] = "4620003bGH", 517 | ["c.ngl.d_3"] = "4620003bVGH", 518 | ["c.lt.d_2"] = "4620003cGH", 519 | ["c.lt.d_3"] = "4620003cVGH", 520 | ["c.nge.d_2"] = "4620003dGH", 521 | ["c.nge.d_3"] = "4620003dVGH", 522 | ["c.le.d_2"] = "4620003eGH", 523 | ["c.le.d_3"] = "4620003eVGH", 524 | ["c.ngt.d_2"] = "4620003fGH", 525 | ["c.ngt.d_3"] = "4620003fVGH", 526 | 527 | ["add.ps_3"] = "46c00000FGH", 528 | ["sub.ps_3"] = "46c00001FGH", 529 | ["mul.ps_3"] = "46c00002FGH", 530 | ["abs.ps_2"] = "46c00005FG", 531 | ["mov.ps_2"] = "46c00006FG", 532 | ["neg.ps_2"] = "46c00007FG", 533 | ["movf.ps_2"] = "46c00011FG", 534 | ["movf.ps_3"] = "46c00011FGC", 535 | ["movt.ps_2"] = "46c10011FG", 536 | ["movt.ps_3"] = "46c10011FGC", 537 | ["movz.ps_3"] = "46c00012FGT", 538 | ["movn.ps_3"] = "46c00013FGT", 539 | ["cvt.s.pu_2"] = "46c00020FG", 540 | ["cvt.s.pl_2"] = "46c00028FG", 541 | ["pll.ps_3"] = "46c0002cFGH", 542 | ["plu.ps_3"] = "46c0002dFGH", 543 | ["pul.ps_3"] = "46c0002eFGH", 544 | ["puu.ps_3"] = "46c0002fFGH", 545 | ["c.f.ps_2"] = "46c00030GH", 546 | ["c.f.ps_3"] = "46c00030VGH", 547 | ["c.un.ps_2"] = "46c00031GH", 548 | ["c.un.ps_3"] = "46c00031VGH", 549 | ["c.eq.ps_2"] = "46c00032GH", 550 | ["c.eq.ps_3"] = "46c00032VGH", 551 | ["c.ueq.ps_2"] = "46c00033GH", 552 | ["c.ueq.ps_3"] = "46c00033VGH", 553 | ["c.olt.ps_2"] = "46c00034GH", 554 | ["c.olt.ps_3"] = "46c00034VGH", 555 | ["c.ult.ps_2"] = "46c00035GH", 556 | ["c.ult.ps_3"] = "46c00035VGH", 557 | ["c.ole.ps_2"] = "46c00036GH", 558 | ["c.ole.ps_3"] = "46c00036VGH", 559 | ["c.ule.ps_2"] = "46c00037GH", 560 | ["c.ule.ps_3"] = "46c00037VGH", 561 | ["c.sf.ps_2"] = "46c00038GH", 562 | ["c.sf.ps_3"] = "46c00038VGH", 563 | ["c.ngle.ps_2"] = "46c00039GH", 564 | ["c.ngle.ps_3"] = "46c00039VGH", 565 | ["c.seq.ps_2"] = "46c0003aGH", 566 | ["c.seq.ps_3"] = "46c0003aVGH", 567 | ["c.ngl.ps_2"] = "46c0003bGH", 568 | ["c.ngl.ps_3"] = "46c0003bVGH", 569 | ["c.lt.ps_2"] = "46c0003cGH", 570 | ["c.lt.ps_3"] = "46c0003cVGH", 571 | ["c.nge.ps_2"] = "46c0003dGH", 572 | ["c.nge.ps_3"] = "46c0003dVGH", 573 | ["c.le.ps_2"] = "46c0003eGH", 574 | ["c.le.ps_3"] = "46c0003eVGH", 575 | ["c.ngt.ps_2"] = "46c0003fGH", 576 | ["c.ngt.ps_3"] = "46c0003fVGH", 577 | 578 | ["cvt.s.w_2"] = "46800020FG", 579 | ["cvt.d.w_2"] = "46800021FG", 580 | 581 | ["cvt.s.l_2"] = "46a00020FG", 582 | ["cvt.d.l_2"] = "46a00021FG", 583 | 584 | -- Opcode COP1X. 585 | lwxc1_2 = "4c000000FX", 586 | ldxc1_2 = "4c000001FX", 587 | luxc1_2 = "4c000005FX", 588 | swxc1_2 = "4c000008FX", 589 | sdxc1_2 = "4c000009FX", 590 | suxc1_2 = "4c00000dFX", 591 | prefx_2 = "4c00000fMX", 592 | ["alnv.ps_4"] = "4c00001eFGHS", 593 | ["madd.s_4"] = "4c000020FRGH", 594 | ["madd.d_4"] = "4c000021FRGH", 595 | ["madd.ps_4"] = "4c000026FRGH", 596 | ["msub.s_4"] = "4c000028FRGH", 597 | ["msub.d_4"] = "4c000029FRGH", 598 | ["msub.ps_4"] = "4c00002eFRGH", 599 | ["nmadd.s_4"] = "4c000030FRGH", 600 | ["nmadd.d_4"] = "4c000031FRGH", 601 | ["nmadd.ps_4"] = "4c000036FRGH", 602 | ["nmsub.s_4"] = "4c000038FRGH", 603 | ["nmsub.d_4"] = "4c000039FRGH", 604 | ["nmsub.ps_4"] = "4c00003eFRGH", 605 | } 606 | 607 | ------------------------------------------------------------------------------ 608 | 609 | local function parse_gpr(expr) 610 | local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") 611 | local tp = map_type[tname or expr] 612 | if tp then 613 | local reg = ovreg or tp.reg 614 | if not reg then 615 | werror("type `"..(tname or expr).."' needs a register override") 616 | end 617 | expr = reg 618 | end 619 | local r = match(expr, "^r([1-3]?[0-9])$") 620 | if r then 621 | r = tonumber(r) 622 | if r <= 31 then return r, tp end 623 | end 624 | werror("bad register name `"..expr.."'") 625 | end 626 | 627 | local function parse_fpr(expr) 628 | local r = match(expr, "^f([1-3]?[0-9])$") 629 | if r then 630 | r = tonumber(r) 631 | if r <= 31 then return r end 632 | end 633 | werror("bad register name `"..expr.."'") 634 | end 635 | 636 | local function parse_imm(imm, bits, shift, scale, signed) 637 | local n = tonumber(imm) 638 | if n then 639 | local m = sar(n, scale) 640 | if shl(m, scale) == n then 641 | if signed then 642 | local s = sar(m, bits-1) 643 | if s == 0 then return shl(m, shift) 644 | elseif s == -1 then return shl(m + shl(1, bits), shift) end 645 | else 646 | if sar(m, bits) == 0 then return shl(m, shift) end 647 | end 648 | end 649 | werror("out of range immediate `"..imm.."'") 650 | elseif match(imm, "^[rf]([1-3]?[0-9])$") or 651 | match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then 652 | werror("expected immediate operand, got register") 653 | else 654 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) 655 | return 0 656 | end 657 | end 658 | 659 | local function parse_disp(disp) 660 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") 661 | if imm then 662 | local r = shl(parse_gpr(reg), 21) 663 | local extname = match(imm, "^extern%s+(%S+)$") 664 | if extname then 665 | waction("REL_EXT", map_extern[extname], nil, 1) 666 | return r 667 | else 668 | return r + parse_imm(imm, 16, 0, 0, true) 669 | end 670 | end 671 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") 672 | if reg and tailr ~= "" then 673 | local r, tp = parse_gpr(reg) 674 | if tp then 675 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) 676 | return shl(r, 21) 677 | end 678 | end 679 | werror("bad displacement `"..disp.."'") 680 | end 681 | 682 | local function parse_index(idx) 683 | local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") 684 | if rt then 685 | rt = parse_gpr(rt) 686 | rs = parse_gpr(rs) 687 | return shl(rt, 16) + shl(rs, 21) 688 | end 689 | werror("bad index `"..idx.."'") 690 | end 691 | 692 | local function parse_label(label, def) 693 | local prefix = sub(label, 1, 2) 694 | -- =>label (pc label reference) 695 | if prefix == "=>" then 696 | return "PC", 0, sub(label, 3) 697 | end 698 | -- ->name (global label reference) 699 | if prefix == "->" then 700 | return "LG", map_global[sub(label, 3)] 701 | end 702 | if def then 703 | -- [1-9] (local label definition) 704 | if match(label, "^[1-9]$") then 705 | return "LG", 10+tonumber(label) 706 | end 707 | else 708 | -- [<>][1-9] (local label reference) 709 | local dir, lnum = match(label, "^([<>])([1-9])$") 710 | if dir then -- Fwd: 1-9, Bkwd: 11-19. 711 | return "LG", lnum + (dir == ">" and 0 or 10) 712 | end 713 | -- extern label (extern label reference) 714 | local extname = match(label, "^extern%s+(%S+)$") 715 | if extname then 716 | return "EXT", map_extern[extname] 717 | end 718 | end 719 | werror("bad label `"..label.."'") 720 | end 721 | 722 | ------------------------------------------------------------------------------ 723 | 724 | -- Handle opcodes defined with template strings. 725 | map_op[".template__"] = function(params, template, nparams) 726 | if not params then return sub(template, 9) end 727 | local op = tonumber(sub(template, 1, 8), 16) 728 | local n = 1 729 | 730 | -- Limit number of section buffer positions used by a single dasm_put(). 731 | -- A single opcode needs a maximum of 2 positions (ins/ext). 732 | if secpos+2 > maxsecpos then wflush() end 733 | local pos = wpos() 734 | 735 | -- Process each character. 736 | for p in gmatch(sub(template, 9), ".") do 737 | if p == "D" then 738 | op = op + shl(parse_gpr(params[n]), 11); n = n + 1 739 | elseif p == "T" then 740 | op = op + shl(parse_gpr(params[n]), 16); n = n + 1 741 | elseif p == "S" then 742 | op = op + shl(parse_gpr(params[n]), 21); n = n + 1 743 | elseif p == "F" then 744 | op = op + shl(parse_fpr(params[n]), 6); n = n + 1 745 | elseif p == "G" then 746 | op = op + shl(parse_fpr(params[n]), 11); n = n + 1 747 | elseif p == "H" then 748 | op = op + shl(parse_fpr(params[n]), 16); n = n + 1 749 | elseif p == "R" then 750 | op = op + shl(parse_fpr(params[n]), 21); n = n + 1 751 | elseif p == "I" then 752 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 753 | elseif p == "U" then 754 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 755 | elseif p == "O" then 756 | op = op + parse_disp(params[n]); n = n + 1 757 | elseif p == "X" then 758 | op = op + parse_index(params[n]); n = n + 1 759 | elseif p == "B" or p == "J" then 760 | local mode, n, s = parse_label(params[n], false) 761 | if p == "B" then n = n + 2048 end 762 | waction("REL_"..mode, n, s, 1) 763 | n = n + 1 764 | elseif p == "A" then 765 | op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 766 | elseif p == "M" then 767 | op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 768 | elseif p == "N" then 769 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 770 | elseif p == "C" then 771 | op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 772 | elseif p == "V" then 773 | op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 774 | elseif p == "W" then 775 | op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 776 | elseif p == "Y" then 777 | op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 778 | elseif p == "Z" then 779 | op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 780 | elseif p == "=" then 781 | op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo. 782 | else 783 | assert(false) 784 | end 785 | end 786 | wputpos(pos, op) 787 | end 788 | 789 | ------------------------------------------------------------------------------ 790 | 791 | -- Pseudo-opcode to mark the position where the action list is to be emitted. 792 | map_op[".actionlist_1"] = function(params) 793 | if not params then return "cvar" end 794 | local name = params[1] -- No syntax check. You get to keep the pieces. 795 | wline(function(out) writeactions(out, name) end) 796 | end 797 | 798 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. 799 | map_op[".globals_1"] = function(params) 800 | if not params then return "prefix" end 801 | local prefix = params[1] -- No syntax check. You get to keep the pieces. 802 | wline(function(out) writeglobals(out, prefix) end) 803 | end 804 | 805 | -- Pseudo-opcode to mark the position where the global names are to be emitted. 806 | map_op[".globalnames_1"] = function(params) 807 | if not params then return "cvar" end 808 | local name = params[1] -- No syntax check. You get to keep the pieces. 809 | wline(function(out) writeglobalnames(out, name) end) 810 | end 811 | 812 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. 813 | map_op[".externnames_1"] = function(params) 814 | if not params then return "cvar" end 815 | local name = params[1] -- No syntax check. You get to keep the pieces. 816 | wline(function(out) writeexternnames(out, name) end) 817 | end 818 | 819 | ------------------------------------------------------------------------------ 820 | 821 | -- Label pseudo-opcode (converted from trailing colon form). 822 | map_op[".label_1"] = function(params) 823 | if not params then return "[1-9] | ->global | =>pcexpr" end 824 | if secpos+1 > maxsecpos then wflush() end 825 | local mode, n, s = parse_label(params[1], true) 826 | if mode == "EXT" then werror("bad label definition") end 827 | waction("LABEL_"..mode, n, s, 1) 828 | end 829 | 830 | ------------------------------------------------------------------------------ 831 | 832 | -- Pseudo-opcodes for data storage. 833 | map_op[".long_*"] = function(params) 834 | if not params then return "imm..." end 835 | for _,p in ipairs(params) do 836 | local n = tonumber(p) 837 | if not n then werror("bad immediate `"..p.."'") end 838 | if n < 0 then n = n + 2^32 end 839 | wputw(n) 840 | if secpos+2 > maxsecpos then wflush() end 841 | end 842 | end 843 | 844 | -- Alignment pseudo-opcode. 845 | map_op[".align_1"] = function(params) 846 | if not params then return "numpow2" end 847 | if secpos+1 > maxsecpos then wflush() end 848 | local align = tonumber(params[1]) 849 | if align then 850 | local x = align 851 | -- Must be a power of 2 in the range (2 ... 256). 852 | for i=1,8 do 853 | x = x / 2 854 | if x == 1 then 855 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. 856 | return 857 | end 858 | end 859 | end 860 | werror("bad alignment") 861 | end 862 | 863 | ------------------------------------------------------------------------------ 864 | 865 | -- Pseudo-opcode for (primitive) type definitions (map to C types). 866 | map_op[".type_3"] = function(params, nparams) 867 | if not params then 868 | return nparams == 2 and "name, ctype" or "name, ctype, reg" 869 | end 870 | local name, ctype, reg = params[1], params[2], params[3] 871 | if not match(name, "^[%a_][%w_]*$") then 872 | werror("bad type name `"..name.."'") 873 | end 874 | local tp = map_type[name] 875 | if tp then 876 | werror("duplicate type `"..name.."'") 877 | end 878 | -- Add #type to defines. A bit unclean to put it in map_archdef. 879 | map_archdef["#"..name] = "sizeof("..ctype..")" 880 | -- Add new type and emit shortcut define. 881 | local num = ctypenum + 1 882 | map_type[name] = { 883 | ctype = ctype, 884 | ctypefmt = format("Dt%X(%%s)", num), 885 | reg = reg, 886 | } 887 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) 888 | ctypenum = num 889 | end 890 | map_op[".type_2"] = map_op[".type_3"] 891 | 892 | -- Dump type definitions. 893 | local function dumptypes(out, lvl) 894 | local t = {} 895 | for name in pairs(map_type) do t[#t+1] = name end 896 | sort(t) 897 | out:write("Type definitions:\n") 898 | for _,name in ipairs(t) do 899 | local tp = map_type[name] 900 | local reg = tp.reg or "" 901 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) 902 | end 903 | out:write("\n") 904 | end 905 | 906 | ------------------------------------------------------------------------------ 907 | 908 | -- Set the current section. 909 | function _M.section(num) 910 | waction("SECTION", num) 911 | wflush(true) -- SECTION is a terminal action. 912 | end 913 | 914 | ------------------------------------------------------------------------------ 915 | 916 | -- Dump architecture description. 917 | function _M.dumparch(out) 918 | out:write(format("DynASM %s version %s, released %s\n\n", 919 | _info.arch, _info.version, _info.release)) 920 | dumpactions(out) 921 | end 922 | 923 | -- Dump all user defined elements. 924 | function _M.dumpdef(out, lvl) 925 | dumptypes(out, lvl) 926 | dumpglobals(out, lvl) 927 | dumpexterns(out, lvl) 928 | end 929 | 930 | ------------------------------------------------------------------------------ 931 | 932 | -- Pass callbacks from/to the DynASM core. 933 | function _M.passcb(wl, we, wf, ww) 934 | wline, werror, wfatal, wwarn = wl, we, wf, ww 935 | return wflush 936 | end 937 | 938 | -- Setup the arch-specific module. 939 | function _M.setup(arch, opt) 940 | g_arch, g_opt = arch, opt 941 | end 942 | 943 | -- Merge the core maps and the arch-specific maps. 944 | function _M.mergemaps(map_coreop, map_def) 945 | setmetatable(map_op, { __index = map_coreop }) 946 | setmetatable(map_def, { __index = map_archdef }) 947 | return map_op, map_def 948 | end 949 | 950 | return _M 951 | 952 | ------------------------------------------------------------------------------ 953 | 954 | -------------------------------------------------------------------------------- /dynasm/dynasm.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM. A dynamic assembler for code generation engines. 3 | -- Originally designed and implemented for LuaJIT. 4 | -- 5 | -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. 6 | -- See below for full copyright notice. 7 | ------------------------------------------------------------------------------ 8 | 9 | -- Application information. 10 | local _info = { 11 | name = "DynASM", 12 | description = "A dynamic assembler for code generation engines", 13 | version = "1.3.0", 14 | vernum = 10300, 15 | release = "2011-05-05", 16 | author = "Mike Pall", 17 | url = "http://luajit.org/dynasm.html", 18 | license = "MIT", 19 | copyright = [[ 20 | Copyright (C) 2005-2017 Mike Pall. All rights reserved. 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining 23 | a copy of this software and associated documentation files (the 24 | "Software"), to deal in the Software without restriction, including 25 | without limitation the rights to use, copy, modify, merge, publish, 26 | distribute, sublicense, and/or sell copies of the Software, and to 27 | permit persons to whom the Software is furnished to do so, subject to 28 | the following conditions: 29 | 30 | The above copyright notice and this permission notice shall be 31 | included in all copies or substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 34 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 35 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 36 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 37 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 38 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 39 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 40 | 41 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 42 | ]], 43 | } 44 | 45 | -- Cache library functions. 46 | local type, pairs, ipairs = type, pairs, ipairs 47 | local pcall, error, assert = pcall, error, assert 48 | local _s = string 49 | local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub 50 | local format, rep, upper = _s.format, _s.rep, _s.upper 51 | local _t = table 52 | local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort 53 | local exit = os.exit 54 | local io = io 55 | local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr 56 | 57 | ------------------------------------------------------------------------------ 58 | 59 | -- Program options. 60 | local g_opt = {} 61 | 62 | -- Global state for current file. 63 | local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch 64 | local g_errcount = 0 65 | 66 | -- Write buffer for output file. 67 | local g_wbuffer, g_capbuffer 68 | 69 | ------------------------------------------------------------------------------ 70 | 71 | -- Write an output line (or callback function) to the buffer. 72 | local function wline(line, needindent) 73 | local buf = g_capbuffer or g_wbuffer 74 | buf[#buf+1] = needindent and g_indent..line or line 75 | g_synclineno = g_synclineno + 1 76 | end 77 | 78 | -- Write assembler line as a comment, if requestd. 79 | local function wcomment(aline) 80 | if g_opt.comment then 81 | wline(g_opt.comment..aline..g_opt.endcomment, true) 82 | end 83 | end 84 | 85 | -- Resync CPP line numbers. 86 | local function wsync() 87 | if g_synclineno ~= g_lineno and g_opt.cpp then 88 | wline("#line "..g_lineno..' "'..g_fname..'"') 89 | g_synclineno = g_lineno 90 | end 91 | end 92 | 93 | -- Dummy action flush function. Replaced with arch-specific function later. 94 | local function wflush(term) 95 | end 96 | 97 | -- Dump all buffered output lines. 98 | local function wdumplines(out, buf) 99 | for _,line in ipairs(buf) do 100 | if type(line) == "string" then 101 | assert(out:write(line, "\n")) 102 | else 103 | -- Special callback to dynamically insert lines after end of processing. 104 | line(out) 105 | end 106 | end 107 | end 108 | 109 | ------------------------------------------------------------------------------ 110 | 111 | -- Emit an error. Processing continues with next statement. 112 | local function werror(msg) 113 | error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) 114 | end 115 | 116 | -- Emit a fatal error. Processing stops. 117 | local function wfatal(msg) 118 | g_errcount = "fatal" 119 | werror(msg) 120 | end 121 | 122 | -- Print a warning. Processing continues. 123 | local function wwarn(msg) 124 | stderr:write(format("%s:%s: warning: %s:\n%s\n", 125 | g_fname, g_lineno, msg, g_curline)) 126 | end 127 | 128 | -- Print caught error message. But suppress excessive errors. 129 | local function wprinterr(...) 130 | if type(g_errcount) == "number" then 131 | -- Regular error. 132 | g_errcount = g_errcount + 1 133 | if g_errcount < 21 then -- Seems to be a reasonable limit. 134 | stderr:write(...) 135 | elseif g_errcount == 21 then 136 | stderr:write(g_fname, 137 | ":*: warning: too many errors (suppressed further messages).\n") 138 | end 139 | else 140 | -- Fatal error. 141 | stderr:write(...) 142 | return true -- Stop processing. 143 | end 144 | end 145 | 146 | ------------------------------------------------------------------------------ 147 | 148 | -- Map holding all option handlers. 149 | local opt_map = {} 150 | local opt_current 151 | 152 | -- Print error and exit with error status. 153 | local function opterror(...) 154 | stderr:write("dynasm.lua: ERROR: ", ...) 155 | stderr:write("\n") 156 | exit(1) 157 | end 158 | 159 | -- Get option parameter. 160 | local function optparam(args) 161 | local argn = args.argn 162 | local p = args[argn] 163 | if not p then 164 | opterror("missing parameter for option `", opt_current, "'.") 165 | end 166 | args.argn = argn + 1 167 | return p 168 | end 169 | 170 | ------------------------------------------------------------------------------ 171 | 172 | -- Core pseudo-opcodes. 173 | local map_coreop = {} 174 | -- Dummy opcode map. Replaced by arch-specific map. 175 | local map_op = {} 176 | 177 | -- Forward declarations. 178 | local dostmt 179 | local readfile 180 | 181 | ------------------------------------------------------------------------------ 182 | 183 | -- Map for defines (initially empty, chains to arch-specific map). 184 | local map_def = {} 185 | 186 | -- Pseudo-opcode to define a substitution. 187 | map_coreop[".define_2"] = function(params, nparams) 188 | if not params then return nparams == 1 and "name" or "name, subst" end 189 | local name, def = params[1], params[2] or "1" 190 | if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end 191 | map_def[name] = def 192 | end 193 | map_coreop[".define_1"] = map_coreop[".define_2"] 194 | 195 | -- Define a substitution on the command line. 196 | function opt_map.D(args) 197 | local namesubst = optparam(args) 198 | local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") 199 | if name then 200 | map_def[name] = subst 201 | elseif match(namesubst, "^[%a_][%w_]*$") then 202 | map_def[namesubst] = "1" 203 | else 204 | opterror("bad define") 205 | end 206 | end 207 | 208 | -- Undefine a substitution on the command line. 209 | function opt_map.U(args) 210 | local name = optparam(args) 211 | if match(name, "^[%a_][%w_]*$") then 212 | map_def[name] = nil 213 | else 214 | opterror("bad define") 215 | end 216 | end 217 | 218 | -- Helper for definesubst. 219 | local gotsubst 220 | 221 | local function definesubst_one(word) 222 | local subst = map_def[word] 223 | if subst then gotsubst = word; return subst else return word end 224 | end 225 | 226 | -- Iteratively substitute defines. 227 | local function definesubst(stmt) 228 | -- Limit number of iterations. 229 | for i=1,100 do 230 | gotsubst = false 231 | stmt = gsub(stmt, "#?[%w_]+", definesubst_one) 232 | if not gotsubst then break end 233 | end 234 | if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end 235 | return stmt 236 | end 237 | 238 | -- Dump all defines. 239 | local function dumpdefines(out, lvl) 240 | local t = {} 241 | for name in pairs(map_def) do 242 | t[#t+1] = name 243 | end 244 | sort(t) 245 | out:write("Defines:\n") 246 | for _,name in ipairs(t) do 247 | local subst = map_def[name] 248 | if g_arch then subst = g_arch.revdef(subst) end 249 | out:write(format(" %-20s %s\n", name, subst)) 250 | end 251 | out:write("\n") 252 | end 253 | 254 | ------------------------------------------------------------------------------ 255 | 256 | -- Support variables for conditional assembly. 257 | local condlevel = 0 258 | local condstack = {} 259 | 260 | -- Evaluate condition with a Lua expression. Substitutions already performed. 261 | local function cond_eval(cond) 262 | local func, err 263 | if setfenv then 264 | func, err = loadstring("return "..cond, "=expr") 265 | else 266 | -- No globals. All unknown identifiers evaluate to nil. 267 | func, err = load("return "..cond, "=expr", "t", {}) 268 | end 269 | if func then 270 | if setfenv then 271 | setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. 272 | end 273 | local ok, res = pcall(func) 274 | if ok then 275 | if res == 0 then return false end -- Oh well. 276 | return not not res 277 | end 278 | err = res 279 | end 280 | wfatal("bad condition: "..err) 281 | end 282 | 283 | -- Skip statements until next conditional pseudo-opcode at the same level. 284 | local function stmtskip() 285 | local dostmt_save = dostmt 286 | local lvl = 0 287 | dostmt = function(stmt) 288 | local op = match(stmt, "^%s*(%S+)") 289 | if op == ".if" then 290 | lvl = lvl + 1 291 | elseif lvl ~= 0 then 292 | if op == ".endif" then lvl = lvl - 1 end 293 | elseif op == ".elif" or op == ".else" or op == ".endif" then 294 | dostmt = dostmt_save 295 | dostmt(stmt) 296 | end 297 | end 298 | end 299 | 300 | -- Pseudo-opcodes for conditional assembly. 301 | map_coreop[".if_1"] = function(params) 302 | if not params then return "condition" end 303 | local lvl = condlevel + 1 304 | local res = cond_eval(params[1]) 305 | condlevel = lvl 306 | condstack[lvl] = res 307 | if not res then stmtskip() end 308 | end 309 | 310 | map_coreop[".elif_1"] = function(params) 311 | if not params then return "condition" end 312 | if condlevel == 0 then wfatal(".elif without .if") end 313 | local lvl = condlevel 314 | local res = condstack[lvl] 315 | if res then 316 | if res == "else" then wfatal(".elif after .else") end 317 | else 318 | res = cond_eval(params[1]) 319 | if res then 320 | condstack[lvl] = res 321 | return 322 | end 323 | end 324 | stmtskip() 325 | end 326 | 327 | map_coreop[".else_0"] = function(params) 328 | if condlevel == 0 then wfatal(".else without .if") end 329 | local lvl = condlevel 330 | local res = condstack[lvl] 331 | condstack[lvl] = "else" 332 | if res then 333 | if res == "else" then wfatal(".else after .else") end 334 | stmtskip() 335 | end 336 | end 337 | 338 | map_coreop[".endif_0"] = function(params) 339 | local lvl = condlevel 340 | if lvl == 0 then wfatal(".endif without .if") end 341 | condlevel = lvl - 1 342 | end 343 | 344 | -- Check for unfinished conditionals. 345 | local function checkconds() 346 | if g_errcount ~= "fatal" and condlevel ~= 0 then 347 | wprinterr(g_fname, ":*: error: unbalanced conditional\n") 348 | end 349 | end 350 | 351 | ------------------------------------------------------------------------------ 352 | 353 | -- Search for a file in the given path and open it for reading. 354 | local function pathopen(path, name) 355 | local dirsep = package and match(package.path, "\\") and "\\" or "/" 356 | for _,p in ipairs(path) do 357 | local fullname = p == "" and name or p..dirsep..name 358 | local fin = io.open(fullname, "r") 359 | if fin then 360 | g_fname = fullname 361 | return fin 362 | end 363 | end 364 | end 365 | 366 | -- Include a file. 367 | map_coreop[".include_1"] = function(params) 368 | if not params then return "filename" end 369 | local name = params[1] 370 | -- Save state. Ugly, I know. but upvalues are fast. 371 | local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent 372 | -- Read the included file. 373 | local fatal = readfile(pathopen(g_opt.include, name) or 374 | wfatal("include file `"..name.."' not found")) 375 | -- Restore state. 376 | g_synclineno = -1 377 | g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi 378 | if fatal then wfatal("in include file") end 379 | end 380 | 381 | -- Make .include and conditionals initially available, too. 382 | map_op[".include_1"] = map_coreop[".include_1"] 383 | map_op[".if_1"] = map_coreop[".if_1"] 384 | map_op[".elif_1"] = map_coreop[".elif_1"] 385 | map_op[".else_0"] = map_coreop[".else_0"] 386 | map_op[".endif_0"] = map_coreop[".endif_0"] 387 | 388 | ------------------------------------------------------------------------------ 389 | 390 | -- Support variables for macros. 391 | local mac_capture, mac_lineno, mac_name 392 | local mac_active = {} 393 | local mac_list = {} 394 | 395 | -- Pseudo-opcode to define a macro. 396 | map_coreop[".macro_*"] = function(mparams) 397 | if not mparams then return "name [, params...]" end 398 | -- Split off and validate macro name. 399 | local name = remove(mparams, 1) 400 | if not name then werror("missing macro name") end 401 | if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then 402 | wfatal("bad macro name `"..name.."'") 403 | end 404 | -- Validate macro parameter names. 405 | local mdup = {} 406 | for _,mp in ipairs(mparams) do 407 | if not match(mp, "^[%a_][%w_]*$") then 408 | wfatal("bad macro parameter name `"..mp.."'") 409 | end 410 | if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end 411 | mdup[mp] = true 412 | end 413 | -- Check for duplicate or recursive macro definitions. 414 | local opname = name.."_"..#mparams 415 | if map_op[opname] or map_op[name.."_*"] then 416 | wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") 417 | end 418 | if mac_capture then wfatal("recursive macro definition") end 419 | 420 | -- Enable statement capture. 421 | local lines = {} 422 | mac_lineno = g_lineno 423 | mac_name = name 424 | mac_capture = function(stmt) -- Statement capture function. 425 | -- Stop macro definition with .endmacro pseudo-opcode. 426 | if not match(stmt, "^%s*.endmacro%s*$") then 427 | lines[#lines+1] = stmt 428 | return 429 | end 430 | mac_capture = nil 431 | mac_lineno = nil 432 | mac_name = nil 433 | mac_list[#mac_list+1] = opname 434 | -- Add macro-op definition. 435 | map_op[opname] = function(params) 436 | if not params then return mparams, lines end 437 | -- Protect against recursive macro invocation. 438 | if mac_active[opname] then wfatal("recursive macro invocation") end 439 | mac_active[opname] = true 440 | -- Setup substitution map. 441 | local subst = {} 442 | for i,mp in ipairs(mparams) do subst[mp] = params[i] end 443 | local mcom 444 | if g_opt.maccomment and g_opt.comment then 445 | mcom = " MACRO "..name.." ("..#mparams..")" 446 | wcomment("{"..mcom) 447 | end 448 | -- Loop through all captured statements 449 | for _,stmt in ipairs(lines) do 450 | -- Substitute macro parameters. 451 | local st = gsub(stmt, "[%w_]+", subst) 452 | st = definesubst(st) 453 | st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. 454 | if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end 455 | -- Emit statement. Use a protected call for better diagnostics. 456 | local ok, err = pcall(dostmt, st) 457 | if not ok then 458 | -- Add the captured statement to the error. 459 | wprinterr(err, "\n", g_indent, "| ", stmt, 460 | "\t[MACRO ", name, " (", #mparams, ")]\n") 461 | end 462 | end 463 | if mcom then wcomment("}"..mcom) end 464 | mac_active[opname] = nil 465 | end 466 | end 467 | end 468 | 469 | -- An .endmacro pseudo-opcode outside of a macro definition is an error. 470 | map_coreop[".endmacro_0"] = function(params) 471 | wfatal(".endmacro without .macro") 472 | end 473 | 474 | -- Dump all macros and their contents (with -PP only). 475 | local function dumpmacros(out, lvl) 476 | sort(mac_list) 477 | out:write("Macros:\n") 478 | for _,opname in ipairs(mac_list) do 479 | local name = sub(opname, 1, -3) 480 | local params, lines = map_op[opname]() 481 | out:write(format(" %-20s %s\n", name, concat(params, ", "))) 482 | if lvl > 1 then 483 | for _,line in ipairs(lines) do 484 | out:write(" |", line, "\n") 485 | end 486 | out:write("\n") 487 | end 488 | end 489 | out:write("\n") 490 | end 491 | 492 | -- Check for unfinished macro definitions. 493 | local function checkmacros() 494 | if mac_capture then 495 | wprinterr(g_fname, ":", mac_lineno, 496 | ": error: unfinished .macro `", mac_name ,"'\n") 497 | end 498 | end 499 | 500 | ------------------------------------------------------------------------------ 501 | 502 | -- Support variables for captures. 503 | local cap_lineno, cap_name 504 | local cap_buffers = {} 505 | local cap_used = {} 506 | 507 | -- Start a capture. 508 | map_coreop[".capture_1"] = function(params) 509 | if not params then return "name" end 510 | wflush() 511 | local name = params[1] 512 | if not match(name, "^[%a_][%w_]*$") then 513 | wfatal("bad capture name `"..name.."'") 514 | end 515 | if cap_name then 516 | wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) 517 | end 518 | cap_name = name 519 | cap_lineno = g_lineno 520 | -- Create or continue a capture buffer and start the output line capture. 521 | local buf = cap_buffers[name] 522 | if not buf then buf = {}; cap_buffers[name] = buf end 523 | g_capbuffer = buf 524 | g_synclineno = 0 525 | end 526 | 527 | -- Stop a capture. 528 | map_coreop[".endcapture_0"] = function(params) 529 | wflush() 530 | if not cap_name then wfatal(".endcapture without a valid .capture") end 531 | cap_name = nil 532 | cap_lineno = nil 533 | g_capbuffer = nil 534 | g_synclineno = 0 535 | end 536 | 537 | -- Dump a capture buffer. 538 | map_coreop[".dumpcapture_1"] = function(params) 539 | if not params then return "name" end 540 | wflush() 541 | local name = params[1] 542 | if not match(name, "^[%a_][%w_]*$") then 543 | wfatal("bad capture name `"..name.."'") 544 | end 545 | cap_used[name] = true 546 | wline(function(out) 547 | local buf = cap_buffers[name] 548 | if buf then wdumplines(out, buf) end 549 | end) 550 | g_synclineno = 0 551 | end 552 | 553 | -- Dump all captures and their buffers (with -PP only). 554 | local function dumpcaptures(out, lvl) 555 | out:write("Captures:\n") 556 | for name,buf in pairs(cap_buffers) do 557 | out:write(format(" %-20s %4s)\n", name, "("..#buf)) 558 | if lvl > 1 then 559 | local bar = rep("=", 76) 560 | out:write(" ", bar, "\n") 561 | for _,line in ipairs(buf) do 562 | out:write(" ", line, "\n") 563 | end 564 | out:write(" ", bar, "\n\n") 565 | end 566 | end 567 | out:write("\n") 568 | end 569 | 570 | -- Check for unfinished or unused captures. 571 | local function checkcaptures() 572 | if cap_name then 573 | wprinterr(g_fname, ":", cap_lineno, 574 | ": error: unfinished .capture `", cap_name,"'\n") 575 | return 576 | end 577 | for name in pairs(cap_buffers) do 578 | if not cap_used[name] then 579 | wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") 580 | end 581 | end 582 | end 583 | 584 | ------------------------------------------------------------------------------ 585 | 586 | -- Sections names. 587 | local map_sections = {} 588 | 589 | -- Pseudo-opcode to define code sections. 590 | -- TODO: Data sections, BSS sections. Needs extra C code and API. 591 | map_coreop[".section_*"] = function(params) 592 | if not params then return "name..." end 593 | if #map_sections > 0 then werror("duplicate section definition") end 594 | wflush() 595 | for sn,name in ipairs(params) do 596 | local opname = "."..name.."_0" 597 | if not match(name, "^[%a][%w_]*$") or 598 | map_op[opname] or map_op["."..name.."_*"] then 599 | werror("bad section name `"..name.."'") 600 | end 601 | map_sections[#map_sections+1] = name 602 | wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) 603 | map_op[opname] = function(params) g_arch.section(sn-1) end 604 | end 605 | wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) 606 | end 607 | 608 | -- Dump all sections. 609 | local function dumpsections(out, lvl) 610 | out:write("Sections:\n") 611 | for _,name in ipairs(map_sections) do 612 | out:write(format(" %s\n", name)) 613 | end 614 | out:write("\n") 615 | end 616 | 617 | ------------------------------------------------------------------------------ 618 | 619 | -- Replacement for customized Lua, which lacks the package library. 620 | local prefix = "" 621 | if not require then 622 | function require(name) 623 | local fp = assert(io.open(prefix..name..".lua")) 624 | local s = fp:read("*a") 625 | assert(fp:close()) 626 | return assert(loadstring(s, "@"..name..".lua"))() 627 | end 628 | end 629 | 630 | -- Load architecture-specific module. 631 | local function loadarch(arch) 632 | if not match(arch, "^[%w_]+$") then return "bad arch name" end 633 | local ok, m_arch = pcall(require, "dasm_"..arch) 634 | if not ok then return "cannot load module: "..m_arch end 635 | g_arch = m_arch 636 | wflush = m_arch.passcb(wline, werror, wfatal, wwarn) 637 | m_arch.setup(arch, g_opt) 638 | map_op, map_def = m_arch.mergemaps(map_coreop, map_def) 639 | end 640 | 641 | -- Dump architecture description. 642 | function opt_map.dumparch(args) 643 | local name = optparam(args) 644 | if not g_arch then 645 | local err = loadarch(name) 646 | if err then opterror(err) end 647 | end 648 | 649 | local t = {} 650 | for name in pairs(map_coreop) do t[#t+1] = name end 651 | for name in pairs(map_op) do t[#t+1] = name end 652 | sort(t) 653 | 654 | local out = stdout 655 | local _arch = g_arch._info 656 | out:write(format("%s version %s, released %s, %s\n", 657 | _info.name, _info.version, _info.release, _info.url)) 658 | g_arch.dumparch(out) 659 | 660 | local pseudo = true 661 | out:write("Pseudo-Opcodes:\n") 662 | for _,sname in ipairs(t) do 663 | local name, nparam = match(sname, "^(.+)_([0-9%*])$") 664 | if name then 665 | if pseudo and sub(name, 1, 1) ~= "." then 666 | out:write("\nOpcodes:\n") 667 | pseudo = false 668 | end 669 | local f = map_op[sname] 670 | local s 671 | if nparam ~= "*" then nparam = nparam + 0 end 672 | if nparam == 0 then 673 | s = "" 674 | elseif type(f) == "string" then 675 | s = map_op[".template__"](nil, f, nparam) 676 | else 677 | s = f(nil, nparam) 678 | end 679 | if type(s) == "table" then 680 | for _,s2 in ipairs(s) do 681 | out:write(format(" %-12s %s\n", name, s2)) 682 | end 683 | else 684 | out:write(format(" %-12s %s\n", name, s)) 685 | end 686 | end 687 | end 688 | out:write("\n") 689 | exit(0) 690 | end 691 | 692 | -- Pseudo-opcode to set the architecture. 693 | -- Only initially available (map_op is replaced when called). 694 | map_op[".arch_1"] = function(params) 695 | if not params then return "name" end 696 | local err = loadarch(params[1]) 697 | if err then wfatal(err) end 698 | wline(format("#if DASM_VERSION != %d", _info.vernum)) 699 | wline('#error "Version mismatch between DynASM and included encoding engine"') 700 | wline("#endif") 701 | end 702 | 703 | -- Dummy .arch pseudo-opcode to improve the error report. 704 | map_coreop[".arch_1"] = function(params) 705 | if not params then return "name" end 706 | wfatal("duplicate .arch statement") 707 | end 708 | 709 | ------------------------------------------------------------------------------ 710 | 711 | -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. 712 | map_coreop[".nop_*"] = function(params) 713 | if not params then return "[ignored...]" end 714 | end 715 | 716 | -- Pseudo-opcodes to raise errors. 717 | map_coreop[".error_1"] = function(params) 718 | if not params then return "message" end 719 | werror(params[1]) 720 | end 721 | 722 | map_coreop[".fatal_1"] = function(params) 723 | if not params then return "message" end 724 | wfatal(params[1]) 725 | end 726 | 727 | -- Dump all user defined elements. 728 | local function dumpdef(out) 729 | local lvl = g_opt.dumpdef 730 | if lvl == 0 then return end 731 | dumpsections(out, lvl) 732 | dumpdefines(out, lvl) 733 | if g_arch then g_arch.dumpdef(out, lvl) end 734 | dumpmacros(out, lvl) 735 | dumpcaptures(out, lvl) 736 | end 737 | 738 | ------------------------------------------------------------------------------ 739 | 740 | -- Helper for splitstmt. 741 | local splitlvl 742 | 743 | local function splitstmt_one(c) 744 | if c == "(" then 745 | splitlvl = ")"..splitlvl 746 | elseif c == "[" then 747 | splitlvl = "]"..splitlvl 748 | elseif c == "{" then 749 | splitlvl = "}"..splitlvl 750 | elseif c == ")" or c == "]" or c == "}" then 751 | if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end 752 | splitlvl = sub(splitlvl, 2) 753 | elseif splitlvl == "" then 754 | return " \0 " 755 | end 756 | return c 757 | end 758 | 759 | -- Split statement into (pseudo-)opcode and params. 760 | local function splitstmt(stmt) 761 | -- Convert label with trailing-colon into .label statement. 762 | local label = match(stmt, "^%s*(.+):%s*$") 763 | if label then return ".label", {label} end 764 | 765 | -- Split at commas and equal signs, but obey parentheses and brackets. 766 | splitlvl = "" 767 | stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) 768 | if splitlvl ~= "" then werror("unbalanced () or []") end 769 | 770 | -- Split off opcode. 771 | local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") 772 | if not op then werror("bad statement syntax") end 773 | 774 | -- Split parameters. 775 | local params = {} 776 | for p in gmatch(other, "%s*(%Z+)%z?") do 777 | params[#params+1] = gsub(p, "%s+$", "") 778 | end 779 | if #params > 16 then werror("too many parameters") end 780 | 781 | params.op = op 782 | return op, params 783 | end 784 | 785 | -- Process a single statement. 786 | dostmt = function(stmt) 787 | -- Ignore empty statements. 788 | if match(stmt, "^%s*$") then return end 789 | 790 | -- Capture macro defs before substitution. 791 | if mac_capture then return mac_capture(stmt) end 792 | stmt = definesubst(stmt) 793 | 794 | -- Emit C code without parsing the line. 795 | if sub(stmt, 1, 1) == "|" then 796 | local tail = sub(stmt, 2) 797 | wflush() 798 | if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end 799 | return 800 | end 801 | 802 | -- Split into (pseudo-)opcode and params. 803 | local op, params = splitstmt(stmt) 804 | 805 | -- Get opcode handler (matching # of parameters or generic handler). 806 | local f = map_op[op.."_"..#params] or map_op[op.."_*"] 807 | if not f then 808 | if not g_arch then wfatal("first statement must be .arch") end 809 | -- Improve error report. 810 | for i=0,9 do 811 | if map_op[op.."_"..i] then 812 | werror("wrong number of parameters for `"..op.."'") 813 | end 814 | end 815 | werror("unknown statement `"..op.."'") 816 | end 817 | 818 | -- Call opcode handler or special handler for template strings. 819 | if type(f) == "string" then 820 | map_op[".template__"](params, f) 821 | else 822 | f(params) 823 | end 824 | end 825 | 826 | -- Process a single line. 827 | local function doline(line) 828 | if g_opt.flushline then wflush() end 829 | 830 | -- Assembler line? 831 | local indent, aline = match(line, "^(%s*)%|(.*)$") 832 | if not aline then 833 | -- No, plain C code line, need to flush first. 834 | wflush() 835 | wsync() 836 | wline(line, false) 837 | return 838 | end 839 | 840 | g_indent = indent -- Remember current line indentation. 841 | 842 | -- Emit C code (even from macros). Avoids echo and line parsing. 843 | if sub(aline, 1, 1) == "|" then 844 | if not mac_capture then 845 | wsync() 846 | elseif g_opt.comment then 847 | wsync() 848 | wcomment(aline) 849 | end 850 | dostmt(aline) 851 | return 852 | end 853 | 854 | -- Echo assembler line as a comment. 855 | if g_opt.comment then 856 | wsync() 857 | wcomment(aline) 858 | end 859 | 860 | -- Strip assembler comments. 861 | aline = gsub(aline, "//.*$", "") 862 | 863 | -- Split line into statements at semicolons. 864 | if match(aline, ";") then 865 | for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end 866 | else 867 | dostmt(aline) 868 | end 869 | end 870 | 871 | ------------------------------------------------------------------------------ 872 | 873 | -- Write DynASM header. 874 | local function dasmhead(out) 875 | out:write(format([[ 876 | /* 877 | ** This file has been pre-processed with DynASM. 878 | ** %s 879 | ** DynASM version %s, DynASM %s version %s 880 | ** DO NOT EDIT! The original file is in "%s". 881 | */ 882 | 883 | ]], _info.url, 884 | _info.version, g_arch._info.arch, g_arch._info.version, 885 | g_fname)) 886 | end 887 | 888 | -- Read input file. 889 | readfile = function(fin) 890 | g_indent = "" 891 | g_lineno = 0 892 | g_synclineno = -1 893 | 894 | -- Process all lines. 895 | for line in fin:lines() do 896 | g_lineno = g_lineno + 1 897 | g_curline = line 898 | local ok, err = pcall(doline, line) 899 | if not ok and wprinterr(err, "\n") then return true end 900 | end 901 | wflush() 902 | 903 | -- Close input file. 904 | assert(fin == stdin or fin:close()) 905 | end 906 | 907 | -- Write output file. 908 | local function writefile(outfile) 909 | local fout 910 | 911 | -- Open output file. 912 | if outfile == nil or outfile == "-" then 913 | fout = stdout 914 | else 915 | fout = assert(io.open(outfile, "w")) 916 | end 917 | 918 | -- Write all buffered lines 919 | wdumplines(fout, g_wbuffer) 920 | 921 | -- Close output file. 922 | assert(fout == stdout or fout:close()) 923 | 924 | -- Optionally dump definitions. 925 | dumpdef(fout == stdout and stderr or stdout) 926 | end 927 | 928 | -- Translate an input file to an output file. 929 | local function translate(infile, outfile) 930 | g_wbuffer = {} 931 | g_indent = "" 932 | g_lineno = 0 933 | g_synclineno = -1 934 | 935 | -- Put header. 936 | wline(dasmhead) 937 | 938 | -- Read input file. 939 | local fin 940 | if infile == "-" then 941 | g_fname = "(stdin)" 942 | fin = stdin 943 | else 944 | g_fname = infile 945 | fin = assert(io.open(infile, "r")) 946 | end 947 | readfile(fin) 948 | 949 | -- Check for errors. 950 | if not g_arch then 951 | wprinterr(g_fname, ":*: error: missing .arch directive\n") 952 | end 953 | checkconds() 954 | checkmacros() 955 | checkcaptures() 956 | 957 | if g_errcount ~= 0 then 958 | stderr:write(g_fname, ":*: info: ", g_errcount, " error", 959 | (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", 960 | " in input file -- no output file generated.\n") 961 | dumpdef(stderr) 962 | exit(1) 963 | end 964 | 965 | -- Write output file. 966 | writefile(outfile) 967 | end 968 | 969 | ------------------------------------------------------------------------------ 970 | 971 | -- Print help text. 972 | function opt_map.help() 973 | stdout:write("DynASM -- ", _info.description, ".\n") 974 | stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") 975 | stdout:write[[ 976 | 977 | Usage: dynasm [OPTION]... INFILE.dasc|- 978 | 979 | -h, --help Display this help text. 980 | -V, --version Display version and copyright information. 981 | 982 | -o, --outfile FILE Output file name (default is stdout). 983 | -I, --include DIR Add directory to the include search path. 984 | 985 | -c, --ccomment Use /* */ comments for assembler lines. 986 | -C, --cppcomment Use // comments for assembler lines (default). 987 | -N, --nocomment Suppress assembler lines in output. 988 | -M, --maccomment Show macro expansions as comments (default off). 989 | 990 | -L, --nolineno Suppress CPP line number information in output. 991 | -F, --flushline Flush action list for every line. 992 | 993 | -D NAME[=SUBST] Define a substitution. 994 | -U NAME Undefine a substitution. 995 | 996 | -P, --dumpdef Dump defines, macros, etc. Repeat for more output. 997 | -A, --dumparch ARCH Load architecture ARCH and dump description. 998 | ]] 999 | exit(0) 1000 | end 1001 | 1002 | -- Print version information. 1003 | function opt_map.version() 1004 | stdout:write(format("%s version %s, released %s\n%s\n\n%s", 1005 | _info.name, _info.version, _info.release, _info.url, _info.copyright)) 1006 | exit(0) 1007 | end 1008 | 1009 | -- Misc. options. 1010 | function opt_map.outfile(args) g_opt.outfile = optparam(args) end 1011 | function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end 1012 | function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end 1013 | function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end 1014 | function opt_map.nocomment() g_opt.comment = false end 1015 | function opt_map.maccomment() g_opt.maccomment = true end 1016 | function opt_map.nolineno() g_opt.cpp = false end 1017 | function opt_map.flushline() g_opt.flushline = true end 1018 | function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end 1019 | 1020 | ------------------------------------------------------------------------------ 1021 | 1022 | -- Short aliases for long options. 1023 | local opt_alias = { 1024 | h = "help", ["?"] = "help", V = "version", 1025 | o = "outfile", I = "include", 1026 | c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", 1027 | L = "nolineno", F = "flushline", 1028 | P = "dumpdef", A = "dumparch", 1029 | } 1030 | 1031 | -- Parse single option. 1032 | local function parseopt(opt, args) 1033 | opt_current = #opt == 1 and "-"..opt or "--"..opt 1034 | local f = opt_map[opt] or opt_map[opt_alias[opt]] 1035 | if not f then 1036 | opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") 1037 | end 1038 | f(args) 1039 | end 1040 | 1041 | -- Parse arguments. 1042 | local function parseargs(args) 1043 | -- Default options. 1044 | g_opt.comment = "//|" 1045 | g_opt.endcomment = "" 1046 | g_opt.cpp = true 1047 | g_opt.dumpdef = 0 1048 | g_opt.include = { "" } 1049 | 1050 | -- Process all option arguments. 1051 | args.argn = 1 1052 | repeat 1053 | local a = args[args.argn] 1054 | if not a then break end 1055 | local lopt, opt = match(a, "^%-(%-?)(.+)") 1056 | if not opt then break end 1057 | args.argn = args.argn + 1 1058 | if lopt == "" then 1059 | -- Loop through short options. 1060 | for o in gmatch(opt, ".") do parseopt(o, args) end 1061 | else 1062 | -- Long option. 1063 | parseopt(opt, args) 1064 | end 1065 | until false 1066 | 1067 | -- Check for proper number of arguments. 1068 | local nargs = #args - args.argn + 1 1069 | if nargs ~= 1 then 1070 | if nargs == 0 then 1071 | if g_opt.dumpdef > 0 then return dumpdef(stdout) end 1072 | end 1073 | opt_map.help() 1074 | end 1075 | 1076 | -- Translate a single input file to a single output file 1077 | -- TODO: Handle multiple files? 1078 | translate(args[args.argn], g_opt.outfile) 1079 | end 1080 | 1081 | ------------------------------------------------------------------------------ 1082 | 1083 | -- Add the directory dynasm.lua resides in to the Lua module search path. 1084 | local arg = arg 1085 | if arg and arg[0] then 1086 | prefix = match(arg[0], "^(.*[/\\])") 1087 | if package and prefix then package.path = prefix.."?.lua;"..package.path end 1088 | end 1089 | 1090 | -- Start DynASM. 1091 | parseargs{...} 1092 | 1093 | ------------------------------------------------------------------------------ 1094 | 1095 | -------------------------------------------------------------------------------- /dynasm/dasm_arm.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM ARM module. 3 | -- 4 | -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | 8 | -- Module information: 9 | local _info = { 10 | arch = "arm", 11 | description = "DynASM ARM module", 12 | version = "1.3.0", 13 | vernum = 10300, 14 | release = "2011-05-05", 15 | author = "Mike Pall", 16 | license = "MIT", 17 | } 18 | 19 | -- Exported glue functions for the arch-specific module. 20 | local _M = { _info = _info } 21 | 22 | -- Cache library functions. 23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs 24 | local assert, setmetatable, rawget = assert, setmetatable, rawget 25 | local _s = string 26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char 27 | local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub 28 | local concat, sort, insert = table.concat, table.sort, table.insert 29 | local bit = bit or require("bit") 30 | local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift 31 | local ror, tohex = bit.ror, bit.tohex 32 | 33 | -- Inherited tables and callbacks. 34 | local g_opt, g_arch 35 | local wline, werror, wfatal, wwarn 36 | 37 | -- Action name list. 38 | -- CHECK: Keep this in sync with the C code! 39 | local action_names = { 40 | "STOP", "SECTION", "ESC", "REL_EXT", 41 | "ALIGN", "REL_LG", "LABEL_LG", 42 | "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8", 43 | } 44 | 45 | -- Maximum number of section buffer positions for dasm_put(). 46 | -- CHECK: Keep this in sync with the C code! 47 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. 48 | 49 | -- Action name -> action number. 50 | local map_action = {} 51 | for n,name in ipairs(action_names) do 52 | map_action[name] = n-1 53 | end 54 | 55 | -- Action list buffer. 56 | local actlist = {} 57 | 58 | -- Argument list for next dasm_put(). Start with offset 0 into action list. 59 | local actargs = { 0 } 60 | 61 | -- Current number of section buffer positions for dasm_put(). 62 | local secpos = 1 63 | 64 | ------------------------------------------------------------------------------ 65 | 66 | -- Dump action names and numbers. 67 | local function dumpactions(out) 68 | out:write("DynASM encoding engine action codes:\n") 69 | for n,name in ipairs(action_names) do 70 | local num = map_action[name] 71 | out:write(format(" %-10s %02X %d\n", name, num, num)) 72 | end 73 | out:write("\n") 74 | end 75 | 76 | -- Write action list buffer as a huge static C array. 77 | local function writeactions(out, name) 78 | local nn = #actlist 79 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end 80 | out:write("static const unsigned int ", name, "[", nn, "] = {\n") 81 | for i = 1,nn-1 do 82 | assert(out:write("0x", tohex(actlist[i]), ",\n")) 83 | end 84 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) 85 | end 86 | 87 | ------------------------------------------------------------------------------ 88 | 89 | -- Add word to action list. 90 | local function wputxw(n) 91 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 92 | actlist[#actlist+1] = n 93 | end 94 | 95 | -- Add action to list with optional arg. Advance buffer pos, too. 96 | local function waction(action, val, a, num) 97 | local w = assert(map_action[action], "bad action name `"..action.."'") 98 | wputxw(w * 0x10000 + (val or 0)) 99 | if a then actargs[#actargs+1] = a end 100 | if a or num then secpos = secpos + (num or 1) end 101 | end 102 | 103 | -- Flush action list (intervening C code or buffer pos overflow). 104 | local function wflush(term) 105 | if #actlist == actargs[1] then return end -- Nothing to flush. 106 | if not term then waction("STOP") end -- Terminate action list. 107 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) 108 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). 109 | secpos = 1 -- The actionlist offset occupies a buffer position, too. 110 | end 111 | 112 | -- Put escaped word. 113 | local function wputw(n) 114 | if n <= 0x000fffff then waction("ESC") end 115 | wputxw(n) 116 | end 117 | 118 | -- Reserve position for word. 119 | local function wpos() 120 | local pos = #actlist+1 121 | actlist[pos] = "" 122 | return pos 123 | end 124 | 125 | -- Store word to reserved position. 126 | local function wputpos(pos, n) 127 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 128 | if n <= 0x000fffff then 129 | insert(actlist, pos+1, n) 130 | n = map_action.ESC * 0x10000 131 | end 132 | actlist[pos] = n 133 | end 134 | 135 | ------------------------------------------------------------------------------ 136 | 137 | -- Global label name -> global label number. With auto assignment on 1st use. 138 | local next_global = 20 139 | local map_global = setmetatable({}, { __index = function(t, name) 140 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end 141 | local n = next_global 142 | if n > 2047 then werror("too many global labels") end 143 | next_global = n + 1 144 | t[name] = n 145 | return n 146 | end}) 147 | 148 | -- Dump global labels. 149 | local function dumpglobals(out, lvl) 150 | local t = {} 151 | for name, n in pairs(map_global) do t[n] = name end 152 | out:write("Global labels:\n") 153 | for i=20,next_global-1 do 154 | out:write(format(" %s\n", t[i])) 155 | end 156 | out:write("\n") 157 | end 158 | 159 | -- Write global label enum. 160 | local function writeglobals(out, prefix) 161 | local t = {} 162 | for name, n in pairs(map_global) do t[n] = name end 163 | out:write("enum {\n") 164 | for i=20,next_global-1 do 165 | out:write(" ", prefix, t[i], ",\n") 166 | end 167 | out:write(" ", prefix, "_MAX\n};\n") 168 | end 169 | 170 | -- Write global label names. 171 | local function writeglobalnames(out, name) 172 | local t = {} 173 | for name, n in pairs(map_global) do t[n] = name end 174 | out:write("static const char *const ", name, "[] = {\n") 175 | for i=20,next_global-1 do 176 | out:write(" \"", t[i], "\",\n") 177 | end 178 | out:write(" (const char *)0\n};\n") 179 | end 180 | 181 | ------------------------------------------------------------------------------ 182 | 183 | -- Extern label name -> extern label number. With auto assignment on 1st use. 184 | local next_extern = 0 185 | local map_extern_ = {} 186 | local map_extern = setmetatable({}, { __index = function(t, name) 187 | -- No restrictions on the name for now. 188 | local n = next_extern 189 | if n > 2047 then werror("too many extern labels") end 190 | next_extern = n + 1 191 | t[name] = n 192 | map_extern_[n] = name 193 | return n 194 | end}) 195 | 196 | -- Dump extern labels. 197 | local function dumpexterns(out, lvl) 198 | out:write("Extern labels:\n") 199 | for i=0,next_extern-1 do 200 | out:write(format(" %s\n", map_extern_[i])) 201 | end 202 | out:write("\n") 203 | end 204 | 205 | -- Write extern label names. 206 | local function writeexternnames(out, name) 207 | out:write("static const char *const ", name, "[] = {\n") 208 | for i=0,next_extern-1 do 209 | out:write(" \"", map_extern_[i], "\",\n") 210 | end 211 | out:write(" (const char *)0\n};\n") 212 | end 213 | 214 | ------------------------------------------------------------------------------ 215 | 216 | -- Arch-specific maps. 217 | 218 | -- Ext. register name -> int. name. 219 | local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } 220 | 221 | -- Int. register name -> ext. name. 222 | local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } 223 | 224 | local map_type = {} -- Type name -> { ctype, reg } 225 | local ctypenum = 0 -- Type number (for Dt... macros). 226 | 227 | -- Reverse defines for registers. 228 | function _M.revdef(s) 229 | return map_reg_rev[s] or s 230 | end 231 | 232 | local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } 233 | 234 | local map_cond = { 235 | eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, 236 | hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, 237 | hs = 2, lo = 3, 238 | } 239 | 240 | ------------------------------------------------------------------------------ 241 | 242 | -- Template strings for ARM instructions. 243 | local map_op = { 244 | -- Basic data processing instructions. 245 | and_3 = "e0000000DNPs", 246 | eor_3 = "e0200000DNPs", 247 | sub_3 = "e0400000DNPs", 248 | rsb_3 = "e0600000DNPs", 249 | add_3 = "e0800000DNPs", 250 | adc_3 = "e0a00000DNPs", 251 | sbc_3 = "e0c00000DNPs", 252 | rsc_3 = "e0e00000DNPs", 253 | tst_2 = "e1100000NP", 254 | teq_2 = "e1300000NP", 255 | cmp_2 = "e1500000NP", 256 | cmn_2 = "e1700000NP", 257 | orr_3 = "e1800000DNPs", 258 | mov_2 = "e1a00000DPs", 259 | bic_3 = "e1c00000DNPs", 260 | mvn_2 = "e1e00000DPs", 261 | 262 | and_4 = "e0000000DNMps", 263 | eor_4 = "e0200000DNMps", 264 | sub_4 = "e0400000DNMps", 265 | rsb_4 = "e0600000DNMps", 266 | add_4 = "e0800000DNMps", 267 | adc_4 = "e0a00000DNMps", 268 | sbc_4 = "e0c00000DNMps", 269 | rsc_4 = "e0e00000DNMps", 270 | tst_3 = "e1100000NMp", 271 | teq_3 = "e1300000NMp", 272 | cmp_3 = "e1500000NMp", 273 | cmn_3 = "e1700000NMp", 274 | orr_4 = "e1800000DNMps", 275 | mov_3 = "e1a00000DMps", 276 | bic_4 = "e1c00000DNMps", 277 | mvn_3 = "e1e00000DMps", 278 | 279 | lsl_3 = "e1a00000DMws", 280 | lsr_3 = "e1a00020DMws", 281 | asr_3 = "e1a00040DMws", 282 | ror_3 = "e1a00060DMws", 283 | rrx_2 = "e1a00060DMs", 284 | 285 | -- Multiply and multiply-accumulate. 286 | mul_3 = "e0000090NMSs", 287 | mla_4 = "e0200090NMSDs", 288 | umaal_4 = "e0400090DNMSs", -- v6 289 | mls_4 = "e0600090DNMSs", -- v6T2 290 | umull_4 = "e0800090DNMSs", 291 | umlal_4 = "e0a00090DNMSs", 292 | smull_4 = "e0c00090DNMSs", 293 | smlal_4 = "e0e00090DNMSs", 294 | 295 | -- Halfword multiply and multiply-accumulate. 296 | smlabb_4 = "e1000080NMSD", -- v5TE 297 | smlatb_4 = "e10000a0NMSD", -- v5TE 298 | smlabt_4 = "e10000c0NMSD", -- v5TE 299 | smlatt_4 = "e10000e0NMSD", -- v5TE 300 | smlawb_4 = "e1200080NMSD", -- v5TE 301 | smulwb_3 = "e12000a0NMS", -- v5TE 302 | smlawt_4 = "e12000c0NMSD", -- v5TE 303 | smulwt_3 = "e12000e0NMS", -- v5TE 304 | smlalbb_4 = "e1400080NMSD", -- v5TE 305 | smlaltb_4 = "e14000a0NMSD", -- v5TE 306 | smlalbt_4 = "e14000c0NMSD", -- v5TE 307 | smlaltt_4 = "e14000e0NMSD", -- v5TE 308 | smulbb_3 = "e1600080NMS", -- v5TE 309 | smultb_3 = "e16000a0NMS", -- v5TE 310 | smulbt_3 = "e16000c0NMS", -- v5TE 311 | smultt_3 = "e16000e0NMS", -- v5TE 312 | 313 | -- Miscellaneous data processing instructions. 314 | clz_2 = "e16f0f10DM", -- v5T 315 | rev_2 = "e6bf0f30DM", -- v6 316 | rev16_2 = "e6bf0fb0DM", -- v6 317 | revsh_2 = "e6ff0fb0DM", -- v6 318 | sel_3 = "e6800fb0DNM", -- v6 319 | usad8_3 = "e780f010NMS", -- v6 320 | usada8_4 = "e7800010NMSD", -- v6 321 | rbit_2 = "e6ff0f30DM", -- v6T2 322 | movw_2 = "e3000000DW", -- v6T2 323 | movt_2 = "e3400000DW", -- v6T2 324 | -- Note: the X encodes width-1, not width. 325 | sbfx_4 = "e7a00050DMvX", -- v6T2 326 | ubfx_4 = "e7e00050DMvX", -- v6T2 327 | -- Note: the X encodes the msb field, not the width. 328 | bfc_3 = "e7c0001fDvX", -- v6T2 329 | bfi_4 = "e7c00010DMvX", -- v6T2 330 | 331 | -- Packing and unpacking instructions. 332 | pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 333 | pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 334 | sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 335 | sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 336 | sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 337 | sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 338 | sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 339 | sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 340 | uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 341 | uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 342 | uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 343 | uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 344 | uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 345 | uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 346 | 347 | -- Saturating instructions. 348 | qadd_3 = "e1000050DMN", -- v5TE 349 | qsub_3 = "e1200050DMN", -- v5TE 350 | qdadd_3 = "e1400050DMN", -- v5TE 351 | qdsub_3 = "e1600050DMN", -- v5TE 352 | -- Note: the X for ssat* encodes sat_imm-1, not sat_imm. 353 | ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 354 | usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 355 | ssat16_3 = "e6a00f30DXM", -- v6 356 | usat16_3 = "e6e00f30DXM", -- v6 357 | 358 | -- Parallel addition and subtraction. 359 | sadd16_3 = "e6100f10DNM", -- v6 360 | sasx_3 = "e6100f30DNM", -- v6 361 | ssax_3 = "e6100f50DNM", -- v6 362 | ssub16_3 = "e6100f70DNM", -- v6 363 | sadd8_3 = "e6100f90DNM", -- v6 364 | ssub8_3 = "e6100ff0DNM", -- v6 365 | qadd16_3 = "e6200f10DNM", -- v6 366 | qasx_3 = "e6200f30DNM", -- v6 367 | qsax_3 = "e6200f50DNM", -- v6 368 | qsub16_3 = "e6200f70DNM", -- v6 369 | qadd8_3 = "e6200f90DNM", -- v6 370 | qsub8_3 = "e6200ff0DNM", -- v6 371 | shadd16_3 = "e6300f10DNM", -- v6 372 | shasx_3 = "e6300f30DNM", -- v6 373 | shsax_3 = "e6300f50DNM", -- v6 374 | shsub16_3 = "e6300f70DNM", -- v6 375 | shadd8_3 = "e6300f90DNM", -- v6 376 | shsub8_3 = "e6300ff0DNM", -- v6 377 | uadd16_3 = "e6500f10DNM", -- v6 378 | uasx_3 = "e6500f30DNM", -- v6 379 | usax_3 = "e6500f50DNM", -- v6 380 | usub16_3 = "e6500f70DNM", -- v6 381 | uadd8_3 = "e6500f90DNM", -- v6 382 | usub8_3 = "e6500ff0DNM", -- v6 383 | uqadd16_3 = "e6600f10DNM", -- v6 384 | uqasx_3 = "e6600f30DNM", -- v6 385 | uqsax_3 = "e6600f50DNM", -- v6 386 | uqsub16_3 = "e6600f70DNM", -- v6 387 | uqadd8_3 = "e6600f90DNM", -- v6 388 | uqsub8_3 = "e6600ff0DNM", -- v6 389 | uhadd16_3 = "e6700f10DNM", -- v6 390 | uhasx_3 = "e6700f30DNM", -- v6 391 | uhsax_3 = "e6700f50DNM", -- v6 392 | uhsub16_3 = "e6700f70DNM", -- v6 393 | uhadd8_3 = "e6700f90DNM", -- v6 394 | uhsub8_3 = "e6700ff0DNM", -- v6 395 | 396 | -- Load/store instructions. 397 | str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", 398 | strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", 399 | ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", 400 | ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", 401 | strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", 402 | ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", 403 | ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE 404 | ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", 405 | strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE 406 | ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", 407 | 408 | ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR", 409 | ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR", 410 | ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR", 411 | ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR", 412 | stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR", 413 | stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR", 414 | stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR", 415 | stmib_2 = "e9800000oR", stmed_2 = "e9800000oR", 416 | pop_1 = "e8bd0000R", push_1 = "e92d0000R", 417 | 418 | -- Branch instructions. 419 | b_1 = "ea000000B", 420 | bl_1 = "eb000000B", 421 | blx_1 = "e12fff30C", 422 | bx_1 = "e12fff10M", 423 | 424 | -- Miscellaneous instructions. 425 | nop_0 = "e1a00000", 426 | mrs_1 = "e10f0000D", 427 | bkpt_1 = "e1200070K", -- v5T 428 | svc_1 = "ef000000T", swi_1 = "ef000000T", 429 | ud_0 = "e7f001f0", 430 | 431 | -- VFP instructions. 432 | ["vadd.f32_3"] = "ee300a00dnm", 433 | ["vadd.f64_3"] = "ee300b00Gdnm", 434 | ["vsub.f32_3"] = "ee300a40dnm", 435 | ["vsub.f64_3"] = "ee300b40Gdnm", 436 | ["vmul.f32_3"] = "ee200a00dnm", 437 | ["vmul.f64_3"] = "ee200b00Gdnm", 438 | ["vnmul.f32_3"] = "ee200a40dnm", 439 | ["vnmul.f64_3"] = "ee200b40Gdnm", 440 | ["vmla.f32_3"] = "ee000a00dnm", 441 | ["vmla.f64_3"] = "ee000b00Gdnm", 442 | ["vmls.f32_3"] = "ee000a40dnm", 443 | ["vmls.f64_3"] = "ee000b40Gdnm", 444 | ["vnmla.f32_3"] = "ee100a40dnm", 445 | ["vnmla.f64_3"] = "ee100b40Gdnm", 446 | ["vnmls.f32_3"] = "ee100a00dnm", 447 | ["vnmls.f64_3"] = "ee100b00Gdnm", 448 | ["vdiv.f32_3"] = "ee800a00dnm", 449 | ["vdiv.f64_3"] = "ee800b00Gdnm", 450 | 451 | ["vabs.f32_2"] = "eeb00ac0dm", 452 | ["vabs.f64_2"] = "eeb00bc0Gdm", 453 | ["vneg.f32_2"] = "eeb10a40dm", 454 | ["vneg.f64_2"] = "eeb10b40Gdm", 455 | ["vsqrt.f32_2"] = "eeb10ac0dm", 456 | ["vsqrt.f64_2"] = "eeb10bc0Gdm", 457 | ["vcmp.f32_2"] = "eeb40a40dm", 458 | ["vcmp.f64_2"] = "eeb40b40Gdm", 459 | ["vcmpe.f32_2"] = "eeb40ac0dm", 460 | ["vcmpe.f64_2"] = "eeb40bc0Gdm", 461 | ["vcmpz.f32_1"] = "eeb50a40d", 462 | ["vcmpz.f64_1"] = "eeb50b40Gd", 463 | ["vcmpze.f32_1"] = "eeb50ac0d", 464 | ["vcmpze.f64_1"] = "eeb50bc0Gd", 465 | 466 | vldr_2 = "ed100a00dl|ed100b00Gdl", 467 | vstr_2 = "ed000a00dl|ed000b00Gdl", 468 | vldm_2 = "ec900a00or", 469 | vldmia_2 = "ec900a00or", 470 | vldmdb_2 = "ed100a00or", 471 | vpop_1 = "ecbd0a00r", 472 | vstm_2 = "ec800a00or", 473 | vstmia_2 = "ec800a00or", 474 | vstmdb_2 = "ed000a00or", 475 | vpush_1 = "ed2d0a00r", 476 | 477 | ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only 478 | ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only 479 | vmov_2 = "ee100a10Dn|ee000a10nD", 480 | vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN", 481 | 482 | vmrs_0 = "eef1fa10", 483 | vmrs_1 = "eef10a10D", 484 | vmsr_1 = "eee10a10D", 485 | 486 | ["vcvt.s32.f32_2"] = "eebd0ac0dm", 487 | ["vcvt.s32.f64_2"] = "eebd0bc0dGm", 488 | ["vcvt.u32.f32_2"] = "eebc0ac0dm", 489 | ["vcvt.u32.f64_2"] = "eebc0bc0dGm", 490 | ["vcvtr.s32.f32_2"] = "eebd0a40dm", 491 | ["vcvtr.s32.f64_2"] = "eebd0b40dGm", 492 | ["vcvtr.u32.f32_2"] = "eebc0a40dm", 493 | ["vcvtr.u32.f64_2"] = "eebc0b40dGm", 494 | ["vcvt.f32.s32_2"] = "eeb80ac0dm", 495 | ["vcvt.f64.s32_2"] = "eeb80bc0GdFm", 496 | ["vcvt.f32.u32_2"] = "eeb80a40dm", 497 | ["vcvt.f64.u32_2"] = "eeb80b40GdFm", 498 | ["vcvt.f32.f64_2"] = "eeb70bc0dGm", 499 | ["vcvt.f64.f32_2"] = "eeb70ac0GdFm", 500 | 501 | -- VFPv4 only: 502 | ["vfma.f32_3"] = "eea00a00dnm", 503 | ["vfma.f64_3"] = "eea00b00Gdnm", 504 | ["vfms.f32_3"] = "eea00a40dnm", 505 | ["vfms.f64_3"] = "eea00b40Gdnm", 506 | ["vfnma.f32_3"] = "ee900a40dnm", 507 | ["vfnma.f64_3"] = "ee900b40Gdnm", 508 | ["vfnms.f32_3"] = "ee900a00dnm", 509 | ["vfnms.f64_3"] = "ee900b00Gdnm", 510 | 511 | -- NYI: Advanced SIMD instructions. 512 | 513 | -- NYI: I have no need for these instructions right now: 514 | -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh 515 | -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe 516 | -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb 517 | -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 518 | } 519 | 520 | -- Add mnemonics for "s" variants. 521 | do 522 | local t = {} 523 | for k,v in pairs(map_op) do 524 | if sub(v, -1) == "s" then 525 | local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) 526 | t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 527 | end 528 | end 529 | for k,v in pairs(t) do 530 | map_op[k] = v 531 | end 532 | end 533 | 534 | ------------------------------------------------------------------------------ 535 | 536 | local function parse_gpr(expr) 537 | local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") 538 | local tp = map_type[tname or expr] 539 | if tp then 540 | local reg = ovreg or tp.reg 541 | if not reg then 542 | werror("type `"..(tname or expr).."' needs a register override") 543 | end 544 | expr = reg 545 | end 546 | local r = match(expr, "^r(1?[0-9])$") 547 | if r then 548 | r = tonumber(r) 549 | if r <= 15 then return r, tp end 550 | end 551 | werror("bad register name `"..expr.."'") 552 | end 553 | 554 | local function parse_gpr_pm(expr) 555 | local pm, expr2 = match(expr, "^([+-]?)(.*)$") 556 | return parse_gpr(expr2), (pm == "-") 557 | end 558 | 559 | local function parse_vr(expr, tp) 560 | local t, r = match(expr, "^([sd])([0-9]+)$") 561 | if t == tp then 562 | r = tonumber(r) 563 | if r <= 31 then 564 | if t == "s" then return shr(r, 1), band(r, 1) end 565 | return band(r, 15), shr(r, 4) 566 | end 567 | end 568 | werror("bad register name `"..expr.."'") 569 | end 570 | 571 | local function parse_reglist(reglist) 572 | reglist = match(reglist, "^{%s*([^}]*)}$") 573 | if not reglist then werror("register list expected") end 574 | local rr = 0 575 | for p in gmatch(reglist..",", "%s*([^,]*),") do 576 | local rbit = shl(1, parse_gpr(gsub(p, "%s+$", ""))) 577 | if band(rr, rbit) ~= 0 then 578 | werror("duplicate register `"..p.."'") 579 | end 580 | rr = rr + rbit 581 | end 582 | return rr 583 | end 584 | 585 | local function parse_vrlist(reglist) 586 | local ta, ra, tb, rb = match(reglist, 587 | "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$") 588 | ra, rb = tonumber(ra), tonumber(rb) 589 | if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then 590 | local nr = rb+1 - ra 591 | if ta == "s" then 592 | return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr 593 | else 594 | return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100 595 | end 596 | end 597 | werror("register list expected") 598 | end 599 | 600 | local function parse_imm(imm, bits, shift, scale, signed) 601 | imm = match(imm, "^#(.*)$") 602 | if not imm then werror("expected immediate operand") end 603 | local n = tonumber(imm) 604 | if n then 605 | local m = sar(n, scale) 606 | if shl(m, scale) == n then 607 | if signed then 608 | local s = sar(m, bits-1) 609 | if s == 0 then return shl(m, shift) 610 | elseif s == -1 then return shl(m + shl(1, bits), shift) end 611 | else 612 | if sar(m, bits) == 0 then return shl(m, shift) end 613 | end 614 | end 615 | werror("out of range immediate `"..imm.."'") 616 | else 617 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) 618 | return 0 619 | end 620 | end 621 | 622 | local function parse_imm12(imm) 623 | local n = tonumber(imm) 624 | if n then 625 | local m = band(n) 626 | for i=0,-15,-1 do 627 | if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end 628 | m = ror(m, 2) 629 | end 630 | werror("out of range immediate `"..imm.."'") 631 | else 632 | waction("IMM12", 0, imm) 633 | return 0 634 | end 635 | end 636 | 637 | local function parse_imm16(imm) 638 | imm = match(imm, "^#(.*)$") 639 | if not imm then werror("expected immediate operand") end 640 | local n = tonumber(imm) 641 | if n then 642 | if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end 643 | werror("out of range immediate `"..imm.."'") 644 | else 645 | waction("IMM16", 32*16, imm) 646 | return 0 647 | end 648 | end 649 | 650 | local function parse_imm_load(imm, ext) 651 | local n = tonumber(imm) 652 | if n then 653 | if ext then 654 | if n >= -255 and n <= 255 then 655 | local up = 0x00800000 656 | if n < 0 then n = -n; up = 0 end 657 | return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up 658 | end 659 | else 660 | if n >= -4095 and n <= 4095 then 661 | if n >= 0 then return n+0x00800000 end 662 | return -n 663 | end 664 | end 665 | werror("out of range immediate `"..imm.."'") 666 | else 667 | waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm) 668 | return 0 669 | end 670 | end 671 | 672 | local function parse_shift(shift, gprok) 673 | if shift == "rrx" then 674 | return 3 * 32 675 | else 676 | local s, s2 = match(shift, "^(%S+)%s*(.*)$") 677 | s = map_shift[s] 678 | if not s then werror("expected shift operand") end 679 | if sub(s2, 1, 1) == "#" then 680 | return parse_imm(s2, 5, 7, 0, false) + shl(s, 5) 681 | else 682 | if not gprok then werror("expected immediate shift operand") end 683 | return shl(parse_gpr(s2), 8) + shl(s, 5) + 16 684 | end 685 | end 686 | end 687 | 688 | local function parse_label(label, def) 689 | local prefix = sub(label, 1, 2) 690 | -- =>label (pc label reference) 691 | if prefix == "=>" then 692 | return "PC", 0, sub(label, 3) 693 | end 694 | -- ->name (global label reference) 695 | if prefix == "->" then 696 | return "LG", map_global[sub(label, 3)] 697 | end 698 | if def then 699 | -- [1-9] (local label definition) 700 | if match(label, "^[1-9]$") then 701 | return "LG", 10+tonumber(label) 702 | end 703 | else 704 | -- [<>][1-9] (local label reference) 705 | local dir, lnum = match(label, "^([<>])([1-9])$") 706 | if dir then -- Fwd: 1-9, Bkwd: 11-19. 707 | return "LG", lnum + (dir == ">" and 0 or 10) 708 | end 709 | -- extern label (extern label reference) 710 | local extname = match(label, "^extern%s+(%S+)$") 711 | if extname then 712 | return "EXT", map_extern[extname] 713 | end 714 | end 715 | werror("bad label `"..label.."'") 716 | end 717 | 718 | local function parse_load(params, nparams, n, op) 719 | local oplo = band(op, 255) 720 | local ext, ldrd = (oplo ~= 0), (oplo == 208) 721 | local d 722 | if (ldrd or oplo == 240) then 723 | d = band(shr(op, 12), 15) 724 | if band(d, 1) ~= 0 then werror("odd destination register") end 725 | end 726 | local pn = params[n] 727 | local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") 728 | local p2 = params[n+1] 729 | if not p1 then 730 | if not p2 then 731 | if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then 732 | local mode, n, s = parse_label(pn, false) 733 | waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) 734 | return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) 735 | end 736 | local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") 737 | if reg and tailr ~= "" then 738 | local d, tp = parse_gpr(reg) 739 | if tp then 740 | waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), 741 | format(tp.ctypefmt, tailr)) 742 | return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0) 743 | end 744 | end 745 | end 746 | werror("expected address operand") 747 | end 748 | if wb == "!" then op = op + 0x00200000 end 749 | if p2 then 750 | if wb == "!" then werror("bad use of '!'") end 751 | local p3 = params[n+2] 752 | op = op + shl(parse_gpr(p1), 16) 753 | local imm = match(p2, "^#(.*)$") 754 | if imm then 755 | local m = parse_imm_load(imm, ext) 756 | if p3 then werror("too many parameters") end 757 | op = op + m + (ext and 0x00400000 or 0) 758 | else 759 | local m, neg = parse_gpr_pm(p2) 760 | if ldrd and (m == d or m-1 == d) then werror("register conflict") end 761 | op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) 762 | if p3 then op = op + parse_shift(p3) end 763 | end 764 | else 765 | local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") 766 | op = op + shl(parse_gpr(p1a), 16) + 0x01000000 767 | if p2 ~= "" then 768 | local imm = match(p2, "^,%s*#(.*)$") 769 | if imm then 770 | local m = parse_imm_load(imm, ext) 771 | op = op + m + (ext and 0x00400000 or 0) 772 | else 773 | local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") 774 | local m, neg = parse_gpr_pm(p2a) 775 | if ldrd and (m == d or m-1 == d) then werror("register conflict") end 776 | op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) 777 | if p3 ~= "" then 778 | if ext then werror("too many parameters") end 779 | op = op + parse_shift(p3) 780 | end 781 | end 782 | else 783 | if wb == "!" then werror("bad use of '!'") end 784 | op = op + (ext and 0x00c00000 or 0x00800000) 785 | end 786 | end 787 | return op 788 | end 789 | 790 | local function parse_vload(q) 791 | local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$") 792 | if reg then 793 | local d = shl(parse_gpr(reg), 16) 794 | if imm == "" then return d end 795 | imm = match(imm, "^,%s*#(.*)$") 796 | if imm then 797 | local n = tonumber(imm) 798 | if n then 799 | if n >= -1020 and n <= 1020 and n%4 == 0 then 800 | return d + (n >= 0 and n/4+0x00800000 or -n/4) 801 | end 802 | werror("out of range immediate `"..imm.."'") 803 | else 804 | waction("IMMV8", 32768 + 32*8, imm) 805 | return d 806 | end 807 | end 808 | else 809 | if match(q, "^[<>=%-]") or match(q, "^extern%s+") then 810 | local mode, n, s = parse_label(q, false) 811 | waction("REL_"..mode, n + 0x2800, s, 1) 812 | return 15 * 65536 813 | end 814 | local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$") 815 | if reg and tailr ~= "" then 816 | local d, tp = parse_gpr(reg) 817 | if tp then 818 | waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr)) 819 | return shl(d, 16) 820 | end 821 | end 822 | end 823 | werror("expected address operand") 824 | end 825 | 826 | ------------------------------------------------------------------------------ 827 | 828 | -- Handle opcodes defined with template strings. 829 | local function parse_template(params, template, nparams, pos) 830 | local op = tonumber(sub(template, 1, 8), 16) 831 | local n = 1 832 | local vr = "s" 833 | 834 | -- Process each character. 835 | for p in gmatch(sub(template, 9), ".") do 836 | local q = params[n] 837 | if p == "D" then 838 | op = op + shl(parse_gpr(q), 12); n = n + 1 839 | elseif p == "N" then 840 | op = op + shl(parse_gpr(q), 16); n = n + 1 841 | elseif p == "S" then 842 | op = op + shl(parse_gpr(q), 8); n = n + 1 843 | elseif p == "M" then 844 | op = op + parse_gpr(q); n = n + 1 845 | elseif p == "d" then 846 | local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1 847 | elseif p == "n" then 848 | local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1 849 | elseif p == "m" then 850 | local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1 851 | elseif p == "P" then 852 | local imm = match(q, "^#(.*)$") 853 | if imm then 854 | op = op + parse_imm12(imm) + 0x02000000 855 | else 856 | op = op + parse_gpr(q) 857 | end 858 | n = n + 1 859 | elseif p == "p" then 860 | op = op + parse_shift(q, true); n = n + 1 861 | elseif p == "L" then 862 | op = parse_load(params, nparams, n, op) 863 | elseif p == "l" then 864 | op = op + parse_vload(q) 865 | elseif p == "B" then 866 | local mode, n, s = parse_label(q, false) 867 | waction("REL_"..mode, n, s, 1) 868 | elseif p == "C" then -- blx gpr vs. blx label. 869 | if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then 870 | op = op + parse_gpr(q) 871 | else 872 | if op < 0xe0000000 then werror("unconditional instruction") end 873 | local mode, n, s = parse_label(q, false) 874 | waction("REL_"..mode, n, s, 1) 875 | op = 0xfa000000 876 | end 877 | elseif p == "F" then 878 | vr = "s" 879 | elseif p == "G" then 880 | vr = "d" 881 | elseif p == "o" then 882 | local r, wb = match(q, "^([^!]*)(!?)$") 883 | op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0) 884 | n = n + 1 885 | elseif p == "R" then 886 | op = op + parse_reglist(q); n = n + 1 887 | elseif p == "r" then 888 | op = op + parse_vrlist(q); n = n + 1 889 | elseif p == "W" then 890 | op = op + parse_imm16(q); n = n + 1 891 | elseif p == "v" then 892 | op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 893 | elseif p == "w" then 894 | local imm = match(q, "^#(.*)$") 895 | if imm then 896 | op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 897 | else 898 | op = op + shl(parse_gpr(q), 8) + 16 899 | end 900 | elseif p == "X" then 901 | op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 902 | elseif p == "Y" then 903 | local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 904 | if not imm or shr(imm, 8) ~= 0 then 905 | werror("bad immediate operand") 906 | end 907 | op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f) 908 | elseif p == "K" then 909 | local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 910 | if not imm or shr(imm, 16) ~= 0 then 911 | werror("bad immediate operand") 912 | end 913 | op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f) 914 | elseif p == "T" then 915 | op = op + parse_imm(q, 24, 0, 0, false); n = n + 1 916 | elseif p == "s" then 917 | -- Ignored. 918 | else 919 | assert(false) 920 | end 921 | end 922 | wputpos(pos, op) 923 | end 924 | 925 | map_op[".template__"] = function(params, template, nparams) 926 | if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end 927 | 928 | -- Limit number of section buffer positions used by a single dasm_put(). 929 | -- A single opcode needs a maximum of 3 positions. 930 | if secpos+3 > maxsecpos then wflush() end 931 | local pos = wpos() 932 | local lpos, apos, spos = #actlist, #actargs, secpos 933 | 934 | local ok, err 935 | for t in gmatch(template, "[^|]+") do 936 | ok, err = pcall(parse_template, params, t, nparams, pos) 937 | if ok then return end 938 | secpos = spos 939 | actlist[lpos+1] = nil 940 | actlist[lpos+2] = nil 941 | actlist[lpos+3] = nil 942 | actargs[apos+1] = nil 943 | actargs[apos+2] = nil 944 | actargs[apos+3] = nil 945 | end 946 | error(err, 0) 947 | end 948 | 949 | ------------------------------------------------------------------------------ 950 | 951 | -- Pseudo-opcode to mark the position where the action list is to be emitted. 952 | map_op[".actionlist_1"] = function(params) 953 | if not params then return "cvar" end 954 | local name = params[1] -- No syntax check. You get to keep the pieces. 955 | wline(function(out) writeactions(out, name) end) 956 | end 957 | 958 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. 959 | map_op[".globals_1"] = function(params) 960 | if not params then return "prefix" end 961 | local prefix = params[1] -- No syntax check. You get to keep the pieces. 962 | wline(function(out) writeglobals(out, prefix) end) 963 | end 964 | 965 | -- Pseudo-opcode to mark the position where the global names are to be emitted. 966 | map_op[".globalnames_1"] = function(params) 967 | if not params then return "cvar" end 968 | local name = params[1] -- No syntax check. You get to keep the pieces. 969 | wline(function(out) writeglobalnames(out, name) end) 970 | end 971 | 972 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. 973 | map_op[".externnames_1"] = function(params) 974 | if not params then return "cvar" end 975 | local name = params[1] -- No syntax check. You get to keep the pieces. 976 | wline(function(out) writeexternnames(out, name) end) 977 | end 978 | 979 | ------------------------------------------------------------------------------ 980 | 981 | -- Label pseudo-opcode (converted from trailing colon form). 982 | map_op[".label_1"] = function(params) 983 | if not params then return "[1-9] | ->global | =>pcexpr" end 984 | if secpos+1 > maxsecpos then wflush() end 985 | local mode, n, s = parse_label(params[1], true) 986 | if mode == "EXT" then werror("bad label definition") end 987 | waction("LABEL_"..mode, n, s, 1) 988 | end 989 | 990 | ------------------------------------------------------------------------------ 991 | 992 | -- Pseudo-opcodes for data storage. 993 | map_op[".long_*"] = function(params) 994 | if not params then return "imm..." end 995 | for _,p in ipairs(params) do 996 | local n = tonumber(p) 997 | if not n then werror("bad immediate `"..p.."'") end 998 | if n < 0 then n = n + 2^32 end 999 | wputw(n) 1000 | if secpos+2 > maxsecpos then wflush() end 1001 | end 1002 | end 1003 | 1004 | -- Alignment pseudo-opcode. 1005 | map_op[".align_1"] = function(params) 1006 | if not params then return "numpow2" end 1007 | if secpos+1 > maxsecpos then wflush() end 1008 | local align = tonumber(params[1]) 1009 | if align then 1010 | local x = align 1011 | -- Must be a power of 2 in the range (2 ... 256). 1012 | for i=1,8 do 1013 | x = x / 2 1014 | if x == 1 then 1015 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. 1016 | return 1017 | end 1018 | end 1019 | end 1020 | werror("bad alignment") 1021 | end 1022 | 1023 | ------------------------------------------------------------------------------ 1024 | 1025 | -- Pseudo-opcode for (primitive) type definitions (map to C types). 1026 | map_op[".type_3"] = function(params, nparams) 1027 | if not params then 1028 | return nparams == 2 and "name, ctype" or "name, ctype, reg" 1029 | end 1030 | local name, ctype, reg = params[1], params[2], params[3] 1031 | if not match(name, "^[%a_][%w_]*$") then 1032 | werror("bad type name `"..name.."'") 1033 | end 1034 | local tp = map_type[name] 1035 | if tp then 1036 | werror("duplicate type `"..name.."'") 1037 | end 1038 | -- Add #type to defines. A bit unclean to put it in map_archdef. 1039 | map_archdef["#"..name] = "sizeof("..ctype..")" 1040 | -- Add new type and emit shortcut define. 1041 | local num = ctypenum + 1 1042 | map_type[name] = { 1043 | ctype = ctype, 1044 | ctypefmt = format("Dt%X(%%s)", num), 1045 | reg = reg, 1046 | } 1047 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) 1048 | ctypenum = num 1049 | end 1050 | map_op[".type_2"] = map_op[".type_3"] 1051 | 1052 | -- Dump type definitions. 1053 | local function dumptypes(out, lvl) 1054 | local t = {} 1055 | for name in pairs(map_type) do t[#t+1] = name end 1056 | sort(t) 1057 | out:write("Type definitions:\n") 1058 | for _,name in ipairs(t) do 1059 | local tp = map_type[name] 1060 | local reg = tp.reg or "" 1061 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) 1062 | end 1063 | out:write("\n") 1064 | end 1065 | 1066 | ------------------------------------------------------------------------------ 1067 | 1068 | -- Set the current section. 1069 | function _M.section(num) 1070 | waction("SECTION", num) 1071 | wflush(true) -- SECTION is a terminal action. 1072 | end 1073 | 1074 | ------------------------------------------------------------------------------ 1075 | 1076 | -- Dump architecture description. 1077 | function _M.dumparch(out) 1078 | out:write(format("DynASM %s version %s, released %s\n\n", 1079 | _info.arch, _info.version, _info.release)) 1080 | dumpactions(out) 1081 | end 1082 | 1083 | -- Dump all user defined elements. 1084 | function _M.dumpdef(out, lvl) 1085 | dumptypes(out, lvl) 1086 | dumpglobals(out, lvl) 1087 | dumpexterns(out, lvl) 1088 | end 1089 | 1090 | ------------------------------------------------------------------------------ 1091 | 1092 | -- Pass callbacks from/to the DynASM core. 1093 | function _M.passcb(wl, we, wf, ww) 1094 | wline, werror, wfatal, wwarn = wl, we, wf, ww 1095 | return wflush 1096 | end 1097 | 1098 | -- Setup the arch-specific module. 1099 | function _M.setup(arch, opt) 1100 | g_arch, g_opt = arch, opt 1101 | end 1102 | 1103 | -- Merge the core maps and the arch-specific maps. 1104 | function _M.mergemaps(map_coreop, map_def) 1105 | setmetatable(map_op, { __index = function(t, k) 1106 | local v = map_coreop[k] 1107 | if v then return v end 1108 | local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$") 1109 | local cv = map_cond[cc] 1110 | if cv then 1111 | local v = rawget(t, k1..k2) 1112 | if type(v) == "string" then 1113 | local scv = format("%x", cv) 1114 | return gsub(scv..sub(v, 2), "|e", "|"..scv) 1115 | end 1116 | end 1117 | end }) 1118 | setmetatable(map_def, { __index = map_archdef }) 1119 | return map_op, map_def 1120 | end 1121 | 1122 | return _M 1123 | 1124 | ------------------------------------------------------------------------------ 1125 | 1126 | --------------------------------------------------------------------------------