2 ** LuaJIT VM builder: Assembler source code emitter.
3 ** Copyright (C) 2005-2015 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 x86/x64 text relocations. */
55 static void emit_asm_reloc_text(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 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
) {
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
);
81 fprintf(ctx
->fp
, "#endif\n");
83 } else if (LJ_32
&& ctx
->mode
== BUILD_machasm
) {
84 fprintf(ctx
->fp
, "\t%s L%s$stub\n", opname
, sym
);
88 fprintf(ctx
->fp
, "\t%s %s\n", opname
, sym
);
91 /* Emit words piecewise as assembler text. */
92 static void emit_asm_words(BuildCtx
*ctx
, uint8_t *p
, int n
)
95 for (i
= 0; i
< n
; i
+= 4) {
97 fprintf(ctx
->fp
, "\t.long 0x%08x", *(uint32_t *)(p
+i
));
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
,
110 emit_asm_words(ctx
, p
, n
-4);
111 ins
= *(uint32_t *)(p
+n
-4);
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
);
120 "Error: unsupported opcode %08x for %s symbol relocation.\n",
124 #elif LJ_TARGET_ARM64
125 if ((ins
>> 26) == 0x25u
) {
126 fprintf(ctx
->fp
, "\tbl %s\n", sym
);
129 "Error: unsupported opcode %08x for %s symbol relocation.\n",
135 #define TOCPREFIX "."
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) {
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
);
151 fprintf(ctx
->fp
, "\t%s " TOCPREFIX
"%s\n", (ins
& 1) ? "bl" : "b", sym
);
154 "Error: unsupported opcode %08x for %s symbol relocation.\n",
160 "Error: unsupported opcode %08x for %s symbol relocation.\n",
164 #error "missing relocation support for this architecture"
170 #define ELFASM_PX "%%"
172 #define ELFASM_PX "@"
175 /* Emit an assembler label. */
176 static void emit_asm_label(BuildCtx
*ctx
, const char *name
, int size
, int isfunc
)
181 if (!strncmp(name
, "lj_vm_", 6) &&
182 strcmp(name
, ctx
->beginsym
) &&
183 !strstr(name
, "hook")) {
186 "\t.section \".opd\",\"aw\"\n"
188 "\t.long .%s,.TOC.@tocbase32\n"
193 "\t.type .%s, " ELFASM_PX
"function\n"
196 name
, name
, name
, name
, name
, name
, name
, name
, size
, name
);
203 "\t.type %s, " ELFASM_PX
"%s\n"
206 name
, name
, name
, isfunc
? "function" : "object", name
, size
, name
);
209 fprintf(ctx
->fp
, "\n\t.globl %s\n", name
);
211 fprintf(ctx
->fp
, "\t.def %s; .scl 3; .type 32; .endef\n", name
);
212 fprintf(ctx
->fp
, "%s:\n", name
);
216 "\n\t.private_extern %s\n"
217 "%s:\n", name
, name
);
224 /* Emit alignment. */
225 static void emit_asm_align(BuildCtx
*ctx
, int bits
)
230 fprintf(ctx
->fp
, "\t.p2align %d\n", bits
);
233 fprintf(ctx
->fp
, "\t.align %d\n", bits
);
240 /* ------------------------------------------------------------------------ */
242 /* Emit assembler source code. */
243 void emit_asm(BuildCtx
*ctx
)
247 fprintf(ctx
->fp
, "\t.file \"buildvm_%s.dasc\"\n", ctx
->dasm_arch
);
249 fprintf(ctx
->fp
, "\t.abiversion 2\n");
251 fprintf(ctx
->fp
, "\t.text\n");
252 emit_asm_align(ctx
, 4);
255 emit_asm_label(ctx
, ctx
->beginsym
, ctx
->codesz
, 0);
257 emit_asm_label(ctx
, ctx
->beginsym
, 0, 0);
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. */
266 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
270 fprintf(ctx
->fp
, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
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"))
279 ".globl lj_err_unwind_arm\n"
280 ".personality lj_err_unwind_arm\n"
283 ".save {r4, r5, r11, lr}\n"
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
292 (ctx
->mode
== BUILD_elfasm
|| ctx
->mode
== BUILD_machasm
)) {
293 emit_asm_reloc_text(ctx
, ctx
->code
+ofs
, n
, ctx
->relocsym
[r
->sym
]);
295 emit_asm_bytes(ctx
, ctx
->code
+ofs
, n
);
296 emit_asm_reloc(ctx
, r
->type
, ctx
->relocsym
[r
->sym
]);
300 emit_asm_wordreloc(ctx
, ctx
->code
+ofs
, n
, ctx
->relocsym
[r
->sym
]);
305 #if LJ_TARGET_X86ORX64
306 emit_asm_bytes(ctx
, ctx
->code
+ofs
, next
-ofs
);
308 emit_asm_words(ctx
, ctx
->code
+ofs
, next
-ofs
);
312 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
315 ".globl lj_err_unwind_arm\n"
316 ".personality lj_err_unwind_arm\n"
321 fprintf(ctx
->fp
, "\n");
324 #if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
325 fprintf(ctx
->fp
, "\t.section .note.GNU-stack,\"\"," ELFASM_PX
"progbits\n");
327 #if LJ_TARGET_PPC && !LJ_TARGET_PS3
328 /* Hard-float ABI. */
329 fprintf(ctx
->fp
, "\t.gnu_attribute 4, 1\n");
333 fprintf(ctx
->fp
, "\t.ident \"%s\"\n", ctx
->dasm_ident
);
338 "\t.ascii \"%s\\0\"\n", ctx
->dasm_ident
);
343 fprintf(ctx
->fp
, "\n");