2009-12-08 18:46:35 +00:00
|
|
|
/*
|
|
|
|
** LuaJIT VM builder: Assembler source code emitter.
|
2011-01-09 16:12:53 +00:00
|
|
|
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
|
2009-12-08 18:46:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "buildvm.h"
|
|
|
|
#include "lj_bc.h"
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2010-08-27 11:08:58 +00:00
|
|
|
#if LJ_TARGET_X86ORX64
|
2009-12-08 18:46:35 +00:00
|
|
|
/* 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 */
|
2010-01-10 08:39:05 +00:00
|
|
|
static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
switch (ctx->mode) {
|
|
|
|
case BUILD_elfasm:
|
2010-01-10 08:39:05 +00:00
|
|
|
if (type)
|
2009-12-08 18:46:35 +00:00
|
|
|
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
|
|
|
|
else
|
|
|
|
fprintf(ctx->fp, "\t.long %s\n", sym);
|
|
|
|
break;
|
|
|
|
case BUILD_coffasm:
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
|
2010-01-10 08:39:05 +00:00
|
|
|
if (type)
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
|
2009-12-08 18:46:35 +00:00
|
|
|
else
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\t.long %s\n", sym);
|
2009-12-08 18:46:35 +00:00
|
|
|
break;
|
|
|
|
default: /* BUILD_machasm for relative relocations handled below. */
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\t.long %s\n", sym);
|
2009-12-08 18:46:35 +00:00
|
|
|
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);
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\t%s %s\n", opname, sym);
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
2010-08-27 11:08:58 +00:00
|
|
|
#else
|
|
|
|
/* Emit words piecewise as assembler text. */
|
|
|
|
static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < n; i += 4) {
|
|
|
|
if ((i & 15) == 0)
|
|
|
|
fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i));
|
|
|
|
else
|
|
|
|
fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i));
|
|
|
|
if ((i & 15) == 12) putc('\n', ctx->fp);
|
|
|
|
}
|
|
|
|
if ((n & 15) != 0) putc('\n', ctx->fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emit relocation as part of an instruction. */
|
|
|
|
static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
|
|
|
|
const char *sym)
|
|
|
|
{
|
|
|
|
uint32_t ins;
|
|
|
|
emit_asm_words(ctx, p, n-4);
|
|
|
|
ins = *(uint32_t *)(p+n-4);
|
2011-01-25 17:50:24 +00:00
|
|
|
#if LJ_TARGET_ARM
|
2011-03-26 17:40:11 +00:00
|
|
|
if ((ins & 0xff000000u) == 0xfa000000u) {
|
|
|
|
fprintf(ctx->fp, "\tblx %s\n", sym);
|
|
|
|
} else if ((ins & 0x0e000000u) == 0x0a000000u) {
|
|
|
|
fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
|
|
|
|
"eqnecsccmiplvsvchilsgeltgtle" + 2*(ins >> 28), sym);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error: unsupported opcode %08x for %s symbol relocation.\n",
|
|
|
|
ins, sym);
|
|
|
|
exit(1);
|
|
|
|
}
|
2011-01-25 17:50:24 +00:00
|
|
|
#elif LJ_TARGET_PPC
|
2010-08-27 11:08:58 +00:00
|
|
|
if ((ins >> 26) == 16) {
|
|
|
|
fprintf(ctx->fp, "\t%s %d, %d, %s\n",
|
|
|
|
(ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
|
|
|
|
} else if ((ins >> 26) == 18) {
|
|
|
|
fprintf(ctx->fp, "\t%s %s\n", (ins & 1) ? "bl" : "b", sym);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error: unsupported opcode %08x for %s symbol relocation.\n",
|
|
|
|
ins, sym);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#error "missing relocation support for this architecture"
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
|
2011-01-25 17:50:24 +00:00
|
|
|
#if LJ_TARGET_ARM
|
|
|
|
#define ELFASM_PX "%%"
|
|
|
|
#else
|
|
|
|
#define ELFASM_PX "@"
|
|
|
|
#endif
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* 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"
|
2011-01-25 17:50:24 +00:00
|
|
|
"\t.type %s, " ELFASM_PX "%s\n"
|
2009-12-08 18:46:35 +00:00
|
|
|
"\t.size %s, %d\n"
|
|
|
|
"%s:\n",
|
|
|
|
name, name, name, isfunc ? "function" : "object", name, size, name);
|
|
|
|
break;
|
|
|
|
case BUILD_coffasm:
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\n\t.globl %s\n", name);
|
2009-12-08 18:46:35 +00:00
|
|
|
if (isfunc)
|
2010-01-22 00:56:49 +00:00
|
|
|
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
|
|
|
|
fprintf(ctx->fp, "%s:\n", name);
|
2009-12-08 18:46:35 +00:00
|
|
|
break;
|
|
|
|
case BUILD_machasm:
|
|
|
|
fprintf(ctx->fp,
|
2010-01-22 00:56:49 +00:00
|
|
|
"\n\t.private_extern %s\n"
|
|
|
|
"%s:\n", name, name);
|
2009-12-08 18:46:35 +00:00
|
|
|
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)
|
|
|
|
{
|
2010-04-14 15:13:13 +00:00
|
|
|
int i, rel;
|
2009-12-08 18:46:35 +00:00
|
|
|
|
|
|
|
fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
|
|
|
|
fprintf(ctx->fp, "\t.text\n");
|
|
|
|
emit_asm_align(ctx, 4);
|
|
|
|
|
2010-04-14 15:13:13 +00:00
|
|
|
emit_asm_label(ctx, ctx->beginsym, 0, 0);
|
2010-01-22 00:56:49 +00:00
|
|
|
if (ctx->mode != BUILD_machasm)
|
2009-12-08 18:46:35 +00:00
|
|
|
fprintf(ctx->fp, ".Lbegin:\n");
|
|
|
|
|
2010-04-14 15:13:13 +00:00
|
|
|
for (i = rel = 0; i < ctx->nsym; i++) {
|
|
|
|
int32_t ofs = ctx->sym[i].ofs;
|
|
|
|
int32_t next = ctx->sym[i+1].ofs;
|
|
|
|
emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
|
2011-03-26 17:40:11 +00:00
|
|
|
while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
|
2010-01-10 08:39:05 +00:00
|
|
|
BuildReloc *r = &ctx->reloc[rel];
|
2010-04-14 15:13:13 +00:00
|
|
|
int n = r->ofs - ofs;
|
2010-08-27 11:08:58 +00:00
|
|
|
#if LJ_TARGET_X86ORX64
|
2010-01-10 08:39:05 +00:00
|
|
|
if (ctx->mode == BUILD_machasm && r->type != 0) {
|
2010-04-14 15:13:13 +00:00
|
|
|
emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
|
2009-12-08 18:46:35 +00:00
|
|
|
} else {
|
2010-04-14 15:13:13 +00:00
|
|
|
emit_asm_bytes(ctx, ctx->code+ofs, n);
|
|
|
|
emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
2010-04-14 15:13:13 +00:00
|
|
|
ofs += n+4;
|
2010-08-27 11:08:58 +00:00
|
|
|
#else
|
|
|
|
emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
|
|
|
|
ofs += n;
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
rel++;
|
|
|
|
}
|
2010-08-27 11:08:58 +00:00
|
|
|
#if LJ_TARGET_X86ORX64
|
2010-04-14 15:13:13 +00:00
|
|
|
emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
|
2010-08-27 11:08:58 +00:00
|
|
|
#else
|
|
|
|
emit_asm_words(ctx, ctx->code+ofs, next-ofs);
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(ctx->fp, "\n");
|
|
|
|
switch (ctx->mode) {
|
|
|
|
case BUILD_elfasm:
|
2011-01-25 17:50:24 +00:00
|
|
|
fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
|
2010-08-27 11:08:58 +00:00
|
|
|
#if LJ_TARGET_PPCSPE
|
|
|
|
/* Soft-float ABI + SPE. */
|
|
|
|
fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
|
|
|
|
#elif LJ_TARGET_PPC
|
|
|
|
/* Hard-float ABI. */
|
|
|
|
fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
/* 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");
|
|
|
|
}
|
|
|
|
|