3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
5 ** This is a tool to build the hand-tuned assembler code required for
6 ** LuaJIT's bytecode interpreter. It supports a variety of output formats
7 ** to feed different toolchains (see usage() below).
9 ** This tool is not particularly optimized because it's only used while
10 ** _building_ LuaJIT. There's no point in distributing or installing it.
11 ** Only the object code generated by this tool is linked into LuaJIT.
13 ** Caveat: some memory is not free'd, error handling is lazy.
14 ** It's a one-shot tool -- any effort fixing this would be wasted.
22 #include "lj_ircall.h"
24 #include "lj_dispatch.h"
36 /* ------------------------------------------------------------------------ */
38 /* DynASM glue definitions. */
40 #define Dst_DECL BuildCtx *ctx
41 #define Dst_REF (ctx->D)
44 #include "../dynasm/dasm_proto.h"
46 /* Glue macros for DynASM. */
47 static int collect_reloc(BuildCtx
*ctx
, uint8_t *addr
, int idx
, int type
);
49 #define DASM_EXTERN(ctx, addr, idx, type) \
50 collect_reloc(ctx, addr, idx, type)
52 /* ------------------------------------------------------------------------ */
54 /* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
55 #define DASM_ALIGNED_WRITES 1
57 /* Embed architecture-specific DynASM encoder. */
58 #if LJ_TARGET_X86ORX64
59 #include "../dynasm/dasm_x86.h"
61 #include "../dynasm/dasm_arm.h"
63 #include "../dynasm/dasm_ppc.h"
64 #elif LJ_TARGET_PPCSPE
65 #include "../dynasm/dasm_ppc.h"
67 #include "../dynasm/dasm_mips.h"
69 #error "No support for this architecture (yet)"
72 /* Embed generated architecture-specific backend. */
73 #include "buildvm_arch.h"
75 /* ------------------------------------------------------------------------ */
77 void owrite(BuildCtx
*ctx
, const void *ptr
, size_t sz
)
79 if (fwrite(ptr
, 1, sz
, ctx
->fp
) != sz
) {
80 fprintf(stderr
, "Error: cannot write to output file: %s\n",
86 /* ------------------------------------------------------------------------ */
88 /* Emit code as raw bytes. Only used for DynASM debugging. */
89 static void emit_raw(BuildCtx
*ctx
)
91 owrite(ctx
, ctx
->code
, ctx
->codesz
);
94 /* -- Build machine code -------------------------------------------------- */
96 static const char *sym_decorate(BuildCtx
*ctx
,
97 const char *prefix
, const char *suffix
)
102 const char *symprefix
= ctx
->mode
== BUILD_machasm
? "_" : "";
103 #elif LJ_TARGET_XBOX360
104 const char *symprefix
= "";
106 const char *symprefix
= ctx
->mode
!= BUILD_elfasm
? "_" : "";
108 sprintf(name
, "%s%s%s", symprefix
, prefix
, suffix
);
109 p
= strchr(name
, '@');
111 if (!LJ_64
&& (ctx
->mode
== BUILD_coffasm
|| ctx
->mode
== BUILD_peobj
))
116 p
= (char *)malloc(strlen(name
)+1); /* MSVC doesn't like strdup. */
121 #define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
123 static int relocmap
[NRELOCSYM
];
125 /* Collect external relocations. */
126 static int collect_reloc(BuildCtx
*ctx
, uint8_t *addr
, int idx
, int type
)
128 if (ctx
->nreloc
>= BUILD_MAX_RELOC
) {
129 fprintf(stderr
, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
132 if (relocmap
[idx
] < 0) {
133 relocmap
[idx
] = ctx
->nrelocsym
;
134 ctx
->relocsym
[ctx
->nrelocsym
] = sym_decorate(ctx
, "", extnames
[idx
]);
137 ctx
->reloc
[ctx
->nreloc
].ofs
= (int32_t)(addr
- ctx
->code
);
138 ctx
->reloc
[ctx
->nreloc
].sym
= relocmap
[idx
];
139 ctx
->reloc
[ctx
->nreloc
].type
= type
;
141 #if LJ_TARGET_XBOX360
142 return (int)(ctx
->code
- addr
) + 4; /* Encode symbol offset of .text. */
144 return 0; /* Encode symbol offset of 0. */
148 /* Naive insertion sort. Performance doesn't matter here. */
149 static void sym_insert(BuildCtx
*ctx
, int32_t ofs
,
150 const char *prefix
, const char *suffix
)
152 ptrdiff_t i
= ctx
->nsym
++;
154 if (ctx
->sym
[i
-1].ofs
<= ofs
)
156 ctx
->sym
[i
] = ctx
->sym
[i
-1];
159 ctx
->sym
[i
].ofs
= ofs
;
160 ctx
->sym
[i
].name
= sym_decorate(ctx
, prefix
, suffix
);
163 /* Build the machine code. */
164 static int build_code(BuildCtx
*ctx
)
169 /* Initialize DynASM structures. */
170 ctx
->nglob
= GLOB__MAX
;
171 ctx
->glob
= (void **)malloc(ctx
->nglob
*sizeof(void *));
172 memset(ctx
->glob
, 0, ctx
->nglob
*sizeof(void *));
175 ctx
->globnames
= globnames
;
176 ctx
->relocsym
= (const char **)malloc(NRELOCSYM
*sizeof(const char *));
178 for (i
= 0; i
< (int)NRELOCSYM
; i
++) relocmap
[i
] = -1;
180 ctx
->dasm_ident
= DASM_IDENT
;
181 ctx
->dasm_arch
= DASM_ARCH
;
183 dasm_init(Dst
, DASM_MAXSECTION
);
184 dasm_setupglobal(Dst
, ctx
->glob
, ctx
->nglob
);
185 dasm_setup(Dst
, build_actionlist
);
187 /* Call arch-specific backend to emit the code. */
188 ctx
->npc
= build_backend(ctx
);
190 /* Finalize the code. */
191 (void)dasm_checkstep(Dst
, -1);
192 if ((status
= dasm_link(Dst
, &ctx
->codesz
))) return status
;
193 ctx
->code
= (uint8_t *)malloc(ctx
->codesz
);
194 if ((status
= dasm_encode(Dst
, (void *)ctx
->code
))) return status
;
196 /* Allocate symbol table and bytecode offsets. */
197 ctx
->beginsym
= sym_decorate(ctx
, "", LABEL_PREFIX
"vm_asm_begin");
198 ctx
->sym
= (BuildSym
*)malloc((ctx
->npc
+ctx
->nglob
+1)*sizeof(BuildSym
));
200 ctx
->bc_ofs
= (int32_t *)malloc(ctx
->npc
*sizeof(int32_t));
202 /* Collect the opcodes (PC labels). */
203 for (i
= 0; i
< ctx
->npc
; i
++) {
204 int32_t ofs
= dasm_getpclabel(Dst
, i
);
205 if (ofs
< 0) return 0x22000000|i
;
206 ctx
->bc_ofs
[i
] = ofs
;
208 !(i
== BC_JFORI
|| i
== BC_JFORL
|| i
== BC_JITERL
|| i
== BC_JLOOP
||
209 i
== BC_IFORL
|| i
== BC_IITERL
|| i
== BC_ILOOP
)) &&
210 (LJ_HASFFI
|| i
!= BC_KCDATA
))
211 sym_insert(ctx
, ofs
, LABEL_PREFIX_BC
, bc_names
[i
]);
214 /* Collect the globals (named labels). */
215 for (i
= 0; i
< ctx
->nglob
; i
++) {
216 const char *gl
= globnames
[i
];
217 int len
= (int)strlen(gl
);
219 fprintf(stderr
, "Error: undefined global %s\n", gl
);
222 /* Skip the _Z symbols. */
223 if (!(len
>= 2 && gl
[len
-2] == '_' && gl
[len
-1] == 'Z'))
224 sym_insert(ctx
, (int32_t)((uint8_t *)(ctx
->glob
[i
]) - ctx
->code
),
225 LABEL_PREFIX
, globnames
[i
]);
228 /* Close the address range. */
229 sym_insert(ctx
, (int32_t)ctx
->codesz
, "", "");
237 /* -- Generate VM enums --------------------------------------------------- */
239 const char *const bc_names
[] = {
240 #define BCNAME(name, ma, mb, mc, mt) #name,
246 const char *const ir_names
[] = {
247 #define IRNAME(name, m, m1, m2) #name,
253 const char *const irt_names
[] = {
254 #define IRTNAME(name, size) #name,
260 const char *const irfpm_names
[] = {
261 #define FPMNAME(name) #name,
267 const char *const irfield_names
[] = {
268 #define FLNAME(name, ofs) #name,
274 const char *const ircall_names
[] = {
275 #define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
276 IRCALLDEF(IRCALLNAME
)
281 static const char *const trace_errors
[] = {
282 #define TREDEF(name, msg) msg,
283 #include "lj_traceerr.h"
287 static const char *lower(char *buf
, const char *s
)
291 *p
++ = (*s
>= 'A' && *s
<= 'Z') ? *s
+0x20 : *s
;
298 /* Emit C source code for bytecode-related definitions. */
299 static void emit_bcdef(BuildCtx
*ctx
)
302 fprintf(ctx
->fp
, "/* This is a generated file. DO NOT EDIT! */\n\n");
303 fprintf(ctx
->fp
, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
304 for (i
= 0; i
< ctx
->npc
; i
++) {
306 fprintf(ctx
->fp
, ",\n");
307 fprintf(ctx
->fp
, "%d", ctx
->bc_ofs
[i
]);
311 /* Emit VM definitions as Lua code for debug modules. */
312 static void emit_vmdef(BuildCtx
*ctx
)
316 fprintf(ctx
->fp
, "-- This is a generated file. DO NOT EDIT!\n\n");
317 fprintf(ctx
->fp
, "module(...)\n\n");
319 fprintf(ctx
->fp
, "bcnames = \"");
320 for (i
= 0; bc_names
[i
]; i
++) fprintf(ctx
->fp
, "%-6s", bc_names
[i
]);
321 fprintf(ctx
->fp
, "\"\n\n");
323 fprintf(ctx
->fp
, "irnames = \"");
324 for (i
= 0; ir_names
[i
]; i
++) fprintf(ctx
->fp
, "%-6s", ir_names
[i
]);
325 fprintf(ctx
->fp
, "\"\n\n");
327 fprintf(ctx
->fp
, "irfpm = { [0]=");
328 for (i
= 0; irfpm_names
[i
]; i
++)
329 fprintf(ctx
->fp
, "\"%s\", ", lower(buf
, irfpm_names
[i
]));
330 fprintf(ctx
->fp
, "}\n\n");
332 fprintf(ctx
->fp
, "irfield = { [0]=");
333 for (i
= 0; irfield_names
[i
]; i
++) {
335 lower(buf
, irfield_names
[i
]);
336 p
= strchr(buf
, '_');
338 fprintf(ctx
->fp
, "\"%s\", ", buf
);
340 fprintf(ctx
->fp
, "}\n\n");
342 fprintf(ctx
->fp
, "ircall = {\n[0]=");
343 for (i
= 0; ircall_names
[i
]; i
++)
344 fprintf(ctx
->fp
, "\"%s\",\n", ircall_names
[i
]);
345 fprintf(ctx
->fp
, "}\n\n");
347 fprintf(ctx
->fp
, "traceerr = {\n[0]=");
348 for (i
= 0; trace_errors
[i
]; i
++)
349 fprintf(ctx
->fp
, "\"%s\",\n", trace_errors
[i
]);
350 fprintf(ctx
->fp
, "}\n\n");
353 /* -- Argument parsing ---------------------------------------------------- */
355 /* Build mode names. */
356 static const char *const modenames
[] = {
357 #define BUILDNAME(name) #name,
363 /* Print usage information and exit. */
364 static void usage(void)
367 fprintf(stderr
, LUAJIT_VERSION
" VM builder.\n");
368 fprintf(stderr
, LUAJIT_COPYRIGHT
", " LUAJIT_URL
"\n");
369 fprintf(stderr
, "Target architecture: " LJ_ARCH_NAME
"\n\n");
370 fprintf(stderr
, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
371 fprintf(stderr
, "Available modes:\n");
372 for (i
= 0; i
< BUILD__MAX
; i
++)
373 fprintf(stderr
, " %s\n", modenames
[i
]);
377 /* Parse the output mode name. */
378 static BuildMode
parsemode(const char *mode
)
381 for (i
= 0; modenames
[i
]; i
++)
382 if (!strcmp(mode
, modenames
[i
]))
385 return (BuildMode
)-1;
388 /* Parse arguments. */
389 static void parseargs(BuildCtx
*ctx
, char **argv
)
393 ctx
->mode
= (BuildMode
)-1;
395 for (i
= 1; (a
= argv
[i
]) != NULL
; i
++) {
407 if (a
[2] || argv
[i
] == NULL
) goto err
;
408 ctx
->mode
= parsemode(argv
[i
]);
412 if (a
[2] || argv
[i
] == NULL
) goto err
;
413 ctx
->outname
= argv
[i
];
422 if (ctx
->mode
== (BuildMode
)-1) goto err
;
425 int main(int argc
, char **argv
)
428 BuildCtx
*ctx
= &ctx_
;
431 if (sizeof(void *) != 4*LJ_32
+8*LJ_64
) {
432 fprintf(stderr
,"Error: pointer size mismatch in cross-build.\n");
433 fprintf(stderr
,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n");
438 parseargs(ctx
, argv
);
440 if ((status
= build_code(ctx
))) {
441 fprintf(stderr
,"Error: DASM error %08x\n", status
);
455 if (ctx
->outname
[0] == '-' && ctx
->outname
[1] == '\0') {
459 _setmode(_fileno(stdout
), _O_BINARY
); /* Yuck. */
461 } else if (!(ctx
->fp
= fopen(ctx
->outname
, binmode
? "wb" : "w"))) {
462 fprintf(stderr
, "Error: cannot open output file '%s': %s\n",
463 ctx
->outname
, strerror(errno
));
501 if (ferror(ctx
->fp
)) {
502 fprintf(stderr
, "Error: cannot write to output file: %s\n",