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
? "_" : "";
104 const char *symprefix
= ctx
->mode
!= BUILD_elfasm
? "_" : "";
106 sprintf(name
, "%s%s%s", symprefix
, prefix
, suffix
);
107 p
= strchr(name
, '@');
109 if (!LJ_64
&& (ctx
->mode
== BUILD_coffasm
|| ctx
->mode
== BUILD_peobj
))
114 p
= (char *)malloc(strlen(name
)+1); /* MSVC doesn't like strdup. */
119 #define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
121 static int relocmap
[NRELOCSYM
];
123 /* Collect external relocations. */
124 static int collect_reloc(BuildCtx
*ctx
, uint8_t *addr
, int idx
, int type
)
126 if (ctx
->nreloc
>= BUILD_MAX_RELOC
) {
127 fprintf(stderr
, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
130 if (relocmap
[idx
] < 0) {
131 relocmap
[idx
] = ctx
->nrelocsym
;
132 ctx
->relocsym
[ctx
->nrelocsym
] = sym_decorate(ctx
, "", extnames
[idx
]);
135 ctx
->reloc
[ctx
->nreloc
].ofs
= (int32_t)(addr
- ctx
->code
);
136 ctx
->reloc
[ctx
->nreloc
].sym
= relocmap
[idx
];
137 ctx
->reloc
[ctx
->nreloc
].type
= type
;
139 return 0; /* Encode symbol offset of 0. */
142 /* Naive insertion sort. Performance doesn't matter here. */
143 static void sym_insert(BuildCtx
*ctx
, int32_t ofs
,
144 const char *prefix
, const char *suffix
)
146 ptrdiff_t i
= ctx
->nsym
++;
148 if (ctx
->sym
[i
-1].ofs
<= ofs
)
150 ctx
->sym
[i
] = ctx
->sym
[i
-1];
153 ctx
->sym
[i
].ofs
= ofs
;
154 ctx
->sym
[i
].name
= sym_decorate(ctx
, prefix
, suffix
);
157 /* Build the machine code. */
158 static int build_code(BuildCtx
*ctx
)
163 /* Initialize DynASM structures. */
164 ctx
->nglob
= GLOB__MAX
;
165 ctx
->glob
= (void **)malloc(ctx
->nglob
*sizeof(void *));
166 memset(ctx
->glob
, 0, ctx
->nglob
*sizeof(void *));
169 ctx
->globnames
= globnames
;
170 ctx
->relocsym
= (const char **)malloc(NRELOCSYM
*sizeof(const char *));
172 for (i
= 0; i
< (int)NRELOCSYM
; i
++) relocmap
[i
] = -1;
174 ctx
->dasm_ident
= DASM_IDENT
;
175 ctx
->dasm_arch
= DASM_ARCH
;
177 dasm_init(Dst
, DASM_MAXSECTION
);
178 dasm_setupglobal(Dst
, ctx
->glob
, ctx
->nglob
);
179 dasm_setup(Dst
, build_actionlist
);
181 /* Call arch-specific backend to emit the code. */
182 ctx
->npc
= build_backend(ctx
);
184 /* Finalize the code. */
185 (void)dasm_checkstep(Dst
, -1);
186 if ((status
= dasm_link(Dst
, &ctx
->codesz
))) return status
;
187 ctx
->code
= (uint8_t *)malloc(ctx
->codesz
);
188 if ((status
= dasm_encode(Dst
, (void *)ctx
->code
))) return status
;
190 /* Allocate symbol table and bytecode offsets. */
191 ctx
->beginsym
= sym_decorate(ctx
, "", LABEL_PREFIX
"vm_asm_begin");
192 ctx
->sym
= (BuildSym
*)malloc((ctx
->npc
+ctx
->nglob
+1)*sizeof(BuildSym
));
194 ctx
->bc_ofs
= (int32_t *)malloc(ctx
->npc
*sizeof(int32_t));
196 /* Collect the opcodes (PC labels). */
197 for (i
= 0; i
< ctx
->npc
; i
++) {
198 int32_t ofs
= dasm_getpclabel(Dst
, i
);
199 if (ofs
< 0) return 0x22000000|i
;
200 ctx
->bc_ofs
[i
] = ofs
;
202 !(i
== BC_JFORI
|| i
== BC_JFORL
|| i
== BC_JITERL
|| i
== BC_JLOOP
||
203 i
== BC_IFORL
|| i
== BC_IITERL
|| i
== BC_ILOOP
)) &&
204 (LJ_HASFFI
|| i
!= BC_KCDATA
))
205 sym_insert(ctx
, ofs
, LABEL_PREFIX_BC
, bc_names
[i
]);
208 /* Collect the globals (named labels). */
209 for (i
= 0; i
< ctx
->nglob
; i
++) {
210 const char *gl
= globnames
[i
];
211 int len
= (int)strlen(gl
);
213 fprintf(stderr
, "Error: undefined global %s\n", gl
);
216 /* Skip the _Z symbols. */
217 if (!(len
>= 2 && gl
[len
-2] == '_' && gl
[len
-1] == 'Z'))
218 sym_insert(ctx
, (int32_t)((uint8_t *)(ctx
->glob
[i
]) - ctx
->code
),
219 LABEL_PREFIX
, globnames
[i
]);
222 /* Close the address range. */
223 sym_insert(ctx
, (int32_t)ctx
->codesz
, "", "");
231 /* -- Generate VM enums --------------------------------------------------- */
233 const char *const bc_names
[] = {
234 #define BCNAME(name, ma, mb, mc, mt) #name,
240 const char *const ir_names
[] = {
241 #define IRNAME(name, m, m1, m2) #name,
247 const char *const irt_names
[] = {
248 #define IRTNAME(name) #name,
254 const char *const irfpm_names
[] = {
255 #define FPMNAME(name) #name,
261 const char *const irfield_names
[] = {
262 #define FLNAME(name, ofs) #name,
268 const char *const ircall_names
[] = {
269 #define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
270 IRCALLDEF(IRCALLNAME
)
275 static const char *const trace_errors
[] = {
276 #define TREDEF(name, msg) msg,
277 #include "lj_traceerr.h"
281 static const char *lower(char *buf
, const char *s
)
285 *p
++ = (*s
>= 'A' && *s
<= 'Z') ? *s
+0x20 : *s
;
292 /* Emit C source code for bytecode-related definitions. */
293 static void emit_bcdef(BuildCtx
*ctx
)
296 fprintf(ctx
->fp
, "/* This is a generated file. DO NOT EDIT! */\n\n");
297 fprintf(ctx
->fp
, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
298 for (i
= 0; i
< ctx
->npc
; i
++) {
300 fprintf(ctx
->fp
, ",\n");
301 fprintf(ctx
->fp
, "%d", ctx
->bc_ofs
[i
]);
305 /* Emit VM definitions as Lua code for debug modules. */
306 static void emit_vmdef(BuildCtx
*ctx
)
310 fprintf(ctx
->fp
, "-- This is a generated file. DO NOT EDIT!\n\n");
311 fprintf(ctx
->fp
, "module(...)\n\n");
313 fprintf(ctx
->fp
, "bcnames = \"");
314 for (i
= 0; bc_names
[i
]; i
++) fprintf(ctx
->fp
, "%-6s", bc_names
[i
]);
315 fprintf(ctx
->fp
, "\"\n\n");
317 fprintf(ctx
->fp
, "irnames = \"");
318 for (i
= 0; ir_names
[i
]; i
++) fprintf(ctx
->fp
, "%-6s", ir_names
[i
]);
319 fprintf(ctx
->fp
, "\"\n\n");
321 fprintf(ctx
->fp
, "irfpm = { [0]=");
322 for (i
= 0; irfpm_names
[i
]; i
++)
323 fprintf(ctx
->fp
, "\"%s\", ", lower(buf
, irfpm_names
[i
]));
324 fprintf(ctx
->fp
, "}\n\n");
326 fprintf(ctx
->fp
, "irfield = { [0]=");
327 for (i
= 0; irfield_names
[i
]; i
++) {
329 lower(buf
, irfield_names
[i
]);
330 p
= strchr(buf
, '_');
332 fprintf(ctx
->fp
, "\"%s\", ", buf
);
334 fprintf(ctx
->fp
, "}\n\n");
336 fprintf(ctx
->fp
, "ircall = {\n[0]=");
337 for (i
= 0; ircall_names
[i
]; i
++)
338 fprintf(ctx
->fp
, "\"%s\",\n", ircall_names
[i
]);
339 fprintf(ctx
->fp
, "}\n\n");
341 fprintf(ctx
->fp
, "traceerr = {\n[0]=");
342 for (i
= 0; trace_errors
[i
]; i
++)
343 fprintf(ctx
->fp
, "\"%s\",\n", trace_errors
[i
]);
344 fprintf(ctx
->fp
, "}\n\n");
347 /* -- Argument parsing ---------------------------------------------------- */
349 /* Build mode names. */
350 static const char *const modenames
[] = {
351 #define BUILDNAME(name) #name,
357 /* Print usage information and exit. */
358 static void usage(void)
361 fprintf(stderr
, LUAJIT_VERSION
" VM builder.\n");
362 fprintf(stderr
, LUAJIT_COPYRIGHT
", " LUAJIT_URL
"\n");
363 fprintf(stderr
, "Target architecture: " LJ_ARCH_NAME
"\n\n");
364 fprintf(stderr
, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
365 fprintf(stderr
, "Available modes:\n");
366 for (i
= 0; i
< BUILD__MAX
; i
++)
367 fprintf(stderr
, " %s\n", modenames
[i
]);
371 /* Parse the output mode name. */
372 static BuildMode
parsemode(const char *mode
)
375 for (i
= 0; modenames
[i
]; i
++)
376 if (!strcmp(mode
, modenames
[i
]))
379 return (BuildMode
)-1;
382 /* Parse arguments. */
383 static void parseargs(BuildCtx
*ctx
, char **argv
)
387 ctx
->mode
= (BuildMode
)-1;
389 for (i
= 1; (a
= argv
[i
]) != NULL
; i
++) {
401 if (a
[2] || argv
[i
] == NULL
) goto err
;
402 ctx
->mode
= parsemode(argv
[i
]);
406 if (a
[2] || argv
[i
] == NULL
) goto err
;
407 ctx
->outname
= argv
[i
];
416 if (ctx
->mode
== (BuildMode
)-1) goto err
;
419 int main(int argc
, char **argv
)
422 BuildCtx
*ctx
= &ctx_
;
425 if (sizeof(void *) != 4*LJ_32
+8*LJ_64
) {
426 fprintf(stderr
,"Error: pointer size mismatch in cross-build.\n");
427 fprintf(stderr
,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n");
432 parseargs(ctx
, argv
);
434 if ((status
= build_code(ctx
))) {
435 fprintf(stderr
,"Error: DASM error %08x\n", status
);
449 if (ctx
->outname
[0] == '-' && ctx
->outname
[1] == '\0') {
453 _setmode(_fileno(stdout
), _O_BINARY
); /* Yuck. */
455 } else if (!(ctx
->fp
= fopen(ctx
->outname
, binmode
? "wb" : "w"))) {
456 fprintf(stderr
, "Error: cannot open output file '%s': %s\n",
457 ctx
->outname
, strerror(errno
));
495 if (ferror(ctx
->fp
)) {
496 fprintf(stderr
, "Error: cannot write to output file: %s\n",