| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- /*
- ** LuaJIT VM builder: Assembler source code emitter.
- ** Copyright (C) 2005-2014 Mike Pall. See Copyright Notice in luajit.h
- */
- #include "buildvm.h"
- #include "lj_bc.h"
- /* ------------------------------------------------------------------------ */
- #if LJ_TARGET_X86ORX64
- /* 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, int type, const char *sym)
- {
- switch (ctx->mode) {
- case BUILD_elfasm:
- if (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 (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);
- fprintf(ctx->fp, "\t%s %s\n", opname, sym);
- }
- #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);
- #if LJ_TARGET_ARM
- 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);
- }
- #elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
- #if LJ_TARGET_PS3
- #define TOCPREFIX "."
- #else
- #define TOCPREFIX ""
- #endif
- if ((ins >> 26) == 16) {
- fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
- (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
- } else if ((ins >> 26) == 18) {
- fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
- } else {
- fprintf(stderr,
- "Error: unsupported opcode %08x for %s symbol relocation.\n",
- ins, sym);
- exit(1);
- }
- #elif LJ_TARGET_MIPS
- 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
- #if LJ_TARGET_ARM
- #define ELFASM_PX "%%"
- #else
- #define ELFASM_PX "@"
- #endif
- /* Emit an assembler label. */
- static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
- {
- switch (ctx->mode) {
- case BUILD_elfasm:
- #if LJ_TARGET_PS3
- if (!strncmp(name, "lj_vm_", 6) &&
- strcmp(name, ctx->beginsym) &&
- !strstr(name, "hook")) {
- fprintf(ctx->fp,
- "\n\t.globl %s\n"
- "\t.section \".opd\",\"aw\"\n"
- "%s:\n"
- "\t.long .%s,.TOC.@tocbase32\n"
- "\t.size %s,8\n"
- "\t.previous\n"
- "\t.globl .%s\n"
- "\t.hidden .%s\n"
- "\t.type .%s, " ELFASM_PX "function\n"
- "\t.size .%s, %d\n"
- ".%s:\n",
- name, name, name, name, name, name, name, name, size, name);
- break;
- }
- #endif
- fprintf(ctx->fp,
- "\n\t.globl %s\n"
- "\t.hidden %s\n"
- "\t.type %s, " ELFASM_PX "%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)
- {
- int i, rel;
- fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
- fprintf(ctx->fp, "\t.text\n");
- emit_asm_align(ctx, 4);
- #if LJ_TARGET_PS3
- emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
- #else
- emit_asm_label(ctx, ctx->beginsym, 0, 0);
- #endif
- if (ctx->mode != BUILD_machasm)
- fprintf(ctx->fp, ".Lbegin:\n");
- #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
- /* This should really be moved into buildvm_arm.dasc. */
- fprintf(ctx->fp,
- ".fnstart\n"
- ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
- ".pad #28\n");
- #endif
- #if LJ_TARGET_MIPS
- fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
- #endif
- for (i = rel = 0; i < ctx->nsym; i++) {
- int32_t ofs = ctx->sym[i].ofs;
- int32_t next = ctx->sym[i+1].ofs;
- #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
- if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
- fprintf(ctx->fp,
- ".globl lj_err_unwind_arm\n"
- ".personality lj_err_unwind_arm\n"
- ".fnend\n"
- ".fnstart\n"
- ".save {r4, r5, r11, lr}\n"
- ".setfp r11, sp\n");
- #endif
- emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
- while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
- BuildReloc *r = &ctx->reloc[rel];
- int n = r->ofs - ofs;
- #if LJ_TARGET_X86ORX64
- if (ctx->mode == BUILD_machasm && r->type != 0) {
- emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
- } else {
- emit_asm_bytes(ctx, ctx->code+ofs, n);
- emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
- }
- ofs += n+4;
- #else
- emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
- ofs += n;
- #endif
- rel++;
- }
- #if LJ_TARGET_X86ORX64
- emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
- #else
- emit_asm_words(ctx, ctx->code+ofs, next-ofs);
- #endif
- }
- #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
- fprintf(ctx->fp,
- #if !LJ_HASFFI
- ".globl lj_err_unwind_arm\n"
- ".personality lj_err_unwind_arm\n"
- #endif
- ".fnend\n");
- #endif
- fprintf(ctx->fp, "\n");
- switch (ctx->mode) {
- case BUILD_elfasm:
- #if !LJ_TARGET_PS3
- fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
- #endif
- #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 && !LJ_TARGET_PS3
- /* Hard-float ABI. */
- fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
- #endif
- /* 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");
- }
|