aboutsummaryrefslogtreecommitdiff
path: root/src/host
diff options
context:
space:
mode:
Diffstat (limited to 'src/host')
-rw-r--r--src/host/.gitignore3
-rw-r--r--src/host/buildvm.c504
-rw-r--r--src/host/buildvm.h104
-rw-r--r--src/host/buildvm_asm.c283
-rw-r--r--src/host/buildvm_fold.c229
-rw-r--r--src/host/buildvm_lib.c377
-rw-r--r--src/host/buildvm_peobj.c352
7 files changed, 1852 insertions, 0 deletions
diff --git a/src/host/.gitignore b/src/host/.gitignore
new file mode 100644
index 00000000..762ac2a0
--- /dev/null
+++ b/src/host/.gitignore
@@ -0,0 +1,3 @@
1minilua
2buildvm
3buildvm_arch.h
diff --git a/src/host/buildvm.c b/src/host/buildvm.c
new file mode 100644
index 00000000..7dbf2cae
--- /dev/null
+++ b/src/host/buildvm.c
@@ -0,0 +1,504 @@
1/*
2** LuaJIT VM builder.
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4**
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).
8**
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.
12**
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.
15*/
16
17#include "buildvm.h"
18#include "lj_obj.h"
19#include "lj_gc.h"
20#include "lj_bc.h"
21#include "lj_ir.h"
22#include "lj_ircall.h"
23#include "lj_frame.h"
24#include "lj_dispatch.h"
25#if LJ_HASFFI
26#include "lj_ctype.h"
27#include "lj_ccall.h"
28#endif
29#include "luajit.h"
30
31#if defined(_WIN32)
32#include <fcntl.h>
33#include <io.h>
34#endif
35
36/* ------------------------------------------------------------------------ */
37
38/* DynASM glue definitions. */
39#define Dst ctx
40#define Dst_DECL BuildCtx *ctx
41#define Dst_REF (ctx->D)
42#define DASM_CHECKS 1
43
44#include "../dynasm/dasm_proto.h"
45
46/* Glue macros for DynASM. */
47static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
48
49#define DASM_EXTERN(ctx, addr, idx, type) \
50 collect_reloc(ctx, addr, idx, type)
51
52/* ------------------------------------------------------------------------ */
53
54/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
55#define DASM_ALIGNED_WRITES 1
56
57/* Embed architecture-specific DynASM encoder. */
58#if LJ_TARGET_X86ORX64
59#include "../dynasm/dasm_x86.h"
60#elif LJ_TARGET_ARM
61#include "../dynasm/dasm_arm.h"
62#elif LJ_TARGET_PPC
63#include "../dynasm/dasm_ppc.h"
64#elif LJ_TARGET_PPCSPE
65#include "../dynasm/dasm_ppc.h"
66#elif LJ_TARGET_MIPS
67#include "../dynasm/dasm_mips.h"
68#else
69#error "No support for this architecture (yet)"
70#endif
71
72/* Embed generated architecture-specific backend. */
73#include "buildvm_arch.h"
74
75/* ------------------------------------------------------------------------ */
76
77void owrite(BuildCtx *ctx, const void *ptr, size_t sz)
78{
79 if (fwrite(ptr, 1, sz, ctx->fp) != sz) {
80 fprintf(stderr, "Error: cannot write to output file: %s\n",
81 strerror(errno));
82 exit(1);
83 }
84}
85
86/* ------------------------------------------------------------------------ */
87
88/* Emit code as raw bytes. Only used for DynASM debugging. */
89static void emit_raw(BuildCtx *ctx)
90{
91 owrite(ctx, ctx->code, ctx->codesz);
92}
93
94/* -- Build machine code -------------------------------------------------- */
95
96static const char *sym_decorate(BuildCtx *ctx,
97 const char *prefix, const char *suffix)
98{
99 char name[256];
100 char *p;
101#if LJ_64
102 const char *symprefix = ctx->mode == BUILD_machasm ? "_" : "";
103#else
104 const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : "";
105#endif
106 sprintf(name, "%s%s%s", symprefix, prefix, suffix);
107 p = strchr(name, '@');
108 if (p) {
109 if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
110 name[0] = '@';
111 else
112 *p = '\0';
113 }
114 p = (char *)malloc(strlen(name)+1); /* MSVC doesn't like strdup. */
115 strcpy(p, name);
116 return p;
117}
118
119#define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
120
121static int relocmap[NRELOCSYM];
122
123/* Collect external relocations. */
124static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type)
125{
126 if (ctx->nreloc >= BUILD_MAX_RELOC) {
127 fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
128 exit(1);
129 }
130 if (relocmap[idx] < 0) {
131 relocmap[idx] = ctx->nrelocsym;
132 ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]);
133 ctx->nrelocsym++;
134 }
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;
138 ctx->nreloc++;
139 return 0; /* Encode symbol offset of 0. */
140}
141
142/* Naive insertion sort. Performance doesn't matter here. */
143static void sym_insert(BuildCtx *ctx, int32_t ofs,
144 const char *prefix, const char *suffix)
145{
146 ptrdiff_t i = ctx->nsym++;
147 while (i > 0) {
148 if (ctx->sym[i-1].ofs <= ofs)
149 break;
150 ctx->sym[i] = ctx->sym[i-1];
151 i--;
152 }
153 ctx->sym[i].ofs = ofs;
154 ctx->sym[i].name = sym_decorate(ctx, prefix, suffix);
155}
156
157/* Build the machine code. */
158static int build_code(BuildCtx *ctx)
159{
160 int status;
161 int i;
162
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 *));
167 ctx->nreloc = 0;
168
169 ctx->globnames = globnames;
170 ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
171 ctx->nrelocsym = 0;
172 for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
173
174 ctx->dasm_ident = DASM_IDENT;
175 ctx->dasm_arch = DASM_ARCH;
176
177 dasm_init(Dst, DASM_MAXSECTION);
178 dasm_setupglobal(Dst, ctx->glob, ctx->nglob);
179 dasm_setup(Dst, build_actionlist);
180
181 /* Call arch-specific backend to emit the code. */
182 ctx->npc = build_backend(ctx);
183
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;
189
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));
193 ctx->nsym = 0;
194 ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t));
195
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;
201 if ((LJ_HASJIT ||
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]);
206 }
207
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);
212 if (!ctx->glob[i]) {
213 fprintf(stderr, "Error: undefined global %s\n", gl);
214 exit(2);
215 }
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]);
220 }
221
222 /* Close the address range. */
223 sym_insert(ctx, (int32_t)ctx->codesz, "", "");
224 ctx->nsym--;
225
226 dasm_free(Dst);
227
228 return 0;
229}
230
231/* -- Generate VM enums --------------------------------------------------- */
232
233const char *const bc_names[] = {
234#define BCNAME(name, ma, mb, mc, mt) #name,
235BCDEF(BCNAME)
236#undef BCNAME
237 NULL
238};
239
240const char *const ir_names[] = {
241#define IRNAME(name, m, m1, m2) #name,
242IRDEF(IRNAME)
243#undef IRNAME
244 NULL
245};
246
247const char *const irt_names[] = {
248#define IRTNAME(name) #name,
249IRTDEF(IRTNAME)
250#undef IRTNAME
251 NULL
252};
253
254const char *const irfpm_names[] = {
255#define FPMNAME(name) #name,
256IRFPMDEF(FPMNAME)
257#undef FPMNAME
258 NULL
259};
260
261const char *const irfield_names[] = {
262#define FLNAME(name, ofs) #name,
263IRFLDEF(FLNAME)
264#undef FLNAME
265 NULL
266};
267
268const char *const ircall_names[] = {
269#define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
270IRCALLDEF(IRCALLNAME)
271#undef IRCALLNAME
272 NULL
273};
274
275static const char *const trace_errors[] = {
276#define TREDEF(name, msg) msg,
277#include "lj_traceerr.h"
278 NULL
279};
280
281static const char *lower(char *buf, const char *s)
282{
283 char *p = buf;
284 while (*s) {
285 *p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s;
286 s++;
287 }
288 *p = '\0';
289 return buf;
290}
291
292/* Emit C source code for bytecode-related definitions. */
293static void emit_bcdef(BuildCtx *ctx)
294{
295 int i;
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++) {
299 if (i != 0)
300 fprintf(ctx->fp, ",\n");
301 fprintf(ctx->fp, "%d", ctx->bc_ofs[i]);
302 }
303}
304
305/* Emit VM definitions as Lua code for debug modules. */
306static void emit_vmdef(BuildCtx *ctx)
307{
308 char buf[80];
309 int i;
310 fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
311 fprintf(ctx->fp, "module(...)\n\n");
312
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");
316
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");
320
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");
325
326 fprintf(ctx->fp, "irfield = { [0]=");
327 for (i = 0; irfield_names[i]; i++) {
328 char *p;
329 lower(buf, irfield_names[i]);
330 p = strchr(buf, '_');
331 if (p) *p = '.';
332 fprintf(ctx->fp, "\"%s\", ", buf);
333 }
334 fprintf(ctx->fp, "}\n\n");
335
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");
340
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");
345}
346
347/* -- Argument parsing ---------------------------------------------------- */
348
349/* Build mode names. */
350static const char *const modenames[] = {
351#define BUILDNAME(name) #name,
352BUILDDEF(BUILDNAME)
353#undef BUILDNAME
354 NULL
355};
356
357/* Print usage information and exit. */
358static void usage(void)
359{
360 int i;
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]);
368 exit(1);
369}
370
371/* Parse the output mode name. */
372static BuildMode parsemode(const char *mode)
373{
374 int i;
375 for (i = 0; modenames[i]; i++)
376 if (!strcmp(mode, modenames[i]))
377 return (BuildMode)i;
378 usage();
379 return (BuildMode)-1;
380}
381
382/* Parse arguments. */
383static void parseargs(BuildCtx *ctx, char **argv)
384{
385 const char *a;
386 int i;
387 ctx->mode = (BuildMode)-1;
388 ctx->outname = "-";
389 for (i = 1; (a = argv[i]) != NULL; i++) {
390 if (a[0] != '-')
391 break;
392 switch (a[1]) {
393 case '-':
394 if (a[2]) goto err;
395 i++;
396 goto ok;
397 case '\0':
398 goto ok;
399 case 'm':
400 i++;
401 if (a[2] || argv[i] == NULL) goto err;
402 ctx->mode = parsemode(argv[i]);
403 break;
404 case 'o':
405 i++;
406 if (a[2] || argv[i] == NULL) goto err;
407 ctx->outname = argv[i];
408 break;
409 default: err:
410 usage();
411 break;
412 }
413 }
414ok:
415 ctx->args = argv+i;
416 if (ctx->mode == (BuildMode)-1) goto err;
417}
418
419int main(int argc, char **argv)
420{
421 BuildCtx ctx_;
422 BuildCtx *ctx = &ctx_;
423 int status, binmode;
424
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=... TARGET=...\n\n");
428 return 1;
429 }
430
431 UNUSED(argc);
432 parseargs(ctx, argv);
433
434 if ((status = build_code(ctx))) {
435 fprintf(stderr,"Error: DASM error %08x\n", status);
436 return 1;
437 }
438
439 switch (ctx->mode) {
440 case BUILD_peobj:
441 case BUILD_raw:
442 binmode = 1;
443 break;
444 default:
445 binmode = 0;
446 break;
447 }
448
449 if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') {
450 ctx->fp = stdout;
451#if defined(_WIN32)
452 if (binmode)
453 _setmode(_fileno(stdout), _O_BINARY); /* Yuck. */
454#endif
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));
458 exit(1);
459 }
460
461 switch (ctx->mode) {
462 case BUILD_elfasm:
463 case BUILD_coffasm:
464 case BUILD_machasm:
465 emit_asm(ctx);
466 emit_asm_debug(ctx);
467 break;
468 case BUILD_peobj:
469 emit_peobj(ctx);
470 break;
471 case BUILD_raw:
472 emit_raw(ctx);
473 break;
474 case BUILD_bcdef:
475 emit_bcdef(ctx);
476 emit_lib(ctx);
477 break;
478 case BUILD_vmdef:
479 emit_vmdef(ctx);
480 emit_lib(ctx);
481 break;
482 case BUILD_ffdef:
483 case BUILD_libdef:
484 case BUILD_recdef:
485 emit_lib(ctx);
486 break;
487 case BUILD_folddef:
488 emit_fold(ctx);
489 break;
490 default:
491 break;
492 }
493
494 fflush(ctx->fp);
495 if (ferror(ctx->fp)) {
496 fprintf(stderr, "Error: cannot write to output file: %s\n",
497 strerror(errno));
498 exit(1);
499 }
500 fclose(ctx->fp);
501
502 return 0;
503}
504
diff --git a/src/host/buildvm.h b/src/host/buildvm.h
new file mode 100644
index 00000000..2b7168ed
--- /dev/null
+++ b/src/host/buildvm.h
@@ -0,0 +1,104 @@
1/*
2** LuaJIT VM builder.
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#ifndef _BUILDVM_H
7#define _BUILDVM_H
8
9#include <sys/types.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <errno.h>
14
15#include "lj_def.h"
16#include "lj_arch.h"
17
18/* Hardcoded limits. Increase as needed. */
19#define BUILD_MAX_RELOC 200 /* Max. number of relocations. */
20#define BUILD_MAX_FOLD 4096 /* Max. number of fold rules. */
21
22/* Prefix for scanned library definitions. */
23#define LIBDEF_PREFIX "LJLIB_"
24
25/* Prefix for scanned fold definitions. */
26#define FOLDDEF_PREFIX "LJFOLD"
27
28/* Prefixes for generated labels. */
29#define LABEL_PREFIX "lj_"
30#define LABEL_PREFIX_BC LABEL_PREFIX "BC_"
31#define LABEL_PREFIX_FF LABEL_PREFIX "ff_"
32#define LABEL_PREFIX_CF LABEL_PREFIX "cf_"
33#define LABEL_PREFIX_FFH LABEL_PREFIX "ffh_"
34#define LABEL_PREFIX_LIBCF LABEL_PREFIX "lib_cf_"
35#define LABEL_PREFIX_LIBINIT LABEL_PREFIX "lib_init_"
36
37/* Forward declaration. */
38struct dasm_State;
39
40/* Build modes. */
41#define BUILDDEF(_) \
42 _(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \
43 _(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \
44 _(folddef)
45
46typedef enum {
47#define BUILDENUM(name) BUILD_##name,
48BUILDDEF(BUILDENUM)
49#undef BUILDENUM
50 BUILD__MAX
51} BuildMode;
52
53/* Code relocation. */
54typedef struct BuildReloc {
55 int32_t ofs;
56 int sym;
57 int type;
58} BuildReloc;
59
60typedef struct BuildSym {
61 const char *name;
62 int32_t ofs;
63} BuildSym;
64
65/* Build context structure. */
66typedef struct BuildCtx {
67 /* DynASM state pointer. Should be first member. */
68 struct dasm_State *D;
69 /* Parsed command line. */
70 BuildMode mode;
71 FILE *fp;
72 const char *outname;
73 char **args;
74 /* Code and symbols generated by DynASM. */
75 uint8_t *code;
76 size_t codesz;
77 int npc, nglob, nsym, nreloc, nrelocsym;
78 void **glob;
79 BuildSym *sym;
80 const char **relocsym;
81 int32_t *bc_ofs;
82 const char *beginsym;
83 /* Strings generated by DynASM. */
84 const char *const *globnames;
85 const char *dasm_ident;
86 const char *dasm_arch;
87 /* Relocations. */
88 BuildReloc reloc[BUILD_MAX_RELOC];
89} BuildCtx;
90
91extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz);
92extern void emit_asm(BuildCtx *ctx);
93extern void emit_peobj(BuildCtx *ctx);
94extern void emit_lib(BuildCtx *ctx);
95extern void emit_fold(BuildCtx *ctx);
96
97extern const char *const bc_names[];
98extern const char *const ir_names[];
99extern const char *const irt_names[];
100extern const char *const irfpm_names[];
101extern const char *const irfield_names[];
102extern const char *const ircall_names[];
103
104#endif
diff --git a/src/host/buildvm_asm.c b/src/host/buildvm_asm.c
new file mode 100644
index 00000000..f975eadc
--- /dev/null
+++ b/src/host/buildvm_asm.c
@@ -0,0 +1,283 @@
1/*
2** LuaJIT VM builder: Assembler source code emitter.
3** Copyright (C) 2005-2012 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. */
13static 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 */
27static 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
49static 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. */
55static 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 {
68err:
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. */
78static 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. */
92static 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 fprintf(stderr,
124 "Error: unsupported opcode %08x for %s symbol relocation.\n",
125 ins, sym);
126 exit(1);
127#else
128#error "missing relocation support for this architecture"
129#endif
130}
131#endif
132
133#if LJ_TARGET_ARM
134#define ELFASM_PX "%%"
135#else
136#define ELFASM_PX "@"
137#endif
138
139/* Emit an assembler label. */
140static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
141{
142 switch (ctx->mode) {
143 case BUILD_elfasm:
144 fprintf(ctx->fp,
145 "\n\t.globl %s\n"
146 "\t.hidden %s\n"
147 "\t.type %s, " ELFASM_PX "%s\n"
148 "\t.size %s, %d\n"
149 "%s:\n",
150 name, name, name, isfunc ? "function" : "object", name, size, name);
151 break;
152 case BUILD_coffasm:
153 fprintf(ctx->fp, "\n\t.globl %s\n", name);
154 if (isfunc)
155 fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
156 fprintf(ctx->fp, "%s:\n", name);
157 break;
158 case BUILD_machasm:
159 fprintf(ctx->fp,
160 "\n\t.private_extern %s\n"
161 "%s:\n", name, name);
162 break;
163 default:
164 break;
165 }
166}
167
168/* Emit alignment. */
169static void emit_asm_align(BuildCtx *ctx, int bits)
170{
171 switch (ctx->mode) {
172 case BUILD_elfasm:
173 case BUILD_coffasm:
174 fprintf(ctx->fp, "\t.p2align %d\n", bits);
175 break;
176 case BUILD_machasm:
177 fprintf(ctx->fp, "\t.align %d\n", bits);
178 break;
179 default:
180 break;
181 }
182}
183
184/* ------------------------------------------------------------------------ */
185
186/* Emit assembler source code. */
187void emit_asm(BuildCtx *ctx)
188{
189 int i, rel;
190
191 fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
192 fprintf(ctx->fp, "\t.text\n");
193 emit_asm_align(ctx, 4);
194
195 emit_asm_label(ctx, ctx->beginsym, 0, 0);
196 if (ctx->mode != BUILD_machasm)
197 fprintf(ctx->fp, ".Lbegin:\n");
198
199#if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
200 /* This should really be moved into buildvm_arm.dasc. */
201 fprintf(ctx->fp,
202 ".fnstart\n"
203 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
204 ".pad #28\n");
205#endif
206#if LJ_TARGET_MIPS
207 fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
208#endif
209
210 for (i = rel = 0; i < ctx->nsym; i++) {
211 int32_t ofs = ctx->sym[i].ofs;
212 int32_t next = ctx->sym[i+1].ofs;
213#if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND) && \
214 LJ_HASFFI
215 if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
216 fprintf(ctx->fp,
217 ".globl lj_err_unwind_arm\n"
218 ".personality lj_err_unwind_arm\n"
219 ".fnend\n"
220 ".fnstart\n"
221 ".save {r4, r5, r11, lr}\n"
222 ".setfp r11, sp\n");
223#endif
224 emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
225 while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
226 BuildReloc *r = &ctx->reloc[rel];
227 int n = r->ofs - ofs;
228#if LJ_TARGET_X86ORX64
229 if (ctx->mode == BUILD_machasm && r->type != 0) {
230 emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
231 } else {
232 emit_asm_bytes(ctx, ctx->code+ofs, n);
233 emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
234 }
235 ofs += n+4;
236#else
237 emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
238 ofs += n;
239#endif
240 rel++;
241 }
242#if LJ_TARGET_X86ORX64
243 emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
244#else
245 emit_asm_words(ctx, ctx->code+ofs, next-ofs);
246#endif
247 }
248
249#if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
250 fprintf(ctx->fp,
251#if !LJ_HASFFI
252 ".globl lj_err_unwind_arm\n"
253 ".personality lj_err_unwind_arm\n"
254#endif
255 ".fnend\n");
256#endif
257
258 fprintf(ctx->fp, "\n");
259 switch (ctx->mode) {
260 case BUILD_elfasm:
261 fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
262#if LJ_TARGET_PPCSPE
263 /* Soft-float ABI + SPE. */
264 fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
265#elif LJ_TARGET_PPC
266 /* Hard-float ABI. */
267 fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
268#endif
269 /* fallthrough */
270 case BUILD_coffasm:
271 fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
272 break;
273 case BUILD_machasm:
274 fprintf(ctx->fp,
275 "\t.cstring\n"
276 "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
277 break;
278 default:
279 break;
280 }
281 fprintf(ctx->fp, "\n");
282}
283
diff --git a/src/host/buildvm_fold.c b/src/host/buildvm_fold.c
new file mode 100644
index 00000000..73f4f80a
--- /dev/null
+++ b/src/host/buildvm_fold.c
@@ -0,0 +1,229 @@
1/*
2** LuaJIT VM builder: IR folding hash table generator.
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#include "buildvm.h"
7#include "lj_obj.h"
8#include "lj_ir.h"
9
10/* Context for the folding hash table generator. */
11static int lineno;
12static int funcidx;
13static uint32_t foldkeys[BUILD_MAX_FOLD];
14static uint32_t nkeys;
15
16/* Try to fill the hash table with keys using the hash parameters. */
17static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol)
18{
19 uint32_t i;
20 if (dorol && ((r & 31) == 0 || (r>>5) == 0))
21 return 0; /* Avoid zero rotates. */
22 memset(htab, 0xff, (sz+1)*sizeof(uint32_t));
23 for (i = 0; i < nkeys; i++) {
24 uint32_t key = foldkeys[i];
25 uint32_t k = key & 0xffffff;
26 uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) :
27 (((k << (r>>5)) - k) << (r&31))) % sz;
28 if (htab[h] != 0xffffffff) { /* Collision on primary slot. */
29 if (htab[h+1] != 0xffffffff) { /* Collision on secondary slot. */
30 /* Try to move the colliding key, if possible. */
31 if (h < sz-1 && htab[h+2] == 0xffffffff) {
32 uint32_t k2 = htab[h+1] & 0xffffff;
33 uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) :
34 (((k2 << (r>>5)) - k2) << (r&31))) % sz;
35 if (h2 != h+1) return 0; /* Cannot resolve collision. */
36 htab[h+2] = htab[h+1]; /* Move colliding key to secondary slot. */
37 } else {
38 return 0; /* Collision. */
39 }
40 }
41 htab[h+1] = key;
42 } else {
43 htab[h] = key;
44 }
45 }
46 return 1; /* Success, all keys could be stored. */
47}
48
49/* Print the generated hash table. */
50static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz)
51{
52 uint32_t i;
53 fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x",
54 sz+1, htab[0]);
55 for (i = 1; i < sz+1; i++)
56 fprintf(ctx->fp, ",\n0x%08x", htab[i]);
57 fprintf(ctx->fp, "\n};\n\n");
58}
59
60/* Exhaustive search for the shortest semi-perfect hash table. */
61static void makehash(BuildCtx *ctx)
62{
63 uint32_t htab[BUILD_MAX_FOLD*2+1];
64 uint32_t sz, r;
65 /* Search for the smallest hash table with an odd size. */
66 for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) {
67 /* First try all shift hash combinations. */
68 for (r = 0; r < 32*32; r++) {
69 if (tryhash(htab, sz, r, 0)) {
70 printhash(ctx, htab, sz);
71 fprintf(ctx->fp,
72 "#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n",
73 r>>5, r&31, sz);
74 return;
75 }
76 }
77 /* Then try all rotate hash combinations. */
78 for (r = 0; r < 32*32; r++) {
79 if (tryhash(htab, sz, r, 1)) {
80 printhash(ctx, htab, sz);
81 fprintf(ctx->fp,
82 "#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n",
83 r>>5, r&31, sz);
84 return;
85 }
86 }
87 }
88 fprintf(stderr, "Error: search for perfect hash failed\n");
89 exit(1);
90}
91
92/* Parse one token of a fold rule. */
93static uint32_t nexttoken(char **pp, int allowlit, int allowany)
94{
95 char *p = *pp;
96 if (p) {
97 uint32_t i;
98 char *q = strchr(p, ' ');
99 if (q) *q++ = '\0';
100 *pp = q;
101 if (allowlit && !strncmp(p, "IRFPM_", 6)) {
102 for (i = 0; irfpm_names[i]; i++)
103 if (!strcmp(irfpm_names[i], p+6))
104 return i;
105 } else if (allowlit && !strncmp(p, "IRFL_", 5)) {
106 for (i = 0; irfield_names[i]; i++)
107 if (!strcmp(irfield_names[i], p+5))
108 return i;
109 } else if (allowlit && !strncmp(p, "IRCALL_", 7)) {
110 for (i = 0; ircall_names[i]; i++)
111 if (!strcmp(ircall_names[i], p+7))
112 return i;
113 } else if (allowlit && !strncmp(p, "IRCONV_", 7)) {
114 for (i = 0; irt_names[i]; i++) {
115 const char *r = strchr(p+7, '_');
116 if (r && !strncmp(irt_names[i], p+7, r-(p+7))) {
117 uint32_t j;
118 for (j = 0; irt_names[j]; j++)
119 if (!strcmp(irt_names[j], r+1))
120 return (i << 5) + j;
121 }
122 }
123 } else if (allowlit && *p >= '0' && *p <= '9') {
124 for (i = 0; *p >= '0' && *p <= '9'; p++)
125 i = i*10 + (*p - '0');
126 if (*p == '\0')
127 return i;
128 } else if (allowany && !strcmp("any", p)) {
129 return allowany;
130 } else {
131 for (i = 0; ir_names[i]; i++)
132 if (!strcmp(ir_names[i], p))
133 return i;
134 }
135 fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno);
136 exit(1);
137 }
138 return 0;
139}
140
141/* Parse a fold rule. */
142static void foldrule(char *p)
143{
144 uint32_t op = nexttoken(&p, 0, 0);
145 uint32_t left = nexttoken(&p, 0, 0x7f);
146 uint32_t right = nexttoken(&p, 1, 0x3ff);
147 uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right;
148 uint32_t i;
149 if (nkeys >= BUILD_MAX_FOLD) {
150 fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n");
151 exit(1);
152 }
153 /* Simple insertion sort to detect duplicates. */
154 for (i = nkeys; i > 0; i--) {
155 if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff))
156 break;
157 if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) {
158 fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno);
159 exit(1);
160 }
161 foldkeys[i] = foldkeys[i-1];
162 }
163 foldkeys[i] = key;
164 nkeys++;
165}
166
167/* Emit C source code for IR folding hash table. */
168void emit_fold(BuildCtx *ctx)
169{
170 char buf[256]; /* We don't care about analyzing lines longer than that. */
171 const char *fname = ctx->args[0];
172 FILE *fp;
173
174 if (fname == NULL) {
175 fprintf(stderr, "Error: missing input filename\n");
176 exit(1);
177 }
178
179 if (fname[0] == '-' && fname[1] == '\0') {
180 fp = stdin;
181 } else {
182 fp = fopen(fname, "r");
183 if (!fp) {
184 fprintf(stderr, "Error: cannot open input file '%s': %s\n",
185 fname, strerror(errno));
186 exit(1);
187 }
188 }
189
190 fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
191 fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n");
192
193 lineno = 0;
194 funcidx = 0;
195 nkeys = 0;
196 while (fgets(buf, sizeof(buf), fp) != NULL) {
197 lineno++;
198 /* The prefix must be at the start of a line, otherwise it's ignored. */
199 if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) {
200 char *p = buf+sizeof(FOLDDEF_PREFIX)-1;
201 char *q = strchr(p, ')');
202 if (p[0] == '(' && q) {
203 p++;
204 *q = '\0';
205 foldrule(p);
206 } else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
207 p += 2;
208 *q = '\0';
209 if (funcidx)
210 fprintf(ctx->fp, ",\n");
211 if (p[-2] == 'X')
212 fprintf(ctx->fp, " %s", p);
213 else
214 fprintf(ctx->fp, " fold_%s", p);
215 funcidx++;
216 } else {
217 buf[strlen(buf)-1] = '\0';
218 fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n",
219 FOLDDEF_PREFIX, p, lineno);
220 exit(1);
221 }
222 }
223 }
224 fclose(fp);
225 fprintf(ctx->fp, "\n};\n\n");
226
227 makehash(ctx);
228}
229
diff --git a/src/host/buildvm_lib.c b/src/host/buildvm_lib.c
new file mode 100644
index 00000000..3231d3ad
--- /dev/null
+++ b/src/host/buildvm_lib.c
@@ -0,0 +1,377 @@
1/*
2** LuaJIT VM builder: library definition compiler.
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#include "buildvm.h"
7#include "lj_obj.h"
8#include "lj_lib.h"
9
10/* Context for library definitions. */
11static uint8_t obuf[8192];
12static uint8_t *optr;
13static char modname[80];
14static size_t modnamelen;
15static char funcname[80];
16static int modstate, regfunc;
17static int ffid, recffid, ffasmfunc;
18
19enum {
20 REGFUNC_OK,
21 REGFUNC_NOREG,
22 REGFUNC_NOREGUV
23};
24
25static void libdef_name(const char *p, int kind)
26{
27 size_t n = strlen(p);
28 if (kind != LIBINIT_STRING) {
29 if (n > modnamelen && p[modnamelen] == '_' &&
30 !strncmp(p, modname, modnamelen)) {
31 p += modnamelen+1;
32 n -= modnamelen+1;
33 }
34 }
35 if (n > LIBINIT_MAXSTR) {
36 fprintf(stderr, "Error: string too long: '%s'\n", p);
37 exit(1);
38 }
39 if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */
40 fprintf(stderr, "Error: output buffer overflow\n");
41 exit(1);
42 }
43 *optr++ = (uint8_t)(n | kind);
44 memcpy(optr, p, n);
45 optr += n;
46}
47
48static void libdef_endmodule(BuildCtx *ctx)
49{
50 if (modstate != 0) {
51 char line[80];
52 const uint8_t *p;
53 int n;
54 if (modstate == 1)
55 fprintf(ctx->fp, " (lua_CFunction)0");
56 fprintf(ctx->fp, "\n};\n");
57 fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n",
58 LABEL_PREFIX_LIBINIT, modname);
59 line[0] = '\0';
60 for (n = 0, p = obuf; p < optr; p++) {
61 n += sprintf(line+n, "%d,", *p);
62 if (n >= 75) {
63 fprintf(ctx->fp, "%s\n", line);
64 n = 0;
65 line[0] = '\0';
66 }
67 }
68 fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END);
69 }
70}
71
72static void libdef_module(BuildCtx *ctx, char *p, int arg)
73{
74 UNUSED(arg);
75 if (ctx->mode == BUILD_libdef) {
76 libdef_endmodule(ctx);
77 optr = obuf;
78 *optr++ = (uint8_t)ffid;
79 *optr++ = (uint8_t)ffasmfunc;
80 *optr++ = 0; /* Hash table size. */
81 modstate = 1;
82 fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p);
83 fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p);
84 fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n",
85 LABEL_PREFIX_LIBCF, p);
86 }
87 modnamelen = strlen(p);
88 if (modnamelen > sizeof(modname)-1) {
89 fprintf(stderr, "Error: module name too long: '%s'\n", p);
90 exit(1);
91 }
92 strcpy(modname, p);
93}
94
95static int find_ffofs(BuildCtx *ctx, const char *name)
96{
97 int i;
98 for (i = 0; i < ctx->nglob; i++) {
99 const char *gl = ctx->globnames[i];
100 if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) {
101 return (int)((uint8_t *)ctx->glob[i] - ctx->code);
102 }
103 }
104 fprintf(stderr, "Error: undefined fast function %s%s\n",
105 LABEL_PREFIX_FF, name);
106 exit(1);
107}
108
109static void libdef_func(BuildCtx *ctx, char *p, int arg)
110{
111 if (arg != LIBINIT_CF)
112 ffasmfunc++;
113 if (ctx->mode == BUILD_libdef) {
114 if (modstate == 0) {
115 fprintf(stderr, "Error: no module for function definition %s\n", p);
116 exit(1);
117 }
118 if (regfunc == REGFUNC_NOREG) {
119 if (optr+1 > obuf+sizeof(obuf)) {
120 fprintf(stderr, "Error: output buffer overflow\n");
121 exit(1);
122 }
123 *optr++ = LIBINIT_FFID;
124 } else {
125 if (arg != LIBINIT_ASM_) {
126 if (modstate != 1) fprintf(ctx->fp, ",\n");
127 modstate = 2;
128 fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p);
129 }
130 if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */
131 libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg);
132 }
133 } else if (ctx->mode == BUILD_ffdef) {
134 fprintf(ctx->fp, "FFDEF(%s)\n", p);
135 } else if (ctx->mode == BUILD_recdef) {
136 if (strlen(p) > sizeof(funcname)-1) {
137 fprintf(stderr, "Error: function name too long: '%s'\n", p);
138 exit(1);
139 }
140 strcpy(funcname, p);
141 } else if (ctx->mode == BUILD_vmdef) {
142 int i;
143 for (i = 1; p[i] && modname[i-1]; i++)
144 if (p[i] == '_') p[i] = '.';
145 fprintf(ctx->fp, "\"%s\",\n", p);
146 } else if (ctx->mode == BUILD_bcdef) {
147 if (arg != LIBINIT_CF)
148 fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p));
149 }
150 ffid++;
151 regfunc = REGFUNC_OK;
152}
153
154static uint32_t find_rec(char *name)
155{
156 char *p = (char *)obuf;
157 uint32_t n;
158 for (n = 2; *p; n++) {
159 if (strcmp(p, name) == 0)
160 return n;
161 p += strlen(p)+1;
162 }
163 if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) {
164 fprintf(stderr, "Error: output buffer overflow\n");
165 exit(1);
166 }
167 strcpy(p, name);
168 return n;
169}
170
171static void libdef_rec(BuildCtx *ctx, char *p, int arg)
172{
173 UNUSED(arg);
174 if (ctx->mode == BUILD_recdef) {
175 char *q;
176 uint32_t n;
177 for (; recffid+1 < ffid; recffid++)
178 fprintf(ctx->fp, ",\n0");
179 recffid = ffid;
180 if (*p == '.') p = funcname;
181 q = strchr(p, ' ');
182 if (q) *q++ = '\0';
183 n = find_rec(p);
184 if (q)
185 fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q);
186 else
187 fprintf(ctx->fp, ",\n0x%02x00", n);
188 }
189}
190
191static void memcpy_endian(void *dst, void *src, size_t n)
192{
193 union { uint8_t b; uint32_t u; } host_endian;
194 host_endian.u = 1;
195 if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) {
196 memcpy(dst, src, n);
197 } else {
198 size_t i;
199 for (i = 0; i < n; i++)
200 ((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1];
201 }
202}
203
204static void libdef_push(BuildCtx *ctx, char *p, int arg)
205{
206 UNUSED(arg);
207 if (ctx->mode == BUILD_libdef) {
208 int len = (int)strlen(p);
209 if (*p == '"') {
210 if (len > 1 && p[len-1] == '"') {
211 p[len-1] = '\0';
212 libdef_name(p+1, LIBINIT_STRING);
213 return;
214 }
215 } else if (*p >= '0' && *p <= '9') {
216 char *ep;
217 double d = strtod(p, &ep);
218 if (*ep == '\0') {
219 if (optr+1+sizeof(double) > obuf+sizeof(obuf)) {
220 fprintf(stderr, "Error: output buffer overflow\n");
221 exit(1);
222 }
223 *optr++ = LIBINIT_NUMBER;
224 memcpy_endian(optr, &d, sizeof(double));
225 optr += sizeof(double);
226 return;
227 }
228 } else if (!strcmp(p, "lastcl")) {
229 if (optr+1 > obuf+sizeof(obuf)) {
230 fprintf(stderr, "Error: output buffer overflow\n");
231 exit(1);
232 }
233 *optr++ = LIBINIT_LASTCL;
234 return;
235 } else if (len > 4 && !strncmp(p, "top-", 4)) {
236 if (optr+2 > obuf+sizeof(obuf)) {
237 fprintf(stderr, "Error: output buffer overflow\n");
238 exit(1);
239 }
240 *optr++ = LIBINIT_COPY;
241 *optr++ = (uint8_t)atoi(p+4);
242 return;
243 }
244 fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p);
245 exit(1);
246 }
247}
248
249static void libdef_set(BuildCtx *ctx, char *p, int arg)
250{
251 UNUSED(arg);
252 if (ctx->mode == BUILD_libdef) {
253 if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */
254 libdef_name(p, LIBINIT_STRING);
255 *optr++ = LIBINIT_SET;
256 obuf[2]++; /* Bump hash table size. */
257 }
258}
259
260static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
261{
262 UNUSED(ctx); UNUSED(p);
263 regfunc = arg;
264}
265
266typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
267
268typedef struct LibDefHandler {
269 const char *suffix;
270 const char *stop;
271 const LibDefFunc func;
272 const int arg;
273} LibDefHandler;
274
275static const LibDefHandler libdef_handlers[] = {
276 { "MODULE_", " \t\r\n", libdef_module, 0 },
277 { "CF(", ")", libdef_func, LIBINIT_CF },
278 { "ASM(", ")", libdef_func, LIBINIT_ASM },
279 { "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
280 { "REC(", ")", libdef_rec, 0 },
281 { "PUSH(", ")", libdef_push, 0 },
282 { "SET(", ")", libdef_set, 0 },
283 { "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV },
284 { "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG },
285 { NULL, NULL, (LibDefFunc)0, 0 }
286};
287
288/* Emit C source code for library function definitions. */
289void emit_lib(BuildCtx *ctx)
290{
291 const char *fname;
292
293 if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef ||
294 ctx->mode == BUILD_recdef)
295 fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
296 else if (ctx->mode == BUILD_vmdef)
297 fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n");
298 if (ctx->mode == BUILD_recdef)
299 fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100");
300 recffid = ffid = FF_C+1;
301 ffasmfunc = 0;
302
303 while ((fname = *ctx->args++)) {
304 char buf[256]; /* We don't care about analyzing lines longer than that. */
305 FILE *fp;
306 if (fname[0] == '-' && fname[1] == '\0') {
307 fp = stdin;
308 } else {
309 fp = fopen(fname, "r");
310 if (!fp) {
311 fprintf(stderr, "Error: cannot open input file '%s': %s\n",
312 fname, strerror(errno));
313 exit(1);
314 }
315 }
316 modstate = 0;
317 regfunc = REGFUNC_OK;
318 while (fgets(buf, sizeof(buf), fp) != NULL) {
319 char *p;
320 for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) {
321 const LibDefHandler *ldh;
322 p += sizeof(LIBDEF_PREFIX)-1;
323 for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) {
324 size_t n, len = strlen(ldh->suffix);
325 if (!strncmp(p, ldh->suffix, len)) {
326 p += len;
327 n = ldh->stop ? strcspn(p, ldh->stop) : 0;
328 if (!p[n]) break;
329 p[n] = '\0';
330 ldh->func(ctx, p, ldh->arg);
331 p += n+1;
332 break;
333 }
334 }
335 if (ldh->suffix == NULL) {
336 buf[strlen(buf)-1] = '\0';
337 fprintf(stderr, "Error: unknown library definition tag %s%s\n",
338 LIBDEF_PREFIX, p);
339 exit(1);
340 }
341 }
342 }
343 fclose(fp);
344 if (ctx->mode == BUILD_libdef) {
345 libdef_endmodule(ctx);
346 }
347 }
348
349 if (ctx->mode == BUILD_ffdef) {
350 fprintf(ctx->fp, "\n#undef FFDEF\n\n");
351 fprintf(ctx->fp,
352 "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
353 ffasmfunc);
354 } else if (ctx->mode == BUILD_vmdef) {
355 fprintf(ctx->fp, "}\n\n");
356 } else if (ctx->mode == BUILD_bcdef) {
357 int i;
358 fprintf(ctx->fp, "\n};\n\n");
359 fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n");
360 fprintf(ctx->fp, "BCDEF(BCMODE)\n");
361 for (i = ffasmfunc-1; i > 0; i--)
362 fprintf(ctx->fp, "BCMODE_FF,\n");
363 fprintf(ctx->fp, "BCMODE_FF\n};\n\n");
364 } else if (ctx->mode == BUILD_recdef) {
365 char *p = (char *)obuf;
366 fprintf(ctx->fp, "\n};\n\n");
367 fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n"
368 "recff_nyi,\n"
369 "recff_c");
370 while (*p) {
371 fprintf(ctx->fp, ",\nrecff_%s", p);
372 p += strlen(p)+1;
373 }
374 fprintf(ctx->fp, "\n};\n\n");
375 }
376}
377
diff --git a/src/host/buildvm_peobj.c b/src/host/buildvm_peobj.c
new file mode 100644
index 00000000..17b3293a
--- /dev/null
+++ b/src/host/buildvm_peobj.c
@@ -0,0 +1,352 @@
1/*
2** LuaJIT VM builder: PE object emitter.
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4**
5** Only used for building on Windows, since we cannot assume the presence
6** of a suitable assembler. The host and target byte order must match.
7*/
8
9#include "buildvm.h"
10#include "lj_bc.h"
11
12#if LJ_TARGET_X86ORX64
13
14/* Context for PE object emitter. */
15static char *strtab;
16static size_t strtabofs;
17
18/* -- PE object definitions ----------------------------------------------- */
19
20/* PE header. */
21typedef struct PEheader {
22 uint16_t arch;
23 uint16_t nsects;
24 uint32_t time;
25 uint32_t symtabofs;
26 uint32_t nsyms;
27 uint16_t opthdrsz;
28 uint16_t flags;
29} PEheader;
30
31/* PE section. */
32typedef struct PEsection {
33 char name[8];
34 uint32_t vsize;
35 uint32_t vaddr;
36 uint32_t size;
37 uint32_t ofs;
38 uint32_t relocofs;
39 uint32_t lineofs;
40 uint16_t nreloc;
41 uint16_t nline;
42 uint32_t flags;
43} PEsection;
44
45/* PE relocation. */
46typedef struct PEreloc {
47 uint32_t vaddr;
48 uint32_t symidx;
49 uint16_t type;
50} PEreloc;
51
52/* Cannot use sizeof, because it pads up to the max. alignment. */
53#define PEOBJ_RELOC_SIZE (4+4+2)
54
55/* PE symbol table entry. */
56typedef struct PEsym {
57 union {
58 char name[8];
59 uint32_t nameref[2];
60 } n;
61 uint32_t value;
62 int16_t sect;
63 uint16_t type;
64 uint8_t scl;
65 uint8_t naux;
66} PEsym;
67
68/* PE symbol table auxiliary entry for a section. */
69typedef struct PEsymaux {
70 uint32_t size;
71 uint16_t nreloc;
72 uint16_t nline;
73 uint32_t cksum;
74 uint16_t assoc;
75 uint8_t comdatsel;
76 uint8_t unused[3];
77} PEsymaux;
78
79/* Cannot use sizeof, because it pads up to the max. alignment. */
80#define PEOBJ_SYM_SIZE (8+4+2+2+1+1)
81
82/* PE object CPU specific defines. */
83#if LJ_TARGET_X86
84#define PEOBJ_ARCH_TARGET 0x014c
85#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */
86#define PEOBJ_RELOC_DIR32 0x06
87#elif LJ_TARGET_X64
88#define PEOBJ_ARCH_TARGET 0x8664
89#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */
90#define PEOBJ_RELOC_DIR32 0x02
91#define PEOBJ_RELOC_ADDR32NB 0x03
92#endif
93
94/* Section numbers (0-based). */
95enum {
96 PEOBJ_SECT_ABS = -2,
97 PEOBJ_SECT_UNDEF = -1,
98 PEOBJ_SECT_TEXT,
99#if LJ_TARGET_X64
100 PEOBJ_SECT_PDATA,
101 PEOBJ_SECT_XDATA,
102#endif
103 PEOBJ_SECT_RDATA_Z,
104 PEOBJ_NSECTIONS
105};
106
107/* Symbol types. */
108#define PEOBJ_TYPE_NULL 0
109#define PEOBJ_TYPE_FUNC 0x20
110
111/* Symbol storage class. */
112#define PEOBJ_SCL_EXTERN 2
113#define PEOBJ_SCL_STATIC 3
114
115/* -- PE object emitter --------------------------------------------------- */
116
117/* Emit PE object symbol. */
118static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
119 int sect, int type, int scl)
120{
121 PEsym sym;
122 size_t len = strlen(name);
123 if (!strtab) { /* Pass 1: only calculate string table length. */
124 if (len > 8) strtabofs += len+1;
125 return;
126 }
127 if (len <= 8) {
128 memcpy(sym.n.name, name, len);
129 memset(sym.n.name+len, 0, 8-len);
130 } else {
131 sym.n.nameref[0] = 0;
132 sym.n.nameref[1] = (uint32_t)strtabofs;
133 memcpy(strtab + strtabofs, name, len);
134 strtab[strtabofs+len] = 0;
135 strtabofs += len+1;
136 }
137 sym.value = value;
138 sym.sect = (int16_t)(sect+1); /* 1-based section number. */
139 sym.type = (uint16_t)type;
140 sym.scl = (uint8_t)scl;
141 sym.naux = 0;
142 owrite(ctx, &sym, PEOBJ_SYM_SIZE);
143}
144
145/* Emit PE object section symbol. */
146static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
147{
148 PEsym sym;
149 PEsymaux aux;
150 if (!strtab) return; /* Pass 1: no output. */
151 memcpy(sym.n.name, pesect[sect].name, 8);
152 sym.value = 0;
153 sym.sect = (int16_t)(sect+1); /* 1-based section number. */
154 sym.type = PEOBJ_TYPE_NULL;
155 sym.scl = PEOBJ_SCL_STATIC;
156 sym.naux = 1;
157 owrite(ctx, &sym, PEOBJ_SYM_SIZE);
158 memset(&aux, 0, sizeof(PEsymaux));
159 aux.size = pesect[sect].size;
160 aux.nreloc = pesect[sect].nreloc;
161 owrite(ctx, &aux, PEOBJ_SYM_SIZE);
162}
163
164/* Emit Windows PE object file. */
165void emit_peobj(BuildCtx *ctx)
166{
167 PEheader pehdr;
168 PEsection pesect[PEOBJ_NSECTIONS];
169 uint32_t sofs;
170 int i, nrsym;
171 union { uint8_t b; uint32_t u; } host_endian;
172
173 host_endian.u = 1;
174 if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
175 fprintf(stderr, "Error: different byte order for host and target\n");
176 exit(1);
177 }
178
179 sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
180
181 /* Fill in PE sections. */
182 memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
183 memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
184 pesect[PEOBJ_SECT_TEXT].ofs = sofs;
185 sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
186 pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
187 sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
188 /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
189 pesect[PEOBJ_SECT_TEXT].flags = 0x60500020;
190
191#if LJ_TARGET_X64
192 memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
193 pesect[PEOBJ_SECT_PDATA].ofs = sofs;
194 sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
195 pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
196 sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
197 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
198 pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
199
200 memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
201 pesect[PEOBJ_SECT_XDATA].ofs = sofs;
202 sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */
203 pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
204 sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
205 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
206 pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
207#endif
208
209 memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
210 pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
211 sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
212 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
213 pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
214
215 /* Fill in PE header. */
216 pehdr.arch = PEOBJ_ARCH_TARGET;
217 pehdr.nsects = PEOBJ_NSECTIONS;
218 pehdr.time = 0; /* Timestamp is optional. */
219 pehdr.symtabofs = sofs;
220 pehdr.opthdrsz = 0;
221 pehdr.flags = 0;
222
223 /* Compute the size of the symbol table:
224 ** @feat.00 + nsections*2
225 ** + asm_start + nsym
226 ** + nrsym
227 */
228 nrsym = ctx->nrelocsym;
229 pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
230#if LJ_TARGET_X64
231 pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */
232#endif
233
234 /* Write PE object header and all sections. */
235 owrite(ctx, &pehdr, sizeof(PEheader));
236 owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
237
238 /* Write .text section. */
239 owrite(ctx, ctx->code, ctx->codesz);
240 for (i = 0; i < ctx->nreloc; i++) {
241 PEreloc reloc;
242 reloc.vaddr = (uint32_t)ctx->reloc[i].ofs;
243 reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */
244 reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
245 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
246 }
247
248#if LJ_TARGET_X64
249 { /* Write .pdata section. */
250 uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
251 uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
252 PEreloc reloc;
253 pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
254 owrite(ctx, &pdata, sizeof(pdata));
255 pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
256 owrite(ctx, &pdata, sizeof(pdata));
257 reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
258 reloc.type = PEOBJ_RELOC_ADDR32NB;
259 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
260 reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
261 reloc.type = PEOBJ_RELOC_ADDR32NB;
262 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
263 reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
264 reloc.type = PEOBJ_RELOC_ADDR32NB;
265 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
266 reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
267 reloc.type = PEOBJ_RELOC_ADDR32NB;
268 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
269 reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
270 reloc.type = PEOBJ_RELOC_ADDR32NB;
271 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
272 reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
273 reloc.type = PEOBJ_RELOC_ADDR32NB;
274 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
275 }
276 { /* Write .xdata section. */
277 uint16_t xdata[8+2+6];
278 PEreloc reloc;
279 xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhandler/ehandler, prolog size 0. */
280 xdata[1] = 0x0005; /* Number of unwind codes, no frame pointer. */
281 xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */
282 xdata[3] = 0x3000; /* Push rbx. */
283 xdata[4] = 0x6000; /* Push rsi. */
284 xdata[5] = 0x7000; /* Push rdi. */
285 xdata[6] = 0x5000; /* Push rbp. */
286 xdata[7] = 0; /* Alignment. */
287 xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */
288 xdata[10] = 0x01; /* Ver. 1, no handler, prolog size 0. */
289 xdata[11] = 0x1504; /* Number of unwind codes, fp = rbp, fpofs = 16. */
290 xdata[12] = 0x0300; /* set_fpreg. */
291 xdata[13] = 0x0200; /* stack offset 0*8+8 = aword*1. */
292 xdata[14] = 0x3000; /* Push rbx. */
293 xdata[15] = 0x5000; /* Push rbp. */
294 owrite(ctx, &xdata, sizeof(xdata));
295 reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
296 reloc.type = PEOBJ_RELOC_ADDR32NB;
297 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
298 }
299#endif
300
301 /* Write .rdata$Z section. */
302 owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
303
304 /* Write symbol table. */
305 strtab = NULL; /* 1st pass: collect string sizes. */
306 for (;;) {
307 strtabofs = 4;
308 /* Mark as SafeSEH compliant. */
309 emit_peobj_sym(ctx, "@feat.00", 1,
310 PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
311
312 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
313 for (i = 0; i < nrsym; i++)
314 emit_peobj_sym(ctx, ctx->relocsym[i], 0,
315 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
316
317#if LJ_TARGET_X64
318 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
319 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
320 emit_peobj_sym(ctx, "lj_err_unwind_win64", 0,
321 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
322#endif
323
324 emit_peobj_sym(ctx, ctx->beginsym, 0,
325 PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
326 for (i = 0; i < ctx->nsym; i++)
327 emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
328 PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
329
330 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
331
332 if (strtab)
333 break;
334 /* 2nd pass: alloc strtab, write syms and copy strings. */
335 strtab = (char *)malloc(strtabofs);
336 *(uint32_t *)strtab = (uint32_t)strtabofs;
337 }
338
339 /* Write string table. */
340 owrite(ctx, strtab, strtabofs);
341}
342
343#else
344
345void emit_peobj(BuildCtx *ctx)
346{
347 UNUSED(ctx);
348 fprintf(stderr, "Error: no PE object support for this target\n");
349 exit(1);
350}
351
352#endif