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