ljx

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

buildvm_asm.c (9389B)


      1 /*
      2 ** LuaJIT VM builder: Assembler source code emitter.
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 */
      5 
      6 #include "buildvm.h"
      7 #include "lj_bc.h"
      8 
      9 /* ------------------------------------------------------------------------ */
     10 
     11 #if LJ_TARGET_X86ORX64
     12 /* Emit bytes piecewise as assembler text. */
     13 static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
     14 {
     15   int i;
     16   for (i = 0; i < n; i++) {
     17     if ((i & 15) == 0)
     18       fprintf(ctx->fp, "\t.byte %d", p[i]);
     19     else
     20       fprintf(ctx->fp, ",%d", p[i]);
     21     if ((i & 15) == 15) putc('\n', ctx->fp);
     22   }
     23   if ((n & 15) != 0) putc('\n', ctx->fp);
     24 }
     25 
     26 /* Emit relocation */
     27 static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
     28 {
     29   switch (ctx->mode) {
     30   case BUILD_elfasm:
     31     if (type)
     32       fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
     33     else
     34       fprintf(ctx->fp, "\t.long %s\n", sym);
     35     break;
     36   case BUILD_coffasm:
     37     fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
     38     if (type)
     39       fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
     40     else
     41       fprintf(ctx->fp, "\t.long %s\n", sym);
     42     break;
     43   default:  /* BUILD_machasm for relative relocations handled below. */
     44     fprintf(ctx->fp, "\t.long %s\n", sym);
     45     break;
     46   }
     47 }
     48 
     49 static const char *const jccnames[] = {
     50   "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
     51   "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
     52 };
     53 
     54 /* Emit x86/x64 text relocations. */
     55 static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n,
     56 				const char *sym)
     57 {
     58   const char *opname = NULL;
     59   if (--n < 0) goto err;
     60   if (cp[n] == 0xe8) {
     61     opname = "call";
     62   } else if (cp[n] == 0xe9) {
     63     opname = "jmp";
     64   } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
     65     opname = jccnames[cp[n]-0x80];
     66     n--;
     67   } else {
     68 err:
     69     fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
     70 	    sym);
     71     exit(1);
     72   }
     73   emit_asm_bytes(ctx, cp, n);
     74   if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) {
     75     /* Various fixups for external symbols outside of our binary. */
     76     if (ctx->mode == BUILD_elfasm) {
     77       if (LJ_32)
     78 	fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym);
     79       fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym);
     80       if (LJ_32)
     81 	fprintf(ctx->fp, "#endif\n");
     82       return;
     83     } else if (LJ_32 && ctx->mode == BUILD_machasm) {
     84       fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym);
     85       return;
     86     }
     87   }
     88   fprintf(ctx->fp, "\t%s %s\n", opname, sym);
     89 }
     90 #else
     91 /* Emit words piecewise as assembler text. */
     92 static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
     93 {
     94   int i;
     95   for (i = 0; i < n; i += 4) {
     96     if ((i & 15) == 0)
     97       fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i));
     98     else
     99       fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i));
    100     if ((i & 15) == 12) putc('\n', ctx->fp);
    101   }
    102   if ((n & 15) != 0) putc('\n', ctx->fp);
    103 }
    104 
    105 /* Emit relocation as part of an instruction. */
    106 static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
    107 			       const char *sym)
    108 {
    109   uint32_t ins;
    110   emit_asm_words(ctx, p, n-4);
    111   ins = *(uint32_t *)(p+n-4);
    112 #if LJ_TARGET_ARM
    113   if ((ins & 0xff000000u) == 0xfa000000u) {
    114     fprintf(ctx->fp, "\tblx %s\n", sym);
    115   } else if ((ins & 0x0e000000u) == 0x0a000000u) {
    116     fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
    117 	    &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
    118   } else {
    119     fprintf(stderr,
    120 	    "Error: unsupported opcode %08x for %s symbol relocation.\n",
    121 	    ins, sym);
    122     exit(1);
    123   }
    124 #elif LJ_TARGET_ARM64
    125   if ((ins >> 26) == 0x25u) {
    126     fprintf(ctx->fp, "\tbl %s\n", sym);
    127   } else {
    128     fprintf(stderr,
    129 	    "Error: unsupported opcode %08x for %s symbol relocation.\n",
    130 	    ins, sym);
    131     exit(1);
    132   }
    133 #elif LJ_TARGET_PPC
    134 #if LJ_TARGET_PS3
    135 #define TOCPREFIX "."
    136 #else
    137 #define TOCPREFIX ""
    138 #endif
    139   if ((ins >> 26) == 16) {
    140     fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
    141 	    (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
    142   } else if ((ins >> 26) == 18) {
    143 #if LJ_ARCH_PPC64
    144     const char *suffix = strchr(sym, '@');
    145     if (suffix && suffix[1] == 'h') {
    146       fprintf(ctx->fp, "\taddis 11, 2, %s\n", sym);
    147     } else if (suffix && suffix[1] == 'l') {
    148       fprintf(ctx->fp, "\tld 12, %s\n", sym);
    149     } else
    150 #endif
    151     fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
    152   } else {
    153     fprintf(stderr,
    154 	    "Error: unsupported opcode %08x for %s symbol relocation.\n",
    155 	    ins, sym);
    156     exit(1);
    157   }
    158 #elif LJ_TARGET_MIPS
    159   fprintf(stderr,
    160 	  "Error: unsupported opcode %08x for %s symbol relocation.\n",
    161 	  ins, sym);
    162   exit(1);
    163 #else
    164 #error "missing relocation support for this architecture"
    165 #endif
    166 }
    167 #endif
    168 
    169 #if LJ_TARGET_ARM
    170 #define ELFASM_PX	"%%"
    171 #else
    172 #define ELFASM_PX	"@"
    173 #endif
    174 
    175 /* Emit an assembler label. */
    176 static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
    177 {
    178   switch (ctx->mode) {
    179   case BUILD_elfasm:
    180 #if LJ_TARGET_PS3
    181     if (!strncmp(name, "lj_vm_", 6) &&
    182 	strcmp(name, ctx->beginsym) &&
    183 	!strstr(name, "hook")) {
    184       fprintf(ctx->fp,
    185 	"\n\t.globl %s\n"
    186 	"\t.section \".opd\",\"aw\"\n"
    187 	"%s:\n"
    188 	"\t.long .%s,.TOC.@tocbase32\n"
    189 	"\t.size %s,8\n"
    190 	"\t.previous\n"
    191 	"\t.globl .%s\n"
    192 	"\t.hidden .%s\n"
    193 	"\t.type .%s, " ELFASM_PX "function\n"
    194 	"\t.size .%s, %d\n"
    195 	".%s:\n",
    196 	name, name, name, name, name, name, name, name, size, name);
    197       break;
    198     }
    199 #endif
    200     fprintf(ctx->fp,
    201       "\n\t.globl %s\n"
    202       "\t.hidden %s\n"
    203       "\t.type %s, " ELFASM_PX "%s\n"
    204       "\t.size %s, %d\n"
    205       "%s:\n",
    206       name, name, name, isfunc ? "function" : "object", name, size, name);
    207     break;
    208   case BUILD_coffasm:
    209     fprintf(ctx->fp, "\n\t.globl %s\n", name);
    210     if (isfunc)
    211       fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
    212     fprintf(ctx->fp, "%s:\n", name);
    213     break;
    214   case BUILD_machasm:
    215     fprintf(ctx->fp,
    216       "\n\t.private_extern %s\n"
    217       "%s:\n", name, name);
    218     break;
    219   default:
    220     break;
    221   }
    222 }
    223 
    224 /* Emit alignment. */
    225 static void emit_asm_align(BuildCtx *ctx, int bits)
    226 {
    227   switch (ctx->mode) {
    228   case BUILD_elfasm:
    229   case BUILD_coffasm:
    230     fprintf(ctx->fp, "\t.p2align %d\n", bits);
    231     break;
    232   case BUILD_machasm:
    233     fprintf(ctx->fp, "\t.align %d\n", bits);
    234     break;
    235   default:
    236     break;
    237   }
    238 }
    239 
    240 /* ------------------------------------------------------------------------ */
    241 
    242 /* Emit assembler source code. */
    243 void emit_asm(BuildCtx *ctx)
    244 {
    245   int i, rel;
    246 
    247   fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
    248 #if LJ_ARCH_PPC64
    249   fprintf(ctx->fp, "\t.abiversion 2\n");
    250 #endif
    251   fprintf(ctx->fp, "\t.text\n");
    252   emit_asm_align(ctx, 4);
    253 
    254 #if LJ_TARGET_PS3
    255   emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
    256 #else
    257   emit_asm_label(ctx, ctx->beginsym, 0, 0);
    258 #endif
    259   if (ctx->mode != BUILD_machasm)
    260     fprintf(ctx->fp, ".Lbegin:\n");
    261 
    262 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
    263   /* This should really be moved into buildvm_arm.dasc. */
    264 #if LJ_ARCH_HASFPU
    265   fprintf(ctx->fp,
    266 	  ".fnstart\n"
    267 	  ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n"
    268 	  ".vsave {d8-d15}\n"
    269 	  ".save {r4}\n"
    270 	  ".pad #28\n");
    271 #else
    272   fprintf(ctx->fp,
    273 	  ".fnstart\n"
    274 	  ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
    275 	  ".pad #28\n");
    276 #endif
    277 #endif
    278 #if LJ_TARGET_MIPS
    279   fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
    280 #endif
    281 
    282   for (i = rel = 0; i < ctx->nsym; i++) {
    283     int32_t ofs = ctx->sym[i].ofs;
    284     int32_t next = ctx->sym[i+1].ofs;
    285 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
    286     if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
    287       fprintf(ctx->fp,
    288 	      ".globl lj_err_unwind_arm\n"
    289 	      ".personality lj_err_unwind_arm\n"
    290 	      ".fnend\n"
    291 	      ".fnstart\n"
    292 	      ".save {r4, r5, r11, lr}\n"
    293 	      ".setfp r11, sp\n");
    294 #endif
    295     emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
    296     while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
    297       BuildReloc *r = &ctx->reloc[rel];
    298       int n = r->ofs - ofs;
    299 #if LJ_TARGET_X86ORX64
    300       if (r->type != 0 &&
    301 	  (ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) {
    302 	emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
    303       } else {
    304 	emit_asm_bytes(ctx, ctx->code+ofs, n);
    305 	emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
    306       }
    307       ofs += n+4;
    308 #else
    309       emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
    310       ofs += n;
    311 #endif
    312       rel++;
    313     }
    314 #if LJ_TARGET_X86ORX64
    315     emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
    316 #else
    317     emit_asm_words(ctx, ctx->code+ofs, next-ofs);
    318 #endif
    319   }
    320 
    321 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
    322   fprintf(ctx->fp,
    323 #if !LJ_HASFFI
    324 	  ".globl lj_err_unwind_arm\n"
    325 	  ".personality lj_err_unwind_arm\n"
    326 #endif
    327 	  ".fnend\n");
    328 #endif
    329 
    330   fprintf(ctx->fp, "\n");
    331   switch (ctx->mode) {
    332   case BUILD_elfasm:
    333 #if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
    334     fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
    335 #endif
    336 #if LJ_TARGET_PPC && !LJ_TARGET_PS3
    337     /* Hard-float ABI. */
    338     fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
    339 #endif
    340     /* fallthrough */
    341   case BUILD_coffasm:
    342     fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
    343     break;
    344   case BUILD_machasm:
    345     fprintf(ctx->fp,
    346       "\t.cstring\n"
    347       "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
    348     break;
    349   default:
    350     break;
    351   }
    352   fprintf(ctx->fp, "\n");
    353 }
    354