diff options
Diffstat (limited to 'libraries/luajit-2.0/src/buildvm_asm.c')
-rw-r--r-- | libraries/luajit-2.0/src/buildvm_asm.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/libraries/luajit-2.0/src/buildvm_asm.c b/libraries/luajit-2.0/src/buildvm_asm.c new file mode 100644 index 0000000..236dd17 --- /dev/null +++ b/libraries/luajit-2.0/src/buildvm_asm.c | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | ** LuaJIT VM builder: Assembler source code emitter. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #include "buildvm.h" | ||
7 | #include "lj_bc.h" | ||
8 | |||
9 | /* ------------------------------------------------------------------------ */ | ||
10 | |||
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) | ||
14 | { | ||
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); | ||
22 | } | ||
23 | if ((n & 15) != 0) putc('\n', ctx->fp); | ||
24 | } | ||
25 | |||
26 | /* Emit relocation */ | ||
27 | static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym) | ||
28 | { | ||
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; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static const char *const jccnames[] = { | ||
50 | "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja", | ||
51 | "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg" | ||
52 | }; | ||
53 | |||
54 | /* Emit relocation for the incredibly stupid OSX assembler. */ | ||
55 | static void emit_asm_reloc_mach(BuildCtx *ctx, uint8_t *cp, int n, | ||
56 | const char *sym) | ||
57 | { | ||
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); | ||
72 | } | ||
73 | emit_asm_bytes(ctx, cp, n); | ||
74 | fprintf(ctx->fp, "\t%s %s\n", opname, sym); | ||
75 | } | ||
76 | #else | ||
77 | /* Emit words piecewise as assembler text. */ | ||
78 | static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n) | ||
79 | { | ||
80 | int i; | ||
81 | for (i = 0; i < n; i += 4) { | ||
82 | if ((i & 15) == 0) | ||
83 | fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i)); | ||
84 | else | ||
85 | fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i)); | ||
86 | if ((i & 15) == 12) putc('\n', ctx->fp); | ||
87 | } | ||
88 | if ((n & 15) != 0) putc('\n', ctx->fp); | ||
89 | } | ||
90 | |||
91 | /* Emit relocation as part of an instruction. */ | ||
92 | static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n, | ||
93 | const char *sym) | ||
94 | { | ||
95 | uint32_t ins; | ||
96 | emit_asm_words(ctx, p, n-4); | ||
97 | ins = *(uint32_t *)(p+n-4); | ||
98 | #if LJ_TARGET_ARM | ||
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); | ||
104 | } else { | ||
105 | fprintf(stderr, | ||
106 | "Error: unsupported opcode %08x for %s symbol relocation.\n", | ||
107 | ins, sym); | ||
108 | exit(1); | ||
109 | } | ||
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); | ||
116 | } else { | ||
117 | fprintf(stderr, | ||
118 | "Error: unsupported opcode %08x for %s symbol relocation.\n", | ||
119 | ins, sym); | ||
120 | exit(1); | ||
121 | } | ||
122 | #elif LJ_TARGET_MIPS | ||
123 | UNUSED(sym); /* NYI */ | ||
124 | #else | ||
125 | #error "missing relocation support for this architecture" | ||
126 | #endif | ||
127 | } | ||
128 | #endif | ||
129 | |||
130 | #if LJ_TARGET_ARM | ||
131 | #define ELFASM_PX "%%" | ||
132 | #else | ||
133 | #define ELFASM_PX "@" | ||
134 | #endif | ||
135 | |||
136 | /* Emit an assembler label. */ | ||
137 | static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc) | ||
138 | { | ||
139 | switch (ctx->mode) { | ||
140 | case BUILD_elfasm: | ||
141 | fprintf(ctx->fp, | ||
142 | "\n\t.globl %s\n" | ||
143 | "\t.hidden %s\n" | ||
144 | "\t.type %s, " ELFASM_PX "%s\n" | ||
145 | "\t.size %s, %d\n" | ||
146 | "%s:\n", | ||
147 | name, name, name, isfunc ? "function" : "object", name, size, name); | ||
148 | break; | ||
149 | case BUILD_coffasm: | ||
150 | fprintf(ctx->fp, "\n\t.globl %s\n", name); | ||
151 | if (isfunc) | ||
152 | fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name); | ||
153 | fprintf(ctx->fp, "%s:\n", name); | ||
154 | break; | ||
155 | case BUILD_machasm: | ||
156 | fprintf(ctx->fp, | ||
157 | "\n\t.private_extern %s\n" | ||
158 | "%s:\n", name, name); | ||
159 | break; | ||
160 | default: | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* Emit alignment. */ | ||
166 | static void emit_asm_align(BuildCtx *ctx, int bits) | ||
167 | { | ||
168 | switch (ctx->mode) { | ||
169 | case BUILD_elfasm: | ||
170 | case BUILD_coffasm: | ||
171 | fprintf(ctx->fp, "\t.p2align %d\n", bits); | ||
172 | break; | ||
173 | case BUILD_machasm: | ||
174 | fprintf(ctx->fp, "\t.align %d\n", bits); | ||
175 | break; | ||
176 | default: | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /* ------------------------------------------------------------------------ */ | ||
182 | |||
183 | /* Emit assembler source code. */ | ||
184 | void emit_asm(BuildCtx *ctx) | ||
185 | { | ||
186 | int i, rel; | ||
187 | |||
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); | ||
191 | |||
192 | emit_asm_label(ctx, ctx->beginsym, 0, 0); | ||
193 | if (ctx->mode != BUILD_machasm) | ||
194 | fprintf(ctx->fp, ".Lbegin:\n"); | ||
195 | |||
196 | #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND) | ||
197 | /* This should really be moved into buildvm_arm.dasc. */ | ||
198 | fprintf(ctx->fp, | ||
199 | ".fnstart\n" | ||
200 | ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" | ||
201 | ".pad #28\n"); | ||
202 | #endif | ||
203 | |||
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) && \ | ||
208 | LJ_HASFFI | ||
209 | if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call")) | ||
210 | fprintf(ctx->fp, | ||
211 | ".globl lj_err_unwind_arm\n" | ||
212 | ".personality lj_err_unwind_arm\n" | ||
213 | ".fnend\n" | ||
214 | ".fnstart\n" | ||
215 | ".save {r4, r5, r11, lr}\n" | ||
216 | ".setfp r11, sp\n"); | ||
217 | #endif | ||
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]); | ||
225 | } else { | ||
226 | emit_asm_bytes(ctx, ctx->code+ofs, n); | ||
227 | emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]); | ||
228 | } | ||
229 | ofs += n+4; | ||
230 | #else | ||
231 | emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]); | ||
232 | ofs += n; | ||
233 | #endif | ||
234 | rel++; | ||
235 | } | ||
236 | #if LJ_TARGET_X86ORX64 | ||
237 | emit_asm_bytes(ctx, ctx->code+ofs, next-ofs); | ||
238 | #else | ||
239 | emit_asm_words(ctx, ctx->code+ofs, next-ofs); | ||
240 | #endif | ||
241 | } | ||
242 | |||
243 | #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND) | ||
244 | fprintf(ctx->fp, | ||
245 | #if !LJ_HASFFI | ||
246 | ".globl lj_err_unwind_arm\n" | ||
247 | ".personality lj_err_unwind_arm\n" | ||
248 | #endif | ||
249 | ".fnend\n"); | ||
250 | #endif | ||
251 | |||
252 | fprintf(ctx->fp, "\n"); | ||
253 | switch (ctx->mode) { | ||
254 | case BUILD_elfasm: | ||
255 | fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n"); | ||
256 | #if LJ_TARGET_PPCSPE | ||
257 | /* Soft-float ABI + SPE. */ | ||
258 | fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n"); | ||
259 | #elif LJ_TARGET_PPC | ||
260 | /* Hard-float ABI. */ | ||
261 | fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n"); | ||
262 | #endif | ||
263 | /* fallthrough */ | ||
264 | case BUILD_coffasm: | ||
265 | fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident); | ||
266 | break; | ||
267 | case BUILD_machasm: | ||
268 | fprintf(ctx->fp, | ||
269 | "\t.cstring\n" | ||
270 | "\t.ascii \"%s\\0\"\n", ctx->dasm_ident); | ||
271 | break; | ||
272 | default: | ||
273 | break; | ||
274 | } | ||
275 | fprintf(ctx->fp, "\n"); | ||
276 | } | ||
277 | |||