diff options
| author | Mike Pall <mike> | 2012-06-09 15:04:03 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2012-06-09 15:12:44 +0200 |
| commit | 9a9509c66a98d0bf42003ad5d06e8f275c5ff1f5 (patch) | |
| tree | f5ca35d9ed7cc66f644828233f511f6db4634849 /src/host | |
| parent | 0a6c8338d240dd318db2f5269414dcf7ddc9ed35 (diff) | |
| download | luajit-9a9509c66a98d0bf42003ad5d06e8f275c5ff1f5.tar.gz luajit-9a9509c66a98d0bf42003ad5d06e8f275c5ff1f5.tar.bz2 luajit-9a9509c66a98d0bf42003ad5d06e8f275c5ff1f5.zip | |
Reorganize build process.
Drop pre-translated buildvm_*.h.
Rename buildvm_*.dasc to vm_*.dasc.
Move buildvm* to host directory.
Build minilua, unless HOST_LUA is set.
Use HOST_LUA to run DynASM.
Translate only vm_*.dasc for target architecture.
Diffstat (limited to 'src/host')
| -rw-r--r-- | src/host/.gitignore | 3 | ||||
| -rw-r--r-- | src/host/buildvm.c | 504 | ||||
| -rw-r--r-- | src/host/buildvm.h | 104 | ||||
| -rw-r--r-- | src/host/buildvm_asm.c | 283 | ||||
| -rw-r--r-- | src/host/buildvm_fold.c | 229 | ||||
| -rw-r--r-- | src/host/buildvm_lib.c | 377 | ||||
| -rw-r--r-- | src/host/buildvm_peobj.c | 352 |
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 @@ | |||
| 1 | minilua | ||
| 2 | buildvm | ||
| 3 | buildvm_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. */ | ||
| 47 | static 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 | |||
| 77 | void 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. */ | ||
| 89 | static void emit_raw(BuildCtx *ctx) | ||
| 90 | { | ||
| 91 | owrite(ctx, ctx->code, ctx->codesz); | ||
| 92 | } | ||
| 93 | |||
| 94 | /* -- Build machine code -------------------------------------------------- */ | ||
| 95 | |||
| 96 | static 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 | |||
| 121 | static int relocmap[NRELOCSYM]; | ||
| 122 | |||
| 123 | /* Collect external relocations. */ | ||
| 124 | static 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. */ | ||
| 143 | static 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. */ | ||
| 158 | static 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 | |||
| 233 | const char *const bc_names[] = { | ||
| 234 | #define BCNAME(name, ma, mb, mc, mt) #name, | ||
| 235 | BCDEF(BCNAME) | ||
| 236 | #undef BCNAME | ||
| 237 | NULL | ||
| 238 | }; | ||
| 239 | |||
| 240 | const char *const ir_names[] = { | ||
| 241 | #define IRNAME(name, m, m1, m2) #name, | ||
| 242 | IRDEF(IRNAME) | ||
| 243 | #undef IRNAME | ||
| 244 | NULL | ||
| 245 | }; | ||
| 246 | |||
| 247 | const char *const irt_names[] = { | ||
| 248 | #define IRTNAME(name) #name, | ||
| 249 | IRTDEF(IRTNAME) | ||
| 250 | #undef IRTNAME | ||
| 251 | NULL | ||
| 252 | }; | ||
| 253 | |||
| 254 | const char *const irfpm_names[] = { | ||
| 255 | #define FPMNAME(name) #name, | ||
| 256 | IRFPMDEF(FPMNAME) | ||
| 257 | #undef FPMNAME | ||
| 258 | NULL | ||
| 259 | }; | ||
| 260 | |||
| 261 | const char *const irfield_names[] = { | ||
| 262 | #define FLNAME(name, ofs) #name, | ||
| 263 | IRFLDEF(FLNAME) | ||
| 264 | #undef FLNAME | ||
| 265 | NULL | ||
| 266 | }; | ||
| 267 | |||
| 268 | const char *const ircall_names[] = { | ||
| 269 | #define IRCALLNAME(cond, name, nargs, kind, type, flags) #name, | ||
| 270 | IRCALLDEF(IRCALLNAME) | ||
| 271 | #undef IRCALLNAME | ||
| 272 | NULL | ||
| 273 | }; | ||
| 274 | |||
| 275 | static const char *const trace_errors[] = { | ||
| 276 | #define TREDEF(name, msg) msg, | ||
| 277 | #include "lj_traceerr.h" | ||
| 278 | NULL | ||
| 279 | }; | ||
| 280 | |||
| 281 | static 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. */ | ||
| 293 | static 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. */ | ||
| 306 | static 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. */ | ||
| 350 | static const char *const modenames[] = { | ||
| 351 | #define BUILDNAME(name) #name, | ||
| 352 | BUILDDEF(BUILDNAME) | ||
| 353 | #undef BUILDNAME | ||
| 354 | NULL | ||
| 355 | }; | ||
| 356 | |||
| 357 | /* Print usage information and exit. */ | ||
| 358 | static 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. */ | ||
| 372 | static 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. */ | ||
| 383 | static 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 | } | ||
| 414 | ok: | ||
| 415 | ctx->args = argv+i; | ||
| 416 | if (ctx->mode == (BuildMode)-1) goto err; | ||
| 417 | } | ||
| 418 | |||
| 419 | int 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. */ | ||
| 38 | struct dasm_State; | ||
| 39 | |||
| 40 | /* Build modes. */ | ||
| 41 | #define BUILDDEF(_) \ | ||
| 42 | _(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \ | ||
| 43 | _(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \ | ||
| 44 | _(folddef) | ||
| 45 | |||
| 46 | typedef enum { | ||
| 47 | #define BUILDENUM(name) BUILD_##name, | ||
| 48 | BUILDDEF(BUILDENUM) | ||
| 49 | #undef BUILDENUM | ||
| 50 | BUILD__MAX | ||
| 51 | } BuildMode; | ||
| 52 | |||
| 53 | /* Code relocation. */ | ||
| 54 | typedef struct BuildReloc { | ||
| 55 | int32_t ofs; | ||
| 56 | int sym; | ||
| 57 | int type; | ||
| 58 | } BuildReloc; | ||
| 59 | |||
| 60 | typedef struct BuildSym { | ||
| 61 | const char *name; | ||
| 62 | int32_t ofs; | ||
| 63 | } BuildSym; | ||
| 64 | |||
| 65 | /* Build context structure. */ | ||
| 66 | typedef 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 | |||
| 91 | extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz); | ||
| 92 | extern void emit_asm(BuildCtx *ctx); | ||
| 93 | extern void emit_peobj(BuildCtx *ctx); | ||
| 94 | extern void emit_lib(BuildCtx *ctx); | ||
| 95 | extern void emit_fold(BuildCtx *ctx); | ||
| 96 | |||
| 97 | extern const char *const bc_names[]; | ||
| 98 | extern const char *const ir_names[]; | ||
| 99 | extern const char *const irt_names[]; | ||
| 100 | extern const char *const irfpm_names[]; | ||
| 101 | extern const char *const irfield_names[]; | ||
| 102 | extern 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. */ | ||
| 13 | static 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 */ | ||
| 27 | static 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 | |||
| 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 | fprintf(ctx->fp, "\t%s %s\n", opname, sym); | ||
| 75 | } | ||
| 76 | #else | ||
| 77 | /* Emit words piecewise as assembler text. */ | ||
| 78 | static 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. */ | ||
| 92 | static 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. */ | ||
| 140 | static 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. */ | ||
| 169 | static 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. */ | ||
| 187 | void 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. */ | ||
| 11 | static int lineno; | ||
| 12 | static int funcidx; | ||
| 13 | static uint32_t foldkeys[BUILD_MAX_FOLD]; | ||
| 14 | static uint32_t nkeys; | ||
| 15 | |||
| 16 | /* Try to fill the hash table with keys using the hash parameters. */ | ||
| 17 | static 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. */ | ||
| 50 | static 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. */ | ||
| 61 | static 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. */ | ||
| 93 | static 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. */ | ||
| 142 | static 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. */ | ||
| 168 | void 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. */ | ||
| 11 | static uint8_t obuf[8192]; | ||
| 12 | static uint8_t *optr; | ||
| 13 | static char modname[80]; | ||
| 14 | static size_t modnamelen; | ||
| 15 | static char funcname[80]; | ||
| 16 | static int modstate, regfunc; | ||
| 17 | static int ffid, recffid, ffasmfunc; | ||
| 18 | |||
| 19 | enum { | ||
| 20 | REGFUNC_OK, | ||
| 21 | REGFUNC_NOREG, | ||
| 22 | REGFUNC_NOREGUV | ||
| 23 | }; | ||
| 24 | |||
| 25 | static 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 | |||
| 48 | static 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 | |||
| 72 | static 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 | |||
| 95 | static 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 | |||
| 109 | static 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 | |||
| 154 | static 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 | |||
| 171 | static 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 | |||
| 191 | static 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 | |||
| 204 | static 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 | |||
| 249 | static 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 | |||
| 260 | static void libdef_regfunc(BuildCtx *ctx, char *p, int arg) | ||
| 261 | { | ||
| 262 | UNUSED(ctx); UNUSED(p); | ||
| 263 | regfunc = arg; | ||
| 264 | } | ||
| 265 | |||
| 266 | typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg); | ||
| 267 | |||
| 268 | typedef struct LibDefHandler { | ||
| 269 | const char *suffix; | ||
| 270 | const char *stop; | ||
| 271 | const LibDefFunc func; | ||
| 272 | const int arg; | ||
| 273 | } LibDefHandler; | ||
| 274 | |||
| 275 | static 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. */ | ||
| 289 | void 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. */ | ||
| 15 | static char *strtab; | ||
| 16 | static size_t strtabofs; | ||
| 17 | |||
| 18 | /* -- PE object definitions ----------------------------------------------- */ | ||
| 19 | |||
| 20 | /* PE header. */ | ||
| 21 | typedef 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. */ | ||
| 32 | typedef 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. */ | ||
| 46 | typedef 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. */ | ||
| 56 | typedef 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. */ | ||
| 69 | typedef 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). */ | ||
| 95 | enum { | ||
| 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. */ | ||
| 118 | static 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. */ | ||
| 146 | static 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. */ | ||
| 165 | void 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 | |||
| 345 | void 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 | ||
