pull/13171/head
parent
2c26f60dbb
commit
84fb01ad0f
20 changed files with 10 additions and 11559 deletions
@ -1,56 +0,0 @@ |
||||
=============================================================================== |
||||
LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ |
||||
|
||||
Copyright (C) 2005-2011 Mike Pall. All rights reserved. |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
||||
|
||||
[ MIT license: http://www.opensource.org/licenses/mit-license.php ] |
||||
|
||||
=============================================================================== |
||||
[ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ] |
||||
|
||||
Copyright (C) 1994-2011 Lua.org, PUC-Rio. |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
||||
|
||||
=============================================================================== |
||||
[ LuaJIT includes code from dlmalloc, which has this license statement: ] |
||||
|
||||
This is a version (aka dlmalloc) of malloc/free/realloc written by |
||||
Doug Lea and released to the public domain, as explained at |
||||
http://creativecommons.org/licenses/publicdomain |
||||
|
||||
=============================================================================== |
@ -1,10 +0,0 @@ |
||||
URL: http://repo.or.cz/w/luajit-2.0.git/tree/6c05739684527919293e25668589f17c35a7c129:/dynasm |
||||
Version: 6c05739684527919293e25668589f17c35a7c129 |
||||
License: MIT |
||||
License File: LICENSE |
||||
Description: |
||||
Taken from the larger LuaJIT project, DynASM is a tiny preprocessor and |
||||
runtime for generating machine code at runtime. |
||||
|
||||
Local Modifications: |
||||
No modifications. |
@ -1,448 +0,0 @@ |
||||
/*
|
||||
** DynASM ARM encoding engine. |
||||
** Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
** Released under the MIT license. See dynasm.lua for full copyright notice. |
||||
*/ |
||||
|
||||
#include <stddef.h> |
||||
#include <stdarg.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#define DASM_ARCH "arm" |
||||
|
||||
#ifndef DASM_EXTERN |
||||
#define DASM_EXTERN(a,b,c,d) 0 |
||||
#endif |
||||
|
||||
/* Action definitions. */ |
||||
enum { |
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, |
||||
/* The following actions need a buffer position. */ |
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, |
||||
/* The following actions also have an argument. */ |
||||
DASM_REL_PC, DASM_LABEL_PC, |
||||
DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, |
||||
DASM__MAX |
||||
}; |
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */ |
||||
#define DASM_MAXSECPOS 25 |
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */ |
||||
#define DASM_S_OK 0x00000000 |
||||
#define DASM_S_NOMEM 0x01000000 |
||||
#define DASM_S_PHASE 0x02000000 |
||||
#define DASM_S_MATCH_SEC 0x03000000 |
||||
#define DASM_S_RANGE_I 0x11000000 |
||||
#define DASM_S_RANGE_SEC 0x12000000 |
||||
#define DASM_S_RANGE_LG 0x13000000 |
||||
#define DASM_S_RANGE_PC 0x14000000 |
||||
#define DASM_S_RANGE_REL 0x15000000 |
||||
#define DASM_S_UNDEF_LG 0x21000000 |
||||
#define DASM_S_UNDEF_PC 0x22000000 |
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */ |
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) |
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000) |
||||
#define DASM_SEC2POS(sec) ((sec)<<24) |
||||
#define DASM_POS2SEC(pos) ((pos)>>24) |
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) |
||||
|
||||
/* Action list type. */ |
||||
typedef const unsigned int *dasm_ActList; |
||||
|
||||
/* Per-section structure. */ |
||||
typedef struct dasm_Section { |
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */ |
||||
int *buf; /* True buffer pointer. */ |
||||
size_t bsize; /* Buffer size in bytes. */ |
||||
int pos; /* Biased buffer position. */ |
||||
int epos; /* End of biased buffer position - max single put. */ |
||||
int ofs; /* Byte offset into section. */ |
||||
} dasm_Section; |
||||
|
||||
/* Core structure holding the DynASM encoding state. */ |
||||
struct dasm_State { |
||||
size_t psize; /* Allocated size of this structure. */ |
||||
dasm_ActList actionlist; /* Current actionlist pointer. */ |
||||
int *lglabels; /* Local/global chain/pos ptrs. */ |
||||
size_t lgsize; |
||||
int *pclabels; /* PC label chains/pos ptrs. */ |
||||
size_t pcsize; |
||||
void **globals; /* Array of globals (bias -10). */ |
||||
dasm_Section *section; /* Pointer to active section. */ |
||||
size_t codesize; /* Total size of all code sections. */ |
||||
int maxsection; /* 0 <= sectionidx < maxsection. */ |
||||
int status; /* Status code. */ |
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */ |
||||
}; |
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */ |
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) |
||||
|
||||
|
||||
/* Initialize DynASM state. */ |
||||
void dasm_init(Dst_DECL, int maxsection) |
||||
{ |
||||
dasm_State *D; |
||||
size_t psz = 0; |
||||
int i; |
||||
Dst_REF = NULL; |
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); |
||||
D = Dst_REF; |
||||
D->psize = psz; |
||||
D->lglabels = NULL; |
||||
D->lgsize = 0; |
||||
D->pclabels = NULL; |
||||
D->pcsize = 0; |
||||
D->globals = NULL; |
||||
D->maxsection = maxsection; |
||||
for (i = 0; i < maxsection; i++) { |
||||
D->sections[i].buf = NULL; /* Need this for pass3. */ |
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); |
||||
D->sections[i].bsize = 0; |
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ |
||||
} |
||||
} |
||||
|
||||
/* Free DynASM state. */ |
||||
void dasm_free(Dst_DECL) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
for (i = 0; i < D->maxsection; i++) |
||||
if (D->sections[i].buf) |
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); |
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); |
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); |
||||
DASM_M_FREE(Dst, D, D->psize); |
||||
} |
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */ |
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */ |
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); |
||||
} |
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */ |
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
size_t osz = D->pcsize; |
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); |
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); |
||||
} |
||||
|
||||
/* Setup encoder. */ |
||||
void dasm_setup(Dst_DECL, const void *actionlist) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
D->actionlist = (dasm_ActList)actionlist; |
||||
D->status = DASM_S_OK; |
||||
D->section = &D->sections[0]; |
||||
memset((void *)D->lglabels, 0, D->lgsize); |
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); |
||||
for (i = 0; i < D->maxsection; i++) { |
||||
D->sections[i].pos = DASM_SEC2POS(i); |
||||
D->sections[i].ofs = 0; |
||||
} |
||||
} |
||||
|
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) |
||||
#define CKPL(kind, st) \ |
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#define CKPL(kind, st) ((void)0) |
||||
#endif |
||||
|
||||
static int dasm_imm12(unsigned int n) |
||||
{ |
||||
int i; |
||||
for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) |
||||
if (n <= 255) return (int)(n + (i << 8)); |
||||
return -1; |
||||
} |
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ |
||||
void dasm_put(Dst_DECL, int start, ...) |
||||
{ |
||||
va_list ap; |
||||
dasm_State *D = Dst_REF; |
||||
dasm_ActList p = D->actionlist + start; |
||||
dasm_Section *sec = D->section; |
||||
int pos = sec->pos, ofs = sec->ofs; |
||||
int *b; |
||||
|
||||
if (pos >= sec->epos) { |
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize, |
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); |
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos); |
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); |
||||
} |
||||
|
||||
b = sec->rbuf; |
||||
b[pos++] = start; |
||||
|
||||
va_start(ap, start); |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16); |
||||
if (action >= DASM__MAX) { |
||||
ofs += 4; |
||||
} else { |
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; |
||||
switch (action) { |
||||
case DASM_STOP: goto stop; |
||||
case DASM_SECTION: |
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); |
||||
D->section = &D->sections[n]; goto stop; |
||||
case DASM_ESC: p++; ofs += 4; break; |
||||
case DASM_REL_EXT: break; |
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; |
||||
case DASM_REL_LG: |
||||
n = (ins & 2047) - 10; pl = D->lglabels + n; |
||||
if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ |
||||
pl += 10; n = *pl; |
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ |
||||
goto linkrel; |
||||
case DASM_REL_PC: |
||||
pl = D->pclabels + n; CKPL(pc, PC); |
||||
putrel: |
||||
n = *pl; |
||||
if (n < 0) { /* Label exists. Get label pos and store it. */ |
||||
b[pos] = -n; |
||||
} else { |
||||
linkrel: |
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */ |
||||
*pl = pos; |
||||
} |
||||
pos++; |
||||
break; |
||||
case DASM_LABEL_LG: |
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; |
||||
case DASM_LABEL_PC: |
||||
pl = D->pclabels + n; CKPL(pc, PC); |
||||
putlabel: |
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; |
||||
} |
||||
*pl = -pos; /* Label exists now. */ |
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */ |
||||
break; |
||||
case DASM_IMM: |
||||
case DASM_IMM16: |
||||
#ifdef DASM_CHECKS |
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); |
||||
if ((ins & 0x8000)) |
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); |
||||
else |
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I); |
||||
#endif |
||||
b[pos++] = n; |
||||
break; |
||||
case DASM_IMML8: |
||||
case DASM_IMML12: |
||||
CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : |
||||
(((-n)>>((ins>>5)&31)) == 0), RANGE_I); |
||||
b[pos++] = n; |
||||
break; |
||||
case DASM_IMM12: |
||||
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); |
||||
b[pos++] = n; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
stop: |
||||
va_end(ap); |
||||
sec->pos = pos; |
||||
sec->ofs = ofs; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */ |
||||
int dasm_link(Dst_DECL, size_t *szp) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int secnum; |
||||
int ofs = 0; |
||||
|
||||
#ifdef DASM_CHECKS |
||||
*szp = 0; |
||||
if (D->status != DASM_S_OK) return D->status; |
||||
{ |
||||
int pc; |
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) |
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; |
||||
} |
||||
#endif |
||||
|
||||
{ /* Handle globals not defined in this translation unit. */ |
||||
int idx; |
||||
for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { |
||||
int n = D->lglabels[idx]; |
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } |
||||
} |
||||
} |
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->rbuf; |
||||
int pos = DASM_SEC2POS(secnum); |
||||
int lastpos = sec->pos; |
||||
|
||||
while (pos != lastpos) { |
||||
dasm_ActList p = D->actionlist + b[pos++]; |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16); |
||||
switch (action) { |
||||
case DASM_STOP: case DASM_SECTION: goto stop; |
||||
case DASM_ESC: p++; break; |
||||
case DASM_REL_EXT: break; |
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; |
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break; |
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; |
||||
case DASM_IMM: case DASM_IMM12: case DASM_IMM16: |
||||
case DASM_IMML8: case DASM_IMML12: pos++; break; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
ofs += sec->ofs; /* Next section starts right after current section. */ |
||||
} |
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */ |
||||
*szp = ofs; |
||||
return DASM_S_OK; |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#endif |
||||
|
||||
/* Pass 3: Encode sections. */ |
||||
int dasm_encode(Dst_DECL, void *buffer) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
char *base = (char *)buffer; |
||||
unsigned int *cp = (unsigned int *)buffer; |
||||
int secnum; |
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->buf; |
||||
int *endb = sec->rbuf + sec->pos; |
||||
|
||||
while (b != endb) { |
||||
dasm_ActList p = D->actionlist + *b++; |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16); |
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; |
||||
switch (action) { |
||||
case DASM_STOP: case DASM_SECTION: goto stop; |
||||
case DASM_ESC: *cp++ = *p++; break; |
||||
case DASM_REL_EXT: |
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); |
||||
goto patchrel; |
||||
case DASM_ALIGN: |
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; |
||||
break; |
||||
case DASM_REL_LG: |
||||
CK(n >= 0, UNDEF_LG); |
||||
case DASM_REL_PC: |
||||
CK(n >= 0, UNDEF_PC); |
||||
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; |
||||
patchrel: |
||||
if ((ins & 0x800) == 0) { |
||||
CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); |
||||
cp[-1] |= ((n >> 2) & 0x00ffffff); |
||||
} else if ((ins & 0x1000)) { |
||||
CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); |
||||
goto patchimml8; |
||||
} else { |
||||
CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); |
||||
goto patchimml12; |
||||
} |
||||
break; |
||||
case DASM_LABEL_LG: |
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); |
||||
break; |
||||
case DASM_LABEL_PC: break; |
||||
case DASM_IMM: |
||||
cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); |
||||
break; |
||||
case DASM_IMM12: |
||||
cp[-1] |= dasm_imm12((unsigned int)n); |
||||
break; |
||||
case DASM_IMM16: |
||||
cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); |
||||
break; |
||||
case DASM_IMML8: patchimml8: |
||||
cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : |
||||
((-n & 0x0f) | ((-n & 0xf0) << 4)); |
||||
break; |
||||
case DASM_IMML12: patchimml12: |
||||
cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); |
||||
break; |
||||
default: *cp++ = ins; break; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
} |
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */ |
||||
return DASM_S_PHASE; |
||||
return DASM_S_OK; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Get PC label offset. */ |
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (pc*sizeof(int) < D->pcsize) { |
||||
int pos = D->pclabels[pc]; |
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos); |
||||
if (pos > 0) return -1; /* Undefined. */ |
||||
} |
||||
return -2; /* Unused or out of range. */ |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
/* Optional sanity checker to call between isolated encoding steps. */ |
||||
int dasm_checkstep(Dst_DECL, int secmatch) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (D->status == DASM_S_OK) { |
||||
int i; |
||||
for (i = 1; i <= 9; i++) { |
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } |
||||
D->lglabels[i] = 0; |
||||
} |
||||
} |
||||
if (D->status == DASM_S_OK && secmatch >= 0 && |
||||
D->section != &D->sections[secmatch]) |
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections); |
||||
return D->status; |
||||
} |
||||
#endif |
||||
|
@ -1,949 +0,0 @@ |
||||
------------------------------------------------------------------------------ |
||||
-- DynASM ARM module. |
||||
-- |
||||
-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
-- See dynasm.lua for full copyright notice. |
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Module information: |
||||
local _info = { |
||||
arch = "arm", |
||||
description = "DynASM ARM module", |
||||
version = "1.3.0", |
||||
vernum = 10300, |
||||
release = "2011-05-05", |
||||
author = "Mike Pall", |
||||
license = "MIT", |
||||
} |
||||
|
||||
-- Exported glue functions for the arch-specific module. |
||||
local _M = { _info = _info } |
||||
|
||||
-- Cache library functions. |
||||
local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs |
||||
local assert, setmetatable, rawget = assert, setmetatable, rawget |
||||
local _s = string |
||||
local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char |
||||
local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub |
||||
local concat, sort, insert = table.concat, table.sort, table.insert |
||||
|
||||
-- Inherited tables and callbacks. |
||||
local g_opt, g_arch |
||||
local wline, werror, wfatal, wwarn |
||||
|
||||
-- Action name list. |
||||
-- CHECK: Keep this in sync with the C code! |
||||
local action_names = { |
||||
"STOP", "SECTION", "ESC", "REL_EXT", |
||||
"ALIGN", "REL_LG", "LABEL_LG", |
||||
"REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", |
||||
} |
||||
|
||||
-- Maximum number of section buffer positions for dasm_put(). |
||||
-- CHECK: Keep this in sync with the C code! |
||||
local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. |
||||
|
||||
-- Action name -> action number. |
||||
local map_action = {} |
||||
for n,name in ipairs(action_names) do |
||||
map_action[name] = n-1 |
||||
end |
||||
|
||||
-- Action list buffer. |
||||
local actlist = {} |
||||
|
||||
-- Argument list for next dasm_put(). Start with offset 0 into action list. |
||||
local actargs = { 0 } |
||||
|
||||
-- Current number of section buffer positions for dasm_put(). |
||||
local secpos = 1 |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Return 8 digit hex number. |
||||
local function tohex(x) |
||||
return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. |
||||
end |
||||
|
||||
-- Dump action names and numbers. |
||||
local function dumpactions(out) |
||||
out:write("DynASM encoding engine action codes:\n") |
||||
for n,name in ipairs(action_names) do |
||||
local num = map_action[name] |
||||
out:write(format(" %-10s %02X %d\n", name, num, num)) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
-- Write action list buffer as a huge static C array. |
||||
local function writeactions(out, name) |
||||
local nn = #actlist |
||||
if nn == 0 then nn = 1; actlist[0] = map_action.STOP end |
||||
out:write("static const unsigned int ", name, "[", nn, "] = {\n") |
||||
for i = 1,nn-1 do |
||||
assert(out:write("0x", tohex(actlist[i]), ",\n")) |
||||
end |
||||
assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Add word to action list. |
||||
local function wputxw(n) |
||||
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") |
||||
actlist[#actlist+1] = n |
||||
end |
||||
|
||||
-- Add action to list with optional arg. Advance buffer pos, too. |
||||
local function waction(action, val, a, num) |
||||
local w = assert(map_action[action], "bad action name `"..action.."'") |
||||
wputxw(w * 0x10000 + (val or 0)) |
||||
if a then actargs[#actargs+1] = a end |
||||
if a or num then secpos = secpos + (num or 1) end |
||||
end |
||||
|
||||
-- Flush action list (intervening C code or buffer pos overflow). |
||||
local function wflush(term) |
||||
if #actlist == actargs[1] then return end -- Nothing to flush. |
||||
if not term then waction("STOP") end -- Terminate action list. |
||||
wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) |
||||
actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). |
||||
secpos = 1 -- The actionlist offset occupies a buffer position, too. |
||||
end |
||||
|
||||
-- Put escaped word. |
||||
local function wputw(n) |
||||
if n <= 0x000fffff then waction("ESC") end |
||||
wputxw(n) |
||||
end |
||||
|
||||
-- Reserve position for word. |
||||
local function wpos() |
||||
local pos = #actlist+1 |
||||
actlist[pos] = "" |
||||
return pos |
||||
end |
||||
|
||||
-- Store word to reserved position. |
||||
local function wputpos(pos, n) |
||||
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") |
||||
if n <= 0x000fffff then |
||||
insert(actlist, pos+1, n) |
||||
n = map_action.ESC * 0x10000 |
||||
end |
||||
actlist[pos] = n |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Global label name -> global label number. With auto assignment on 1st use. |
||||
local next_global = 20 |
||||
local map_global = setmetatable({}, { __index = function(t, name) |
||||
if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end |
||||
local n = next_global |
||||
if n > 2047 then werror("too many global labels") end |
||||
next_global = n + 1 |
||||
t[name] = n |
||||
return n |
||||
end}) |
||||
|
||||
-- Dump global labels. |
||||
local function dumpglobals(out, lvl) |
||||
local t = {} |
||||
for name, n in pairs(map_global) do t[n] = name end |
||||
out:write("Global labels:\n") |
||||
for i=20,next_global-1 do |
||||
out:write(format(" %s\n", t[i])) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
-- Write global label enum. |
||||
local function writeglobals(out, prefix) |
||||
local t = {} |
||||
for name, n in pairs(map_global) do t[n] = name end |
||||
out:write("enum {\n") |
||||
for i=20,next_global-1 do |
||||
out:write(" ", prefix, t[i], ",\n") |
||||
end |
||||
out:write(" ", prefix, "_MAX\n};\n") |
||||
end |
||||
|
||||
-- Write global label names. |
||||
local function writeglobalnames(out, name) |
||||
local t = {} |
||||
for name, n in pairs(map_global) do t[n] = name end |
||||
out:write("static const char *const ", name, "[] = {\n") |
||||
for i=20,next_global-1 do |
||||
out:write(" \"", t[i], "\",\n") |
||||
end |
||||
out:write(" (const char *)0\n};\n") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Extern label name -> extern label number. With auto assignment on 1st use. |
||||
local next_extern = 0 |
||||
local map_extern_ = {} |
||||
local map_extern = setmetatable({}, { __index = function(t, name) |
||||
-- No restrictions on the name for now. |
||||
local n = next_extern |
||||
if n > 2047 then werror("too many extern labels") end |
||||
next_extern = n + 1 |
||||
t[name] = n |
||||
map_extern_[n] = name |
||||
return n |
||||
end}) |
||||
|
||||
-- Dump extern labels. |
||||
local function dumpexterns(out, lvl) |
||||
out:write("Extern labels:\n") |
||||
for i=0,next_extern-1 do |
||||
out:write(format(" %s\n", map_extern_[i])) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
-- Write extern label names. |
||||
local function writeexternnames(out, name) |
||||
out:write("static const char *const ", name, "[] = {\n") |
||||
for i=0,next_extern-1 do |
||||
out:write(" \"", map_extern_[i], "\",\n") |
||||
end |
||||
out:write(" (const char *)0\n};\n") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Arch-specific maps. |
||||
|
||||
-- Ext. register name -> int. name. |
||||
local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } |
||||
|
||||
-- Int. register name -> ext. name. |
||||
local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } |
||||
|
||||
local map_type = {} -- Type name -> { ctype, reg } |
||||
local ctypenum = 0 -- Type number (for Dt... macros). |
||||
|
||||
-- Reverse defines for registers. |
||||
function _M.revdef(s) |
||||
return map_reg_rev[s] or s |
||||
end |
||||
|
||||
local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } |
||||
|
||||
local map_cond = { |
||||
eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, |
||||
hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, |
||||
hs = 2, lo = 3, |
||||
} |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Template strings for ARM instructions. |
||||
local map_op = { |
||||
-- Basic data processing instructions. |
||||
and_3 = "e0000000DNPs", |
||||
eor_3 = "e0200000DNPs", |
||||
sub_3 = "e0400000DNPs", |
||||
rsb_3 = "e0600000DNPs", |
||||
add_3 = "e0800000DNPs", |
||||
adc_3 = "e0a00000DNPs", |
||||
sbc_3 = "e0c00000DNPs", |
||||
rsc_3 = "e0e00000DNPs", |
||||
tst_2 = "e1100000NP", |
||||
teq_2 = "e1300000NP", |
||||
cmp_2 = "e1500000NP", |
||||
cmn_2 = "e1700000NP", |
||||
orr_3 = "e1800000DNPs", |
||||
mov_2 = "e1a00000DPs", |
||||
bic_3 = "e1c00000DNPs", |
||||
mvn_2 = "e1e00000DPs", |
||||
|
||||
and_4 = "e0000000DNMps", |
||||
eor_4 = "e0200000DNMps", |
||||
sub_4 = "e0400000DNMps", |
||||
rsb_4 = "e0600000DNMps", |
||||
add_4 = "e0800000DNMps", |
||||
adc_4 = "e0a00000DNMps", |
||||
sbc_4 = "e0c00000DNMps", |
||||
rsc_4 = "e0e00000DNMps", |
||||
tst_3 = "e1100000NMp", |
||||
teq_3 = "e1300000NMp", |
||||
cmp_3 = "e1500000NMp", |
||||
cmn_3 = "e1700000NMp", |
||||
orr_4 = "e1800000DNMps", |
||||
mov_3 = "e1a00000DMps", |
||||
bic_4 = "e1c00000DNMps", |
||||
mvn_3 = "e1e00000DMps", |
||||
|
||||
lsl_3 = "e1a00000DMws", |
||||
lsr_3 = "e1a00020DMws", |
||||
asr_3 = "e1a00040DMws", |
||||
ror_3 = "e1a00060DMws", |
||||
rrx_2 = "e1a00060DMs", |
||||
|
||||
-- Multiply and multiply-accumulate. |
||||
mul_3 = "e0000090NMSs", |
||||
mla_4 = "e0200090NMSDs", |
||||
umaal_4 = "e0400090DNMSs", -- v6 |
||||
mls_4 = "e0600090DNMSs", -- v6T2 |
||||
umull_4 = "e0800090DNMSs", |
||||
umlal_4 = "e0a00090DNMSs", |
||||
smull_4 = "e0c00090DNMSs", |
||||
smlal_4 = "e0e00090DNMSs", |
||||
|
||||
-- Halfword multiply and multiply-accumulate. |
||||
smlabb_4 = "e1000080NMSD", -- v5TE |
||||
smlatb_4 = "e10000a0NMSD", -- v5TE |
||||
smlabt_4 = "e10000c0NMSD", -- v5TE |
||||
smlatt_4 = "e10000e0NMSD", -- v5TE |
||||
smlawb_4 = "e1200080NMSD", -- v5TE |
||||
smulwb_3 = "e12000a0NMS", -- v5TE |
||||
smlawt_4 = "e12000c0NMSD", -- v5TE |
||||
smulwt_3 = "e12000e0NMS", -- v5TE |
||||
smlalbb_4 = "e1400080NMSD", -- v5TE |
||||
smlaltb_4 = "e14000a0NMSD", -- v5TE |
||||
smlalbt_4 = "e14000c0NMSD", -- v5TE |
||||
smlaltt_4 = "e14000e0NMSD", -- v5TE |
||||
smulbb_3 = "e1600080NMS", -- v5TE |
||||
smultb_3 = "e16000a0NMS", -- v5TE |
||||
smulbt_3 = "e16000c0NMS", -- v5TE |
||||
smultt_3 = "e16000e0NMS", -- v5TE |
||||
|
||||
-- Miscellaneous data processing instructions. |
||||
clz_2 = "e16f0f10DM", -- v5T |
||||
rev_2 = "e6bf0f30DM", -- v6 |
||||
rev16_2 = "e6bf0fb0DM", -- v6 |
||||
revsh_2 = "e6ff0fb0DM", -- v6 |
||||
sel_3 = "e6800fb0DNM", -- v6 |
||||
usad8_3 = "e780f010NMS", -- v6 |
||||
usada8_4 = "e7800010NMSD", -- v6 |
||||
rbit_2 = "e6ff0f30DM", -- v6T2 |
||||
movw_2 = "e3000000DW", -- v6T2 |
||||
movt_2 = "e3400000DW", -- v6T2 |
||||
-- Note: the X encodes width-1, not width. |
||||
sbfx_4 = "e7a00050DMvX", -- v6T2 |
||||
ubfx_4 = "e7e00050DMvX", -- v6T2 |
||||
-- Note: the X encodes the msb field, not the width. |
||||
bfc_3 = "e7c0001fDvX", -- v6T2 |
||||
bfi_4 = "e7c00010DMvX", -- v6T2 |
||||
|
||||
-- Packing and unpacking instructions. |
||||
pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 |
||||
pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 |
||||
sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 |
||||
sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 |
||||
sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 |
||||
sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 |
||||
sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 |
||||
sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 |
||||
uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 |
||||
uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 |
||||
uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 |
||||
uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 |
||||
uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 |
||||
uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 |
||||
|
||||
-- Saturating instructions. |
||||
qadd_3 = "e1000050DMN", -- v5TE |
||||
qsub_3 = "e1200050DMN", -- v5TE |
||||
qdadd_3 = "e1400050DMN", -- v5TE |
||||
qdsub_3 = "e1600050DMN", -- v5TE |
||||
-- Note: the X for ssat* encodes sat_imm-1, not sat_imm. |
||||
ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 |
||||
usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 |
||||
ssat16_3 = "e6a00f30DXM", -- v6 |
||||
usat16_3 = "e6e00f30DXM", -- v6 |
||||
|
||||
-- Parallel addition and subtraction. |
||||
sadd16_3 = "e6100f10DNM", -- v6 |
||||
sasx_3 = "e6100f30DNM", -- v6 |
||||
ssax_3 = "e6100f50DNM", -- v6 |
||||
ssub16_3 = "e6100f70DNM", -- v6 |
||||
sadd8_3 = "e6100f90DNM", -- v6 |
||||
ssub8_3 = "e6100ff0DNM", -- v6 |
||||
qadd16_3 = "e6200f10DNM", -- v6 |
||||
qasx_3 = "e6200f30DNM", -- v6 |
||||
qsax_3 = "e6200f50DNM", -- v6 |
||||
qsub16_3 = "e6200f70DNM", -- v6 |
||||
qadd8_3 = "e6200f90DNM", -- v6 |
||||
qsub8_3 = "e6200ff0DNM", -- v6 |
||||
shadd16_3 = "e6300f10DNM", -- v6 |
||||
shasx_3 = "e6300f30DNM", -- v6 |
||||
shsax_3 = "e6300f50DNM", -- v6 |
||||
shsub16_3 = "e6300f70DNM", -- v6 |
||||
shadd8_3 = "e6300f90DNM", -- v6 |
||||
shsub8_3 = "e6300ff0DNM", -- v6 |
||||
uadd16_3 = "e6500f10DNM", -- v6 |
||||
uasx_3 = "e6500f30DNM", -- v6 |
||||
usax_3 = "e6500f50DNM", -- v6 |
||||
usub16_3 = "e6500f70DNM", -- v6 |
||||
uadd8_3 = "e6500f90DNM", -- v6 |
||||
usub8_3 = "e6500ff0DNM", -- v6 |
||||
uqadd16_3 = "e6600f10DNM", -- v6 |
||||
uqasx_3 = "e6600f30DNM", -- v6 |
||||
uqsax_3 = "e6600f50DNM", -- v6 |
||||
uqsub16_3 = "e6600f70DNM", -- v6 |
||||
uqadd8_3 = "e6600f90DNM", -- v6 |
||||
uqsub8_3 = "e6600ff0DNM", -- v6 |
||||
uhadd16_3 = "e6700f10DNM", -- v6 |
||||
uhasx_3 = "e6700f30DNM", -- v6 |
||||
uhsax_3 = "e6700f50DNM", -- v6 |
||||
uhsub16_3 = "e6700f70DNM", -- v6 |
||||
uhadd8_3 = "e6700f90DNM", -- v6 |
||||
uhsub8_3 = "e6700ff0DNM", -- v6 |
||||
|
||||
-- Load/store instructions. |
||||
str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", |
||||
strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", |
||||
ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", |
||||
ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", |
||||
strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", |
||||
ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", |
||||
ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE |
||||
ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", |
||||
strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE |
||||
ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", |
||||
|
||||
ldm_2 = "e8900000nR", ldmia_2 = "e8900000nR", ldmfd_2 = "e8900000nR", |
||||
ldmda_2 = "e8100000nR", ldmfa_2 = "e8100000nR", |
||||
ldmdb_2 = "e9100000nR", ldmea_2 = "e9100000nR", |
||||
ldmib_2 = "e9900000nR", ldmed_2 = "e9900000nR", |
||||
stm_2 = "e8800000nR", stmia_2 = "e8800000nR", stmfd_2 = "e8800000nR", |
||||
stmda_2 = "e8000000nR", stmfa_2 = "e8000000nR", |
||||
stmdb_2 = "e9000000nR", stmea_2 = "e9000000nR", |
||||
stmib_2 = "e9800000nR", stmed_2 = "e9800000nR", |
||||
pop_1 = "e8bd0000R", push_1 = "e92d0000R", |
||||
|
||||
-- Branch instructions. |
||||
b_1 = "ea000000B", |
||||
bl_1 = "eb000000B", |
||||
blx_1 = "e12fff30C", |
||||
bx_1 = "e12fff10M", |
||||
|
||||
-- Miscellaneous instructions. |
||||
nop_0 = "e1a00000", |
||||
mrs_1 = "e10f0000D", |
||||
bkpt_1 = "e1200070K", -- v5T |
||||
svc_1 = "ef000000T", swi_1 = "ef000000T", |
||||
ud_0 = "e7f001f0", |
||||
|
||||
-- NYI: Advanced SIMD and VFP instructions. |
||||
|
||||
-- NYI instructions, since I have no need for them right now: |
||||
-- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh |
||||
-- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe |
||||
-- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb |
||||
-- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 |
||||
} |
||||
|
||||
-- Add mnemonics for "s" variants. |
||||
do |
||||
local t = {} |
||||
for k,v in pairs(map_op) do |
||||
if sub(v, -1) == "s" then |
||||
local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) |
||||
t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 |
||||
end |
||||
end |
||||
for k,v in pairs(t) do |
||||
map_op[k] = v |
||||
end |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
local function parse_gpr(expr) |
||||
local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") |
||||
local tp = map_type[tname or expr] |
||||
if tp then |
||||
local reg = ovreg or tp.reg |
||||
if not reg then |
||||
werror("type `"..(tname or expr).."' needs a register override") |
||||
end |
||||
expr = reg |
||||
end |
||||
local r = match(expr, "^r(1?[0-9])$") |
||||
if r then |
||||
r = tonumber(r) |
||||
if r <= 15 then return r, tp end |
||||
end |
||||
werror("bad register name `"..expr.."'") |
||||
end |
||||
|
||||
local function parse_gpr_pm(expr) |
||||
local pm, expr2 = match(expr, "^([+-]?)(.*)$") |
||||
return parse_gpr(expr2), (pm == "-") |
||||
end |
||||
|
||||
local function parse_reglist(reglist) |
||||
reglist = match(reglist, "^{%s*([^}]*)}$") |
||||
if not reglist then werror("register list expected") end |
||||
local rr = 0 |
||||
for p in gmatch(reglist..",", "%s*([^,]*),") do |
||||
local rbit = 2^parse_gpr(gsub(p, "%s+$", "")) |
||||
if ((rr - (rr % rbit)) / rbit) % 2 ~= 0 then |
||||
werror("duplicate register `"..p.."'") |
||||
end |
||||
rr = rr + rbit |
||||
end |
||||
return rr |
||||
end |
||||
|
||||
local function parse_imm(imm, bits, shift, scale, signed) |
||||
imm = match(imm, "^#(.*)$") |
||||
if not imm then werror("expected immediate operand") end |
||||
local n = tonumber(imm) |
||||
if n then |
||||
if n % 2^scale == 0 then |
||||
n = n / 2^scale |
||||
if signed then |
||||
if n >= 0 then |
||||
if n < 2^(bits-1) then return n*2^shift end |
||||
else |
||||
if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end |
||||
end |
||||
else |
||||
if n >= 0 and n <= 2^bits-1 then return n*2^shift end |
||||
end |
||||
end |
||||
werror("out of range immediate `"..imm.."'") |
||||
else |
||||
waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) |
||||
return 0 |
||||
end |
||||
end |
||||
|
||||
local function parse_imm12(imm) |
||||
local n = tonumber(imm) |
||||
if n then |
||||
local m = n |
||||
for i=0,-15,-1 do |
||||
if m >= 0 and m <= 255 and n % 1 == 0 then return m + (i%16) * 256 end |
||||
local t = m % 4 |
||||
m = (m - t) / 4 + t * 2^30 |
||||
end |
||||
werror("out of range immediate `"..imm.."'") |
||||
else |
||||
waction("IMM12", 0, imm) |
||||
return 0 |
||||
end |
||||
end |
||||
|
||||
local function parse_imm16(imm) |
||||
imm = match(imm, "^#(.*)$") |
||||
if not imm then werror("expected immediate operand") end |
||||
local n = tonumber(imm) |
||||
if n then |
||||
if n >= 0 and n <= 65535 and n % 1 == 0 then |
||||
local t = n % 4096 |
||||
return (n - t) * 16 + t |
||||
end |
||||
werror("out of range immediate `"..imm.."'") |
||||
else |
||||
waction("IMM16", 32*16, imm) |
||||
return 0 |
||||
end |
||||
end |
||||
|
||||
local function parse_imm_load(imm, ext) |
||||
local n = tonumber(imm) |
||||
if n then |
||||
if ext then |
||||
if n >= -255 and n <= 255 then |
||||
local up = 0x00800000 |
||||
if n < 0 then n = -n; up = 0 end |
||||
return (n-(n%16))*16+(n%16) + up |
||||
end |
||||
else |
||||
if n >= -4095 and n <= 4095 then |
||||
if n >= 0 then return n+0x00800000 end |
||||
return -n |
||||
end |
||||
end |
||||
werror("out of range immediate `"..imm.."'") |
||||
else |
||||
waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), imm) |
||||
return 0 |
||||
end |
||||
end |
||||
|
||||
local function parse_shift(shift, gprok) |
||||
if shift == "rrx" then |
||||
return 3 * 32 |
||||
else |
||||
local s, s2 = match(shift, "^(%S+)%s*(.*)$") |
||||
s = map_shift[s] |
||||
if not s then werror("expected shift operand") end |
||||
if sub(s2, 1, 1) == "#" then |
||||
return parse_imm(s2, 5, 7, 0, false) + s * 32 |
||||
else |
||||
if not gprok then werror("expected immediate shift operand") end |
||||
return parse_gpr(s2) * 256 + s * 32 + 16 |
||||
end |
||||
end |
||||
end |
||||
|
||||
local function parse_label(label, def) |
||||
local prefix = sub(label, 1, 2) |
||||
-- =>label (pc label reference) |
||||
if prefix == "=>" then |
||||
return "PC", 0, sub(label, 3) |
||||
end |
||||
-- ->name (global label reference) |
||||
if prefix == "->" then |
||||
return "LG", map_global[sub(label, 3)] |
||||
end |
||||
if def then |
||||
-- [1-9] (local label definition) |
||||
if match(label, "^[1-9]$") then |
||||
return "LG", 10+tonumber(label) |
||||
end |
||||
else |
||||
-- [<>][1-9] (local label reference) |
||||
local dir, lnum = match(label, "^([<>])([1-9])$") |
||||
if dir then -- Fwd: 1-9, Bkwd: 11-19. |
||||
return "LG", lnum + (dir == ">" and 0 or 10) |
||||
end |
||||
-- extern label (extern label reference) |
||||
local extname = match(label, "^extern%s+(%S+)$") |
||||
if extname then |
||||
return "EXT", map_extern[extname] |
||||
end |
||||
end |
||||
werror("bad label `"..label.."'") |
||||
end |
||||
|
||||
local function parse_load(params, nparams, n, op) |
||||
local oplo = op % 256 |
||||
local ext, ldrd = (oplo ~= 0), (oplo == 208) |
||||
local d |
||||
if (ldrd or oplo == 240) then |
||||
d = ((op - (op % 4096)) / 4096) % 16 |
||||
if d % 2 ~= 0 then werror("odd destination register") end |
||||
end |
||||
local pn = params[n] |
||||
local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") |
||||
local p2 = params[n+1] |
||||
if not p1 then |
||||
if not p2 then |
||||
if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then |
||||
local mode, n, s = parse_label(pn, false) |
||||
waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) |
||||
return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) |
||||
end |
||||
local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") |
||||
if reg and tailr ~= "" then |
||||
local d, tp = parse_gpr(reg) |
||||
if tp then |
||||
waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), |
||||
format(tp.ctypefmt, tailr)) |
||||
return op + d * 65536 + 0x01000000 + (ext and 0x00400000 or 0) |
||||
end |
||||
end |
||||
end |
||||
werror("expected address operand") |
||||
end |
||||
if wb == "!" then op = op + 0x00200000 end |
||||
if p2 then |
||||
if wb == "!" then werror("bad use of '!'") end |
||||
local p3 = params[n+2] |
||||
op = op + parse_gpr(p1) * 65536 |
||||
local imm = match(p2, "^#(.*)$") |
||||
if imm then |
||||
local m = parse_imm_load(imm, ext) |
||||
if p3 then werror("too many parameters") end |
||||
op = op + m + (ext and 0x00400000 or 0) |
||||
else |
||||
local m, neg = parse_gpr_pm(p2) |
||||
if ldrd and (m == d or m-1 == d) then werror("register conflict") end |
||||
op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) |
||||
if p3 then op = op + parse_shift(p3) end |
||||
end |
||||
else |
||||
local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") |
||||
op = op + parse_gpr(p1a) * 65536 + 0x01000000 |
||||
if p2 ~= "" then |
||||
local imm = match(p2, "^,%s*#(.*)$") |
||||
if imm then |
||||
local m = parse_imm_load(imm, ext) |
||||
op = op + m + (ext and 0x00400000 or 0) |
||||
else |
||||
local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") |
||||
local m, neg = parse_gpr_pm(p2a) |
||||
if ldrd and (m == d or m-1 == d) then werror("register conflict") end |
||||
op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) |
||||
if p3 ~= "" then |
||||
if ext then werror("too many parameters") end |
||||
op = op + parse_shift(p3) |
||||
end |
||||
end |
||||
else |
||||
if wb == "!" then werror("bad use of '!'") end |
||||
op = op + (ext and 0x00c00000 or 0x00800000) |
||||
end |
||||
end |
||||
return op |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Handle opcodes defined with template strings. |
||||
map_op[".template__"] = function(params, template, nparams) |
||||
if not params then return sub(template, 9) end |
||||
local op = tonumber(sub(template, 1, 8), 16) |
||||
local n = 1 |
||||
|
||||
-- Limit number of section buffer positions used by a single dasm_put(). |
||||
-- A single opcode needs a maximum of 3 positions. |
||||
if secpos+3 > maxsecpos then wflush() end |
||||
local pos = wpos() |
||||
|
||||
-- Process each character. |
||||
for p in gmatch(sub(template, 9), ".") do |
||||
if p == "D" then |
||||
op = op + parse_gpr(params[n]) * 4096; n = n + 1 |
||||
elseif p == "N" then |
||||
op = op + parse_gpr(params[n]) * 65536; n = n + 1 |
||||
elseif p == "S" then |
||||
op = op + parse_gpr(params[n]) * 256; n = n + 1 |
||||
elseif p == "M" then |
||||
op = op + parse_gpr(params[n]); n = n + 1 |
||||
elseif p == "P" then |
||||
local imm = match(params[n], "^#(.*)$") |
||||
if imm then |
||||
op = op + parse_imm12(imm) + 0x02000000 |
||||
else |
||||
op = op + parse_gpr(params[n]) |
||||
end |
||||
n = n + 1 |
||||
elseif p == "p" then |
||||
op = op + parse_shift(params[n], true); n = n + 1 |
||||
elseif p == "L" then |
||||
op = parse_load(params, nparams, n, op) |
||||
elseif p == "B" then |
||||
local mode, n, s = parse_label(params[n], false) |
||||
waction("REL_"..mode, n, s, 1) |
||||
elseif p == "C" then -- blx gpr vs. blx label. |
||||
local p = params[n] |
||||
if match(p, "^([%w_]+):(r1?[0-9])$") or match(p, "^r(1?[0-9])$") then |
||||
op = op + parse_gpr(p) |
||||
else |
||||
if op < 0xe0000000 then werror("unconditional instruction") end |
||||
local mode, n, s = parse_label(p, false) |
||||
waction("REL_"..mode, n, s, 1) |
||||
op = 0xfa000000 |
||||
end |
||||
elseif p == "n" then |
||||
local r, wb = match(params[n], "^([^!]*)(!?)$") |
||||
op = op + parse_gpr(r) * 65536 + (wb == "!" and 0x00200000 or 0) |
||||
n = n + 1 |
||||
elseif p == "R" then |
||||
op = op + parse_reglist(params[n]); n = n + 1 |
||||
elseif p == "W" then |
||||
op = op + parse_imm16(params[n]); n = n + 1 |
||||
elseif p == "v" then |
||||
op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1 |
||||
elseif p == "w" then |
||||
local imm = match(params[n], "^#(.*)$") |
||||
if imm then |
||||
op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1 |
||||
else |
||||
op = op + parse_gpr(params[n]) * 256 + 16 |
||||
end |
||||
elseif p == "X" then |
||||
op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 |
||||
elseif p == "K" then |
||||
local imm = tonumber(match(params[n], "^#(.*)$")); n = n + 1 |
||||
if not imm or imm % 1 ~= 0 or imm < 0 or imm > 0xffff then |
||||
werror("bad immediate operand") |
||||
end |
||||
local t = imm % 16 |
||||
op = op + (imm - t) * 16 + t |
||||
elseif p == "T" then |
||||
op = op + parse_imm(params[n], 24, 0, 0, false); n = n + 1 |
||||
elseif p == "s" then |
||||
-- Ignored. |
||||
else |
||||
assert(false) |
||||
end |
||||
end |
||||
wputpos(pos, op) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pseudo-opcode to mark the position where the action list is to be emitted. |
||||
map_op[".actionlist_1"] = function(params) |
||||
if not params then return "cvar" end |
||||
local name = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeactions(out, name) end) |
||||
end |
||||
|
||||
-- Pseudo-opcode to mark the position where the global enum is to be emitted. |
||||
map_op[".globals_1"] = function(params) |
||||
if not params then return "prefix" end |
||||
local prefix = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeglobals(out, prefix) end) |
||||
end |
||||
|
||||
-- Pseudo-opcode to mark the position where the global names are to be emitted. |
||||
map_op[".globalnames_1"] = function(params) |
||||
if not params then return "cvar" end |
||||
local name = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeglobalnames(out, name) end) |
||||
end |
||||
|
||||
-- Pseudo-opcode to mark the position where the extern names are to be emitted. |
||||
map_op[".externnames_1"] = function(params) |
||||
if not params then return "cvar" end |
||||
local name = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeexternnames(out, name) end) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Label pseudo-opcode (converted from trailing colon form). |
||||
map_op[".label_1"] = function(params) |
||||
if not params then return "[1-9] | ->global | =>pcexpr" end |
||||
if secpos+1 > maxsecpos then wflush() end |
||||
local mode, n, s = parse_label(params[1], true) |
||||
if mode == "EXT" then werror("bad label definition") end |
||||
waction("LABEL_"..mode, n, s, 1) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pseudo-opcodes for data storage. |
||||
map_op[".long_*"] = function(params) |
||||
if not params then return "imm..." end |
||||
for _,p in ipairs(params) do |
||||
local n = tonumber(p) |
||||
if not n then werror("bad immediate `"..p.."'") end |
||||
if n < 0 then n = n + 2^32 end |
||||
wputw(n) |
||||
if secpos+2 > maxsecpos then wflush() end |
||||
end |
||||
end |
||||
|
||||
-- Alignment pseudo-opcode. |
||||
map_op[".align_1"] = function(params) |
||||
if not params then return "numpow2" end |
||||
if secpos+1 > maxsecpos then wflush() end |
||||
local align = tonumber(params[1]) |
||||
if align then |
||||
local x = align |
||||
-- Must be a power of 2 in the range (2 ... 256). |
||||
for i=1,8 do |
||||
x = x / 2 |
||||
if x == 1 then |
||||
waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. |
||||
return |
||||
end |
||||
end |
||||
end |
||||
werror("bad alignment") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pseudo-opcode for (primitive) type definitions (map to C types). |
||||
map_op[".type_3"] = function(params, nparams) |
||||
if not params then |
||||
return nparams == 2 and "name, ctype" or "name, ctype, reg" |
||||
end |
||||
local name, ctype, reg = params[1], params[2], params[3] |
||||
if not match(name, "^[%a_][%w_]*$") then |
||||
werror("bad type name `"..name.."'") |
||||
end |
||||
local tp = map_type[name] |
||||
if tp then |
||||
werror("duplicate type `"..name.."'") |
||||
end |
||||
-- Add #type to defines. A bit unclean to put it in map_archdef. |
||||
map_archdef["#"..name] = "sizeof("..ctype..")" |
||||
-- Add new type and emit shortcut define. |
||||
local num = ctypenum + 1 |
||||
map_type[name] = { |
||||
ctype = ctype, |
||||
ctypefmt = format("Dt%X(%%s)", num), |
||||
reg = reg, |
||||
} |
||||
wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) |
||||
ctypenum = num |
||||
end |
||||
map_op[".type_2"] = map_op[".type_3"] |
||||
|
||||
-- Dump type definitions. |
||||
local function dumptypes(out, lvl) |
||||
local t = {} |
||||
for name in pairs(map_type) do t[#t+1] = name end |
||||
sort(t) |
||||
out:write("Type definitions:\n") |
||||
for _,name in ipairs(t) do |
||||
local tp = map_type[name] |
||||
local reg = tp.reg or "" |
||||
out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Set the current section. |
||||
function _M.section(num) |
||||
waction("SECTION", num) |
||||
wflush(true) -- SECTION is a terminal action. |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Dump architecture description. |
||||
function _M.dumparch(out) |
||||
out:write(format("DynASM %s version %s, released %s\n\n", |
||||
_info.arch, _info.version, _info.release)) |
||||
dumpactions(out) |
||||
end |
||||
|
||||
-- Dump all user defined elements. |
||||
function _M.dumpdef(out, lvl) |
||||
dumptypes(out, lvl) |
||||
dumpglobals(out, lvl) |
||||
dumpexterns(out, lvl) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pass callbacks from/to the DynASM core. |
||||
function _M.passcb(wl, we, wf, ww) |
||||
wline, werror, wfatal, wwarn = wl, we, wf, ww |
||||
return wflush |
||||
end |
||||
|
||||
-- Setup the arch-specific module. |
||||
function _M.setup(arch, opt) |
||||
g_arch, g_opt = arch, opt |
||||
end |
||||
|
||||
-- Merge the core maps and the arch-specific maps. |
||||
function _M.mergemaps(map_coreop, map_def) |
||||
setmetatable(map_op, { __index = function(t, k) |
||||
local v = map_coreop[k] |
||||
if v then return v end |
||||
local cc = sub(k, -4, -3) |
||||
local cv = map_cond[cc] |
||||
if cv then |
||||
local v = rawget(t, sub(k, 1, -5)..sub(k, -2)) |
||||
if type(v) == "string" then return format("%x%s", cv, sub(v, 2)) end |
||||
end |
||||
end }) |
||||
setmetatable(map_def, { __index = map_archdef }) |
||||
return map_op, map_def |
||||
end |
||||
|
||||
return _M |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
@ -1,415 +0,0 @@ |
||||
/*
|
||||
** DynASM MIPS encoding engine. |
||||
** Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
** Released under the MIT license. See dynasm.lua for full copyright notice. |
||||
*/ |
||||
|
||||
#include <stddef.h> |
||||
#include <stdarg.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#define DASM_ARCH "mips" |
||||
|
||||
#ifndef DASM_EXTERN |
||||
#define DASM_EXTERN(a,b,c,d) 0 |
||||
#endif |
||||
|
||||
/* Action definitions. */ |
||||
enum { |
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, |
||||
/* The following actions need a buffer position. */ |
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, |
||||
/* The following actions also have an argument. */ |
||||
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, |
||||
DASM__MAX |
||||
}; |
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */ |
||||
#define DASM_MAXSECPOS 25 |
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */ |
||||
#define DASM_S_OK 0x00000000 |
||||
#define DASM_S_NOMEM 0x01000000 |
||||
#define DASM_S_PHASE 0x02000000 |
||||
#define DASM_S_MATCH_SEC 0x03000000 |
||||
#define DASM_S_RANGE_I 0x11000000 |
||||
#define DASM_S_RANGE_SEC 0x12000000 |
||||
#define DASM_S_RANGE_LG 0x13000000 |
||||
#define DASM_S_RANGE_PC 0x14000000 |
||||
#define DASM_S_RANGE_REL 0x15000000 |
||||
#define DASM_S_UNDEF_LG 0x21000000 |
||||
#define DASM_S_UNDEF_PC 0x22000000 |
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */ |
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) |
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000) |
||||
#define DASM_SEC2POS(sec) ((sec)<<24) |
||||
#define DASM_POS2SEC(pos) ((pos)>>24) |
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) |
||||
|
||||
/* Action list type. */ |
||||
typedef const unsigned int *dasm_ActList; |
||||
|
||||
/* Per-section structure. */ |
||||
typedef struct dasm_Section { |
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */ |
||||
int *buf; /* True buffer pointer. */ |
||||
size_t bsize; /* Buffer size in bytes. */ |
||||
int pos; /* Biased buffer position. */ |
||||
int epos; /* End of biased buffer position - max single put. */ |
||||
int ofs; /* Byte offset into section. */ |
||||
} dasm_Section; |
||||
|
||||
/* Core structure holding the DynASM encoding state. */ |
||||
struct dasm_State { |
||||
size_t psize; /* Allocated size of this structure. */ |
||||
dasm_ActList actionlist; /* Current actionlist pointer. */ |
||||
int *lglabels; /* Local/global chain/pos ptrs. */ |
||||
size_t lgsize; |
||||
int *pclabels; /* PC label chains/pos ptrs. */ |
||||
size_t pcsize; |
||||
void **globals; /* Array of globals (bias -10). */ |
||||
dasm_Section *section; /* Pointer to active section. */ |
||||
size_t codesize; /* Total size of all code sections. */ |
||||
int maxsection; /* 0 <= sectionidx < maxsection. */ |
||||
int status; /* Status code. */ |
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */ |
||||
}; |
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */ |
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) |
||||
|
||||
|
||||
/* Initialize DynASM state. */ |
||||
void dasm_init(Dst_DECL, int maxsection) |
||||
{ |
||||
dasm_State *D; |
||||
size_t psz = 0; |
||||
int i; |
||||
Dst_REF = NULL; |
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); |
||||
D = Dst_REF; |
||||
D->psize = psz; |
||||
D->lglabels = NULL; |
||||
D->lgsize = 0; |
||||
D->pclabels = NULL; |
||||
D->pcsize = 0; |
||||
D->globals = NULL; |
||||
D->maxsection = maxsection; |
||||
for (i = 0; i < maxsection; i++) { |
||||
D->sections[i].buf = NULL; /* Need this for pass3. */ |
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); |
||||
D->sections[i].bsize = 0; |
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ |
||||
} |
||||
} |
||||
|
||||
/* Free DynASM state. */ |
||||
void dasm_free(Dst_DECL) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
for (i = 0; i < D->maxsection; i++) |
||||
if (D->sections[i].buf) |
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); |
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); |
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); |
||||
DASM_M_FREE(Dst, D, D->psize); |
||||
} |
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */ |
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */ |
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); |
||||
} |
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */ |
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
size_t osz = D->pcsize; |
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); |
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); |
||||
} |
||||
|
||||
/* Setup encoder. */ |
||||
void dasm_setup(Dst_DECL, const void *actionlist) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
D->actionlist = (dasm_ActList)actionlist; |
||||
D->status = DASM_S_OK; |
||||
D->section = &D->sections[0]; |
||||
memset((void *)D->lglabels, 0, D->lgsize); |
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); |
||||
for (i = 0; i < D->maxsection; i++) { |
||||
D->sections[i].pos = DASM_SEC2POS(i); |
||||
D->sections[i].ofs = 0; |
||||
} |
||||
} |
||||
|
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) |
||||
#define CKPL(kind, st) \ |
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#define CKPL(kind, st) ((void)0) |
||||
#endif |
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ |
||||
void dasm_put(Dst_DECL, int start, ...) |
||||
{ |
||||
va_list ap; |
||||
dasm_State *D = Dst_REF; |
||||
dasm_ActList p = D->actionlist + start; |
||||
dasm_Section *sec = D->section; |
||||
int pos = sec->pos, ofs = sec->ofs; |
||||
int *b; |
||||
|
||||
if (pos >= sec->epos) { |
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize, |
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); |
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos); |
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); |
||||
} |
||||
|
||||
b = sec->rbuf; |
||||
b[pos++] = start; |
||||
|
||||
va_start(ap, start); |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16) - 0xff00; |
||||
if (action >= DASM__MAX) { |
||||
ofs += 4; |
||||
} else { |
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; |
||||
switch (action) { |
||||
case DASM_STOP: goto stop; |
||||
case DASM_SECTION: |
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); |
||||
D->section = &D->sections[n]; goto stop; |
||||
case DASM_ESC: p++; ofs += 4; break; |
||||
case DASM_REL_EXT: break; |
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; |
||||
case DASM_REL_LG: |
||||
n = (ins & 2047) - 10; pl = D->lglabels + n; |
||||
if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ |
||||
pl += 10; n = *pl; |
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ |
||||
goto linkrel; |
||||
case DASM_REL_PC: |
||||
pl = D->pclabels + n; CKPL(pc, PC); |
||||
putrel: |
||||
n = *pl; |
||||
if (n < 0) { /* Label exists. Get label pos and store it. */ |
||||
b[pos] = -n; |
||||
} else { |
||||
linkrel: |
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */ |
||||
*pl = pos; |
||||
} |
||||
pos++; |
||||
break; |
||||
case DASM_LABEL_LG: |
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; |
||||
case DASM_LABEL_PC: |
||||
pl = D->pclabels + n; CKPL(pc, PC); |
||||
putlabel: |
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; |
||||
} |
||||
*pl = -pos; /* Label exists now. */ |
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */ |
||||
break; |
||||
case DASM_IMM: |
||||
#ifdef DASM_CHECKS |
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); |
||||
#endif |
||||
n >>= ((ins>>10)&31); |
||||
#ifdef DASM_CHECKS |
||||
if (ins & 0x8000) |
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); |
||||
else |
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I); |
||||
#endif |
||||
b[pos++] = n; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
stop: |
||||
va_end(ap); |
||||
sec->pos = pos; |
||||
sec->ofs = ofs; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */ |
||||
int dasm_link(Dst_DECL, size_t *szp) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int secnum; |
||||
int ofs = 0; |
||||
|
||||
#ifdef DASM_CHECKS |
||||
*szp = 0; |
||||
if (D->status != DASM_S_OK) return D->status; |
||||
{ |
||||
int pc; |
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) |
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; |
||||
} |
||||
#endif |
||||
|
||||
{ /* Handle globals not defined in this translation unit. */ |
||||
int idx; |
||||
for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { |
||||
int n = D->lglabels[idx]; |
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } |
||||
} |
||||
} |
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->rbuf; |
||||
int pos = DASM_SEC2POS(secnum); |
||||
int lastpos = sec->pos; |
||||
|
||||
while (pos != lastpos) { |
||||
dasm_ActList p = D->actionlist + b[pos++]; |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16) - 0xff00; |
||||
switch (action) { |
||||
case DASM_STOP: case DASM_SECTION: goto stop; |
||||
case DASM_ESC: p++; break; |
||||
case DASM_REL_EXT: break; |
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; |
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break; |
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; |
||||
case DASM_IMM: pos++; break; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
ofs += sec->ofs; /* Next section starts right after current section. */ |
||||
} |
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */ |
||||
*szp = ofs; |
||||
return DASM_S_OK; |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#endif |
||||
|
||||
/* Pass 3: Encode sections. */ |
||||
int dasm_encode(Dst_DECL, void *buffer) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
char *base = (char *)buffer; |
||||
unsigned int *cp = (unsigned int *)buffer; |
||||
int secnum; |
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->buf; |
||||
int *endb = sec->rbuf + sec->pos; |
||||
|
||||
while (b != endb) { |
||||
dasm_ActList p = D->actionlist + *b++; |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16) - 0xff00; |
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; |
||||
switch (action) { |
||||
case DASM_STOP: case DASM_SECTION: goto stop; |
||||
case DASM_ESC: *cp++ = *p++; break; |
||||
case DASM_REL_EXT: |
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); |
||||
goto patchrel; |
||||
case DASM_ALIGN: |
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; |
||||
break; |
||||
case DASM_REL_LG: |
||||
CK(n >= 0, UNDEF_LG); |
||||
case DASM_REL_PC: |
||||
CK(n >= 0, UNDEF_PC); |
||||
n = *DASM_POS2PTR(D, n); |
||||
if (ins & 2048) |
||||
n = n - (int)((char *)cp - base); |
||||
else |
||||
n = (n + (int)base) & 0x0fffffff; |
||||
patchrel: |
||||
CK((n & 3) == 0 && |
||||
((n + ((ins & 2048) ? 0x00020000 : 0)) >> |
||||
((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); |
||||
cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); |
||||
break; |
||||
case DASM_LABEL_LG: |
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); |
||||
break; |
||||
case DASM_LABEL_PC: break; |
||||
case DASM_IMM: |
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); |
||||
break; |
||||
default: *cp++ = ins; break; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
} |
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */ |
||||
return DASM_S_PHASE; |
||||
return DASM_S_OK; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Get PC label offset. */ |
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (pc*sizeof(int) < D->pcsize) { |
||||
int pos = D->pclabels[pc]; |
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos); |
||||
if (pos > 0) return -1; /* Undefined. */ |
||||
} |
||||
return -2; /* Unused or out of range. */ |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
/* Optional sanity checker to call between isolated encoding steps. */ |
||||
int dasm_checkstep(Dst_DECL, int secmatch) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (D->status == DASM_S_OK) { |
||||
int i; |
||||
for (i = 1; i <= 9; i++) { |
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } |
||||
D->lglabels[i] = 0; |
||||
} |
||||
} |
||||
if (D->status == DASM_S_OK && secmatch >= 0 && |
||||
D->section != &D->sections[secmatch]) |
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections); |
||||
return D->status; |
||||
} |
||||
#endif |
||||
|
@ -1,959 +0,0 @@ |
||||
------------------------------------------------------------------------------ |
||||
-- DynASM MIPS module. |
||||
-- |
||||
-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
-- See dynasm.lua for full copyright notice. |
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Module information: |
||||
local _info = { |
||||
arch = "mips", |
||||
description = "DynASM MIPS module", |
||||
version = "1.3.0", |
||||
vernum = 10300, |
||||
release = "2012-01-23", |
||||
author = "Mike Pall", |
||||
license = "MIT", |
||||
} |
||||
|
||||
-- Exported glue functions for the arch-specific module. |
||||
local _M = { _info = _info } |
||||
|
||||
-- Cache library functions. |
||||
local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs |
||||
local assert, setmetatable = assert, setmetatable |
||||
local _s = string |
||||
local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char |
||||
local match, gmatch = _s.match, _s.gmatch |
||||
local concat, sort = table.concat, table.sort |
||||
|
||||
-- Inherited tables and callbacks. |
||||
local g_opt, g_arch |
||||
local wline, werror, wfatal, wwarn |
||||
|
||||
-- Action name list. |
||||
-- CHECK: Keep this in sync with the C code! |
||||
local action_names = { |
||||
"STOP", "SECTION", "ESC", "REL_EXT", |
||||
"ALIGN", "REL_LG", "LABEL_LG", |
||||
"REL_PC", "LABEL_PC", "IMM", |
||||
} |
||||
|
||||
-- Maximum number of section buffer positions for dasm_put(). |
||||
-- CHECK: Keep this in sync with the C code! |
||||
local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. |
||||
|
||||
-- Action name -> action number. |
||||
local map_action = {} |
||||
for n,name in ipairs(action_names) do |
||||
map_action[name] = n-1 |
||||
end |
||||
|
||||
-- Action list buffer. |
||||
local actlist = {} |
||||
|
||||
-- Argument list for next dasm_put(). Start with offset 0 into action list. |
||||
local actargs = { 0 } |
||||
|
||||
-- Current number of section buffer positions for dasm_put(). |
||||
local secpos = 1 |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Return 8 digit hex number. |
||||
local function tohex(x) |
||||
return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. |
||||
end |
||||
|
||||
-- Dump action names and numbers. |
||||
local function dumpactions(out) |
||||
out:write("DynASM encoding engine action codes:\n") |
||||
for n,name in ipairs(action_names) do |
||||
local num = map_action[name] |
||||
out:write(format(" %-10s %02X %d\n", name, num, num)) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
-- Write action list buffer as a huge static C array. |
||||
local function writeactions(out, name) |
||||
local nn = #actlist |
||||
if nn == 0 then nn = 1; actlist[0] = map_action.STOP end |
||||
out:write("static const unsigned int ", name, "[", nn, "] = {\n") |
||||
for i = 1,nn-1 do |
||||
assert(out:write("0x", tohex(actlist[i]), ",\n")) |
||||
end |
||||
assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Add word to action list. |
||||
local function wputxw(n) |
||||
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") |
||||
actlist[#actlist+1] = n |
||||
end |
||||
|
||||
-- Add action to list with optional arg. Advance buffer pos, too. |
||||
local function waction(action, val, a, num) |
||||
local w = assert(map_action[action], "bad action name `"..action.."'") |
||||
wputxw(0xff000000 + w * 0x10000 + (val or 0)) |
||||
if a then actargs[#actargs+1] = a end |
||||
if a or num then secpos = secpos + (num or 1) end |
||||
end |
||||
|
||||
-- Flush action list (intervening C code or buffer pos overflow). |
||||
local function wflush(term) |
||||
if #actlist == actargs[1] then return end -- Nothing to flush. |
||||
if not term then waction("STOP") end -- Terminate action list. |
||||
wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) |
||||
actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). |
||||
secpos = 1 -- The actionlist offset occupies a buffer position, too. |
||||
end |
||||
|
||||
-- Put escaped word. |
||||
local function wputw(n) |
||||
if n >= 0xff000000 then waction("ESC") end |
||||
wputxw(n) |
||||
end |
||||
|
||||
-- Reserve position for word. |
||||
local function wpos() |
||||
local pos = #actlist+1 |
||||
actlist[pos] = "" |
||||
return pos |
||||
end |
||||
|
||||
-- Store word to reserved position. |
||||
local function wputpos(pos, n) |
||||
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") |
||||
actlist[pos] = n |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Global label name -> global label number. With auto assignment on 1st use. |
||||
local next_global = 20 |
||||
local map_global = setmetatable({}, { __index = function(t, name) |
||||
if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end |
||||
local n = next_global |
||||
if n > 2047 then werror("too many global labels") end |
||||
next_global = n + 1 |
||||
t[name] = n |
||||
return n |
||||
end}) |
||||
|
||||
-- Dump global labels. |
||||
local function dumpglobals(out, lvl) |
||||
local t = {} |
||||
for name, n in pairs(map_global) do t[n] = name end |
||||
out:write("Global labels:\n") |
||||
for i=20,next_global-1 do |
||||
out:write(format(" %s\n", t[i])) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
-- Write global label enum. |
||||
local function writeglobals(out, prefix) |
||||
local t = {} |
||||
for name, n in pairs(map_global) do t[n] = name end |
||||
out:write("enum {\n") |
||||
for i=20,next_global-1 do |
||||
out:write(" ", prefix, t[i], ",\n") |
||||
end |
||||
out:write(" ", prefix, "_MAX\n};\n") |
||||
end |
||||
|
||||
-- Write global label names. |
||||
local function writeglobalnames(out, name) |
||||
local t = {} |
||||
for name, n in pairs(map_global) do t[n] = name end |
||||
out:write("static const char *const ", name, "[] = {\n") |
||||
for i=20,next_global-1 do |
||||
out:write(" \"", t[i], "\",\n") |
||||
end |
||||
out:write(" (const char *)0\n};\n") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Extern label name -> extern label number. With auto assignment on 1st use. |
||||
local next_extern = 0 |
||||
local map_extern_ = {} |
||||
local map_extern = setmetatable({}, { __index = function(t, name) |
||||
-- No restrictions on the name for now. |
||||
local n = next_extern |
||||
if n > 2047 then werror("too many extern labels") end |
||||
next_extern = n + 1 |
||||
t[name] = n |
||||
map_extern_[n] = name |
||||
return n |
||||
end}) |
||||
|
||||
-- Dump extern labels. |
||||
local function dumpexterns(out, lvl) |
||||
out:write("Extern labels:\n") |
||||
for i=0,next_extern-1 do |
||||
out:write(format(" %s\n", map_extern_[i])) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
-- Write extern label names. |
||||
local function writeexternnames(out, name) |
||||
out:write("static const char *const ", name, "[] = {\n") |
||||
for i=0,next_extern-1 do |
||||
out:write(" \"", map_extern_[i], "\",\n") |
||||
end |
||||
out:write(" (const char *)0\n};\n") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Arch-specific maps. |
||||
local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. |
||||
|
||||
local map_type = {} -- Type name -> { ctype, reg } |
||||
local ctypenum = 0 -- Type number (for Dt... macros). |
||||
|
||||
-- Reverse defines for registers. |
||||
function _M.revdef(s) |
||||
if s == "r29" then return "sp" |
||||
elseif s == "r31" then return "ra" end |
||||
return s |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Template strings for MIPS instructions. |
||||
local map_op = { |
||||
-- First-level opcodes. |
||||
j_1 = "08000000J", |
||||
jal_1 = "0c000000J", |
||||
b_1 = "10000000B", |
||||
beqz_2 = "10000000SB", |
||||
beq_3 = "10000000STB", |
||||
bnez_2 = "14000000SB", |
||||
bne_3 = "14000000STB", |
||||
blez_2 = "18000000SB", |
||||
bgtz_2 = "1c000000SB", |
||||
addi_3 = "20000000TSI", |
||||
li_2 = "24000000TI", |
||||
addiu_3 = "24000000TSI", |
||||
slti_3 = "28000000TSI", |
||||
sltiu_3 = "2c000000TSI", |
||||
andi_3 = "30000000TSU", |
||||
lu_2 = "34000000TU", |
||||
ori_3 = "34000000TSU", |
||||
xori_3 = "38000000TSU", |
||||
lui_2 = "3c000000TU", |
||||
beqzl_2 = "50000000SB", |
||||
beql_3 = "50000000STB", |
||||
bnezl_2 = "54000000SB", |
||||
bnel_3 = "54000000STB", |
||||
blezl_2 = "58000000SB", |
||||
bgtzl_2 = "5c000000SB", |
||||
lb_2 = "80000000TO", |
||||
lh_2 = "84000000TO", |
||||
lwl_2 = "88000000TO", |
||||
lw_2 = "8c000000TO", |
||||
lbu_2 = "90000000TO", |
||||
lhu_2 = "94000000TO", |
||||
lwr_2 = "98000000TO", |
||||
sb_2 = "a0000000TO", |
||||
sh_2 = "a4000000TO", |
||||
swl_2 = "a8000000TO", |
||||
sw_2 = "ac000000TO", |
||||
swr_2 = "b8000000TO", |
||||
cache_2 = "bc000000NO", |
||||
ll_2 = "c0000000TO", |
||||
lwc1_2 = "c4000000HO", |
||||
pref_2 = "cc000000NO", |
||||
ldc1_2 = "d4000000HO", |
||||
sc_2 = "e0000000TO", |
||||
swc1_2 = "e4000000HO", |
||||
sdc1_2 = "f4000000HO", |
||||
|
||||
-- Opcode SPECIAL. |
||||
nop_0 = "00000000", |
||||
sll_3 = "00000000DTA", |
||||
movf_2 = "00000001DS", |
||||
movf_3 = "00000001DSC", |
||||
movt_2 = "00010001DS", |
||||
movt_3 = "00010001DSC", |
||||
srl_3 = "00000002DTA", |
||||
rotr_3 = "00200002DTA", |
||||
sra_3 = "00000003DTA", |
||||
sllv_3 = "00000004DTS", |
||||
srlv_3 = "00000006DTS", |
||||
rotrv_3 = "00000046DTS", |
||||
srav_3 = "00000007DTS", |
||||
jr_1 = "00000008S", |
||||
jalr_1 = "0000f809S", |
||||
jalr_2 = "00000009DS", |
||||
movz_3 = "0000000aDST", |
||||
movn_3 = "0000000bDST", |
||||
syscall_0 = "0000000c", |
||||
syscall_1 = "0000000cY", |
||||
break_0 = "0000000d", |
||||
break_1 = "0000000dY", |
||||
sync_0 = "0000000f", |
||||
mfhi_1 = "00000010D", |
||||
mthi_1 = "00000011S", |
||||
mflo_1 = "00000012D", |
||||
mtlo_1 = "00000013S", |
||||
mult_2 = "00000018ST", |
||||
multu_2 = "00000019ST", |
||||
div_2 = "0000001aST", |
||||
divu_2 = "0000001bST", |
||||
add_3 = "00000020DST", |
||||
move_2 = "00000021DS", |
||||
addu_3 = "00000021DST", |
||||
sub_3 = "00000022DST", |
||||
negu_2 = "00000023DT", |
||||
subu_3 = "00000023DST", |
||||
and_3 = "00000024DST", |
||||
or_3 = "00000025DST", |
||||
xor_3 = "00000026DST", |
||||
not_2 = "00000027DS", |
||||
nor_3 = "00000027DST", |
||||
slt_3 = "0000002aDST", |
||||
sltu_3 = "0000002bDST", |
||||
tge_2 = "00000030ST", |
||||
tge_3 = "00000030STZ", |
||||
tgeu_2 = "00000031ST", |
||||
tgeu_3 = "00000031STZ", |
||||
tlt_2 = "00000032ST", |
||||
tlt_3 = "00000032STZ", |
||||
tltu_2 = "00000033ST", |
||||
tltu_3 = "00000033STZ", |
||||
teq_2 = "00000034ST", |
||||
teq_3 = "00000034STZ", |
||||
tne_2 = "00000036ST", |
||||
tne_3 = "00000036STZ", |
||||
|
||||
-- Opcode REGIMM. |
||||
bltz_2 = "04000000SB", |
||||
bgez_2 = "04010000SB", |
||||
bltzl_2 = "04020000SB", |
||||
bgezl_2 = "04030000SB", |
||||
tgei_2 = "04080000SI", |
||||
tgeiu_2 = "04090000SI", |
||||
tlti_2 = "040a0000SI", |
||||
tltiu_2 = "040b0000SI", |
||||
teqi_2 = "040c0000SI", |
||||
tnei_2 = "040e0000SI", |
||||
bltzal_2 = "04100000SB", |
||||
bal_1 = "04110000B", |
||||
bgezal_2 = "04110000SB", |
||||
bltzall_2 = "04120000SB", |
||||
bgezall_2 = "04130000SB", |
||||
synci_1 = "041f0000O", |
||||
|
||||
-- Opcode SPECIAL2. |
||||
madd_2 = "70000000ST", |
||||
maddu_2 = "70000001ST", |
||||
mul_3 = "70000002DST", |
||||
msub_2 = "70000004ST", |
||||
msubu_2 = "70000005ST", |
||||
clz_2 = "70000020DS=", |
||||
clo_2 = "70000021DS=", |
||||
sdbbp_0 = "7000003f", |
||||
sdbbp_1 = "7000003fY", |
||||
|
||||
-- Opcode SPECIAL3. |
||||
ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 |
||||
ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 |
||||
wsbh_2 = "7c0000a0DT", |
||||
seb_2 = "7c000420DT", |
||||
seh_2 = "7c000620DT", |
||||
rdhwr_2 = "7c00003bTD", |
||||
|
||||
-- Opcode COP0. |
||||
mfc0_2 = "40000000TD", |
||||
mfc0_3 = "40000000TDW", |
||||
mtc0_2 = "40800000TD", |
||||
mtc0_3 = "40800000TDW", |
||||
rdpgpr_2 = "41400000DT", |
||||
di_0 = "41606000", |
||||
di_1 = "41606000T", |
||||
ei_0 = "41606020", |
||||
ei_1 = "41606020T", |
||||
wrpgpr_2 = "41c00000DT", |
||||
tlbr_0 = "42000001", |
||||
tlbwi_0 = "42000002", |
||||
tlbwr_0 = "42000006", |
||||
tlbp_0 = "42000008", |
||||
eret_0 = "42000018", |
||||
deret_0 = "4200001f", |
||||
wait_0 = "42000020", |
||||
|
||||
-- Opcode COP1. |
||||
mfc1_2 = "44000000TG", |
||||
cfc1_2 = "44400000TG", |
||||
mfhc1_2 = "44600000TG", |
||||
mtc1_2 = "44800000TG", |
||||
ctc1_2 = "44c00000TG", |
||||
mthc1_2 = "44e00000TG", |
||||
|
||||
bc1f_1 = "45000000B", |
||||
bc1f_2 = "45000000CB", |
||||
bc1t_1 = "45010000B", |
||||
bc1t_2 = "45010000CB", |
||||
bc1fl_1 = "45020000B", |
||||
bc1fl_2 = "45020000CB", |
||||
bc1tl_1 = "45030000B", |
||||
bc1tl_2 = "45030000CB", |
||||
|
||||
["add.s_3"] = "46000000FGH", |
||||
["sub.s_3"] = "46000001FGH", |
||||
["mul.s_3"] = "46000002FGH", |
||||
["div.s_3"] = "46000003FGH", |
||||
["sqrt.s_2"] = "46000004FG", |
||||
["abs.s_2"] = "46000005FG", |
||||
["mov.s_2"] = "46000006FG", |
||||
["neg.s_2"] = "46000007FG", |
||||
["round.l.s_2"] = "46000008FG", |
||||
["trunc.l.s_2"] = "46000009FG", |
||||
["ceil.l.s_2"] = "4600000aFG", |
||||
["floor.l.s_2"] = "4600000bFG", |
||||
["round.w.s_2"] = "4600000cFG", |
||||
["trunc.w.s_2"] = "4600000dFG", |
||||
["ceil.w.s_2"] = "4600000eFG", |
||||
["floor.w.s_2"] = "4600000fFG", |
||||
["movf.s_2"] = "46000011FG", |
||||
["movf.s_3"] = "46000011FGC", |
||||
["movt.s_2"] = "46010011FG", |
||||
["movt.s_3"] = "46010011FGC", |
||||
["movz.s_3"] = "46000012FGT", |
||||
["movn.s_3"] = "46000013FGT", |
||||
["recip.s_2"] = "46000015FG", |
||||
["rsqrt.s_2"] = "46000016FG", |
||||
["cvt.d.s_2"] = "46000021FG", |
||||
["cvt.w.s_2"] = "46000024FG", |
||||
["cvt.l.s_2"] = "46000025FG", |
||||
["cvt.ps.s_3"] = "46000026FGH", |
||||
["c.f.s_2"] = "46000030GH", |
||||
["c.f.s_3"] = "46000030VGH", |
||||
["c.un.s_2"] = "46000031GH", |
||||
["c.un.s_3"] = "46000031VGH", |
||||
["c.eq.s_2"] = "46000032GH", |
||||
["c.eq.s_3"] = "46000032VGH", |
||||
["c.ueq.s_2"] = "46000033GH", |
||||
["c.ueq.s_3"] = "46000033VGH", |
||||
["c.olt.s_2"] = "46000034GH", |
||||
["c.olt.s_3"] = "46000034VGH", |
||||
["c.ult.s_2"] = "46000035GH", |
||||
["c.ult.s_3"] = "46000035VGH", |
||||
["c.ole.s_2"] = "46000036GH", |
||||
["c.ole.s_3"] = "46000036VGH", |
||||
["c.ule.s_2"] = "46000037GH", |
||||
["c.ule.s_3"] = "46000037VGH", |
||||
["c.sf.s_2"] = "46000038GH", |
||||
["c.sf.s_3"] = "46000038VGH", |
||||
["c.ngle.s_2"] = "46000039GH", |
||||
["c.ngle.s_3"] = "46000039VGH", |
||||
["c.seq.s_2"] = "4600003aGH", |
||||
["c.seq.s_3"] = "4600003aVGH", |
||||
["c.ngl.s_2"] = "4600003bGH", |
||||
["c.ngl.s_3"] = "4600003bVGH", |
||||
["c.lt.s_2"] = "4600003cGH", |
||||
["c.lt.s_3"] = "4600003cVGH", |
||||
["c.nge.s_2"] = "4600003dGH", |
||||
["c.nge.s_3"] = "4600003dVGH", |
||||
["c.le.s_2"] = "4600003eGH", |
||||
["c.le.s_3"] = "4600003eVGH", |
||||
["c.ngt.s_2"] = "4600003fGH", |
||||
["c.ngt.s_3"] = "4600003fVGH", |
||||
|
||||
["add.d_3"] = "46200000FGH", |
||||
["sub.d_3"] = "46200001FGH", |
||||
["mul.d_3"] = "46200002FGH", |
||||
["div.d_3"] = "46200003FGH", |
||||
["sqrt.d_2"] = "46200004FG", |
||||
["abs.d_2"] = "46200005FG", |
||||
["mov.d_2"] = "46200006FG", |
||||
["neg.d_2"] = "46200007FG", |
||||
["round.l.d_2"] = "46200008FG", |
||||
["trunc.l.d_2"] = "46200009FG", |
||||
["ceil.l.d_2"] = "4620000aFG", |
||||
["floor.l.d_2"] = "4620000bFG", |
||||
["round.w.d_2"] = "4620000cFG", |
||||
["trunc.w.d_2"] = "4620000dFG", |
||||
["ceil.w.d_2"] = "4620000eFG", |
||||
["floor.w.d_2"] = "4620000fFG", |
||||
["movf.d_2"] = "46200011FG", |
||||
["movf.d_3"] = "46200011FGC", |
||||
["movt.d_2"] = "46210011FG", |
||||
["movt.d_3"] = "46210011FGC", |
||||
["movz.d_3"] = "46200012FGT", |
||||
["movn.d_3"] = "46200013FGT", |
||||
["recip.d_2"] = "46200015FG", |
||||
["rsqrt.d_2"] = "46200016FG", |
||||
["cvt.s.d_2"] = "46200020FG", |
||||
["cvt.w.d_2"] = "46200024FG", |
||||
["cvt.l.d_2"] = "46200025FG", |
||||
["c.f.d_2"] = "46200030GH", |
||||
["c.f.d_3"] = "46200030VGH", |
||||
["c.un.d_2"] = "46200031GH", |
||||
["c.un.d_3"] = "46200031VGH", |
||||
["c.eq.d_2"] = "46200032GH", |
||||
["c.eq.d_3"] = "46200032VGH", |
||||
["c.ueq.d_2"] = "46200033GH", |
||||
["c.ueq.d_3"] = "46200033VGH", |
||||
["c.olt.d_2"] = "46200034GH", |
||||
["c.olt.d_3"] = "46200034VGH", |
||||
["c.ult.d_2"] = "46200035GH", |
||||
["c.ult.d_3"] = "46200035VGH", |
||||
["c.ole.d_2"] = "46200036GH", |
||||
["c.ole.d_3"] = "46200036VGH", |
||||
["c.ule.d_2"] = "46200037GH", |
||||
["c.ule.d_3"] = "46200037VGH", |
||||
["c.sf.d_2"] = "46200038GH", |
||||
["c.sf.d_3"] = "46200038VGH", |
||||
["c.ngle.d_2"] = "46200039GH", |
||||
["c.ngle.d_3"] = "46200039VGH", |
||||
["c.seq.d_2"] = "4620003aGH", |
||||
["c.seq.d_3"] = "4620003aVGH", |
||||
["c.ngl.d_2"] = "4620003bGH", |
||||
["c.ngl.d_3"] = "4620003bVGH", |
||||
["c.lt.d_2"] = "4620003cGH", |
||||
["c.lt.d_3"] = "4620003cVGH", |
||||
["c.nge.d_2"] = "4620003dGH", |
||||
["c.nge.d_3"] = "4620003dVGH", |
||||
["c.le.d_2"] = "4620003eGH", |
||||
["c.le.d_3"] = "4620003eVGH", |
||||
["c.ngt.d_2"] = "4620003fGH", |
||||
["c.ngt.d_3"] = "4620003fVGH", |
||||
|
||||
["add.ps_3"] = "46c00000FGH", |
||||
["sub.ps_3"] = "46c00001FGH", |
||||
["mul.ps_3"] = "46c00002FGH", |
||||
["abs.ps_2"] = "46c00005FG", |
||||
["mov.ps_2"] = "46c00006FG", |
||||
["neg.ps_2"] = "46c00007FG", |
||||
["movf.ps_2"] = "46c00011FG", |
||||
["movf.ps_3"] = "46c00011FGC", |
||||
["movt.ps_2"] = "46c10011FG", |
||||
["movt.ps_3"] = "46c10011FGC", |
||||
["movz.ps_3"] = "46c00012FGT", |
||||
["movn.ps_3"] = "46c00013FGT", |
||||
["cvt.s.pu_2"] = "46c00020FG", |
||||
["cvt.s.pl_2"] = "46c00028FG", |
||||
["pll.ps_3"] = "46c0002cFGH", |
||||
["plu.ps_3"] = "46c0002dFGH", |
||||
["pul.ps_3"] = "46c0002eFGH", |
||||
["puu.ps_3"] = "46c0002fFGH", |
||||
["c.f.ps_2"] = "46c00030GH", |
||||
["c.f.ps_3"] = "46c00030VGH", |
||||
["c.un.ps_2"] = "46c00031GH", |
||||
["c.un.ps_3"] = "46c00031VGH", |
||||
["c.eq.ps_2"] = "46c00032GH", |
||||
["c.eq.ps_3"] = "46c00032VGH", |
||||
["c.ueq.ps_2"] = "46c00033GH", |
||||
["c.ueq.ps_3"] = "46c00033VGH", |
||||
["c.olt.ps_2"] = "46c00034GH", |
||||
["c.olt.ps_3"] = "46c00034VGH", |
||||
["c.ult.ps_2"] = "46c00035GH", |
||||
["c.ult.ps_3"] = "46c00035VGH", |
||||
["c.ole.ps_2"] = "46c00036GH", |
||||
["c.ole.ps_3"] = "46c00036VGH", |
||||
["c.ule.ps_2"] = "46c00037GH", |
||||
["c.ule.ps_3"] = "46c00037VGH", |
||||
["c.sf.ps_2"] = "46c00038GH", |
||||
["c.sf.ps_3"] = "46c00038VGH", |
||||
["c.ngle.ps_2"] = "46c00039GH", |
||||
["c.ngle.ps_3"] = "46c00039VGH", |
||||
["c.seq.ps_2"] = "46c0003aGH", |
||||
["c.seq.ps_3"] = "46c0003aVGH", |
||||
["c.ngl.ps_2"] = "46c0003bGH", |
||||
["c.ngl.ps_3"] = "46c0003bVGH", |
||||
["c.lt.ps_2"] = "46c0003cGH", |
||||
["c.lt.ps_3"] = "46c0003cVGH", |
||||
["c.nge.ps_2"] = "46c0003dGH", |
||||
["c.nge.ps_3"] = "46c0003dVGH", |
||||
["c.le.ps_2"] = "46c0003eGH", |
||||
["c.le.ps_3"] = "46c0003eVGH", |
||||
["c.ngt.ps_2"] = "46c0003fGH", |
||||
["c.ngt.ps_3"] = "46c0003fVGH", |
||||
|
||||
["cvt.s.w_2"] = "46800020FG", |
||||
["cvt.d.w_2"] = "46800021FG", |
||||
|
||||
["cvt.s.l_2"] = "46a00020FG", |
||||
["cvt.d.l_2"] = "46a00021FG", |
||||
|
||||
-- Opcode COP1X. |
||||
lwxc1_2 = "4c000000FX", |
||||
ldxc1_2 = "4c000001FX", |
||||
luxc1_2 = "4c000005FX", |
||||
swxc1_2 = "4c000008FX", |
||||
sdxc1_2 = "4c000009FX", |
||||
suxc1_2 = "4c00000dFX", |
||||
prefx_2 = "4c00000fMX", |
||||
["alnv.ps_4"] = "4c00001eFGHS", |
||||
["madd.s_4"] = "4c000020FRGH", |
||||
["madd.d_4"] = "4c000021FRGH", |
||||
["madd.ps_4"] = "4c000026FRGH", |
||||
["msub.s_4"] = "4c000028FRGH", |
||||
["msub.d_4"] = "4c000029FRGH", |
||||
["msub.ps_4"] = "4c00002eFRGH", |
||||
["nmadd.s_4"] = "4c000030FRGH", |
||||
["nmadd.d_4"] = "4c000031FRGH", |
||||
["nmadd.ps_4"] = "4c000036FRGH", |
||||
["nmsub.s_4"] = "4c000038FRGH", |
||||
["nmsub.d_4"] = "4c000039FRGH", |
||||
["nmsub.ps_4"] = "4c00003eFRGH", |
||||
} |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
local function parse_gpr(expr) |
||||
local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") |
||||
local tp = map_type[tname or expr] |
||||
if tp then |
||||
local reg = ovreg or tp.reg |
||||
if not reg then |
||||
werror("type `"..(tname or expr).."' needs a register override") |
||||
end |
||||
expr = reg |
||||
end |
||||
local r = match(expr, "^r([1-3]?[0-9])$") |
||||
if r then |
||||
r = tonumber(r) |
||||
if r <= 31 then return r, tp end |
||||
end |
||||
werror("bad register name `"..expr.."'") |
||||
end |
||||
|
||||
local function parse_fpr(expr) |
||||
local r = match(expr, "^f([1-3]?[0-9])$") |
||||
if r then |
||||
r = tonumber(r) |
||||
if r <= 31 then return r end |
||||
end |
||||
werror("bad register name `"..expr.."'") |
||||
end |
||||
|
||||
local function parse_imm(imm, bits, shift, scale, signed) |
||||
local n = tonumber(imm) |
||||
if n then |
||||
if n % 2^scale == 0 then |
||||
n = n / 2^scale |
||||
if signed then |
||||
if n >= 0 then |
||||
if n < 2^(bits-1) then return n*2^shift end |
||||
else |
||||
if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end |
||||
end |
||||
else |
||||
if n >= 0 and n <= 2^bits-1 then return n*2^shift end |
||||
end |
||||
end |
||||
werror("out of range immediate `"..imm.."'") |
||||
elseif match(imm, "^[rf]([1-3]?[0-9])$") or |
||||
match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then |
||||
werror("expected immediate operand, got register") |
||||
else |
||||
waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) |
||||
return 0 |
||||
end |
||||
end |
||||
|
||||
local function parse_disp(disp) |
||||
local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") |
||||
if imm then |
||||
local r = parse_gpr(reg)*2^21 |
||||
local extname = match(imm, "^extern%s+(%S+)$") |
||||
if extname then |
||||
waction("REL_EXT", map_extern[extname], nil, 1) |
||||
return r |
||||
else |
||||
return r + parse_imm(imm, 16, 0, 0, true) |
||||
end |
||||
end |
||||
local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") |
||||
if reg and tailr ~= "" then |
||||
local r, tp = parse_gpr(reg) |
||||
if tp then |
||||
waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) |
||||
return r*2^21 |
||||
end |
||||
end |
||||
werror("bad displacement `"..disp.."'") |
||||
end |
||||
|
||||
local function parse_index(idx) |
||||
local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") |
||||
if rt then |
||||
rt = parse_gpr(rt) |
||||
rs = parse_gpr(rs) |
||||
return rt*2^16 + rs*2^21 |
||||
end |
||||
werror("bad index `"..idx.."'") |
||||
end |
||||
|
||||
local function parse_label(label, def) |
||||
local prefix = sub(label, 1, 2) |
||||
-- =>label (pc label reference) |
||||
if prefix == "=>" then |
||||
return "PC", 0, sub(label, 3) |
||||
end |
||||
-- ->name (global label reference) |
||||
if prefix == "->" then |
||||
return "LG", map_global[sub(label, 3)] |
||||
end |
||||
if def then |
||||
-- [1-9] (local label definition) |
||||
if match(label, "^[1-9]$") then |
||||
return "LG", 10+tonumber(label) |
||||
end |
||||
else |
||||
-- [<>][1-9] (local label reference) |
||||
local dir, lnum = match(label, "^([<>])([1-9])$") |
||||
if dir then -- Fwd: 1-9, Bkwd: 11-19. |
||||
return "LG", lnum + (dir == ">" and 0 or 10) |
||||
end |
||||
-- extern label (extern label reference) |
||||
local extname = match(label, "^extern%s+(%S+)$") |
||||
if extname then |
||||
return "EXT", map_extern[extname] |
||||
end |
||||
end |
||||
werror("bad label `"..label.."'") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Handle opcodes defined with template strings. |
||||
map_op[".template__"] = function(params, template, nparams) |
||||
if not params then return sub(template, 9) end |
||||
local op = tonumber(sub(template, 1, 8), 16) |
||||
local n = 1 |
||||
|
||||
-- Limit number of section buffer positions used by a single dasm_put(). |
||||
-- A single opcode needs a maximum of 2 positions (ins/ext). |
||||
if secpos+2 > maxsecpos then wflush() end |
||||
local pos = wpos() |
||||
|
||||
-- Process each character. |
||||
for p in gmatch(sub(template, 9), ".") do |
||||
if p == "D" then |
||||
op = op + parse_gpr(params[n]) * 2^11; n = n + 1 |
||||
elseif p == "T" then |
||||
op = op + parse_gpr(params[n]) * 2^16; n = n + 1 |
||||
elseif p == "S" then |
||||
op = op + parse_gpr(params[n]) * 2^21; n = n + 1 |
||||
elseif p == "F" then |
||||
op = op + parse_fpr(params[n]) * 2^6; n = n + 1 |
||||
elseif p == "G" then |
||||
op = op + parse_fpr(params[n]) * 2^11; n = n + 1 |
||||
elseif p == "H" then |
||||
op = op + parse_fpr(params[n]) * 2^16; n = n + 1 |
||||
elseif p == "R" then |
||||
op = op + parse_fpr(params[n]) * 2^21; n = n + 1 |
||||
elseif p == "I" then |
||||
op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 |
||||
elseif p == "U" then |
||||
op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 |
||||
elseif p == "O" then |
||||
op = op + parse_disp(params[n]); n = n + 1 |
||||
elseif p == "X" then |
||||
op = op + parse_index(params[n]); n = n + 1 |
||||
elseif p == "B" or p == "J" then |
||||
local mode, n, s = parse_label(params[n], false) |
||||
if p == "B" then n = n + 2048 end |
||||
waction("REL_"..mode, n, s, 1) |
||||
n = n + 1 |
||||
elseif p == "A" then |
||||
op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 |
||||
elseif p == "M" then |
||||
op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 |
||||
elseif p == "N" then |
||||
op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 |
||||
elseif p == "C" then |
||||
op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 |
||||
elseif p == "V" then |
||||
op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 |
||||
elseif p == "W" then |
||||
op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 |
||||
elseif p == "Y" then |
||||
op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 |
||||
elseif p == "Z" then |
||||
op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 |
||||
elseif p == "=" then |
||||
local d = ((op - op % 2^11) / 2^11) % 32 |
||||
op = op + d * 2^16 -- Copy D to T for clz, clo. |
||||
else |
||||
assert(false) |
||||
end |
||||
end |
||||
wputpos(pos, op) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pseudo-opcode to mark the position where the action list is to be emitted. |
||||
map_op[".actionlist_1"] = function(params) |
||||
if not params then return "cvar" end |
||||
local name = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeactions(out, name) end) |
||||
end |
||||
|
||||
-- Pseudo-opcode to mark the position where the global enum is to be emitted. |
||||
map_op[".globals_1"] = function(params) |
||||
if not params then return "prefix" end |
||||
local prefix = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeglobals(out, prefix) end) |
||||
end |
||||
|
||||
-- Pseudo-opcode to mark the position where the global names are to be emitted. |
||||
map_op[".globalnames_1"] = function(params) |
||||
if not params then return "cvar" end |
||||
local name = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeglobalnames(out, name) end) |
||||
end |
||||
|
||||
-- Pseudo-opcode to mark the position where the extern names are to be emitted. |
||||
map_op[".externnames_1"] = function(params) |
||||
if not params then return "cvar" end |
||||
local name = params[1] -- No syntax check. You get to keep the pieces. |
||||
wline(function(out) writeexternnames(out, name) end) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Label pseudo-opcode (converted from trailing colon form). |
||||
map_op[".label_1"] = function(params) |
||||
if not params then return "[1-9] | ->global | =>pcexpr" end |
||||
if secpos+1 > maxsecpos then wflush() end |
||||
local mode, n, s = parse_label(params[1], true) |
||||
if mode == "EXT" then werror("bad label definition") end |
||||
waction("LABEL_"..mode, n, s, 1) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pseudo-opcodes for data storage. |
||||
map_op[".long_*"] = function(params) |
||||
if not params then return "imm..." end |
||||
for _,p in ipairs(params) do |
||||
local n = tonumber(p) |
||||
if not n then werror("bad immediate `"..p.."'") end |
||||
if n < 0 then n = n + 2^32 end |
||||
wputw(n) |
||||
if secpos+2 > maxsecpos then wflush() end |
||||
end |
||||
end |
||||
|
||||
-- Alignment pseudo-opcode. |
||||
map_op[".align_1"] = function(params) |
||||
if not params then return "numpow2" end |
||||
if secpos+1 > maxsecpos then wflush() end |
||||
local align = tonumber(params[1]) |
||||
if align then |
||||
local x = align |
||||
-- Must be a power of 2 in the range (2 ... 256). |
||||
for i=1,8 do |
||||
x = x / 2 |
||||
if x == 1 then |
||||
waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. |
||||
return |
||||
end |
||||
end |
||||
end |
||||
werror("bad alignment") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pseudo-opcode for (primitive) type definitions (map to C types). |
||||
map_op[".type_3"] = function(params, nparams) |
||||
if not params then |
||||
return nparams == 2 and "name, ctype" or "name, ctype, reg" |
||||
end |
||||
local name, ctype, reg = params[1], params[2], params[3] |
||||
if not match(name, "^[%a_][%w_]*$") then |
||||
werror("bad type name `"..name.."'") |
||||
end |
||||
local tp = map_type[name] |
||||
if tp then |
||||
werror("duplicate type `"..name.."'") |
||||
end |
||||
-- Add #type to defines. A bit unclean to put it in map_archdef. |
||||
map_archdef["#"..name] = "sizeof("..ctype..")" |
||||
-- Add new type and emit shortcut define. |
||||
local num = ctypenum + 1 |
||||
map_type[name] = { |
||||
ctype = ctype, |
||||
ctypefmt = format("Dt%X(%%s)", num), |
||||
reg = reg, |
||||
} |
||||
wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) |
||||
ctypenum = num |
||||
end |
||||
map_op[".type_2"] = map_op[".type_3"] |
||||
|
||||
-- Dump type definitions. |
||||
local function dumptypes(out, lvl) |
||||
local t = {} |
||||
for name in pairs(map_type) do t[#t+1] = name end |
||||
sort(t) |
||||
out:write("Type definitions:\n") |
||||
for _,name in ipairs(t) do |
||||
local tp = map_type[name] |
||||
local reg = tp.reg or "" |
||||
out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) |
||||
end |
||||
out:write("\n") |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Set the current section. |
||||
function _M.section(num) |
||||
waction("SECTION", num) |
||||
wflush(true) -- SECTION is a terminal action. |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Dump architecture description. |
||||
function _M.dumparch(out) |
||||
out:write(format("DynASM %s version %s, released %s\n\n", |
||||
_info.arch, _info.version, _info.release)) |
||||
dumpactions(out) |
||||
end |
||||
|
||||
-- Dump all user defined elements. |
||||
function _M.dumpdef(out, lvl) |
||||
dumptypes(out, lvl) |
||||
dumpglobals(out, lvl) |
||||
dumpexterns(out, lvl) |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
||||
-- Pass callbacks from/to the DynASM core. |
||||
function _M.passcb(wl, we, wf, ww) |
||||
wline, werror, wfatal, wwarn = wl, we, wf, ww |
||||
return wflush |
||||
end |
||||
|
||||
-- Setup the arch-specific module. |
||||
function _M.setup(arch, opt) |
||||
g_arch, g_opt = arch, opt |
||||
end |
||||
|
||||
-- Merge the core maps and the arch-specific maps. |
||||
function _M.mergemaps(map_coreop, map_def) |
||||
setmetatable(map_op, { __index = map_coreop }) |
||||
setmetatable(map_def, { __index = map_archdef }) |
||||
return map_op, map_def |
||||
end |
||||
|
||||
return _M |
||||
|
||||
------------------------------------------------------------------------------ |
||||
|
@ -1,411 +0,0 @@ |
||||
/*
|
||||
** DynASM PPC encoding engine. |
||||
** Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
** Released under the MIT license. See dynasm.lua for full copyright notice. |
||||
*/ |
||||
|
||||
#include <stddef.h> |
||||
#include <stdarg.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#define DASM_ARCH "ppc" |
||||
|
||||
#ifndef DASM_EXTERN |
||||
#define DASM_EXTERN(a,b,c,d) 0 |
||||
#endif |
||||
|
||||
/* Action definitions. */ |
||||
enum { |
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, |
||||
/* The following actions need a buffer position. */ |
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, |
||||
/* The following actions also have an argument. */ |
||||
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, |
||||
DASM__MAX |
||||
}; |
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */ |
||||
#define DASM_MAXSECPOS 25 |
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */ |
||||
#define DASM_S_OK 0x00000000 |
||||
#define DASM_S_NOMEM 0x01000000 |
||||
#define DASM_S_PHASE 0x02000000 |
||||
#define DASM_S_MATCH_SEC 0x03000000 |
||||
#define DASM_S_RANGE_I 0x11000000 |
||||
#define DASM_S_RANGE_SEC 0x12000000 |
||||
#define DASM_S_RANGE_LG 0x13000000 |
||||
#define DASM_S_RANGE_PC 0x14000000 |
||||
#define DASM_S_RANGE_REL 0x15000000 |
||||
#define DASM_S_UNDEF_LG 0x21000000 |
||||
#define DASM_S_UNDEF_PC 0x22000000 |
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */ |
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) |
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000) |
||||
#define DASM_SEC2POS(sec) ((sec)<<24) |
||||
#define DASM_POS2SEC(pos) ((pos)>>24) |
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) |
||||
|
||||
/* Action list type. */ |
||||
typedef const unsigned int *dasm_ActList; |
||||
|
||||
/* Per-section structure. */ |
||||
typedef struct dasm_Section { |
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */ |
||||
int *buf; /* True buffer pointer. */ |
||||
size_t bsize; /* Buffer size in bytes. */ |
||||
int pos; /* Biased buffer position. */ |
||||
int epos; /* End of biased buffer position - max single put. */ |
||||
int ofs; /* Byte offset into section. */ |
||||
} dasm_Section; |
||||
|
||||
/* Core structure holding the DynASM encoding state. */ |
||||
struct dasm_State { |
||||
size_t psize; /* Allocated size of this structure. */ |
||||
dasm_ActList actionlist; /* Current actionlist pointer. */ |
||||
int *lglabels; /* Local/global chain/pos ptrs. */ |
||||
size_t lgsize; |
||||
int *pclabels; /* PC label chains/pos ptrs. */ |
||||
size_t pcsize; |
||||
void **globals; /* Array of globals (bias -10). */ |
||||
dasm_Section *section; /* Pointer to active section. */ |
||||
size_t codesize; /* Total size of all code sections. */ |
||||
int maxsection; /* 0 <= sectionidx < maxsection. */ |
||||
int status; /* Status code. */ |
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */ |
||||
}; |
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */ |
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) |
||||
|
||||
|
||||
/* Initialize DynASM state. */ |
||||
void dasm_init(Dst_DECL, int maxsection) |
||||
{ |
||||
dasm_State *D; |
||||
size_t psz = 0; |
||||
int i; |
||||
Dst_REF = NULL; |
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); |
||||
D = Dst_REF; |
||||
D->psize = psz; |
||||
D->lglabels = NULL; |
||||
D->lgsize = 0; |
||||
D->pclabels = NULL; |
||||
D->pcsize = 0; |
||||
D->globals = NULL; |
||||
D->maxsection = maxsection; |
||||
for (i = 0; i < maxsection; i++) { |
||||
D->sections[i].buf = NULL; /* Need this for pass3. */ |
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); |
||||
D->sections[i].bsize = 0; |
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ |
||||
} |
||||
} |
||||
|
||||
/* Free DynASM state. */ |
||||
void dasm_free(Dst_DECL) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
for (i = 0; i < D->maxsection; i++) |
||||
if (D->sections[i].buf) |
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); |
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); |
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); |
||||
DASM_M_FREE(Dst, D, D->psize); |
||||
} |
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */ |
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */ |
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); |
||||
} |
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */ |
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
size_t osz = D->pcsize; |
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); |
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); |
||||
} |
||||
|
||||
/* Setup encoder. */ |
||||
void dasm_setup(Dst_DECL, const void *actionlist) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
D->actionlist = (dasm_ActList)actionlist; |
||||
D->status = DASM_S_OK; |
||||
D->section = &D->sections[0]; |
||||
memset((void *)D->lglabels, 0, D->lgsize); |
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); |
||||
for (i = 0; i < D->maxsection; i++) { |
||||
D->sections[i].pos = DASM_SEC2POS(i); |
||||
D->sections[i].ofs = 0; |
||||
} |
||||
} |
||||
|
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) |
||||
#define CKPL(kind, st) \ |
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#define CKPL(kind, st) ((void)0) |
||||
#endif |
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ |
||||
void dasm_put(Dst_DECL, int start, ...) |
||||
{ |
||||
va_list ap; |
||||
dasm_State *D = Dst_REF; |
||||
dasm_ActList p = D->actionlist + start; |
||||
dasm_Section *sec = D->section; |
||||
int pos = sec->pos, ofs = sec->ofs; |
||||
int *b; |
||||
|
||||
if (pos >= sec->epos) { |
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize, |
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); |
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos); |
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); |
||||
} |
||||
|
||||
b = sec->rbuf; |
||||
b[pos++] = start; |
||||
|
||||
va_start(ap, start); |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16); |
||||
if (action >= DASM__MAX) { |
||||
ofs += 4; |
||||
} else { |
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; |
||||
switch (action) { |
||||
case DASM_STOP: goto stop; |
||||
case DASM_SECTION: |
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); |
||||
D->section = &D->sections[n]; goto stop; |
||||
case DASM_ESC: p++; ofs += 4; break; |
||||
case DASM_REL_EXT: break; |
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; |
||||
case DASM_REL_LG: |
||||
n = (ins & 2047) - 10; pl = D->lglabels + n; |
||||
if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ |
||||
pl += 10; n = *pl; |
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ |
||||
goto linkrel; |
||||
case DASM_REL_PC: |
||||
pl = D->pclabels + n; CKPL(pc, PC); |
||||
putrel: |
||||
n = *pl; |
||||
if (n < 0) { /* Label exists. Get label pos and store it. */ |
||||
b[pos] = -n; |
||||
} else { |
||||
linkrel: |
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */ |
||||
*pl = pos; |
||||
} |
||||
pos++; |
||||
break; |
||||
case DASM_LABEL_LG: |
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; |
||||
case DASM_LABEL_PC: |
||||
pl = D->pclabels + n; CKPL(pc, PC); |
||||
putlabel: |
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; |
||||
} |
||||
*pl = -pos; /* Label exists now. */ |
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */ |
||||
break; |
||||
case DASM_IMM: |
||||
#ifdef DASM_CHECKS |
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); |
||||
#endif |
||||
n >>= ((ins>>10)&31); |
||||
#ifdef DASM_CHECKS |
||||
if (ins & 0x8000) |
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); |
||||
else |
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I); |
||||
#endif |
||||
b[pos++] = n; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
stop: |
||||
va_end(ap); |
||||
sec->pos = pos; |
||||
sec->ofs = ofs; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */ |
||||
int dasm_link(Dst_DECL, size_t *szp) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int secnum; |
||||
int ofs = 0; |
||||
|
||||
#ifdef DASM_CHECKS |
||||
*szp = 0; |
||||
if (D->status != DASM_S_OK) return D->status; |
||||
{ |
||||
int pc; |
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) |
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; |
||||
} |
||||
#endif |
||||
|
||||
{ /* Handle globals not defined in this translation unit. */ |
||||
int idx; |
||||
for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { |
||||
int n = D->lglabels[idx]; |
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } |
||||
} |
||||
} |
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->rbuf; |
||||
int pos = DASM_SEC2POS(secnum); |
||||
int lastpos = sec->pos; |
||||
|
||||
while (pos != lastpos) { |
||||
dasm_ActList p = D->actionlist + b[pos++]; |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16); |
||||
switch (action) { |
||||
case DASM_STOP: case DASM_SECTION: goto stop; |
||||
case DASM_ESC: p++; break; |
||||
case DASM_REL_EXT: break; |
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; |
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break; |
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; |
||||
case DASM_IMM: pos++; break; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
ofs += sec->ofs; /* Next section starts right after current section. */ |
||||
} |
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */ |
||||
*szp = ofs; |
||||
return DASM_S_OK; |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#endif |
||||
|
||||
/* Pass 3: Encode sections. */ |
||||
int dasm_encode(Dst_DECL, void *buffer) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
char *base = (char *)buffer; |
||||
unsigned int *cp = (unsigned int *)buffer; |
||||
int secnum; |
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->buf; |
||||
int *endb = sec->rbuf + sec->pos; |
||||
|
||||
while (b != endb) { |
||||
dasm_ActList p = D->actionlist + *b++; |
||||
while (1) { |
||||
unsigned int ins = *p++; |
||||
unsigned int action = (ins >> 16); |
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; |
||||
switch (action) { |
||||
case DASM_STOP: case DASM_SECTION: goto stop; |
||||
case DASM_ESC: *cp++ = *p++; break; |
||||
case DASM_REL_EXT: |
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; |
||||
goto patchrel; |
||||
case DASM_ALIGN: |
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; |
||||
break; |
||||
case DASM_REL_LG: |
||||
CK(n >= 0, UNDEF_LG); |
||||
case DASM_REL_PC: |
||||
CK(n >= 0, UNDEF_PC); |
||||
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); |
||||
patchrel: |
||||
CK((n & 3) == 0 && |
||||
(((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> |
||||
((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); |
||||
cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); |
||||
break; |
||||
case DASM_LABEL_LG: |
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); |
||||
break; |
||||
case DASM_LABEL_PC: break; |
||||
case DASM_IMM: |
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); |
||||
break; |
||||
default: *cp++ = ins; break; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
} |
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */ |
||||
return DASM_S_PHASE; |
||||
return DASM_S_OK; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Get PC label offset. */ |
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (pc*sizeof(int) < D->pcsize) { |
||||
int pos = D->pclabels[pc]; |
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos); |
||||
if (pos > 0) return -1; /* Undefined. */ |
||||
} |
||||
return -2; /* Unused or out of range. */ |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
/* Optional sanity checker to call between isolated encoding steps. */ |
||||
int dasm_checkstep(Dst_DECL, int secmatch) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (D->status == DASM_S_OK) { |
||||
int i; |
||||
for (i = 1; i <= 9; i++) { |
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } |
||||
D->lglabels[i] = 0; |
||||
} |
||||
} |
||||
if (D->status == DASM_S_OK && secmatch >= 0 && |
||||
D->section != &D->sections[secmatch]) |
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections); |
||||
return D->status; |
||||
} |
||||
#endif |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,83 +0,0 @@ |
||||
/*
|
||||
** DynASM encoding engine prototypes. |
||||
** Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
** Released under the MIT license. See dynasm.lua for full copyright notice. |
||||
*/ |
||||
|
||||
#ifndef _DASM_PROTO_H |
||||
#define _DASM_PROTO_H |
||||
|
||||
#include <stddef.h> |
||||
#include <stdarg.h> |
||||
|
||||
#define DASM_IDENT "DynASM 1.3.0" |
||||
#define DASM_VERSION 10300 /* 1.3.0 */ |
||||
|
||||
#ifndef Dst_DECL |
||||
#define Dst_DECL dasm_State **Dst |
||||
#endif |
||||
|
||||
#ifndef Dst_REF |
||||
#define Dst_REF (*Dst) |
||||
#endif |
||||
|
||||
#ifndef DASM_FDEF |
||||
#define DASM_FDEF extern |
||||
#endif |
||||
|
||||
#ifndef DASM_M_GROW |
||||
#define DASM_M_GROW(ctx, t, p, sz, need) \ |
||||
do { \
|
||||
size_t _sz = (sz), _need = (need); \
|
||||
if (_sz < _need) { \
|
||||
if (_sz < 16) _sz = 16; \
|
||||
while (_sz < _need) _sz += _sz; \
|
||||
(p) = (t *)realloc((p), _sz); \
|
||||
if ((p) == NULL) exit(1); \
|
||||
(sz) = _sz; \
|
||||
} \
|
||||
} while(0) |
||||
#endif |
||||
|
||||
#ifndef DASM_M_FREE |
||||
#define DASM_M_FREE(ctx, p, sz) free(p) |
||||
#endif |
||||
|
||||
/* Internal DynASM encoder state. */ |
||||
typedef struct dasm_State dasm_State; |
||||
|
||||
|
||||
/* Initialize and free DynASM state. */ |
||||
DASM_FDEF void dasm_init(Dst_DECL, int maxsection); |
||||
DASM_FDEF void dasm_free(Dst_DECL); |
||||
|
||||
/* Setup global array. Must be called before dasm_setup(). */ |
||||
DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); |
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */ |
||||
DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); |
||||
|
||||
/* Setup encoder. */ |
||||
DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); |
||||
|
||||
/* Feed encoder with actions. Calls are generated by pre-processor. */ |
||||
DASM_FDEF void dasm_put(Dst_DECL, int start, ...); |
||||
|
||||
/* Link sections and return the resulting size. */ |
||||
DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); |
||||
|
||||
/* Encode sections into buffer. */ |
||||
DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); |
||||
|
||||
/* Get PC label offset. */ |
||||
DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); |
||||
|
||||
#ifdef DASM_CHECKS |
||||
/* Optional sanity checker to call between isolated encoding steps. */ |
||||
DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); |
||||
#else |
||||
#define dasm_checkstep(a, b) 0 |
||||
#endif |
||||
|
||||
|
||||
#endif /* _DASM_PROTO_H */ |
@ -1,12 +0,0 @@ |
||||
------------------------------------------------------------------------------ |
||||
-- DynASM x64 module. |
||||
-- |
||||
-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
-- See dynasm.lua for full copyright notice. |
||||
------------------------------------------------------------------------------ |
||||
-- This module just sets 64 bit mode for the combined x86/x64 module. |
||||
-- All the interesting stuff is there. |
||||
------------------------------------------------------------------------------ |
||||
|
||||
x64 = true -- Using a global is an ugly, but effective solution. |
||||
return require("dasm_x86") |
@ -1,470 +0,0 @@ |
||||
/*
|
||||
** DynASM x86 encoding engine. |
||||
** Copyright (C) 2005-2012 Mike Pall. All rights reserved. |
||||
** Released under the MIT license. See dynasm.lua for full copyright notice. |
||||
*/ |
||||
|
||||
#include <stddef.h> |
||||
#include <stdarg.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#define DASM_ARCH "x86" |
||||
|
||||
#ifndef DASM_EXTERN |
||||
#define DASM_EXTERN(a,b,c,d) 0 |
||||
#endif |
||||
|
||||
/* Action definitions. DASM_STOP must be 255. */ |
||||
enum { |
||||
DASM_DISP = 233, |
||||
DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, |
||||
DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, |
||||
DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, |
||||
DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP |
||||
}; |
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */ |
||||
#define DASM_MAXSECPOS 25 |
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */ |
||||
#define DASM_S_OK 0x00000000 |
||||
#define DASM_S_NOMEM 0x01000000 |
||||
#define DASM_S_PHASE 0x02000000 |
||||
#define DASM_S_MATCH_SEC 0x03000000 |
||||
#define DASM_S_RANGE_I 0x11000000 |
||||
#define DASM_S_RANGE_SEC 0x12000000 |
||||
#define DASM_S_RANGE_LG 0x13000000 |
||||
#define DASM_S_RANGE_PC 0x14000000 |
||||
#define DASM_S_RANGE_VREG 0x15000000 |
||||
#define DASM_S_UNDEF_L 0x21000000 |
||||
#define DASM_S_UNDEF_PC 0x22000000 |
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */ |
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) |
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000) |
||||
#define DASM_SEC2POS(sec) ((sec)<<24) |
||||
#define DASM_POS2SEC(pos) ((pos)>>24) |
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) |
||||
|
||||
/* Action list type. */ |
||||
typedef const unsigned char *dasm_ActList; |
||||
|
||||
/* Per-section structure. */ |
||||
typedef struct dasm_Section { |
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */ |
||||
int *buf; /* True buffer pointer. */ |
||||
size_t bsize; /* Buffer size in bytes. */ |
||||
int pos; /* Biased buffer position. */ |
||||
int epos; /* End of biased buffer position - max single put. */ |
||||
int ofs; /* Byte offset into section. */ |
||||
} dasm_Section; |
||||
|
||||
/* Core structure holding the DynASM encoding state. */ |
||||
struct dasm_State { |
||||
size_t psize; /* Allocated size of this structure. */ |
||||
dasm_ActList actionlist; /* Current actionlist pointer. */ |
||||
int *lglabels; /* Local/global chain/pos ptrs. */ |
||||
size_t lgsize; |
||||
int *pclabels; /* PC label chains/pos ptrs. */ |
||||
size_t pcsize; |
||||
void **globals; /* Array of globals (bias -10). */ |
||||
dasm_Section *section; /* Pointer to active section. */ |
||||
size_t codesize; /* Total size of all code sections. */ |
||||
int maxsection; /* 0 <= sectionidx < maxsection. */ |
||||
int status; /* Status code. */ |
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */ |
||||
}; |
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */ |
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) |
||||
|
||||
|
||||
/* Initialize DynASM state. */ |
||||
void dasm_init(Dst_DECL, int maxsection) |
||||
{ |
||||
dasm_State *D; |
||||
size_t psz = 0; |
||||
int i; |
||||
Dst_REF = NULL; |
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); |
||||
D = Dst_REF; |
||||
D->psize = psz; |
||||
D->lglabels = NULL; |
||||
D->lgsize = 0; |
||||
D->pclabels = NULL; |
||||
D->pcsize = 0; |
||||
D->globals = NULL; |
||||
D->maxsection = maxsection; |
||||
for (i = 0; i < maxsection; i++) { |
||||
D->sections[i].buf = NULL; /* Need this for pass3. */ |
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); |
||||
D->sections[i].bsize = 0; |
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ |
||||
} |
||||
} |
||||
|
||||
/* Free DynASM state. */ |
||||
void dasm_free(Dst_DECL) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
for (i = 0; i < D->maxsection; i++) |
||||
if (D->sections[i].buf) |
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); |
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); |
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); |
||||
DASM_M_FREE(Dst, D, D->psize); |
||||
} |
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */ |
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */ |
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); |
||||
} |
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */ |
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
size_t osz = D->pcsize; |
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); |
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); |
||||
} |
||||
|
||||
/* Setup encoder. */ |
||||
void dasm_setup(Dst_DECL, const void *actionlist) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int i; |
||||
D->actionlist = (dasm_ActList)actionlist; |
||||
D->status = DASM_S_OK; |
||||
D->section = &D->sections[0]; |
||||
memset((void *)D->lglabels, 0, D->lgsize); |
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); |
||||
for (i = 0; i < D->maxsection; i++) { |
||||
D->sections[i].pos = DASM_SEC2POS(i); |
||||
D->sections[i].ofs = 0; |
||||
} |
||||
} |
||||
|
||||
|
||||
#ifdef DASM_CHECKS |
||||
#define CK(x, st) \ |
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) |
||||
#define CKPL(kind, st) \ |
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) |
||||
#else |
||||
#define CK(x, st) ((void)0) |
||||
#define CKPL(kind, st) ((void)0) |
||||
#endif |
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ |
||||
void dasm_put(Dst_DECL, int start, ...) |
||||
{ |
||||
va_list ap; |
||||
dasm_State *D = Dst_REF; |
||||
dasm_ActList p = D->actionlist + start; |
||||
dasm_Section *sec = D->section; |
||||
int pos = sec->pos, ofs = sec->ofs, mrm = 4; |
||||
int *b; |
||||
|
||||
if (pos >= sec->epos) { |
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize, |
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); |
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos); |
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); |
||||
} |
||||
|
||||
b = sec->rbuf; |
||||
b[pos++] = start; |
||||
|
||||
va_start(ap, start); |
||||
while (1) { |
||||
int action = *p++; |
||||
if (action < DASM_DISP) { |
||||
ofs++; |
||||
} else if (action <= DASM_REL_A) { |
||||
int n = va_arg(ap, int); |
||||
b[pos++] = n; |
||||
switch (action) { |
||||
case DASM_DISP: |
||||
if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; } |
||||
case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; |
||||
case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ |
||||
case DASM_IMM_D: ofs += 4; break; |
||||
case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; |
||||
case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; |
||||
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; |
||||
case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; |
||||
case DASM_SPACE: p++; ofs += n; break; |
||||
case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ |
||||
case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG); |
||||
if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue; |
||||
} |
||||
mrm = 4; |
||||
} else { |
||||
int *pl, n; |
||||
switch (action) { |
||||
case DASM_REL_LG: |
||||
case DASM_IMM_LG: |
||||
n = *p++; pl = D->lglabels + n; |
||||
if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ |
||||
pl -= 246; n = *pl; |
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ |
||||
goto linkrel; |
||||
case DASM_REL_PC: |
||||
case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); |
||||
putrel: |
||||
n = *pl; |
||||
if (n < 0) { /* Label exists. Get label pos and store it. */ |
||||
b[pos] = -n; |
||||
} else { |
||||
linkrel: |
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */ |
||||
*pl = pos; |
||||
} |
||||
pos++; |
||||
ofs += 4; /* Maximum offset needed. */ |
||||
if (action == DASM_REL_LG || action == DASM_REL_PC) |
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */ |
||||
break; |
||||
case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; |
||||
case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); |
||||
putlabel: |
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } |
||||
*pl = -pos; /* Label exists now. */ |
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */ |
||||
break; |
||||
case DASM_ALIGN: |
||||
ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ |
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */ |
||||
break; |
||||
case DASM_EXTERN: p += 2; ofs += 4; break; |
||||
case DASM_ESC: p++; ofs++; break; |
||||
case DASM_MARK: mrm = p[-2]; break; |
||||
case DASM_SECTION: |
||||
n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; |
||||
case DASM_STOP: goto stop; |
||||
} |
||||
} |
||||
} |
||||
stop: |
||||
va_end(ap); |
||||
sec->pos = pos; |
||||
sec->ofs = ofs; |
||||
} |
||||
#undef CK |
||||
|
||||
/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ |
||||
int dasm_link(Dst_DECL, size_t *szp) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
int secnum; |
||||
int ofs = 0; |
||||
|
||||
#ifdef DASM_CHECKS |
||||
*szp = 0; |
||||
if (D->status != DASM_S_OK) return D->status; |
||||
{ |
||||
int pc; |
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) |
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; |
||||
} |
||||
#endif |
||||
|
||||
{ /* Handle globals not defined in this translation unit. */ |
||||
int idx; |
||||
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { |
||||
int n = D->lglabels[idx]; |
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */ |
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } |
||||
} |
||||
} |
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->rbuf; |
||||
int pos = DASM_SEC2POS(secnum); |
||||
int lastpos = sec->pos; |
||||
|
||||
while (pos != lastpos) { |
||||
dasm_ActList p = D->actionlist + b[pos++]; |
||||
while (1) { |
||||
int op, action = *p++; |
||||
switch (action) { |
||||
case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; |
||||
case DASM_REL_PC: op = p[-2]; rel_pc: { |
||||
int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); |
||||
if (shrink) { /* Shrinkable branch opcode? */ |
||||
int lofs, lpos = b[pos]; |
||||
if (lpos < 0) goto noshrink; /* Ext global? */ |
||||
lofs = *DASM_POS2PTR(D, lpos); |
||||
if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ |
||||
int i; |
||||
for (i = secnum; i < DASM_POS2SEC(lpos); i++) |
||||
lofs += D->sections[i].ofs; |
||||
} else { |
||||
lofs -= ofs; /* Bkwd label: unfix offset. */ |
||||
} |
||||
lofs -= b[pos+1]; /* Short branch ok? */ |
||||
if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ |
||||
else { noshrink: shrink = 0; } /* No, cannot shrink op. */ |
||||
} |
||||
b[pos+1] = shrink; |
||||
pos += 2; |
||||
break; |
||||
} |
||||
case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; |
||||
case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: |
||||
case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: |
||||
case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; |
||||
case DASM_LABEL_LG: p++; |
||||
case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ |
||||
case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ |
||||
case DASM_EXTERN: p += 2; break; |
||||
case DASM_ESC: p++; break; |
||||
case DASM_MARK: break; |
||||
case DASM_SECTION: case DASM_STOP: goto stop; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
ofs += sec->ofs; /* Next section starts right after current section. */ |
||||
} |
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */ |
||||
*szp = ofs; |
||||
return DASM_S_OK; |
||||
} |
||||
|
||||
#define dasmb(x) *cp++ = (unsigned char)(x) |
||||
#ifndef DASM_ALIGNED_WRITES |
||||
#define dasmw(x) \ |
||||
do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) |
||||
#define dasmd(x) \ |
||||
do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) |
||||
#else |
||||
#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) |
||||
#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) |
||||
#endif |
||||
|
||||
/* Pass 3: Encode sections. */ |
||||
int dasm_encode(Dst_DECL, void *buffer) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
unsigned char *base = (unsigned char *)buffer; |
||||
unsigned char *cp = base; |
||||
int secnum; |
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */ |
||||
for (secnum = 0; secnum < D->maxsection; secnum++) { |
||||
dasm_Section *sec = D->sections + secnum; |
||||
int *b = sec->buf; |
||||
int *endb = sec->rbuf + sec->pos; |
||||
|
||||
while (b != endb) { |
||||
dasm_ActList p = D->actionlist + *b++; |
||||
unsigned char *mark = NULL; |
||||
while (1) { |
||||
int action = *p++; |
||||
int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; |
||||
switch (action) { |
||||
case DASM_DISP: if (!mark) mark = cp; { |
||||
unsigned char *mm = mark; |
||||
if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; |
||||
if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; |
||||
if (mrm != 5) { mm[-1] -= 0x80; break; } } |
||||
if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; |
||||
} |
||||
case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; |
||||
case DASM_IMM_DB: if (((n+128)&-256) == 0) { |
||||
db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; |
||||
} else mark = NULL; |
||||
case DASM_IMM_D: wd: dasmd(n); break; |
||||
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; |
||||
case DASM_IMM_W: dasmw(n); break; |
||||
case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; } |
||||
case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; |
||||
b++; n = (int)(ptrdiff_t)D->globals[-n]; |
||||
case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ |
||||
case DASM_REL_PC: rel_pc: { |
||||
int shrink = *b++; |
||||
int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } |
||||
n = *pb - ((int)(cp-base) + 4-shrink); |
||||
if (shrink == 0) goto wd; |
||||
if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; |
||||
goto wb; |
||||
} |
||||
case DASM_IMM_LG: |
||||
p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } |
||||
case DASM_IMM_PC: { |
||||
int *pb = DASM_POS2PTR(D, n); |
||||
n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); |
||||
goto wd; |
||||
} |
||||
case DASM_LABEL_LG: { |
||||
int idx = *p++; |
||||
if (idx >= 10) |
||||
D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); |
||||
break; |
||||
} |
||||
case DASM_LABEL_PC: case DASM_SETLABEL: break; |
||||
case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } |
||||
case DASM_ALIGN: |
||||
n = *p++; |
||||
while (((cp-base) & n)) *cp++ = 0x90; /* nop */ |
||||
break; |
||||
case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; |
||||
case DASM_MARK: mark = cp; break; |
||||
case DASM_ESC: action = *p++; |
||||
default: *cp++ = action; break; |
||||
case DASM_SECTION: case DASM_STOP: goto stop; |
||||
} |
||||
} |
||||
stop: (void)0; |
||||
} |
||||
} |
||||
|
||||
if (base + D->codesize != cp) /* Check for phase errors. */ |
||||
return DASM_S_PHASE; |
||||
return DASM_S_OK; |
||||
} |
||||
|
||||
/* Get PC label offset. */ |
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (pc*sizeof(int) < D->pcsize) { |
||||
int pos = D->pclabels[pc]; |
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos); |
||||
if (pos > 0) return -1; /* Undefined. */ |
||||
} |
||||
return -2; /* Unused or out of range. */ |
||||
} |
||||
|
||||
#ifdef DASM_CHECKS |
||||
/* Optional sanity checker to call between isolated encoding steps. */ |
||||
int dasm_checkstep(Dst_DECL, int secmatch) |
||||
{ |
||||
dasm_State *D = Dst_REF; |
||||
if (D->status == DASM_S_OK) { |
||||
int i; |
||||
for (i = 1; i <= 9; i++) { |
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } |
||||
D->lglabels[i] = 0; |
||||
} |
||||
} |
||||
if (D->status == DASM_S_OK && secmatch >= 0 && |
||||
D->section != &D->sections[secmatch]) |
||||
D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); |
||||
return D->status; |
||||
} |
||||
#endif |
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@ |
||||
Subproject commit 5aeee3dc910d37f37b75f5a6d1486fe75cb09284 |
@ -1,511 +0,0 @@ |
||||
/*
|
||||
** Driver code for the x64 JIT compiler. |
||||
*/ |
||||
|
||||
/* Needed to ensure we get defines like MAP_ANON. */ |
||||
#define _GNU_SOURCE |
||||
|
||||
#include <dlfcn.h> |
||||
#include <stdio.h> |
||||
#include <sys/mman.h> |
||||
#include <unistd.h> |
||||
#include "upb/msg.h" |
||||
#include "upb/pb/decoder.h" |
||||
#include "upb/pb/decoder.int.h" |
||||
#include "upb/pb/varint.int.h" |
||||
|
||||
/* To debug the JIT:
|
||||
* |
||||
* 1. Uncomment: |
||||
* #define UPB_JIT_LOAD_SO |
||||
* |
||||
* Note: this mode requires that we can shell out to gcc. |
||||
* |
||||
* 2. Run the test locally. This will load the JIT code by building a |
||||
* .so (/tmp/upb-jit-code.so) and using dlopen, so more of the tooling will |
||||
* work properly (like GDB). |
||||
* |
||||
* IF YOU ALSO WANT AUTOMATIC JIT DEBUG OUTPUT: |
||||
* |
||||
* 3. Run: upb/pb/make-gdb-script.rb > script.gdb. This reads |
||||
* /tmp/upb-jit-code.so as input and generates a GDB script that is specific |
||||
* to this jit code. |
||||
* |
||||
* 4. Run: gdb --command=script.gdb --args path/to/test |
||||
* This will drop you to a GDB prompt which you can now use normally. |
||||
* But when you run the test it will print a message to stdout every time |
||||
* the JIT executes assembly for a particular bytecode. Sample output: |
||||
* |
||||
* X.enterjit bytes=18 |
||||
* buf_ofs=1 data_rem=17 delim_rem=-2 X.0x6.OP_PARSE_DOUBLE |
||||
* buf_ofs=9 data_rem=9 delim_rem=-10 X.0x7.OP_CHECKDELIM |
||||
* buf_ofs=9 data_rem=9 delim_rem=-10 X.0x8.OP_TAG1 |
||||
* X.0x3.dispatch.DecoderTest |
||||
* X.parse_unknown |
||||
* X.0x3.dispatch.DecoderTest |
||||
* X.decode_unknown_tag_fallback |
||||
* X.exitjit |
||||
* |
||||
* This output should roughly correspond to the output that the bytecode |
||||
* interpreter emits when compiled with UPB_DUMP_BYTECODE (modulo some |
||||
* extra JIT-specific output). */ |
||||
|
||||
/* These defines are necessary for DynASM codegen.
|
||||
* See dynasm/dasm_proto.h for more info. */ |
||||
#define Dst_DECL jitcompiler *jc |
||||
#define Dst_REF (jc->dynasm) |
||||
#define Dst (jc) |
||||
|
||||
/* In debug mode, make DynASM do internal checks (must be defined before any
|
||||
* dasm header is included. */ |
||||
#ifndef NDEBUG |
||||
#define DASM_CHECKS |
||||
#endif |
||||
|
||||
#ifndef MAP_ANONYMOUS |
||||
#define MAP_ANONYMOUS MAP_ANON |
||||
#endif |
||||
|
||||
typedef struct { |
||||
mgroup *group; |
||||
uint32_t *pc; |
||||
|
||||
/* This pointer is allocated by dasm_init() and freed by dasm_free(). */ |
||||
struct dasm_State *dynasm; |
||||
|
||||
/* Maps some key (an arbitrary void*) to a pclabel.
|
||||
* |
||||
* The pclabel represents a location in the generated code -- DynASM exposes |
||||
* a pclabel -> (machine code offset) lookup function. |
||||
* |
||||
* The key can be anything. There are two main kinds of keys: |
||||
* - bytecode location -- the void* points to the bytecode instruction |
||||
* itself. We can then use this to generate jumps to this instruction. |
||||
* - other object (like dispatch table). We use these to represent parts |
||||
* of the generated code that do not exactly correspond to a bytecode |
||||
* instruction. */ |
||||
upb_inttable jmptargets; |
||||
|
||||
#ifndef NDEBUG |
||||
/* Like jmptargets, but members are present in the table when they have had
|
||||
* define_jmptarget() (as opposed to jmptarget) called. Used to verify that |
||||
* define_jmptarget() is called exactly once for every target. |
||||
* The value is ignored. */ |
||||
upb_inttable jmpdefined; |
||||
|
||||
/* For checking that two asmlabels aren't defined for the same byte. */ |
||||
int lastlabelofs; |
||||
#endif |
||||
|
||||
#ifdef UPB_JIT_LOAD_SO |
||||
/* For marking labels that should go into the generated code.
|
||||
* Maps pclabel -> char* label (string is owned by the table). */ |
||||
upb_inttable asmlabels; |
||||
#endif |
||||
|
||||
/* The total number of pclabels currently defined.
|
||||
* Note that this contains both jmptargets and asmlabels, which both use |
||||
* pclabels but for different purposes. */ |
||||
uint32_t pclabel_count; |
||||
|
||||
/* Used by DynASM to store globals. */ |
||||
void **globals; |
||||
} jitcompiler; |
||||
|
||||
/* Functions called by codegen. */ |
||||
static int jmptarget(jitcompiler *jc, const void *key); |
||||
static int define_jmptarget(jitcompiler *jc, const void *key); |
||||
static void asmlabel(jitcompiler *jc, const char *fmt, ...); |
||||
static int pcofs(jitcompiler* jc); |
||||
static int alloc_pclabel(jitcompiler *jc); |
||||
|
||||
#ifdef UPB_JIT_LOAD_SO |
||||
static char *upb_vasprintf(const char *fmt, va_list ap); |
||||
static char *upb_asprintf(const char *fmt, ...); |
||||
#endif |
||||
|
||||
#include "third_party/dynasm/dasm_proto.h" |
||||
#include "third_party/dynasm/dasm_x86.h" |
||||
#include "upb/pb/compile_decoder_x64.h" |
||||
|
||||
static jitcompiler *newjitcompiler(mgroup *group) { |
||||
jitcompiler *jc = malloc(sizeof(jitcompiler)); |
||||
jc->group = group; |
||||
jc->pclabel_count = 0; |
||||
upb_inttable_init(&jc->jmptargets, UPB_CTYPE_UINT32); |
||||
#ifndef NDEBUG |
||||
jc->lastlabelofs = -1; |
||||
upb_inttable_init(&jc->jmpdefined, UPB_CTYPE_BOOL); |
||||
#endif |
||||
#ifdef UPB_JIT_LOAD_SO |
||||
upb_inttable_init(&jc->asmlabels, UPB_CTYPE_PTR); |
||||
#endif |
||||
jc->globals = malloc(UPB_JIT_GLOBAL__MAX * sizeof(*jc->globals)); |
||||
|
||||
dasm_init(jc, 1); |
||||
dasm_setupglobal(jc, jc->globals, UPB_JIT_GLOBAL__MAX); |
||||
dasm_setup(jc, upb_jit_actionlist); |
||||
|
||||
return jc; |
||||
} |
||||
|
||||
static void freejitcompiler(jitcompiler *jc) { |
||||
#ifdef UPB_JIT_LOAD_SO |
||||
upb_inttable_iter i; |
||||
upb_inttable_begin(&i, &jc->asmlabels); |
||||
for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
free(upb_value_getptr(upb_inttable_iter_value(&i))); |
||||
} |
||||
upb_inttable_uninit(&jc->asmlabels); |
||||
#endif |
||||
#ifndef NDEBUG |
||||
upb_inttable_uninit(&jc->jmpdefined); |
||||
#endif |
||||
upb_inttable_uninit(&jc->jmptargets); |
||||
dasm_free(jc); |
||||
free(jc->globals); |
||||
free(jc); |
||||
} |
||||
|
||||
#ifdef UPB_JIT_LOAD_SO |
||||
|
||||
/* Like sprintf except allocates the string, which is returned and owned by the
|
||||
* caller. |
||||
* |
||||
* Like the GNU extension asprintf(), except we abort on error (since this is |
||||
* only for debugging). */ |
||||
static char *upb_vasprintf(const char *fmt, va_list args) { |
||||
/* Run once to get the length of the string. */ |
||||
va_list args_copy; |
||||
va_copy(args_copy, args); |
||||
int len = _upb_vsnprintf(NULL, 0, fmt, args_copy); |
||||
va_end(args_copy); |
||||
|
||||
char *ret = malloc(len + 1); /* + 1 for NULL terminator. */ |
||||
if (!ret) abort(); |
||||
int written = _upb_vsnprintf(ret, len + 1, fmt, args); |
||||
UPB_ASSERT(written == len); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static char *upb_asprintf(const char *fmt, ...) { |
||||
va_list args; |
||||
va_start(args, fmt); |
||||
char *ret = upb_vasprintf(fmt, args); |
||||
va_end(args); |
||||
return ret; |
||||
} |
||||
|
||||
#endif |
||||
|
||||
static int alloc_pclabel(jitcompiler *jc) { |
||||
int newpc = jc->pclabel_count++; |
||||
dasm_growpc(jc, jc->pclabel_count); |
||||
return newpc; |
||||
} |
||||
|
||||
static bool try_getjmptarget(jitcompiler *jc, const void *key, int *pclabel) { |
||||
upb_value v; |
||||
if (upb_inttable_lookupptr(&jc->jmptargets, key, &v)) { |
||||
*pclabel = upb_value_getuint32(v); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/* Gets the pclabel for this bytecode location's jmptarget. Requires that the
|
||||
* jmptarget() has been previously defined. */ |
||||
static int getjmptarget(jitcompiler *jc, const void *key) { |
||||
int pclabel = 0; |
||||
bool ok; |
||||
|
||||
UPB_ASSERT_DEBUGVAR(upb_inttable_lookupptr(&jc->jmpdefined, key, NULL)); |
||||
ok = try_getjmptarget(jc, key, &pclabel); |
||||
UPB_ASSERT(ok); |
||||
return pclabel; |
||||
} |
||||
|
||||
/* Returns a pclabel that serves as a jmp target for the given bytecode pointer.
|
||||
* This should only be called for code that is jumping to the target; code |
||||
* defining the target should use define_jmptarget(). |
||||
* |
||||
* Creates/allocates a pclabel for this target if one does not exist already. */ |
||||
static int jmptarget(jitcompiler *jc, const void *key) { |
||||
/* Optimizer sometimes can't figure out that initializing this is unnecessary.
|
||||
*/ |
||||
int pclabel = 0; |
||||
if (!try_getjmptarget(jc, key, &pclabel)) { |
||||
pclabel = alloc_pclabel(jc); |
||||
upb_inttable_insertptr(&jc->jmptargets, key, upb_value_uint32(pclabel)); |
||||
} |
||||
return pclabel; |
||||
} |
||||
|
||||
/* Defines a pclabel associated with the given bytecode location.
|
||||
* Must be called exactly once by the code that is generating the code for this |
||||
* bytecode. |
||||
* |
||||
* Must be called exactly once before bytecode generation is complete (this is a |
||||
* sanity check to make sure the label is defined exactly once). */ |
||||
static int define_jmptarget(jitcompiler *jc, const void *key) { |
||||
#ifndef NDEBUG |
||||
upb_inttable_insertptr(&jc->jmpdefined, key, upb_value_bool(true)); |
||||
#endif |
||||
return jmptarget(jc, key); |
||||
} |
||||
|
||||
/* Returns a bytecode pc offset relative to the beginning of the group's
|
||||
* code. */ |
||||
static int pcofs(jitcompiler *jc) { |
||||
return jc->pc - jc->group->bytecode; |
||||
} |
||||
|
||||
/* Returns a machine code offset corresponding to the given key.
|
||||
* Requires that this key was defined with define_jmptarget. */ |
||||
static int machine_code_ofs(jitcompiler *jc, const void *key) { |
||||
int pclabel = getjmptarget(jc, key); |
||||
/* Despite its name, this function takes a pclabel and returns the
|
||||
* corresponding machine code offset. */ |
||||
return dasm_getpclabel(jc, pclabel); |
||||
} |
||||
|
||||
/* Returns a machine code offset corresponding to the given method-relative
|
||||
* bytecode offset. Note that the bytecode offset is relative to the given |
||||
* method, but the returned machine code offset is relative to the beginning of |
||||
* *all* the machine code. */ |
||||
static int machine_code_ofs2(jitcompiler *jc, const upb_pbdecodermethod *method, |
||||
int pcofs) { |
||||
void *bc_target = jc->group->bytecode + method->code_base.ofs + pcofs; |
||||
return machine_code_ofs(jc, bc_target); |
||||
} |
||||
|
||||
/* Given a pcofs relative to this method's base, returns a machine code offset
|
||||
* relative to jmptarget(dispatch->array) (which is used in jitdispatch as the |
||||
* machine code base for dispatch table lookups). */ |
||||
uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method, |
||||
int pcofs) { |
||||
int mc_base = machine_code_ofs(jc, method->dispatch.array); |
||||
int mc_target = machine_code_ofs2(jc, method, pcofs); |
||||
int ret; |
||||
|
||||
UPB_ASSERT(mc_base > 0); |
||||
UPB_ASSERT(mc_target > 0); |
||||
ret = mc_target - mc_base; |
||||
UPB_ASSERT(ret > 0); |
||||
return ret; |
||||
} |
||||
|
||||
/* Rewrites the dispatch tables into machine code offsets. */ |
||||
static void patchdispatch(jitcompiler *jc) { |
||||
upb_inttable_iter i; |
||||
upb_inttable_begin(&i, &jc->group->methods); |
||||
for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); |
||||
upb_inttable *dispatch = &method->dispatch; |
||||
upb_inttable_iter i2; |
||||
|
||||
method->is_native_ = true; |
||||
|
||||
/* Remove DISPATCH_ENDMSG -- only the bytecode interpreter needs it.
|
||||
* And leaving it around will cause us to find field 0 improperly. */ |
||||
upb_inttable_remove(dispatch, DISPATCH_ENDMSG, NULL); |
||||
|
||||
upb_inttable_begin(&i2, dispatch); |
||||
for (; !upb_inttable_done(&i2); upb_inttable_next(&i2)) { |
||||
uintptr_t key = upb_inttable_iter_key(&i2); |
||||
uint64_t val = upb_value_getuint64(upb_inttable_iter_value(&i2)); |
||||
uint64_t newval; |
||||
bool ok; |
||||
if (key <= UPB_MAX_FIELDNUMBER) { |
||||
/* Primary slot. */ |
||||
uint64_t ofs; |
||||
uint8_t wt1; |
||||
uint8_t wt2; |
||||
upb_pbdecoder_unpackdispatch(val, &ofs, &wt1, &wt2); |
||||
|
||||
/* Update offset and repack. */ |
||||
ofs = dispatchofs(jc, method, ofs); |
||||
newval = upb_pbdecoder_packdispatch(ofs, wt1, wt2); |
||||
UPB_ASSERT((int64_t)newval > 0); |
||||
} else { |
||||
/* Secondary slot. Since we have 64 bits for the value, we use an
|
||||
* absolute offset. */ |
||||
int mcofs = machine_code_ofs2(jc, method, val); |
||||
newval = (uint64_t)((char*)jc->group->jit_code + mcofs); |
||||
} |
||||
ok = upb_inttable_replace(dispatch, key, upb_value_uint64(newval)); |
||||
UPB_ASSERT(ok); |
||||
} |
||||
|
||||
/* Update entry point for this method to point at mc base instead of bc
|
||||
* base. Set this only *after* we have patched the offsets |
||||
* (machine_code_ofs2() uses this). */ |
||||
method->code_base.ptr = (char*)jc->group->jit_code + machine_code_ofs(jc, method); |
||||
|
||||
{ |
||||
upb_byteshandler *h = &method->input_handler_; |
||||
upb_byteshandler_setstartstr(h, upb_pbdecoder_startjit, NULL); |
||||
upb_byteshandler_setstring(h, jc->group->jit_code, method->code_base.ptr); |
||||
upb_byteshandler_setendstr(h, upb_pbdecoder_end, method); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#ifdef UPB_JIT_LOAD_SO |
||||
|
||||
static void load_so(jitcompiler *jc) { |
||||
/* Dump to a .so file in /tmp and load that, so all the tooling works right
|
||||
* (for example, debuggers and profilers will see symbol names for the JIT-ted |
||||
* code). This is the same goal of the GDB JIT code below, but the GDB JIT |
||||
* interface is only used/understood by GDB. Hopefully a standard will |
||||
* develop for registering JIT-ted code that all tools will recognize, |
||||
* rendering this obsolete. |
||||
* |
||||
* jc->asmlabels maps: |
||||
* pclabel -> char* label |
||||
* |
||||
* Use this to build mclabels, which maps: |
||||
* machine code offset -> char* label |
||||
* |
||||
* Then we can use mclabels to emit the labels as we iterate over the bytes we |
||||
* are outputting. */ |
||||
upb_inttable_iter i; |
||||
upb_inttable mclabels; |
||||
upb_inttable_init(&mclabels, UPB_CTYPE_PTR); |
||||
upb_inttable_begin(&i, &jc->asmlabels); |
||||
for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
upb_inttable_insert(&mclabels, |
||||
dasm_getpclabel(jc, upb_inttable_iter_key(&i)), |
||||
upb_inttable_iter_value(&i)); |
||||
} |
||||
|
||||
/* We write a .s file in text format, as input to the assembler.
|
||||
* Then we run gcc to turn it into a .so file. |
||||
* |
||||
* The last "XXXXXX" will be replaced with something randomly generated by |
||||
* mkstmemp(). We don't add ".s" to this filename because it makes the string |
||||
* processing for mkstemp() and system() more complicated. */ |
||||
char s_filename[] = "/tmp/upb-jit-codeXXXXXX"; |
||||
int fd = mkstemp(s_filename); |
||||
FILE *f; |
||||
if (fd >= 0 && (f = fdopen(fd, "wb")) != NULL) { |
||||
uint8_t *jit_code = (uint8_t*)jc->group->jit_code; |
||||
size_t linelen = 0; |
||||
size_t i; |
||||
fputs(" .text\n\n", f); |
||||
for (i = 0; i < jc->group->jit_size; i++) { |
||||
upb_value v; |
||||
if (upb_inttable_lookup(&mclabels, i, &v)) { |
||||
const char *label = upb_value_getptr(v); |
||||
/* "X." makes our JIT syms recognizable as such, which we build into
|
||||
* other tooling. */ |
||||
fprintf(f, "\n\nX.%s:\n", label); |
||||
fprintf(f, " .globl X.%s", label); |
||||
linelen = 1000; |
||||
} |
||||
if (linelen >= 77) { |
||||
linelen = fprintf(f, "\n .byte %u", jit_code[i]); |
||||
} else { |
||||
linelen += fprintf(f, ",%u", jit_code[i]); |
||||
} |
||||
} |
||||
fputs("\n", f); |
||||
fclose(f); |
||||
} else { |
||||
fprintf(stderr, "Error opening tmp file for JIT debug output.\n"); |
||||
abort(); |
||||
} |
||||
|
||||
/* This is exploitable if you have an adversary on your machine who can write
|
||||
* to this tmp directory. But this is just for debugging so we don't worry |
||||
* too much about that. It shouldn't be prone to races against concurrent |
||||
* (non-adversarial) upb JIT's because we used mkstemp(). */ |
||||
char *cmd = upb_asprintf("gcc -shared -o %s.so -x assembler %s", s_filename, |
||||
s_filename); |
||||
if (system(cmd) != 0) { |
||||
fprintf(stderr, "Error compiling %s\n", s_filename); |
||||
abort(); |
||||
} |
||||
free(cmd); |
||||
|
||||
char *so_filename = upb_asprintf("%s.so", s_filename); |
||||
|
||||
/* Some convenience symlinks.
|
||||
* This is racy, but just for convenience. */ |
||||
int ret; |
||||
unlink("/tmp/upb-jit-code.so"); |
||||
unlink("/tmp/upb-jit-code.s"); |
||||
ret = symlink(s_filename, "/tmp/upb-jit-code.s"); |
||||
ret = symlink(so_filename, "/tmp/upb-jit-code.so"); |
||||
UPB_UNUSED(ret); // We don't care if this fails.
|
||||
|
||||
jc->group->dl = dlopen(so_filename, RTLD_LAZY); |
||||
free(so_filename); |
||||
if (!jc->group->dl) { |
||||
fprintf(stderr, "Couldn't dlopen(): %s\n", dlerror()); |
||||
abort(); |
||||
} |
||||
|
||||
munmap(jc->group->jit_code, jc->group->jit_size); |
||||
jc->group->jit_code = dlsym(jc->group->dl, "X.enterjit"); |
||||
if (!jc->group->jit_code) { |
||||
fprintf(stderr, "Couldn't find enterjit sym\n"); |
||||
abort(); |
||||
} |
||||
|
||||
upb_inttable_uninit(&mclabels); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
void upb_pbdecoder_jit(mgroup *group) { |
||||
jitcompiler *jc; |
||||
char *jit_code; |
||||
int dasm_status; |
||||
|
||||
group->debug_info = NULL; |
||||
group->dl = NULL; |
||||
|
||||
UPB_ASSERT(group->bytecode); |
||||
jc = newjitcompiler(group); |
||||
emit_static_asm(jc); |
||||
jitbytecode(jc); |
||||
|
||||
dasm_status = dasm_link(jc, &jc->group->jit_size); |
||||
if (dasm_status != DASM_S_OK) { |
||||
fprintf(stderr, "DynASM error; returned status: 0x%08x\n", dasm_status); |
||||
abort(); |
||||
} |
||||
|
||||
jit_code = mmap(NULL, jc->group->jit_size, PROT_READ | PROT_WRITE, |
||||
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
||||
dasm_encode(jc, jit_code); |
||||
mprotect(jit_code, jc->group->jit_size, PROT_EXEC | PROT_READ); |
||||
jc->group->jit_code = (upb_string_handlerfunc *)jit_code; |
||||
|
||||
#ifdef UPB_JIT_LOAD_SO |
||||
load_so(jc); |
||||
#endif |
||||
|
||||
patchdispatch(jc); |
||||
|
||||
freejitcompiler(jc); |
||||
|
||||
/* Now the bytecode is no longer needed. */ |
||||
free(group->bytecode); |
||||
group->bytecode = NULL; |
||||
} |
||||
|
||||
void upb_pbdecoder_freejit(mgroup *group) { |
||||
if (!group->jit_code) return; |
||||
if (group->dl) { |
||||
#ifdef UPB_JIT_LOAD_SO |
||||
dlclose(group->dl); |
||||
#endif |
||||
} else { |
||||
munmap((void*)group->jit_code, group->jit_size); |
||||
} |
||||
free(group->debug_info); |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue