diff options
Diffstat (limited to 'src/buildvm_asm.c')
-rw-r--r-- | src/buildvm_asm.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/buildvm_asm.c b/src/buildvm_asm.c new file mode 100644 index 00000000..e6972bd5 --- /dev/null +++ b/src/buildvm_asm.c | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | ** LuaJIT VM builder: Assembler source code emitter. | ||
3 | ** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #include "buildvm.h" | ||
7 | #include "lj_bc.h" | ||
8 | |||
9 | /* ------------------------------------------------------------------------ */ | ||
10 | |||
11 | /* Emit bytes piecewise as assembler text. */ | ||
12 | static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n) | ||
13 | { | ||
14 | int i; | ||
15 | for (i = 0; i < n; i++) { | ||
16 | if ((i & 15) == 0) | ||
17 | fprintf(ctx->fp, "\t.byte %d", p[i]); | ||
18 | else | ||
19 | fprintf(ctx->fp, ",%d", p[i]); | ||
20 | if ((i & 15) == 15) putc('\n', ctx->fp); | ||
21 | } | ||
22 | if ((n & 15) != 0) putc('\n', ctx->fp); | ||
23 | } | ||
24 | |||
25 | /* Emit relocation */ | ||
26 | static void emit_asm_reloc(BuildCtx *ctx, BuildReloc *r) | ||
27 | { | ||
28 | const char *sym = ctx->extnames[r->sym]; | ||
29 | switch (ctx->mode) { | ||
30 | case BUILD_elfasm: | ||
31 | if (r->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 (r->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 | if (!strncmp(sym, LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) | ||
75 | fprintf(ctx->fp, "\t%s _%s\n", opname, sym); | ||
76 | else | ||
77 | fprintf(ctx->fp, "\t%s _" LABEL_PREFIX "wrapper_%s\n", opname, sym); | ||
78 | } | ||
79 | |||
80 | /* Emit an assembler label. */ | ||
81 | static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc) | ||
82 | { | ||
83 | switch (ctx->mode) { | ||
84 | case BUILD_elfasm: | ||
85 | fprintf(ctx->fp, | ||
86 | "\n\t.globl %s\n" | ||
87 | "\t.hidden %s\n" | ||
88 | "\t.type %s, @%s\n" | ||
89 | "\t.size %s, %d\n" | ||
90 | "%s:\n", | ||
91 | name, name, name, isfunc ? "function" : "object", name, size, name); | ||
92 | break; | ||
93 | case BUILD_coffasm: | ||
94 | fprintf(ctx->fp, "\n\t.globl _%s\n", name); | ||
95 | if (isfunc) | ||
96 | fprintf(ctx->fp, "\t.def _%s; .scl 3; .type 32; .endef\n", name); | ||
97 | fprintf(ctx->fp, "_%s:\n", name); | ||
98 | break; | ||
99 | case BUILD_machasm: | ||
100 | fprintf(ctx->fp, | ||
101 | "\n\t.private_extern _%s\n" | ||
102 | "_%s:\n", name, name); | ||
103 | break; | ||
104 | default: | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | /* Emit alignment. */ | ||
110 | static void emit_asm_align(BuildCtx *ctx, int bits) | ||
111 | { | ||
112 | switch (ctx->mode) { | ||
113 | case BUILD_elfasm: | ||
114 | case BUILD_coffasm: | ||
115 | fprintf(ctx->fp, "\t.p2align %d\n", bits); | ||
116 | break; | ||
117 | case BUILD_machasm: | ||
118 | fprintf(ctx->fp, "\t.align %d\n", bits); | ||
119 | break; | ||
120 | default: | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /* ------------------------------------------------------------------------ */ | ||
126 | |||
127 | /* Emit assembler source code. */ | ||
128 | void emit_asm(BuildCtx *ctx) | ||
129 | { | ||
130 | char name[80]; | ||
131 | int32_t prev; | ||
132 | int i, pi, rel; | ||
133 | |||
134 | fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch); | ||
135 | fprintf(ctx->fp, "\t.text\n"); | ||
136 | emit_asm_align(ctx, 4); | ||
137 | |||
138 | emit_asm_label(ctx, LABEL_ASM_BEGIN, 0, 1); | ||
139 | if (ctx->mode == BUILD_elfasm) | ||
140 | fprintf(ctx->fp, ".Lbegin:\n"); | ||
141 | |||
142 | i = 0; | ||
143 | do { | ||
144 | pi = ctx->perm[i++]; | ||
145 | prev = ctx->sym_ofs[pi]; | ||
146 | } while (prev < 0); /* Skip the _Z symbols. */ | ||
147 | |||
148 | for (rel = 0; i <= ctx->nsym; i++) { | ||
149 | int ni = ctx->perm[i]; | ||
150 | int32_t next = ctx->sym_ofs[ni]; | ||
151 | int size = (int)(next - prev); | ||
152 | int32_t stop = next; | ||
153 | if (pi >= ctx->npc) { | ||
154 | sprintf(name, LABEL_PREFIX "%s", ctx->globnames[pi-ctx->npc]); | ||
155 | emit_asm_label(ctx, name, size, 1); | ||
156 | #if LJ_HASJIT | ||
157 | } else { | ||
158 | #else | ||
159 | } else if (!(pi == BC_JFORI || pi == BC_JFORL || pi == BC_JITERL || | ||
160 | pi == BC_JLOOP || pi == BC_IFORL || pi == BC_IITERL || | ||
161 | pi == BC_ILOOP)) { | ||
162 | #endif | ||
163 | sprintf(name, LABEL_PREFIX_BC "%s", bc_names[pi]); | ||
164 | emit_asm_label(ctx, name, size, 1); | ||
165 | } | ||
166 | while (rel < ctx->nreloc && ctx->reloc[rel].ofs < stop) { | ||
167 | int n = ctx->reloc[rel].ofs - prev; | ||
168 | if (ctx->mode == BUILD_machasm && ctx->reloc[rel].type != 0) { | ||
169 | emit_asm_reloc_mach(ctx, ctx->code+prev, n, | ||
170 | ctx->extnames[ctx->reloc[rel].sym]); | ||
171 | } else { | ||
172 | emit_asm_bytes(ctx, ctx->code+prev, n); | ||
173 | emit_asm_reloc(ctx, &ctx->reloc[rel]); | ||
174 | } | ||
175 | prev += n+4; | ||
176 | rel++; | ||
177 | } | ||
178 | emit_asm_bytes(ctx, ctx->code+prev, stop-prev); | ||
179 | prev = next; | ||
180 | pi = ni; | ||
181 | } | ||
182 | |||
183 | switch (ctx->mode) { | ||
184 | case BUILD_elfasm: | ||
185 | fprintf(ctx->fp, "\n\t.section .rodata\n"); | ||
186 | break; | ||
187 | case BUILD_coffasm: | ||
188 | fprintf(ctx->fp, "\n\t.section .rdata,\"dr\"\n"); | ||
189 | break; | ||
190 | case BUILD_machasm: | ||
191 | fprintf(ctx->fp, "\n\t.const\n"); | ||
192 | break; | ||
193 | default: | ||
194 | break; | ||
195 | } | ||
196 | emit_asm_align(ctx, 5); | ||
197 | |||
198 | emit_asm_label(ctx, LABEL_OP_OFS, 2*ctx->npc, 0); | ||
199 | for (i = 0; i < ctx->npc; i++) | ||
200 | fprintf(ctx->fp, "\t.short %d\n", ctx->sym_ofs[i]); | ||
201 | |||
202 | fprintf(ctx->fp, "\n"); | ||
203 | switch (ctx->mode) { | ||
204 | case BUILD_elfasm: | ||
205 | fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\",@progbits\n"); | ||
206 | /* fallthrough */ | ||
207 | case BUILD_coffasm: | ||
208 | fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident); | ||
209 | break; | ||
210 | case BUILD_machasm: | ||
211 | fprintf(ctx->fp, | ||
212 | "\t.cstring\n" | ||
213 | "\t.ascii \"%s\\0\"\n", ctx->dasm_ident); | ||
214 | break; | ||
215 | default: | ||
216 | break; | ||
217 | } | ||
218 | fprintf(ctx->fp, "\n"); | ||
219 | } | ||
220 | |||