summaryrefslogtreecommitdiff
path: root/src/buildvm_asm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/buildvm_asm.c')
-rw-r--r--src/buildvm_asm.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/buildvm_asm.c b/src/buildvm_asm.c
new file mode 100644
index 00000000..e6972bd5
--- /dev/null
+++ b/src/buildvm_asm.c
@@ -0,0 +1,220 @@
+/*
+** LuaJIT VM builder: Assembler source code emitter.
+** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#include "buildvm.h"
+#include "lj_bc.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Emit bytes piecewise as assembler text. */
+static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
+{
+ int i;
+ for (i = 0; i < n; i++) {
+ if ((i & 15) == 0)
+ fprintf(ctx->fp, "\t.byte %d", p[i]);
+ else
+ fprintf(ctx->fp, ",%d", p[i]);
+ if ((i & 15) == 15) putc('\n', ctx->fp);
+ }
+ if ((n & 15) != 0) putc('\n', ctx->fp);
+}
+
+/* Emit relocation */
+static void emit_asm_reloc(BuildCtx *ctx, BuildReloc *r)
+{
+ const char *sym = ctx->extnames[r->sym];
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ if (r->type)
+ fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
+ else
+ fprintf(ctx->fp, "\t.long %s\n", sym);
+ break;
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\t.def _%s; .scl 3; .type 32; .endef\n", sym);
+ if (r->type)
+ fprintf(ctx->fp, "\t.long _%s-.-4\n", sym);
+ else
+ fprintf(ctx->fp, "\t.long _%s\n", sym);
+ break;
+ default: /* BUILD_machasm for relative relocations handled below. */
+ fprintf(ctx->fp, "\t.long _%s\n", sym);
+ break;
+ }
+}
+
+static const char *const jccnames[] = {
+ "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
+ "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
+};
+
+/* Emit relocation for the incredibly stupid OSX assembler. */
+static void emit_asm_reloc_mach(BuildCtx *ctx, uint8_t *cp, int n,
+ const char *sym)
+{
+ const char *opname = NULL;
+ if (--n < 0) goto err;
+ if (cp[n] == 0xe8) {
+ opname = "call";
+ } else if (cp[n] == 0xe9) {
+ opname = "jmp";
+ } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
+ opname = jccnames[cp[n]-0x80];
+ n--;
+ } else {
+err:
+ fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
+ sym);
+ exit(1);
+ }
+ emit_asm_bytes(ctx, cp, n);
+ if (!strncmp(sym, LABEL_PREFIX, sizeof(LABEL_PREFIX)-1))
+ fprintf(ctx->fp, "\t%s _%s\n", opname, sym);
+ else
+ fprintf(ctx->fp, "\t%s _" LABEL_PREFIX "wrapper_%s\n", opname, sym);
+}
+
+/* Emit an assembler label. */
+static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
+{
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ fprintf(ctx->fp,
+ "\n\t.globl %s\n"
+ "\t.hidden %s\n"
+ "\t.type %s, @%s\n"
+ "\t.size %s, %d\n"
+ "%s:\n",
+ name, name, name, isfunc ? "function" : "object", name, size, name);
+ break;
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\n\t.globl _%s\n", name);
+ if (isfunc)
+ fprintf(ctx->fp, "\t.def _%s; .scl 3; .type 32; .endef\n", name);
+ fprintf(ctx->fp, "_%s:\n", name);
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp,
+ "\n\t.private_extern _%s\n"
+ "_%s:\n", name, name);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Emit alignment. */
+static void emit_asm_align(BuildCtx *ctx, int bits)
+{
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\t.p2align %d\n", bits);
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp, "\t.align %d\n", bits);
+ break;
+ default:
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Emit assembler source code. */
+void emit_asm(BuildCtx *ctx)
+{
+ char name[80];
+ int32_t prev;
+ int i, pi, rel;
+
+ fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
+ fprintf(ctx->fp, "\t.text\n");
+ emit_asm_align(ctx, 4);
+
+ emit_asm_label(ctx, LABEL_ASM_BEGIN, 0, 1);
+ if (ctx->mode == BUILD_elfasm)
+ fprintf(ctx->fp, ".Lbegin:\n");
+
+ i = 0;
+ do {
+ pi = ctx->perm[i++];
+ prev = ctx->sym_ofs[pi];
+ } while (prev < 0); /* Skip the _Z symbols. */
+
+ for (rel = 0; i <= ctx->nsym; i++) {
+ int ni = ctx->perm[i];
+ int32_t next = ctx->sym_ofs[ni];
+ int size = (int)(next - prev);
+ int32_t stop = next;
+ if (pi >= ctx->npc) {
+ sprintf(name, LABEL_PREFIX "%s", ctx->globnames[pi-ctx->npc]);
+ emit_asm_label(ctx, name, size, 1);
+#if LJ_HASJIT
+ } else {
+#else
+ } else if (!(pi == BC_JFORI || pi == BC_JFORL || pi == BC_JITERL ||
+ pi == BC_JLOOP || pi == BC_IFORL || pi == BC_IITERL ||
+ pi == BC_ILOOP)) {
+#endif
+ sprintf(name, LABEL_PREFIX_BC "%s", bc_names[pi]);
+ emit_asm_label(ctx, name, size, 1);
+ }
+ while (rel < ctx->nreloc && ctx->reloc[rel].ofs < stop) {
+ int n = ctx->reloc[rel].ofs - prev;
+ if (ctx->mode == BUILD_machasm && ctx->reloc[rel].type != 0) {
+ emit_asm_reloc_mach(ctx, ctx->code+prev, n,
+ ctx->extnames[ctx->reloc[rel].sym]);
+ } else {
+ emit_asm_bytes(ctx, ctx->code+prev, n);
+ emit_asm_reloc(ctx, &ctx->reloc[rel]);
+ }
+ prev += n+4;
+ rel++;
+ }
+ emit_asm_bytes(ctx, ctx->code+prev, stop-prev);
+ prev = next;
+ pi = ni;
+ }
+
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ fprintf(ctx->fp, "\n\t.section .rodata\n");
+ break;
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\n\t.section .rdata,\"dr\"\n");
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp, "\n\t.const\n");
+ break;
+ default:
+ break;
+ }
+ emit_asm_align(ctx, 5);
+
+ emit_asm_label(ctx, LABEL_OP_OFS, 2*ctx->npc, 0);
+ for (i = 0; i < ctx->npc; i++)
+ fprintf(ctx->fp, "\t.short %d\n", ctx->sym_ofs[i]);
+
+ fprintf(ctx->fp, "\n");
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\",@progbits\n");
+ /* fallthrough */
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp,
+ "\t.cstring\n"
+ "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
+ break;
+ default:
+ break;
+ }
+ fprintf(ctx->fp, "\n");
+}
+