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_text
  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 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     uint32_t ins = *(uint32_t *)(p+i);
  97 #if LJ_TARGET_ARM64 && LJ_BE
  98     ins = lj_bswap(ins);  /* ARM64 instructions are always little-endian. */
  99 #endif
 100     if ((i & 15) == 0)
 101       fprintf(ctx->fp, "\t.long 0x%08x", ins);
 102     else
 103       fprintf(ctx->fp, ",0x%08x", ins);
 104     if ((i & 15) == 12) putc('\n', ctx->fp);
 105   }
 106   if ((n & 15) != 0) putc('\n', ctx->fp);
 107 }
 108 
 109 /* Emit relocation as part of an instruction. */
 110 static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
 111                                const char *sym)
 112 {
 113   uint32_t ins;
 114   emit_asm_words(ctx, p, n-4);
 115   ins = *(uint32_t *)(p+n-4);
 116 #if LJ_TARGET_ARM
 117   if ((ins & 0xff000000u) == 0xfa000000u) {
 118     fprintf(ctx->fp, "\tblx %s\n", sym);
 119   } else if ((ins & 0x0e000000u) == 0x0a000000u) {
 120     fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
 121             &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
 122   } else {
 123     fprintf(stderr,
 124             "Error: unsupported opcode %08x for %s symbol relocation.\n",
 125             ins, sym);
 126     exit(1);
 127   }
 128 #elif LJ_TARGET_ARM64
 129   if ((ins >> 26) == 0x25u) {
 130     fprintf(ctx->fp, "\tbl %s\n", sym);
 131   } else {
 132     fprintf(stderr,
 133             "Error: unsupported opcode %08x for %s symbol relocation.\n",
 134             ins, sym);
 135     exit(1);
 136   }
 137 #elif LJ_TARGET_PPC
 138 #if LJ_TARGET_PS3
 139 #define TOCPREFIX "."
 140 #else
 141 #define TOCPREFIX ""
 142 #endif
 143   if ((ins >> 26) == 16) {
 144     fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
 145             (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
 146   } else if ((ins >> 26) == 18) {
 147 #if LJ_ARCH_PPC64
 148     const char *suffix = strchr(sym, '@');
 149     if (suffix && suffix[1] == 'h') {
 150       fprintf(ctx->fp, "\taddis 11, 2, %s\n", sym);
 151     } else if (suffix && suffix[1] == 'l') {
 152       fprintf(ctx->fp, "\tld 12, %s\n", sym);
 153     } else
 154 #endif
 155     fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
 156   } else {
 157     fprintf(stderr,
 158             "Error: unsupported opcode %08x for %s symbol relocation.\n",
 159             ins, sym);
 160     exit(1);
 161   }
 162 #elif LJ_TARGET_MIPS
 163   fprintf(stderr,
 164           "Error: unsupported opcode %08x for %s symbol relocation.\n",
 165           ins, sym);
 166   exit(1);
 167 #else
 168 #error "missing relocation support for this architecture"
 169 #endif
 170 }
 171 #endif
 172 
 173 #if LJ_TARGET_ARM
 174 #define ELFASM_PX       "%%"
 175 #else
 176 #define ELFASM_PX       "@"
 177 #endif
 178 
 179 /* Emit an assembler label. */
 180 static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
 181 {
 182   switch (ctx->mode) {
 183   case BUILD_elfasm:
 184 #if LJ_TARGET_PS3
 185     if (!strncmp(name, "lj_vm_", 6) &&
 186         strcmp(name, ctx->beginsym) &&
 187         !strstr(name, "hook")) {
 188       fprintf(ctx->fp,
 189         "\n\t.globl %s\n"
 190         "\t.section \".opd\",\"aw\"\n"
 191         "%s:\n"
 192         "\t.long .%s,.TOC.@tocbase32\n"
 193         "\t.size %s,8\n"
 194         "\t.previous\n"
 195         "\t.globl .%s\n"
 196         "\t.hidden .%s\n"
 197         "\t.type .%s, " ELFASM_PX "function\n"
 198         "\t.size .%s, %d\n"
 199         ".%s:\n",
 200         name, name, name, name, name, name, name, name, size, name);
 201       break;
 202     }
 203 #endif
 204     fprintf(ctx->fp,
 205       "\n\t.globl %s\n"
 206       "\t.hidden %s\n"
 207       "\t.type %s, " ELFASM_PX "%s\n"
 208       "\t.size %s, %d\n"
 209       "%s:\n",
 210       name, name, name, isfunc ? "function" : "object", name, size, name);
 211     break;
 212   case BUILD_coffasm:
 213     fprintf(ctx->fp, "\n\t.globl %s\n", name);
 214     if (isfunc)
 215       fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
 216     fprintf(ctx->fp, "%s:\n", name);
 217     break;
 218   case BUILD_machasm:
 219     fprintf(ctx->fp,
 220       "\n\t.private_extern %s\n"
 221       "\t.no_dead_strip %s\n"
 222       "%s:\n", name, name, name);
 223     break;
 224   default:
 225     break;
 226   }
 227 }
 228 
 229 /* Emit alignment. */
 230 static void emit_asm_align(BuildCtx *ctx, int bits)
 231 {
 232   switch (ctx->mode) {
 233   case BUILD_elfasm:
 234   case BUILD_coffasm:
 235     fprintf(ctx->fp, "\t.p2align %d\n", bits);
 236     break;
 237   case BUILD_machasm:
 238     fprintf(ctx->fp, "\t.align %d\n", bits);
 239     break;
 240   default:
 241     break;
 242   }
 243 }
 244 
 245 /* ------------------------------------------------------------------------ */
 246 
 247 /* Emit assembler source code. */
 248 void emit_asm(BuildCtx *ctx)
 249 {
 250   int i, rel;
 251 
 252   fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
 253 #if LJ_ARCH_PPC64
 254   fprintf(ctx->fp, "\t.abiversion 2\n");
 255 #endif
 256   fprintf(ctx->fp, "\t.text\n");
 257   emit_asm_align(ctx, 4);
 258 
 259 #if LJ_TARGET_PS3
 260   emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
 261 #else
 262   emit_asm_label(ctx, ctx->beginsym, 0, 0);
 263 #endif
 264   if (ctx->mode != BUILD_machasm)
 265     fprintf(ctx->fp, ".Lbegin:\n");
 266 
 267 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
 268   /* This should really be moved into buildvm_arm.dasc. */
 269 #if LJ_ARCH_HASFPU
 270   fprintf(ctx->fp,
 271           ".fnstart\n"
 272           ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n"
 273           ".vsave {d8-d15}\n"
 274           ".save {r4}\n"
 275           ".pad #28\n");
 276 #else
 277   fprintf(ctx->fp,
 278           ".fnstart\n"
 279           ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
 280           ".pad #28\n");
 281 #endif
 282 #endif
 283 #if LJ_TARGET_MIPS
 284   fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
 285 #endif
 286 
 287   for (i = rel = 0; i < ctx->nsym; i++) {
 288     int32_t ofs = ctx->sym[i].ofs;
 289     int32_t next = ctx->sym[i+1].ofs;
 290 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
 291     if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
 292       fprintf(ctx->fp,
 293               ".globl lj_err_unwind_arm\n"
 294               ".personality lj_err_unwind_arm\n"
 295               ".fnend\n"
 296               ".fnstart\n"
 297               ".save {r4, r5, r11, lr}\n"
 298               ".setfp r11, sp\n");
 299 #endif
 300     emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
 301     while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
 302       BuildReloc *r = &ctx->reloc[rel];
 303       int n = r->ofs - ofs;
 304 #if LJ_TARGET_X86ORX64
 305       if (r->type != 0 &&
 306           (ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) {
 307         emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
 308       } else {
 309         emit_asm_bytes(ctx, ctx->code+ofs, n);
 310         emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
 311       }
 312       ofs += n+4;
 313 #else
 314       emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
 315       ofs += n;
 316 #endif
 317       rel++;
 318     }
 319 #if LJ_TARGET_X86ORX64
 320     emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
 321 #else
 322     emit_asm_words(ctx, ctx->code+ofs, next-ofs);
 323 #endif
 324   }
 325 
 326 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
 327   fprintf(ctx->fp,
 328 #if !LJ_HASFFI
 329           ".globl lj_err_unwind_arm\n"
 330           ".personality lj_err_unwind_arm\n"
 331 #endif
 332           ".fnend\n");
 333 #endif
 334 
 335   fprintf(ctx->fp, "\n");
 336   switch (ctx->mode) {
 337   case BUILD_elfasm:
 338 #if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
 339     fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
 340 #endif
 341 #if LJ_TARGET_PPC && !LJ_TARGET_PS3 && !LJ_ABI_SOFTFP
 342     /* Hard-float ABI. */
 343     fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
 344 #endif
 345     /* fallthrough */
 346   case BUILD_coffasm:
 347     fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
 348     break;
 349   case BUILD_machasm:
 350     fprintf(ctx->fp,
 351       "\t.cstring\n"
 352       "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
 353     break;
 354   default:
 355     break;
 356   }
 357   fprintf(ctx->fp, "\n");
 358 }
 359 

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