2 ** LuaJIT VM builder: Assembler source code emitter.
3 ** Copyright (C) 2005-2012 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",
124 "Error: unsupported opcode %08x for %s symbol relocation.\n",
128 #error "missing relocation support for this architecture"
134 #define ELFASM_PX "%%"
136 #define ELFASM_PX "@"
139 /* Emit an assembler label. */
140 static void emit_asm_label(BuildCtx
*ctx
, const char *name
, int size
, int isfunc
)
147 "\t.type %s, " ELFASM_PX
"%s\n"
150 name
, name
, name
, isfunc
? "function" : "object", name
, size
, name
);
153 fprintf(ctx
->fp
, "\n\t.globl %s\n", name
);
155 fprintf(ctx
->fp
, "\t.def %s; .scl 3; .type 32; .endef\n", name
);
156 fprintf(ctx
->fp
, "%s:\n", name
);
160 "\n\t.private_extern %s\n"
161 "%s:\n", name
, name
);
168 /* Emit alignment. */
169 static void emit_asm_align(BuildCtx
*ctx
, int bits
)
174 fprintf(ctx
->fp
, "\t.p2align %d\n", bits
);
177 fprintf(ctx
->fp
, "\t.align %d\n", bits
);
184 /* ------------------------------------------------------------------------ */
186 /* Emit assembler source code. */
187 void emit_asm(BuildCtx
*ctx
)
191 fprintf(ctx
->fp
, "\t.file \"buildvm_%s.dasc\"\n", ctx
->dasm_arch
);
192 fprintf(ctx
->fp
, "\t.text\n");
193 emit_asm_align(ctx
, 4);
195 emit_asm_label(ctx
, ctx
->beginsym
, 0, 0);
196 if (ctx
->mode
!= BUILD_machasm
)
197 fprintf(ctx
->fp
, ".Lbegin:\n");
199 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
200 /* This should really be moved into buildvm_arm.dasc. */
203 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
207 fprintf(ctx
->fp
, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
210 for (i
= rel
= 0; i
< ctx
->nsym
; i
++) {
211 int32_t ofs
= ctx
->sym
[i
].ofs
;
212 int32_t next
= ctx
->sym
[i
+1].ofs
;
213 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND) && \
215 if (!strcmp(ctx
->sym
[i
].name
, "lj_vm_ffi_call"))
217 ".globl lj_err_unwind_arm\n"
218 ".personality lj_err_unwind_arm\n"
221 ".save {r4, r5, r11, lr}\n"
224 emit_asm_label(ctx
, ctx
->sym
[i
].name
, next
- ofs
, 1);
225 while (rel
< ctx
->nreloc
&& ctx
->reloc
[rel
].ofs
<= next
) {
226 BuildReloc
*r
= &ctx
->reloc
[rel
];
227 int n
= r
->ofs
- ofs
;
228 #if LJ_TARGET_X86ORX64
229 if (ctx
->mode
== BUILD_machasm
&& r
->type
!= 0) {
230 emit_asm_reloc_mach(ctx
, ctx
->code
+ofs
, n
, ctx
->relocsym
[r
->sym
]);
232 emit_asm_bytes(ctx
, ctx
->code
+ofs
, n
);
233 emit_asm_reloc(ctx
, r
->type
, ctx
->relocsym
[r
->sym
]);
237 emit_asm_wordreloc(ctx
, ctx
->code
+ofs
, n
, ctx
->relocsym
[r
->sym
]);
242 #if LJ_TARGET_X86ORX64
243 emit_asm_bytes(ctx
, ctx
->code
+ofs
, next
-ofs
);
245 emit_asm_words(ctx
, ctx
->code
+ofs
, next
-ofs
);
249 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
252 ".globl lj_err_unwind_arm\n"
253 ".personality lj_err_unwind_arm\n"
258 fprintf(ctx
->fp
, "\n");
261 fprintf(ctx
->fp
, "\t.section .note.GNU-stack,\"\"," ELFASM_PX
"progbits\n");
263 /* Soft-float ABI + SPE. */
264 fprintf(ctx
->fp
, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
266 /* Hard-float ABI. */
267 fprintf(ctx
->fp
, "\t.gnu_attribute 4, 1\n");
271 fprintf(ctx
->fp
, "\t.ident \"%s\"\n", ctx
->dasm_ident
);
276 "\t.ascii \"%s\\0\"\n", ctx
->dasm_ident
);
281 fprintf(ctx
->fp
, "\n");