ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

dasm_mips.h (12327B)


      1 /*
      2 ** DynASM MIPS encoding engine.
      3 ** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
      4 ** Released under the MIT license. See dynasm.lua for full copyright notice.
      5 */
      6 
      7 #include <stddef.h>
      8 #include <stdarg.h>
      9 #include <string.h>
     10 #include <stdlib.h>
     11 
     12 #define DASM_ARCH		"mips"
     13 
     14 #ifndef DASM_EXTERN
     15 #define DASM_EXTERN(a,b,c,d)	0
     16 #endif
     17 
     18 /* Action definitions. */
     19 enum {
     20   DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
     21   /* The following actions need a buffer position. */
     22   DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
     23   /* The following actions also have an argument. */
     24   DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS,
     25   DASM__MAX
     26 };
     27 
     28 /* Maximum number of section buffer positions for a single dasm_put() call. */
     29 #define DASM_MAXSECPOS		25
     30 
     31 /* DynASM encoder status codes. Action list offset or number are or'ed in. */
     32 #define DASM_S_OK		0x00000000
     33 #define DASM_S_NOMEM		0x01000000
     34 #define DASM_S_PHASE		0x02000000
     35 #define DASM_S_MATCH_SEC	0x03000000
     36 #define DASM_S_RANGE_I		0x11000000
     37 #define DASM_S_RANGE_SEC	0x12000000
     38 #define DASM_S_RANGE_LG		0x13000000
     39 #define DASM_S_RANGE_PC		0x14000000
     40 #define DASM_S_RANGE_REL	0x15000000
     41 #define DASM_S_UNDEF_LG		0x21000000
     42 #define DASM_S_UNDEF_PC		0x22000000
     43 
     44 /* Macros to convert positions (8 bit section + 24 bit index). */
     45 #define DASM_POS2IDX(pos)	((pos)&0x00ffffff)
     46 #define DASM_POS2BIAS(pos)	((pos)&0xff000000)
     47 #define DASM_SEC2POS(sec)	((sec)<<24)
     48 #define DASM_POS2SEC(pos)	((pos)>>24)
     49 #define DASM_POS2PTR(D, pos)	(D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
     50 
     51 /* Action list type. */
     52 typedef const unsigned int *dasm_ActList;
     53 
     54 /* Per-section structure. */
     55 typedef struct dasm_Section {
     56   int *rbuf;		/* Biased buffer pointer (negative section bias). */
     57   int *buf;		/* True buffer pointer. */
     58   size_t bsize;		/* Buffer size in bytes. */
     59   int pos;		/* Biased buffer position. */
     60   int epos;		/* End of biased buffer position - max single put. */
     61   int ofs;		/* Byte offset into section. */
     62 } dasm_Section;
     63 
     64 /* Core structure holding the DynASM encoding state. */
     65 struct dasm_State {
     66   size_t psize;			/* Allocated size of this structure. */
     67   dasm_ActList actionlist;	/* Current actionlist pointer. */
     68   int *lglabels;		/* Local/global chain/pos ptrs. */
     69   size_t lgsize;
     70   int *pclabels;		/* PC label chains/pos ptrs. */
     71   size_t pcsize;
     72   void **globals;		/* Array of globals (bias -10). */
     73   dasm_Section *section;	/* Pointer to active section. */
     74   size_t codesize;		/* Total size of all code sections. */
     75   int maxsection;		/* 0 <= sectionidx < maxsection. */
     76   int status;			/* Status code. */
     77   dasm_Section sections[1];	/* All sections. Alloc-extended. */
     78 };
     79 
     80 /* The size of the core structure depends on the max. number of sections. */
     81 #define DASM_PSZ(ms)	(sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
     82 
     83 
     84 /* Initialize DynASM state. */
     85 void dasm_init(Dst_DECL, int maxsection)
     86 {
     87   dasm_State *D;
     88   size_t psz = 0;
     89   int i;
     90   Dst_REF = NULL;
     91   DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
     92   D = Dst_REF;
     93   D->psize = psz;
     94   D->lglabels = NULL;
     95   D->lgsize = 0;
     96   D->pclabels = NULL;
     97   D->pcsize = 0;
     98   D->globals = NULL;
     99   D->maxsection = maxsection;
    100   for (i = 0; i < maxsection; i++) {
    101     D->sections[i].buf = NULL;  /* Need this for pass3. */
    102     D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
    103     D->sections[i].bsize = 0;
    104     D->sections[i].epos = 0;  /* Wrong, but is recalculated after resize. */
    105   }
    106 }
    107 
    108 /* Free DynASM state. */
    109 void dasm_free(Dst_DECL)
    110 {
    111   dasm_State *D = Dst_REF;
    112   int i;
    113   for (i = 0; i < D->maxsection; i++)
    114     if (D->sections[i].buf)
    115       DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
    116   if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
    117   if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
    118   DASM_M_FREE(Dst, D, D->psize);
    119 }
    120 
    121 /* Setup global label array. Must be called before dasm_setup(). */
    122 void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
    123 {
    124   dasm_State *D = Dst_REF;
    125   D->globals = gl - 10;  /* Negative bias to compensate for locals. */
    126   DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
    127 }
    128 
    129 /* Grow PC label array. Can be called after dasm_setup(), too. */
    130 void dasm_growpc(Dst_DECL, unsigned int maxpc)
    131 {
    132   dasm_State *D = Dst_REF;
    133   size_t osz = D->pcsize;
    134   DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
    135   memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
    136 }
    137 
    138 /* Setup encoder. */
    139 void dasm_setup(Dst_DECL, const void *actionlist)
    140 {
    141   dasm_State *D = Dst_REF;
    142   int i;
    143   D->actionlist = (dasm_ActList)actionlist;
    144   D->status = DASM_S_OK;
    145   D->section = &D->sections[0];
    146   memset((void *)D->lglabels, 0, D->lgsize);
    147   if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
    148   for (i = 0; i < D->maxsection; i++) {
    149     D->sections[i].pos = DASM_SEC2POS(i);
    150     D->sections[i].ofs = 0;
    151   }
    152 }
    153 
    154 
    155 #ifdef DASM_CHECKS
    156 #define CK(x, st) \
    157   do { if (!(x)) { \
    158     D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
    159 #define CKPL(kind, st) \
    160   do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
    161     D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
    162 #else
    163 #define CK(x, st)	((void)0)
    164 #define CKPL(kind, st)	((void)0)
    165 #endif
    166 
    167 /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
    168 void dasm_put(Dst_DECL, int start, ...)
    169 {
    170   va_list ap;
    171   dasm_State *D = Dst_REF;
    172   dasm_ActList p = D->actionlist + start;
    173   dasm_Section *sec = D->section;
    174   int pos = sec->pos, ofs = sec->ofs;
    175   int *b;
    176 
    177   if (pos >= sec->epos) {
    178     DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
    179       sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
    180     sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
    181     sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
    182   }
    183 
    184   b = sec->rbuf;
    185   b[pos++] = start;
    186 
    187   va_start(ap, start);
    188   while (1) {
    189     unsigned int ins = *p++;
    190     unsigned int action = (ins >> 16) - 0xff00;
    191     if (action >= DASM__MAX) {
    192       ofs += 4;
    193     } else {
    194       int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
    195       switch (action) {
    196       case DASM_STOP: goto stop;
    197       case DASM_SECTION:
    198 	n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
    199 	D->section = &D->sections[n]; goto stop;
    200       case DASM_ESC: p++; ofs += 4; break;
    201       case DASM_REL_EXT: break;
    202       case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
    203       case DASM_REL_LG:
    204 	n = (ins & 2047) - 10; pl = D->lglabels + n;
    205 	/* Bkwd rel or global. */
    206 	if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
    207 	pl += 10; n = *pl;
    208 	if (n < 0) n = 0;  /* Start new chain for fwd rel if label exists. */
    209 	goto linkrel;
    210       case DASM_REL_PC:
    211 	pl = D->pclabels + n; CKPL(pc, PC);
    212       putrel:
    213 	n = *pl;
    214 	if (n < 0) {  /* Label exists. Get label pos and store it. */
    215 	  b[pos] = -n;
    216 	} else {
    217       linkrel:
    218 	  b[pos] = n;  /* Else link to rel chain, anchored at label. */
    219 	  *pl = pos;
    220 	}
    221 	pos++;
    222 	break;
    223       case DASM_LABEL_LG:
    224 	pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
    225       case DASM_LABEL_PC:
    226 	pl = D->pclabels + n; CKPL(pc, PC);
    227       putlabel:
    228 	n = *pl;  /* n > 0: Collapse rel chain and replace with label pos. */
    229 	while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
    230 	}
    231 	*pl = -pos;  /* Label exists now. */
    232 	b[pos++] = ofs;  /* Store pass1 offset estimate. */
    233 	break;
    234       case DASM_IMM: case DASM_IMMS:
    235 #ifdef DASM_CHECKS
    236 	CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
    237 #endif
    238 	n >>= ((ins>>10)&31);
    239 #ifdef DASM_CHECKS
    240 	if (ins & 0x8000)
    241 	  CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
    242 	else
    243 	  CK((n>>((ins>>5)&31)) == 0, RANGE_I);
    244 #endif
    245 	b[pos++] = n;
    246 	break;
    247       }
    248     }
    249   }
    250 stop:
    251   va_end(ap);
    252   sec->pos = pos;
    253   sec->ofs = ofs;
    254 }
    255 #undef CK
    256 
    257 /* Pass 2: Link sections, shrink aligns, fix label offsets. */
    258 int dasm_link(Dst_DECL, size_t *szp)
    259 {
    260   dasm_State *D = Dst_REF;
    261   int secnum;
    262   int ofs = 0;
    263 
    264 #ifdef DASM_CHECKS
    265   *szp = 0;
    266   if (D->status != DASM_S_OK) return D->status;
    267   {
    268     int pc;
    269     for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
    270       if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
    271   }
    272 #endif
    273 
    274   { /* Handle globals not defined in this translation unit. */
    275     int idx;
    276     for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
    277       int n = D->lglabels[idx];
    278       /* Undefined label: Collapse rel chain and replace with marker (< 0). */
    279       while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
    280     }
    281   }
    282 
    283   /* Combine all code sections. No support for data sections (yet). */
    284   for (secnum = 0; secnum < D->maxsection; secnum++) {
    285     dasm_Section *sec = D->sections + secnum;
    286     int *b = sec->rbuf;
    287     int pos = DASM_SEC2POS(secnum);
    288     int lastpos = sec->pos;
    289 
    290     while (pos != lastpos) {
    291       dasm_ActList p = D->actionlist + b[pos++];
    292       while (1) {
    293 	unsigned int ins = *p++;
    294 	unsigned int action = (ins >> 16) - 0xff00;
    295 	switch (action) {
    296 	case DASM_STOP: case DASM_SECTION: goto stop;
    297 	case DASM_ESC: p++; break;
    298 	case DASM_REL_EXT: break;
    299 	case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
    300 	case DASM_REL_LG: case DASM_REL_PC: pos++; break;
    301 	case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
    302 	case DASM_IMM: case DASM_IMMS: pos++; break;
    303 	}
    304       }
    305       stop: (void)0;
    306     }
    307     ofs += sec->ofs;  /* Next section starts right after current section. */
    308   }
    309 
    310   D->codesize = ofs;  /* Total size of all code sections */
    311   *szp = ofs;
    312   return DASM_S_OK;
    313 }
    314 
    315 #ifdef DASM_CHECKS
    316 #define CK(x, st) \
    317   do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
    318 #else
    319 #define CK(x, st)	((void)0)
    320 #endif
    321 
    322 /* Pass 3: Encode sections. */
    323 int dasm_encode(Dst_DECL, void *buffer)
    324 {
    325   dasm_State *D = Dst_REF;
    326   char *base = (char *)buffer;
    327   unsigned int *cp = (unsigned int *)buffer;
    328   int secnum;
    329 
    330   /* Encode all code sections. No support for data sections (yet). */
    331   for (secnum = 0; secnum < D->maxsection; secnum++) {
    332     dasm_Section *sec = D->sections + secnum;
    333     int *b = sec->buf;
    334     int *endb = sec->rbuf + sec->pos;
    335 
    336     while (b != endb) {
    337       dasm_ActList p = D->actionlist + *b++;
    338       while (1) {
    339 	unsigned int ins = *p++;
    340 	unsigned int action = (ins >> 16) - 0xff00;
    341 	int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
    342 	switch (action) {
    343 	case DASM_STOP: case DASM_SECTION: goto stop;
    344 	case DASM_ESC: *cp++ = *p++; break;
    345 	case DASM_REL_EXT:
    346 	  n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
    347 	  goto patchrel;
    348 	case DASM_ALIGN:
    349 	  ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
    350 	  break;
    351 	case DASM_REL_LG:
    352 	  CK(n >= 0, UNDEF_LG);
    353 	case DASM_REL_PC:
    354 	  CK(n >= 0, UNDEF_PC);
    355 	  n = *DASM_POS2PTR(D, n);
    356 	  if (ins & 2048)
    357 	    n = n - (int)((char *)cp - base);
    358 	  else
    359 	    n = (n + (int)(size_t)base) & 0x0fffffff;
    360 	patchrel:
    361 	  CK((n & 3) == 0 &&
    362 	     ((n + ((ins & 2048) ? 0x00020000 : 0)) >>
    363 	       ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL);
    364 	  cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff));
    365 	  break;
    366 	case DASM_LABEL_LG:
    367 	  ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
    368 	  break;
    369 	case DASM_LABEL_PC: break;
    370 	case DASM_IMMS:
    371 	  cp[-1] |= ((n>>3) & 4); n &= 0x1f;
    372 	  /* fallthrough */
    373 	case DASM_IMM:
    374 	  cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
    375 	  break;
    376 	default: *cp++ = ins; break;
    377 	}
    378       }
    379       stop: (void)0;
    380     }
    381   }
    382 
    383   if (base + D->codesize != (char *)cp)  /* Check for phase errors. */
    384     return DASM_S_PHASE;
    385   return DASM_S_OK;
    386 }
    387 #undef CK
    388 
    389 /* Get PC label offset. */
    390 int dasm_getpclabel(Dst_DECL, unsigned int pc)
    391 {
    392   dasm_State *D = Dst_REF;
    393   if (pc*sizeof(int) < D->pcsize) {
    394     int pos = D->pclabels[pc];
    395     if (pos < 0) return *DASM_POS2PTR(D, -pos);
    396     if (pos > 0) return -1;  /* Undefined. */
    397   }
    398   return -2;  /* Unused or out of range. */
    399 }
    400 
    401 #ifdef DASM_CHECKS
    402 /* Optional sanity checker to call between isolated encoding steps. */
    403 int dasm_checkstep(Dst_DECL, int secmatch)
    404 {
    405   dasm_State *D = Dst_REF;
    406   if (D->status == DASM_S_OK) {
    407     int i;
    408     for (i = 1; i <= 9; i++) {
    409       if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
    410       D->lglabels[i] = 0;
    411     }
    412   }
    413   if (D->status == DASM_S_OK && secmatch >= 0 &&
    414       D->section != &D->sections[secmatch])
    415     D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
    416   return D->status;
    417 }
    418 #endif
    419