3 ** Copyright (C) 2005-2011 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"
35 /* ------------------------------------------------------------------------ */
37 /* DynASM glue definitions. */
39 #define Dst_DECL BuildCtx *ctx
40 #define Dst_REF (ctx->D)
43 #include "../dynasm/dasm_proto.h"
45 /* Glue macros for DynASM. */
46 static int collect_reloc(BuildCtx
*ctx
, uint8_t *addr
, int idx
, int type
);
48 #define DASM_EXTERN(ctx, addr, idx, type) \
49 collect_reloc(ctx, addr, idx, type)
51 /* ------------------------------------------------------------------------ */
53 /* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
54 #define DASM_ALIGNED_WRITES 1
56 /* Embed architecture-specific DynASM encoder and backend. */
58 #include "../dynasm/dasm_x86.h"
59 #include "buildvm_x86.h"
61 #include "../dynasm/dasm_x86.h"
63 #include "buildvm_x64win.h"
65 #include "buildvm_x64.h"
68 #include "../dynasm/dasm_arm.h"
69 #include "buildvm_arm.h"
71 #include "../dynasm/dasm_ppc.h"
72 #include "buildvm_ppc.h"
73 #elif LJ_TARGET_PPCSPE
74 #include "../dynasm/dasm_ppc.h"
75 #include "buildvm_ppcspe.h"
77 #error "No support for this architecture (yet)"
80 /* ------------------------------------------------------------------------ */
82 void owrite(BuildCtx
*ctx
, const void *ptr
, size_t sz
)
84 if (fwrite(ptr
, 1, sz
, ctx
->fp
) != sz
) {
85 fprintf(stderr
, "Error: cannot write to output file: %s\n",
91 /* ------------------------------------------------------------------------ */
93 /* Emit code as raw bytes. Only used for DynASM debugging. */
94 static void emit_raw(BuildCtx
*ctx
)
96 owrite(ctx
, ctx
->code
, ctx
->codesz
);
99 /* -- Build machine code -------------------------------------------------- */
101 static const char *sym_decorate(BuildCtx
*ctx
,
102 const char *prefix
, const char *suffix
)
107 const char *symprefix
= ctx
->mode
== BUILD_machasm
? "_" : "";
109 const char *symprefix
= ctx
->mode
!= BUILD_elfasm
? "_" : "";
111 sprintf(name
, "%s%s%s", symprefix
, prefix
, suffix
);
112 p
= strchr(name
, '@');
114 if (!LJ_64
&& (ctx
->mode
== BUILD_coffasm
|| ctx
->mode
== BUILD_peobj
))
119 p
= (char *)malloc(strlen(name
)+1); /* MSVC doesn't like strdup. */
124 #define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
126 static int relocmap
[NRELOCSYM
];
128 /* Collect external relocations. */
129 static int collect_reloc(BuildCtx
*ctx
, uint8_t *addr
, int idx
, int type
)
131 if (ctx
->nreloc
>= BUILD_MAX_RELOC
) {
132 fprintf(stderr
, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
135 if (relocmap
[idx
] < 0) {
136 relocmap
[idx
] = ctx
->nrelocsym
;
137 ctx
->relocsym
[ctx
->nrelocsym
] = sym_decorate(ctx
, "", extnames
[idx
]);
140 ctx
->reloc
[ctx
->nreloc
].ofs
= (int32_t)(addr
- ctx
->code
);
141 ctx
->reloc
[ctx
->nreloc
].sym
= relocmap
[idx
];
142 ctx
->reloc
[ctx
->nreloc
].type
= type
;
144 return 0; /* Encode symbol offset of 0. */
147 /* Naive insertion sort. Performance doesn't matter here. */
148 static void sym_insert(BuildCtx
*ctx
, int32_t ofs
,
149 const char *prefix
, const char *suffix
)
151 ptrdiff_t i
= ctx
->nsym
++;
153 if (ctx
->sym
[i
-1].ofs
<= ofs
)
155 ctx
->sym
[i
] = ctx
->sym
[i
-1];
158 ctx
->sym
[i
].ofs
= ofs
;
159 ctx
->sym
[i
].name
= sym_decorate(ctx
, prefix
, suffix
);
162 /* Build the machine code. */
163 static int build_code(BuildCtx
*ctx
)
168 /* Initialize DynASM structures. */
169 ctx
->nglob
= GLOB__MAX
;
170 ctx
->glob
= (void **)malloc(ctx
->nglob
*sizeof(void *));
171 memset(ctx
->glob
, 0, ctx
->nglob
*sizeof(void *));
174 ctx
->globnames
= globnames
;
175 ctx
->relocsym
= (const char **)malloc(NRELOCSYM
*sizeof(const char *));
177 for (i
= 0; i
< (int)NRELOCSYM
; i
++) relocmap
[i
] = -1;
179 ctx
->dasm_ident
= DASM_IDENT
;
180 ctx
->dasm_arch
= DASM_ARCH
;
182 dasm_init(Dst
, DASM_MAXSECTION
);
183 dasm_setupglobal(Dst
, ctx
->glob
, ctx
->nglob
);
184 dasm_setup(Dst
, build_actionlist
);
186 /* Call arch-specific backend to emit the code. */
187 ctx
->npc
= build_backend(ctx
);
189 /* Finalize the code. */
190 (void)dasm_checkstep(Dst
, -1);
191 if ((status
= dasm_link(Dst
, &ctx
->codesz
))) return status
;
192 ctx
->code
= (uint8_t *)malloc(ctx
->codesz
);
193 if ((status
= dasm_encode(Dst
, (void *)ctx
->code
))) return status
;
195 /* Allocate symbol table and bytecode offsets. */
196 ctx
->beginsym
= sym_decorate(ctx
, "", LABEL_PREFIX
"vm_asm_begin");
197 ctx
->sym
= (BuildSym
*)malloc((ctx
->npc
+ctx
->nglob
+1)*sizeof(BuildSym
));
199 ctx
->bc_ofs
= (int32_t *)malloc(ctx
->npc
*sizeof(int32_t));
201 /* Collect the opcodes (PC labels). */
202 for (i
= 0; i
< ctx
->npc
; i
++) {
203 int32_t ofs
= dasm_getpclabel(Dst
, i
);
204 if (ofs
< 0) return 0x22000000|i
;
205 ctx
->bc_ofs
[i
] = ofs
;
207 !(i
== BC_JFORI
|| i
== BC_JFORL
|| i
== BC_JITERL
|| i
== BC_JLOOP
||
208 i
== BC_IFORL
|| i
== BC_IITERL
|| i
== BC_ILOOP
)) &&
209 (LJ_HASFFI
|| i
!= BC_KCDATA
))
210 sym_insert(ctx
, ofs
, LABEL_PREFIX_BC
, bc_names
[i
]);
213 /* Collect the globals (named labels). */
214 for (i
= 0; i
< ctx
->nglob
; i
++) {
215 const char *gl
= globnames
[i
];
216 int len
= (int)strlen(gl
);
218 fprintf(stderr
, "Error: undefined global %s\n", gl
);
221 /* Skip the _Z symbols. */
222 if (!(len
>= 2 && gl
[len
-2] == '_' && gl
[len
-1] == 'Z'))
223 sym_insert(ctx
, (int32_t)((uint8_t *)(ctx
->glob
[i
]) - ctx
->code
),
224 LABEL_PREFIX
, globnames
[i
]);
227 /* Close the address range. */
228 sym_insert(ctx
, (int32_t)ctx
->codesz
, "", "");
236 /* -- Generate VM enums --------------------------------------------------- */
238 const char *const bc_names
[] = {
239 #define BCNAME(name, ma, mb, mc, mt) #name,
245 const char *const ir_names
[] = {
246 #define IRNAME(name, m, m1, m2) #name,
252 const char *const irt_names
[] = {
253 #define IRTNAME(name) #name,
259 const char *const irfpm_names
[] = {
260 #define FPMNAME(name) #name,
266 const char *const irfield_names
[] = {
267 #define FLNAME(name, ofs) #name,
273 const char *const ircall_names
[] = {
274 #define IRCALLNAME(name, nargs, kind, type, flags) #name,
275 IRCALLDEF(IRCALLNAME
)
280 static const char *const trace_errors
[] = {
281 #define TREDEF(name, msg) msg,
282 #include "lj_traceerr.h"
286 static const char *lower(char *buf
, const char *s
)
290 *p
++ = (*s
>= 'A' && *s
<= 'Z') ? *s
+0x20 : *s
;
297 /* Emit C source code for bytecode-related definitions. */
298 static void emit_bcdef(BuildCtx
*ctx
)
301 fprintf(ctx
->fp
, "/* This is a generated file. DO NOT EDIT! */\n\n");
302 fprintf(ctx
->fp
, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
303 for (i
= 0; i
< ctx
->npc
; i
++) {
305 fprintf(ctx
->fp
, ",\n");
306 fprintf(ctx
->fp
, "%d", ctx
->bc_ofs
[i
]);
310 /* Emit VM definitions as Lua code for debug modules. */
311 static void emit_vmdef(BuildCtx
*ctx
)
315 fprintf(ctx
->fp
, "-- This is a generated file. DO NOT EDIT!\n\n");
316 fprintf(ctx
->fp
, "module(...)\n\n");
318 fprintf(ctx
->fp
, "bcnames = \"");
319 for (i
= 0; bc_names
[i
]; i
++) fprintf(ctx
->fp
, "%-6s", bc_names
[i
]);
320 fprintf(ctx
->fp
, "\"\n\n");
322 fprintf(ctx
->fp
, "irnames = \"");
323 for (i
= 0; ir_names
[i
]; i
++) fprintf(ctx
->fp
, "%-6s", ir_names
[i
]);
324 fprintf(ctx
->fp
, "\"\n\n");
326 fprintf(ctx
->fp
, "irfpm = { [0]=");
327 for (i
= 0; irfpm_names
[i
]; i
++)
328 fprintf(ctx
->fp
, "\"%s\", ", lower(buf
, irfpm_names
[i
]));
329 fprintf(ctx
->fp
, "}\n\n");
331 fprintf(ctx
->fp
, "irfield = { [0]=");
332 for (i
= 0; irfield_names
[i
]; i
++) {
334 lower(buf
, irfield_names
[i
]);
335 p
= strchr(buf
, '_');
337 fprintf(ctx
->fp
, "\"%s\", ", buf
);
339 fprintf(ctx
->fp
, "}\n\n");
341 fprintf(ctx
->fp
, "ircall = {\n[0]=");
342 for (i
= 0; ircall_names
[i
]; i
++)
343 fprintf(ctx
->fp
, "\"%s\",\n", ircall_names
[i
]);
344 fprintf(ctx
->fp
, "}\n\n");
346 fprintf(ctx
->fp
, "traceerr = {\n[0]=");
347 for (i
= 0; trace_errors
[i
]; i
++)
348 fprintf(ctx
->fp
, "\"%s\",\n", trace_errors
[i
]);
349 fprintf(ctx
->fp
, "}\n\n");
352 /* -- Argument parsing ---------------------------------------------------- */
354 /* Build mode names. */
355 static const char *const modenames
[] = {
356 #define BUILDNAME(name) #name,
362 /* Print usage information and exit. */
363 static void usage(void)
366 fprintf(stderr
, LUAJIT_VERSION
" VM builder.\n");
367 fprintf(stderr
, LUAJIT_COPYRIGHT
", " LUAJIT_URL
"\n");
368 fprintf(stderr
, "Target architecture: " LJ_ARCH_NAME
"\n\n");
369 fprintf(stderr
, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
370 fprintf(stderr
, "Available modes:\n");
371 for (i
= 0; i
< BUILD__MAX
; i
++)
372 fprintf(stderr
, " %s\n", modenames
[i
]);
376 /* Parse the output mode name. */
377 static BuildMode
parsemode(const char *mode
)
380 for (i
= 0; modenames
[i
]; i
++)
381 if (!strcmp(mode
, modenames
[i
]))
384 return (BuildMode
)-1;
387 /* Parse arguments. */
388 static void parseargs(BuildCtx
*ctx
, char **argv
)
392 ctx
->mode
= (BuildMode
)-1;
394 for (i
= 1; (a
= argv
[i
]) != NULL
; i
++) {
406 if (a
[2] || argv
[i
] == NULL
) goto err
;
407 ctx
->mode
= parsemode(argv
[i
]);
411 if (a
[2] || argv
[i
] == NULL
) goto err
;
412 ctx
->outname
= argv
[i
];
421 if (ctx
->mode
== (BuildMode
)-1) goto err
;
424 int main(int argc
, char **argv
)
427 BuildCtx
*ctx
= &ctx_
;
430 if (sizeof(void *) != 4*LJ_32
+8*LJ_64
) {
431 fprintf(stderr
,"Error: pointer size mismatch in cross-build.\n");
432 fprintf(stderr
,"Try: make HOST_CC=\"gcc -m32\" CROSS=... TARGET=...\n\n");
437 parseargs(ctx
, argv
);
439 if ((status
= build_code(ctx
))) {
440 fprintf(stderr
,"Error: DASM error %08x\n", status
);
454 if (ctx
->outname
[0] == '-' && ctx
->outname
[1] == '\0') {
458 _setmode(_fileno(stdout
), _O_BINARY
); /* Yuck. */
460 } else if (!(ctx
->fp
= fopen(ctx
->outname
, binmode
? "wb" : "w"))) {
461 fprintf(stderr
, "Error: cannot open output file '%s': %s\n",
462 ctx
->outname
, strerror(errno
));
500 if (ferror(ctx
->fp
)) {
501 fprintf(stderr
, "Error: cannot write to output file: %s\n",