root/host/buildvm_asm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. emit_asm_bytes
  2. emit_asm_reloc
  3. emit_asm_reloc_mach
  4. emit_asm_words
  5. emit_asm_wordreloc
  6. emit_asm_label
  7. emit_asm_align
  8. emit_asm

   1 /*
   2 ** LuaJIT VM builder: Assembler source code emitter.
   3 ** Copyright (C) 2005-2017 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 relocation for the incredibly stupid OSX assembler. */
  55 static void emit_asm_reloc_mach(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   fprintf(ctx->fp, "\t%s %s\n", opname, sym);
  75 }
  76 #else
  77 /* Emit words piecewise as assembler text. */
  78 static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
  79 {
  80   int i;
  81   for (i = 0; i < n; i += 4) {
  82     if ((i & 15) == 0)
  83       fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i));
  84     else
  85       fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i));
  86     if ((i & 15) == 12) putc('\n', ctx->fp);
  87   }
  88   if ((n & 15) != 0) putc('\n', ctx->fp);
  89 }
  90 
  91 /* Emit relocation as part of an instruction. */
  92 static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
  93                                const char *sym)
  94 {
  95   uint32_t ins;
  96   emit_asm_words(ctx, p, n-4);
  97   ins = *(uint32_t *)(p+n-4);
  98 #if LJ_TARGET_ARM
  99   if ((ins & 0xff000000u) == 0xfa000000u) {
 100     fprintf(ctx->fp, "\tblx %s\n", sym);
 101   } else if ((ins & 0x0e000000u) == 0x0a000000u) {
 102     fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
 103             &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
 104   } else {
 105     fprintf(stderr,
 106             "Error: unsupported opcode %08x for %s symbol relocation.\n",
 107             ins, sym);
 108     exit(1);
 109   }
 110 #elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
 111 #if LJ_TARGET_PS3
 112 #define TOCPREFIX "."
 113 #else
 114 #define TOCPREFIX ""
 115 #endif
 116   if ((ins >> 26) == 16) {
 117     fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
 118             (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
 119   } else if ((ins >> 26) == 18) {
 120     fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
 121   } else {
 122     fprintf(stderr,
 123             "Error: unsupported opcode %08x for %s symbol relocation.\n",
 124             ins, sym);
 125     exit(1);
 126   }
 127 #elif LJ_TARGET_MIPS
 128   fprintf(stderr,
 129           "Error: unsupported opcode %08x for %s symbol relocation.\n",
 130           ins, sym);
 131   exit(1);
 132 #else
 133 #error "missing relocation support for this architecture"
 134 #endif
 135 }
 136 #endif
 137 
 138 #if LJ_TARGET_ARM
 139 #define ELFASM_PX       "%%"
 140 #else
 141 #define ELFASM_PX       "@"
 142 #endif
 143 
 144 /* Emit an assembler label. */
 145 static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
 146 {
 147   switch (ctx->mode) {
 148   case BUILD_elfasm:
 149 #if LJ_TARGET_PS3
 150     if (!strncmp(name, "lj_vm_", 6) &&
 151         strcmp(name, ctx->beginsym) &&
 152         !strstr(name, "hook")) {
 153       fprintf(ctx->fp,
 154         "\n\t.globl %s\n"
 155         "\t.section \".opd\",\"aw\"\n"
 156         "%s:\n"
 157         "\t.long .%s,.TOC.@tocbase32\n"
 158         "\t.size %s,8\n"
 159         "\t.previous\n"
 160         "\t.globl .%s\n"
 161         "\t.hidden .%s\n"
 162         "\t.type .%s, " ELFASM_PX "function\n"
 163         "\t.size .%s, %d\n"
 164         ".%s:\n",
 165         name, name, name, name, name, name, name, name, size, name);
 166       break;
 167     }
 168 #endif
 169     fprintf(ctx->fp,
 170       "\n\t.globl %s\n"
 171       "\t.hidden %s\n"
 172       "\t.type %s, " ELFASM_PX "%s\n"
 173       "\t.size %s, %d\n"
 174       "%s:\n",
 175       name, name, name, isfunc ? "function" : "object", name, size, name);
 176     break;
 177   case BUILD_coffasm:
 178     fprintf(ctx->fp, "\n\t.globl %s\n", name);
 179     if (isfunc)
 180       fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
 181     fprintf(ctx->fp, "%s:\n", name);
 182     break;
 183   case BUILD_machasm:
 184     fprintf(ctx->fp,
 185       "\n\t.private_extern %s\n"
 186       "\t.no_dead_strip %s\n"
 187       "%s:\n", name, name, name);
 188     break;
 189   default:
 190     break;
 191   }
 192 }
 193 
 194 /* Emit alignment. */
 195 static void emit_asm_align(BuildCtx *ctx, int bits)
 196 {
 197   switch (ctx->mode) {
 198   case BUILD_elfasm:
 199   case BUILD_coffasm:
 200     fprintf(ctx->fp, "\t.p2align %d\n", bits);
 201     break;
 202   case BUILD_machasm:
 203     fprintf(ctx->fp, "\t.align %d\n", bits);
 204     break;
 205   default:
 206     break;
 207   }
 208 }
 209 
 210 /* ------------------------------------------------------------------------ */
 211 
 212 /* Emit assembler source code. */
 213 void emit_asm(BuildCtx *ctx)
 214 {
 215   int i, rel;
 216 
 217   fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
 218   fprintf(ctx->fp, "\t.text\n");
 219   emit_asm_align(ctx, 4);
 220 
 221 #if LJ_TARGET_PS3
 222   emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
 223 #else
 224   emit_asm_label(ctx, ctx->beginsym, 0, 0);
 225 #endif
 226   if (ctx->mode != BUILD_machasm)
 227     fprintf(ctx->fp, ".Lbegin:\n");
 228 
 229 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
 230   /* This should really be moved into buildvm_arm.dasc. */
 231   fprintf(ctx->fp,
 232           ".fnstart\n"
 233           ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
 234           ".pad #28\n");
 235 #endif
 236 #if LJ_TARGET_MIPS
 237   fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
 238 #endif
 239 
 240   for (i = rel = 0; i < ctx->nsym; i++) {
 241     int32_t ofs = ctx->sym[i].ofs;
 242     int32_t next = ctx->sym[i+1].ofs;
 243 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
 244     if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
 245       fprintf(ctx->fp,
 246               ".globl lj_err_unwind_arm\n"
 247               ".personality lj_err_unwind_arm\n"
 248               ".fnend\n"
 249               ".fnstart\n"
 250               ".save {r4, r5, r11, lr}\n"
 251               ".setfp r11, sp\n");
 252 #endif
 253     emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
 254     while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
 255       BuildReloc *r = &ctx->reloc[rel];
 256       int n = r->ofs - ofs;
 257 #if LJ_TARGET_X86ORX64
 258       if (ctx->mode == BUILD_machasm && r->type != 0) {
 259         emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
 260       } else {
 261         emit_asm_bytes(ctx, ctx->code+ofs, n);
 262         emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
 263       }
 264       ofs += n+4;
 265 #else
 266       emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
 267       ofs += n;
 268 #endif
 269       rel++;
 270     }
 271 #if LJ_TARGET_X86ORX64
 272     emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
 273 #else
 274     emit_asm_words(ctx, ctx->code+ofs, next-ofs);
 275 #endif
 276   }
 277 
 278 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
 279   fprintf(ctx->fp,
 280 #if !LJ_HASFFI
 281           ".globl lj_err_unwind_arm\n"
 282           ".personality lj_err_unwind_arm\n"
 283 #endif
 284           ".fnend\n");
 285 #endif
 286 
 287   fprintf(ctx->fp, "\n");
 288   switch (ctx->mode) {
 289   case BUILD_elfasm:
 290 #if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
 291     fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
 292 #endif
 293 #if LJ_TARGET_PPCSPE
 294     /* Soft-float ABI + SPE. */
 295     fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
 296 #elif LJ_TARGET_PPC && !LJ_TARGET_PS3
 297     /* Hard-float ABI. */
 298     fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
 299 #endif
 300     /* fallthrough */
 301   case BUILD_coffasm:
 302     fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
 303     break;
 304   case BUILD_machasm:
 305     fprintf(ctx->fp,
 306       "\t.cstring\n"
 307       "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
 308     break;
 309   default:
 310     break;
 311   }
 312   fprintf(ctx->fp, "\n");
 313 }
 314 

/* [<][>][^][v][top][bottom][index][help] */