2 ** LuaJIT VM builder: Assembler source code emitter.
3 ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
9 /* ------------------------------------------------------------------------ */
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
)
16 for (i
= 0; i
< n
; i
++) {
18 fprintf(ctx
->fp
, "\t.byte %d", p
[i
]);
20 fprintf(ctx
->fp
, ",%d", p
[i
]);
21 if ((i
& 15) == 15) putc('\n', ctx
->fp
);
23 if ((n
& 15) != 0) putc('\n', ctx
->fp
);
27 static void emit_asm_reloc(BuildCtx
*ctx
, int type
, const char *sym
)
32 fprintf(ctx
->fp
, "\t.long %s-.-4\n", sym
);
34 fprintf(ctx
->fp
, "\t.long %s\n", sym
);
37 fprintf(ctx
->fp
, "\t.def %s; .scl 3; .type 32; .endef\n", sym
);
39 fprintf(ctx
->fp
, "\t.long %s-.-4\n", sym
);
41 fprintf(ctx
->fp
, "\t.long %s\n", sym
);
43 default: /* BUILD_machasm for relative relocations handled below. */
44 fprintf(ctx
->fp
, "\t.long %s\n", sym
);
49 static const char *const jccnames
[] = {
50 "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
51 "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
54 /* Emit relocation for the incredibly stupid OSX assembler. */
55 static void emit_asm_reloc_mach(BuildCtx
*ctx
, uint8_t *cp
, int n
,
58 const char *opname
= NULL
;
59 if (--n
< 0) goto err
;
62 } else if (cp
[n
] == 0xe9) {
64 } else if (cp
[n
] >= 0x80 && cp
[n
] <= 0x8f && n
> 0 && cp
[n
-1] == 0x0f) {
65 opname
= jccnames
[cp
[n
]-0x80];
69 fprintf(stderr
, "Error: unsupported opcode for %s symbol relocation.\n",
73 emit_asm_bytes(ctx
, cp
, n
);
74 fprintf(ctx
->fp
, "\t%s %s\n", opname
, sym
);
77 /* Emit words piecewise as assembler text. */
78 static void emit_asm_words(BuildCtx
*ctx
, uint8_t *p
, int n
)
81 for (i
= 0; i
< n
; i
+= 4) {
83 fprintf(ctx
->fp
, "\t.long 0x%08x", *(uint32_t *)(p
+i
));
85 fprintf(ctx
->fp
, ",0x%08x", *(uint32_t *)(p
+i
));
86 if ((i
& 15) == 12) putc('\n', ctx
->fp
);
88 if ((n
& 15) != 0) putc('\n', ctx
->fp
);
91 /* Emit relocation as part of an instruction. */
92 static void emit_asm_wordreloc(BuildCtx
*ctx
, uint8_t *p
, int n
,
96 emit_asm_words(ctx
, p
, n
-4);
97 ins
= *(uint32_t *)(p
+n
-4);
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
);
106 "Error: unsupported opcode %08x for %s symbol relocation.\n",
110 #elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
111 if ((ins
>> 26) == 16) {
112 fprintf(ctx
->fp
, "\t%s %d, %d, %s\n",
113 (ins
& 1) ? "bcl" : "bc", (ins
>> 21) & 31, (ins
>> 16) & 31, sym
);
114 } else if ((ins
>> 26) == 18) {
115 fprintf(ctx
->fp
, "\t%s %s\n", (ins
& 1) ? "bl" : "b", sym
);
118 "Error: unsupported opcode %08x for %s symbol relocation.\n",
123 UNUSED(sym
); /* NYI */
125 #error "missing relocation support for this architecture"
131 #define ELFASM_PX "%%"
133 #define ELFASM_PX "@"
136 /* Emit an assembler label. */
137 static void emit_asm_label(BuildCtx
*ctx
, const char *name
, int size
, int isfunc
)
144 "\t.type %s, " ELFASM_PX
"%s\n"
147 name
, name
, name
, isfunc
? "function" : "object", name
, size
, name
);
150 fprintf(ctx
->fp
, "\n\t.globl %s\n", name
);
152 fprintf(ctx
->fp
, "\t.def %s; .scl 3; .type 32; .endef\n", name
);
153 fprintf(ctx
->fp
, "%s:\n", name
);
157 "\n\t.private_extern %s\n"
158 "%s:\n", name
, name
);
165 /* Emit alignment. */
166 static void emit_asm_align(BuildCtx
*ctx
, int bits
)
171 fprintf(ctx
->fp
, "\t.p2align %d\n", bits
);
174 fprintf(ctx
->fp
, "\t.align %d\n", bits
);
181 /* ------------------------------------------------------------------------ */
183 /* Emit assembler source code. */
184 void emit_asm(BuildCtx
*ctx
)
188 fprintf(ctx
->fp
, "\t.file \"buildvm_%s.dasc\"\n", ctx
->dasm_arch
);
189 fprintf(ctx
->fp
, "\t.text\n");
190 emit_asm_align(ctx
, 4);
192 emit_asm_label(ctx
, ctx
->beginsym
, 0, 0);
193 if (ctx
->mode
!= BUILD_machasm
)
194 fprintf(ctx
->fp
, ".Lbegin:\n");
196 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
197 /* This should really be moved into buildvm_arm.dasc. */
200 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
204 for (i
= rel
= 0; i
< ctx
->nsym
; i
++) {
205 int32_t ofs
= ctx
->sym
[i
].ofs
;
206 int32_t next
= ctx
->sym
[i
+1].ofs
;
207 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND) && \
209 if (!strcmp(ctx
->sym
[i
].name
, "lj_vm_ffi_call"))
211 ".globl lj_err_unwind_arm\n"
212 ".personality lj_err_unwind_arm\n"
215 ".save {r4, r5, r11, lr}\n"
218 emit_asm_label(ctx
, ctx
->sym
[i
].name
, next
- ofs
, 1);
219 while (rel
< ctx
->nreloc
&& ctx
->reloc
[rel
].ofs
<= next
) {
220 BuildReloc
*r
= &ctx
->reloc
[rel
];
221 int n
= r
->ofs
- ofs
;
222 #if LJ_TARGET_X86ORX64
223 if (ctx
->mode
== BUILD_machasm
&& r
->type
!= 0) {
224 emit_asm_reloc_mach(ctx
, ctx
->code
+ofs
, n
, ctx
->relocsym
[r
->sym
]);
226 emit_asm_bytes(ctx
, ctx
->code
+ofs
, n
);
227 emit_asm_reloc(ctx
, r
->type
, ctx
->relocsym
[r
->sym
]);
231 emit_asm_wordreloc(ctx
, ctx
->code
+ofs
, n
, ctx
->relocsym
[r
->sym
]);
236 #if LJ_TARGET_X86ORX64
237 emit_asm_bytes(ctx
, ctx
->code
+ofs
, next
-ofs
);
239 emit_asm_words(ctx
, ctx
->code
+ofs
, next
-ofs
);
243 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
246 ".globl lj_err_unwind_arm\n"
247 ".personality lj_err_unwind_arm\n"
252 fprintf(ctx
->fp
, "\n");
255 fprintf(ctx
->fp
, "\t.section .note.GNU-stack,\"\"," ELFASM_PX
"progbits\n");
257 /* Soft-float ABI + SPE. */
258 fprintf(ctx
->fp
, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
260 /* Hard-float ABI. */
261 fprintf(ctx
->fp
, "\t.gnu_attribute 4, 1\n");
265 fprintf(ctx
->fp
, "\t.ident \"%s\"\n", ctx
->dasm_ident
);
270 "\t.ascii \"%s\\0\"\n", ctx
->dasm_ident
);
275 fprintf(ctx
->fp
, "\n");