aboutsummaryrefslogtreecommitdiff
path: root/src/host
diff options
context:
space:
mode:
Diffstat (limited to 'src/host')
-rw-r--r--src/host/buildvm.c36
-rw-r--r--src/host/buildvm.h1
-rw-r--r--src/host/buildvm_asm.c67
-rw-r--r--src/host/buildvm_fold.c7
-rw-r--r--src/host/buildvm_lib.c63
-rw-r--r--src/host/buildvm_libbc.h81
-rw-r--r--src/host/buildvm_peobj.c151
-rw-r--r--src/host/genlibbc.lua234
8 files changed, 591 insertions, 49 deletions
diff --git a/src/host/buildvm.c b/src/host/buildvm.c
index eb22bbbd..27f90066 100644
--- a/src/host/buildvm.c
+++ b/src/host/buildvm.c
@@ -18,8 +18,10 @@
18#include "lj_obj.h" 18#include "lj_obj.h"
19#include "lj_gc.h" 19#include "lj_gc.h"
20#include "lj_bc.h" 20#include "lj_bc.h"
21#if LJ_HASJIT
21#include "lj_ir.h" 22#include "lj_ir.h"
22#include "lj_ircall.h" 23#include "lj_ircall.h"
24#endif
23#include "lj_frame.h" 25#include "lj_frame.h"
24#include "lj_dispatch.h" 26#include "lj_dispatch.h"
25#if LJ_HASFFI 27#if LJ_HASFFI
@@ -59,10 +61,10 @@ static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
59#include "../dynasm/dasm_x86.h" 61#include "../dynasm/dasm_x86.h"
60#elif LJ_TARGET_ARM 62#elif LJ_TARGET_ARM
61#include "../dynasm/dasm_arm.h" 63#include "../dynasm/dasm_arm.h"
64#elif LJ_TARGET_ARM64
65#include "../dynasm/dasm_arm64.h"
62#elif LJ_TARGET_PPC 66#elif LJ_TARGET_PPC
63#include "../dynasm/dasm_ppc.h" 67#include "../dynasm/dasm_ppc.h"
64#elif LJ_TARGET_PPCSPE
65#include "../dynasm/dasm_ppc.h"
66#elif LJ_TARGET_MIPS 68#elif LJ_TARGET_MIPS
67#include "../dynasm/dasm_mips.h" 69#include "../dynasm/dasm_mips.h"
68#else 70#else
@@ -110,11 +112,11 @@ static const char *sym_decorate(BuildCtx *ctx,
110 if (p) { 112 if (p) {
111#if LJ_TARGET_X86ORX64 113#if LJ_TARGET_X86ORX64
112 if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj)) 114 if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
113 name[0] = '@'; 115 name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */
114 else 116 else
115 *p = '\0'; 117 *p = '\0';
116#elif (LJ_TARGET_PPC || LJ_TARGET_PPCSPE) && !LJ_TARGET_CONSOLE 118#elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE
117 /* Keep @plt. */ 119 /* Keep @plt etc. */
118#else 120#else
119 *p = '\0'; 121 *p = '\0';
120#endif 122#endif
@@ -179,6 +181,7 @@ static int build_code(BuildCtx *ctx)
179 ctx->nreloc = 0; 181 ctx->nreloc = 0;
180 182
181 ctx->globnames = globnames; 183 ctx->globnames = globnames;
184 ctx->extnames = extnames;
182 ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *)); 185 ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
183 ctx->nrelocsym = 0; 186 ctx->nrelocsym = 0;
184 for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1; 187 for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
@@ -249,6 +252,7 @@ BCDEF(BCNAME)
249 NULL 252 NULL
250}; 253};
251 254
255#if LJ_HASJIT
252const char *const ir_names[] = { 256const char *const ir_names[] = {
253#define IRNAME(name, m, m1, m2) #name, 257#define IRNAME(name, m, m1, m2) #name,
254IRDEF(IRNAME) 258IRDEF(IRNAME)
@@ -289,7 +293,9 @@ static const char *const trace_errors[] = {
289#include "lj_traceerr.h" 293#include "lj_traceerr.h"
290 NULL 294 NULL
291}; 295};
296#endif
292 297
298#if LJ_HASJIT
293static const char *lower(char *buf, const char *s) 299static const char *lower(char *buf, const char *s)
294{ 300{
295 char *p = buf; 301 char *p = buf;
@@ -300,6 +306,7 @@ static const char *lower(char *buf, const char *s)
300 *p = '\0'; 306 *p = '\0';
301 return buf; 307 return buf;
302} 308}
309#endif
303 310
304/* Emit C source code for bytecode-related definitions. */ 311/* Emit C source code for bytecode-related definitions. */
305static void emit_bcdef(BuildCtx *ctx) 312static void emit_bcdef(BuildCtx *ctx)
@@ -317,24 +324,27 @@ static void emit_bcdef(BuildCtx *ctx)
317/* Emit VM definitions as Lua code for debug modules. */ 324/* Emit VM definitions as Lua code for debug modules. */
318static void emit_vmdef(BuildCtx *ctx) 325static void emit_vmdef(BuildCtx *ctx)
319{ 326{
327#if LJ_HASJIT
320 char buf[80]; 328 char buf[80];
329#endif
321 int i; 330 int i;
322 fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n"); 331 fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
323 fprintf(ctx->fp, "assert(require(\"jit\").version == \"%s\", \"LuaJIT core/library version mismatch\")\n\n", LUAJIT_VERSION); 332 fprintf(ctx->fp, "assert(require(\"jit\").version == \"%s\", \"LuaJIT core/library version mismatch\")\n\n", LUAJIT_VERSION);
324 fprintf(ctx->fp, "module(...)\n\n"); 333 fprintf(ctx->fp, "return {\n\n");
325 334
326 fprintf(ctx->fp, "bcnames = \""); 335 fprintf(ctx->fp, "bcnames = \"");
327 for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]); 336 for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]);
328 fprintf(ctx->fp, "\"\n\n"); 337 fprintf(ctx->fp, "\",\n\n");
329 338
339#if LJ_HASJIT
330 fprintf(ctx->fp, "irnames = \""); 340 fprintf(ctx->fp, "irnames = \"");
331 for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]); 341 for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]);
332 fprintf(ctx->fp, "\"\n\n"); 342 fprintf(ctx->fp, "\",\n\n");
333 343
334 fprintf(ctx->fp, "irfpm = { [0]="); 344 fprintf(ctx->fp, "irfpm = { [0]=");
335 for (i = 0; irfpm_names[i]; i++) 345 for (i = 0; irfpm_names[i]; i++)
336 fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i])); 346 fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i]));
337 fprintf(ctx->fp, "}\n\n"); 347 fprintf(ctx->fp, "},\n\n");
338 348
339 fprintf(ctx->fp, "irfield = { [0]="); 349 fprintf(ctx->fp, "irfield = { [0]=");
340 for (i = 0; irfield_names[i]; i++) { 350 for (i = 0; irfield_names[i]; i++) {
@@ -344,17 +354,18 @@ static void emit_vmdef(BuildCtx *ctx)
344 if (p) *p = '.'; 354 if (p) *p = '.';
345 fprintf(ctx->fp, "\"%s\", ", buf); 355 fprintf(ctx->fp, "\"%s\", ", buf);
346 } 356 }
347 fprintf(ctx->fp, "}\n\n"); 357 fprintf(ctx->fp, "},\n\n");
348 358
349 fprintf(ctx->fp, "ircall = {\n[0]="); 359 fprintf(ctx->fp, "ircall = {\n[0]=");
350 for (i = 0; ircall_names[i]; i++) 360 for (i = 0; ircall_names[i]; i++)
351 fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]); 361 fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]);
352 fprintf(ctx->fp, "}\n\n"); 362 fprintf(ctx->fp, "},\n\n");
353 363
354 fprintf(ctx->fp, "traceerr = {\n[0]="); 364 fprintf(ctx->fp, "traceerr = {\n[0]=");
355 for (i = 0; trace_errors[i]; i++) 365 for (i = 0; trace_errors[i]; i++)
356 fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]); 366 fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]);
357 fprintf(ctx->fp, "}\n\n"); 367 fprintf(ctx->fp, "},\n\n");
368#endif
358} 369}
359 370
360/* -- Argument parsing ---------------------------------------------------- */ 371/* -- Argument parsing ---------------------------------------------------- */
@@ -491,6 +502,7 @@ int main(int argc, char **argv)
491 case BUILD_vmdef: 502 case BUILD_vmdef:
492 emit_vmdef(ctx); 503 emit_vmdef(ctx);
493 emit_lib(ctx); 504 emit_lib(ctx);
505 fprintf(ctx->fp, "}\n\n");
494 break; 506 break;
495 case BUILD_ffdef: 507 case BUILD_ffdef:
496 case BUILD_libdef: 508 case BUILD_libdef:
diff --git a/src/host/buildvm.h b/src/host/buildvm.h
index 9fe2f0b6..cfdadc2c 100644
--- a/src/host/buildvm.h
+++ b/src/host/buildvm.h
@@ -82,6 +82,7 @@ typedef struct BuildCtx {
82 const char *beginsym; 82 const char *beginsym;
83 /* Strings generated by DynASM. */ 83 /* Strings generated by DynASM. */
84 const char *const *globnames; 84 const char *const *globnames;
85 const char *const *extnames;
85 const char *dasm_ident; 86 const char *dasm_ident;
86 const char *dasm_arch; 87 const char *dasm_arch;
87 /* Relocations. */ 88 /* Relocations. */
diff --git a/src/host/buildvm_asm.c b/src/host/buildvm_asm.c
index 7a059762..8cd8727b 100644
--- a/src/host/buildvm_asm.c
+++ b/src/host/buildvm_asm.c
@@ -51,8 +51,8 @@ static const char *const jccnames[] = {
51 "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg" 51 "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
52}; 52};
53 53
54/* Emit relocation for the incredibly stupid OSX assembler. */ 54/* Emit x86/x64 text relocations. */
55static void emit_asm_reloc_mach(BuildCtx *ctx, uint8_t *cp, int n, 55static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n,
56 const char *sym) 56 const char *sym)
57{ 57{
58 const char *opname = NULL; 58 const char *opname = NULL;
@@ -71,6 +71,20 @@ err:
71 exit(1); 71 exit(1);
72 } 72 }
73 emit_asm_bytes(ctx, cp, n); 73 emit_asm_bytes(ctx, cp, n);
74 if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) {
75 /* Various fixups for external symbols outside of our binary. */
76 if (ctx->mode == BUILD_elfasm) {
77 if (LJ_32)
78 fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym);
79 fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym);
80 if (LJ_32)
81 fprintf(ctx->fp, "#endif\n");
82 return;
83 } else if (LJ_32 && ctx->mode == BUILD_machasm) {
84 fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym);
85 return;
86 }
87 }
74 fprintf(ctx->fp, "\t%s %s\n", opname, sym); 88 fprintf(ctx->fp, "\t%s %s\n", opname, sym);
75} 89}
76#else 90#else
@@ -79,10 +93,14 @@ static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
79{ 93{
80 int i; 94 int i;
81 for (i = 0; i < n; i += 4) { 95 for (i = 0; i < n; i += 4) {
96 uint32_t ins = *(uint32_t *)(p+i);
97#if LJ_TARGET_ARM64 && LJ_BE
98 ins = lj_bswap(ins); /* ARM64 instructions are always little-endian. */
99#endif
82 if ((i & 15) == 0) 100 if ((i & 15) == 0)
83 fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i)); 101 fprintf(ctx->fp, "\t.long 0x%08x", ins);
84 else 102 else
85 fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i)); 103 fprintf(ctx->fp, ",0x%08x", ins);
86 if ((i & 15) == 12) putc('\n', ctx->fp); 104 if ((i & 15) == 12) putc('\n', ctx->fp);
87 } 105 }
88 if ((n & 15) != 0) putc('\n', ctx->fp); 106 if ((n & 15) != 0) putc('\n', ctx->fp);
@@ -107,7 +125,16 @@ static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
107 ins, sym); 125 ins, sym);
108 exit(1); 126 exit(1);
109 } 127 }
110#elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE 128#elif LJ_TARGET_ARM64
129 if ((ins >> 26) == 0x25u) {
130 fprintf(ctx->fp, "\tbl %s\n", sym);
131 } else {
132 fprintf(stderr,
133 "Error: unsupported opcode %08x for %s symbol relocation.\n",
134 ins, sym);
135 exit(1);
136 }
137#elif LJ_TARGET_PPC
111#if LJ_TARGET_PS3 138#if LJ_TARGET_PS3
112#define TOCPREFIX "." 139#define TOCPREFIX "."
113#else 140#else
@@ -216,6 +243,12 @@ void emit_asm(BuildCtx *ctx)
216 243
217 fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch); 244 fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
218 fprintf(ctx->fp, "\t.text\n"); 245 fprintf(ctx->fp, "\t.text\n");
246#if LJ_TARGET_MIPS32 && !LJ_ABI_SOFTFP
247 fprintf(ctx->fp, "\t.module fp=32\n");
248#endif
249#if LJ_TARGET_MIPS
250 fprintf(ctx->fp, "\t.set nomips16\n\t.abicalls\n\t.set noreorder\n\t.set nomacro\n");
251#endif
219 emit_asm_align(ctx, 4); 252 emit_asm_align(ctx, 4);
220 253
221#if LJ_TARGET_PS3 254#if LJ_TARGET_PS3
@@ -228,13 +261,19 @@ void emit_asm(BuildCtx *ctx)
228 261
229#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND 262#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
230 /* This should really be moved into buildvm_arm.dasc. */ 263 /* This should really be moved into buildvm_arm.dasc. */
264#if LJ_ARCH_HASFPU
265 fprintf(ctx->fp,
266 ".fnstart\n"
267 ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n"
268 ".vsave {d8-d15}\n"
269 ".save {r4}\n"
270 ".pad #28\n");
271#else
231 fprintf(ctx->fp, 272 fprintf(ctx->fp,
232 ".fnstart\n" 273 ".fnstart\n"
233 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 274 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
234 ".pad #28\n"); 275 ".pad #28\n");
235#endif 276#endif
236#if LJ_TARGET_MIPS
237 fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
238#endif 277#endif
239 278
240 for (i = rel = 0; i < ctx->nsym; i++) { 279 for (i = rel = 0; i < ctx->nsym; i++) {
@@ -255,8 +294,9 @@ void emit_asm(BuildCtx *ctx)
255 BuildReloc *r = &ctx->reloc[rel]; 294 BuildReloc *r = &ctx->reloc[rel];
256 int n = r->ofs - ofs; 295 int n = r->ofs - ofs;
257#if LJ_TARGET_X86ORX64 296#if LJ_TARGET_X86ORX64
258 if (ctx->mode == BUILD_machasm && r->type != 0) { 297 if (r->type != 0 &&
259 emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]); 298 (ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) {
299 emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
260 } else { 300 } else {
261 emit_asm_bytes(ctx, ctx->code+ofs, n); 301 emit_asm_bytes(ctx, ctx->code+ofs, n);
262 emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]); 302 emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
@@ -290,10 +330,7 @@ void emit_asm(BuildCtx *ctx)
290#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA) 330#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
291 fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n"); 331 fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
292#endif 332#endif
293#if LJ_TARGET_PPCSPE 333#if LJ_TARGET_PPC && !LJ_TARGET_PS3 && !LJ_ABI_SOFTFP
294 /* Soft-float ABI + SPE. */
295 fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
296#elif LJ_TARGET_PPC && !LJ_TARGET_PS3
297 /* Hard-float ABI. */ 334 /* Hard-float ABI. */
298 fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n"); 335 fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
299#endif 336#endif
@@ -302,6 +339,10 @@ void emit_asm(BuildCtx *ctx)
302 fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident); 339 fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
303 break; 340 break;
304 case BUILD_machasm: 341 case BUILD_machasm:
342#if defined(__apple_build_version__) && __apple_build_version__ >= 15000000 && __apple_build_version__ < 15000300
343 /* Workaround for XCode 15.0 - 15.2. */
344 fprintf(ctx->fp, "\t.subsections_via_symbols\n");
345#endif
305 fprintf(ctx->fp, 346 fprintf(ctx->fp,
306 "\t.cstring\n" 347 "\t.cstring\n"
307 "\t.ascii \"%s\\0\"\n", ctx->dasm_ident); 348 "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
diff --git a/src/host/buildvm_fold.c b/src/host/buildvm_fold.c
index 3aa445ac..e0b19e8c 100644
--- a/src/host/buildvm_fold.c
+++ b/src/host/buildvm_fold.c
@@ -5,6 +5,7 @@
5 5
6#include "buildvm.h" 6#include "buildvm.h"
7#include "lj_obj.h" 7#include "lj_obj.h"
8#if LJ_HASJIT
8#include "lj_ir.h" 9#include "lj_ir.h"
9 10
10/* Context for the folding hash table generator. */ 11/* Context for the folding hash table generator. */
@@ -226,4 +227,10 @@ void emit_fold(BuildCtx *ctx)
226 227
227 makehash(ctx); 228 makehash(ctx);
228} 229}
230#else
231void emit_fold(BuildCtx *ctx)
232{
233 UNUSED(ctx);
234}
235#endif
229 236
diff --git a/src/host/buildvm_lib.c b/src/host/buildvm_lib.c
index 7147c2c8..51ac5f12 100644
--- a/src/host/buildvm_lib.c
+++ b/src/host/buildvm_lib.c
@@ -5,7 +5,9 @@
5 5
6#include "buildvm.h" 6#include "buildvm.h"
7#include "lj_obj.h" 7#include "lj_obj.h"
8#include "lj_bc.h"
8#include "lj_lib.h" 9#include "lj_lib.h"
10#include "buildvm_libbc.h"
9 11
10/* Context for library definitions. */ 12/* Context for library definitions. */
11static uint8_t obuf[8192]; 13static uint8_t obuf[8192];
@@ -151,6 +153,62 @@ static void libdef_func(BuildCtx *ctx, char *p, int arg)
151 regfunc = REGFUNC_OK; 153 regfunc = REGFUNC_OK;
152} 154}
153 155
156static uint8_t *libdef_uleb128(uint8_t *p, uint32_t *vv)
157{
158 uint32_t v = *p++;
159 if (v >= 0x80) {
160 int sh = 0; v &= 0x7f;
161 do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
162 }
163 *vv = v;
164 return p;
165}
166
167static void libdef_fixupbc(uint8_t *p)
168{
169 uint32_t i, sizebc;
170 p += 4;
171 p = libdef_uleb128(p, &sizebc);
172 p = libdef_uleb128(p, &sizebc);
173 p = libdef_uleb128(p, &sizebc);
174 for (i = 0; i < sizebc; i++, p += 4) {
175 uint8_t op = p[libbc_endian ? 3 : 0];
176 uint8_t ra = p[libbc_endian ? 2 : 1];
177 uint8_t rc = p[libbc_endian ? 1 : 2];
178 uint8_t rb = p[libbc_endian ? 0 : 3];
179 if (!LJ_DUALNUM && op == BC_ISTYPE && rc == ~LJ_TNUMX+1) {
180 op = BC_ISNUM; rc++;
181 }
182 p[LJ_ENDIAN_SELECT(0, 3)] = op;
183 p[LJ_ENDIAN_SELECT(1, 2)] = ra;
184 p[LJ_ENDIAN_SELECT(2, 1)] = rc;
185 p[LJ_ENDIAN_SELECT(3, 0)] = rb;
186 }
187}
188
189static void libdef_lua(BuildCtx *ctx, char *p, int arg)
190{
191 UNUSED(arg);
192 if (ctx->mode == BUILD_libdef) {
193 int i;
194 for (i = 0; libbc_map[i].name != NULL; i++) {
195 if (!strcmp(libbc_map[i].name, p)) {
196 int ofs = libbc_map[i].ofs;
197 int len = libbc_map[i+1].ofs - ofs;
198 obuf[2]++; /* Bump hash table size. */
199 *optr++ = LIBINIT_LUA;
200 libdef_name(p, 0);
201 memcpy(optr, libbc_code + ofs, len);
202 libdef_fixupbc(optr);
203 optr += len;
204 return;
205 }
206 }
207 fprintf(stderr, "Error: missing libbc definition for %s\n", p);
208 exit(1);
209 }
210}
211
154static uint32_t find_rec(char *name) 212static uint32_t find_rec(char *name)
155{ 213{
156 char *p = (char *)obuf; 214 char *p = (char *)obuf;
@@ -277,6 +335,7 @@ static const LibDefHandler libdef_handlers[] = {
277 { "CF(", ")", libdef_func, LIBINIT_CF }, 335 { "CF(", ")", libdef_func, LIBINIT_CF },
278 { "ASM(", ")", libdef_func, LIBINIT_ASM }, 336 { "ASM(", ")", libdef_func, LIBINIT_ASM },
279 { "ASM_(", ")", libdef_func, LIBINIT_ASM_ }, 337 { "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
338 { "LUA(", ")", libdef_lua, 0 },
280 { "REC(", ")", libdef_rec, 0 }, 339 { "REC(", ")", libdef_rec, 0 },
281 { "PUSH(", ")", libdef_push, 0 }, 340 { "PUSH(", ")", libdef_push, 0 },
282 { "SET(", ")", libdef_set, 0 }, 341 { "SET(", ")", libdef_set, 0 },
@@ -333,6 +392,8 @@ void emit_lib(BuildCtx *ctx)
333 ok = LJ_HASJIT; 392 ok = LJ_HASJIT;
334 else if (!strcmp(buf, "#if LJ_HASFFI")) 393 else if (!strcmp(buf, "#if LJ_HASFFI"))
335 ok = LJ_HASFFI; 394 ok = LJ_HASFFI;
395 else if (!strcmp(buf, "#if LJ_HASBUFFER"))
396 ok = LJ_HASBUFFER;
336 if (!ok) { 397 if (!ok) {
337 int lvl = 1; 398 int lvl = 1;
338 while (fgets(buf, sizeof(buf), fp) != NULL) { 399 while (fgets(buf, sizeof(buf), fp) != NULL) {
@@ -380,7 +441,7 @@ void emit_lib(BuildCtx *ctx)
380 "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n", 441 "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
381 ffasmfunc); 442 ffasmfunc);
382 } else if (ctx->mode == BUILD_vmdef) { 443 } else if (ctx->mode == BUILD_vmdef) {
383 fprintf(ctx->fp, "}\n\n"); 444 fprintf(ctx->fp, "},\n\n");
384 } else if (ctx->mode == BUILD_bcdef) { 445 } else if (ctx->mode == BUILD_bcdef) {
385 int i; 446 int i;
386 fprintf(ctx->fp, "\n};\n\n"); 447 fprintf(ctx->fp, "\n};\n\n");
diff --git a/src/host/buildvm_libbc.h b/src/host/buildvm_libbc.h
new file mode 100644
index 00000000..276463b2
--- /dev/null
+++ b/src/host/buildvm_libbc.h
@@ -0,0 +1,81 @@
1/* This is a generated file. DO NOT EDIT! */
2
3static const int libbc_endian = 0;
4
5static const uint8_t libbc_code[] = {
6#if LJ_FR2
7/* math.deg */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,241,135,158,166,3,
8220,203,178,130,4,
9/* math.rad */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,243,244,148,165,20,
10198,190,199,252,3,
11/* string.len */ 0,1,2,0,0,0,3,BC_ISTYPE,0,5,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
12/* table.foreachi */ 0,2,10,0,0,0,15,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,
13BC_KSHORT,2,1,0,BC_LEN,3,0,0,BC_KSHORT,4,1,0,BC_FORI,2,8,128,BC_MOV,6,1,0,
14BC_MOV,8,5,0,BC_TGETR,9,5,0,BC_CALL,6,3,2,BC_ISEQP,6,0,0,BC_JMP,7,1,128,
15BC_RET1,6,2,0,BC_FORL,2,248,127,BC_RET0,0,1,0,
16/* table.foreach */ 0,2,11,0,0,1,16,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,BC_KPRI,
172,0,0,BC_MOV,3,0,0,BC_KNUM,4,0,0,BC_JMP,5,7,128,BC_MOV,7,1,0,BC_MOV,9,5,0,
18BC_MOV,10,6,0,BC_CALL,7,3,2,BC_ISEQP,7,0,0,BC_JMP,8,1,128,BC_RET1,7,2,0,
19BC_ITERN,5,3,3,BC_ITERL,5,247,127,BC_RET0,0,1,0,1,255,255,249,255,15,
20/* table.getn */ 0,1,2,0,0,0,3,BC_ISTYPE,0,12,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
21/* table.remove */ 0,2,10,0,0,2,30,BC_ISTYPE,0,12,0,BC_LEN,2,0,0,BC_ISNEP,1,0,
220,BC_JMP,3,7,128,BC_ISEQN,2,0,0,BC_JMP,3,23,128,BC_TGETR,3,2,0,BC_KPRI,4,0,0,
23BC_TSETR,4,2,0,BC_RET1,3,2,0,BC_JMP,3,18,128,BC_ISTYPE,1,14,0,BC_KSHORT,3,1,0,
24BC_ISGT,3,1,0,BC_JMP,3,14,128,BC_ISGT,1,2,0,BC_JMP,3,12,128,BC_TGETR,3,1,0,
25BC_ADDVN,4,1,1,BC_MOV,5,2,0,BC_KSHORT,6,1,0,BC_FORI,4,4,128,BC_SUBVN,8,1,7,
26BC_TGETR,9,7,0,BC_TSETR,9,8,0,BC_FORL,4,252,127,BC_KPRI,4,0,0,BC_TSETR,4,2,0,
27BC_RET1,3,2,0,BC_RET0,0,1,0,0,2,
28/* table.move */ 0,5,12,0,0,0,35,BC_ISTYPE,0,12,0,BC_ISTYPE,1,14,0,BC_ISTYPE,
292,14,0,BC_ISTYPE,3,14,0,BC_ISNEP,4,0,0,BC_JMP,5,1,128,BC_MOV,4,0,0,BC_ISTYPE,
304,12,0,BC_ISGT,1,2,0,BC_JMP,5,24,128,BC_SUBVV,5,1,3,BC_ISLT,2,3,0,BC_JMP,6,4,
31128,BC_ISLE,3,1,0,BC_JMP,6,2,128,BC_ISEQV,4,0,0,BC_JMP,6,9,128,BC_MOV,6,1,0,
32BC_MOV,7,2,0,BC_KSHORT,8,1,0,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,
33BC_TSETR,11,10,4,BC_FORL,6,252,127,BC_JMP,6,8,128,BC_MOV,6,2,0,BC_MOV,7,1,0,
34BC_KSHORT,8,255,255,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,BC_TSETR,
3511,10,4,BC_FORL,6,252,127,BC_RET1,4,2,0,
36#else
37/* math.deg */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,241,135,158,166,3,
38220,203,178,130,4,
39/* math.rad */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,243,244,148,165,20,
40198,190,199,252,3,
41/* string.len */ 0,1,2,0,0,0,3,BC_ISTYPE,0,5,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
42/* table.foreachi */ 0,2,9,0,0,0,15,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,
43BC_KSHORT,2,1,0,BC_LEN,3,0,0,BC_KSHORT,4,1,0,BC_FORI,2,8,128,BC_MOV,6,1,0,
44BC_MOV,7,5,0,BC_TGETR,8,5,0,BC_CALL,6,3,2,BC_ISEQP,6,0,0,BC_JMP,7,1,128,
45BC_RET1,6,2,0,BC_FORL,2,248,127,BC_RET0,0,1,0,
46/* table.foreach */ 0,2,10,0,0,1,16,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,BC_KPRI,
472,0,0,BC_MOV,3,0,0,BC_KNUM,4,0,0,BC_JMP,5,7,128,BC_MOV,7,1,0,BC_MOV,8,5,0,
48BC_MOV,9,6,0,BC_CALL,7,3,2,BC_ISEQP,7,0,0,BC_JMP,8,1,128,BC_RET1,7,2,0,
49BC_ITERN,5,3,3,BC_ITERL,5,247,127,BC_RET0,0,1,0,1,255,255,249,255,15,
50/* table.getn */ 0,1,2,0,0,0,3,BC_ISTYPE,0,12,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
51/* table.remove */ 0,2,10,0,0,2,30,BC_ISTYPE,0,12,0,BC_LEN,2,0,0,BC_ISNEP,1,0,
520,BC_JMP,3,7,128,BC_ISEQN,2,0,0,BC_JMP,3,23,128,BC_TGETR,3,2,0,BC_KPRI,4,0,0,
53BC_TSETR,4,2,0,BC_RET1,3,2,0,BC_JMP,3,18,128,BC_ISTYPE,1,14,0,BC_KSHORT,3,1,0,
54BC_ISGT,3,1,0,BC_JMP,3,14,128,BC_ISGT,1,2,0,BC_JMP,3,12,128,BC_TGETR,3,1,0,
55BC_ADDVN,4,1,1,BC_MOV,5,2,0,BC_KSHORT,6,1,0,BC_FORI,4,4,128,BC_SUBVN,8,1,7,
56BC_TGETR,9,7,0,BC_TSETR,9,8,0,BC_FORL,4,252,127,BC_KPRI,4,0,0,BC_TSETR,4,2,0,
57BC_RET1,3,2,0,BC_RET0,0,1,0,0,2,
58/* table.move */ 0,5,12,0,0,0,35,BC_ISTYPE,0,12,0,BC_ISTYPE,1,14,0,BC_ISTYPE,
592,14,0,BC_ISTYPE,3,14,0,BC_ISNEP,4,0,0,BC_JMP,5,1,128,BC_MOV,4,0,0,BC_ISTYPE,
604,12,0,BC_ISGT,1,2,0,BC_JMP,5,24,128,BC_SUBVV,5,1,3,BC_ISLT,2,3,0,BC_JMP,6,4,
61128,BC_ISLE,3,1,0,BC_JMP,6,2,128,BC_ISEQV,4,0,0,BC_JMP,6,9,128,BC_MOV,6,1,0,
62BC_MOV,7,2,0,BC_KSHORT,8,1,0,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,
63BC_TSETR,11,10,4,BC_FORL,6,252,127,BC_JMP,6,8,128,BC_MOV,6,2,0,BC_MOV,7,1,0,
64BC_KSHORT,8,255,255,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,BC_TSETR,
6511,10,4,BC_FORL,6,252,127,BC_RET1,4,2,0,
66#endif
670
68};
69
70static const struct { const char *name; int ofs; } libbc_map[] = {
71{"math_deg",0},
72{"math_rad",25},
73{"string_len",50},
74{"table_foreachi",69},
75{"table_foreach",136},
76{"table_getn",213},
77{"table_remove",232},
78{"table_move",361},
79{NULL,508}
80};
81
diff --git a/src/host/buildvm_peobj.c b/src/host/buildvm_peobj.c
index 7cbe1438..247b9d2d 100644
--- a/src/host/buildvm_peobj.c
+++ b/src/host/buildvm_peobj.c
@@ -9,7 +9,7 @@
9#include "buildvm.h" 9#include "buildvm.h"
10#include "lj_bc.h" 10#include "lj_bc.h"
11 11
12#if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC 12#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
13 13
14/* Context for PE object emitter. */ 14/* Context for PE object emitter. */
15static char *strtab; 15static char *strtab;
@@ -93,12 +93,17 @@ typedef struct PEsymaux {
93#define PEOBJ_RELOC_ADDR32NB 0x03 93#define PEOBJ_RELOC_ADDR32NB 0x03
94#define PEOBJ_RELOC_OFS 0 94#define PEOBJ_RELOC_OFS 0
95#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */ 95#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
96#elif LJ_TARGET_PPC 96#define PEOBJ_PDATA_NRELOC 6
97#define PEOBJ_ARCH_TARGET 0x01f2 97#define PEOBJ_XDATA_SIZE (8*2+4+6*2)
98#define PEOBJ_RELOC_REL32 0x06 98#elif LJ_TARGET_ARM64
99#define PEOBJ_RELOC_DIR32 0x02 99#define PEOBJ_ARCH_TARGET 0xaa64
100#define PEOBJ_RELOC_REL32 0x03 /* MS: BRANCH26. */
101#define PEOBJ_RELOC_DIR32 0x01
102#define PEOBJ_RELOC_ADDR32NB 0x02
100#define PEOBJ_RELOC_OFS (-4) 103#define PEOBJ_RELOC_OFS (-4)
101#define PEOBJ_TEXT_FLAGS 0x60400020 /* 60=r+x, 40=align8, 20=code. */ 104#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
105#define PEOBJ_PDATA_NRELOC 4
106#define PEOBJ_XDATA_SIZE (4+24+4 +4+8)
102#endif 107#endif
103 108
104/* Section numbers (0-based). */ 109/* Section numbers (0-based). */
@@ -106,9 +111,11 @@ enum {
106 PEOBJ_SECT_ABS = -2, 111 PEOBJ_SECT_ABS = -2,
107 PEOBJ_SECT_UNDEF = -1, 112 PEOBJ_SECT_UNDEF = -1,
108 PEOBJ_SECT_TEXT, 113 PEOBJ_SECT_TEXT,
109#if LJ_TARGET_X64 114#ifdef PEOBJ_PDATA_NRELOC
110 PEOBJ_SECT_PDATA, 115 PEOBJ_SECT_PDATA,
111 PEOBJ_SECT_XDATA, 116 PEOBJ_SECT_XDATA,
117#elif LJ_TARGET_X86
118 PEOBJ_SECT_SXDATA,
112#endif 119#endif
113 PEOBJ_SECT_RDATA_Z, 120 PEOBJ_SECT_RDATA_Z,
114 PEOBJ_NSECTIONS 121 PEOBJ_NSECTIONS
@@ -179,6 +186,9 @@ void emit_peobj(BuildCtx *ctx)
179 uint32_t sofs; 186 uint32_t sofs;
180 int i, nrsym; 187 int i, nrsym;
181 union { uint8_t b; uint32_t u; } host_endian; 188 union { uint8_t b; uint32_t u; } host_endian;
189#ifdef PEOBJ_PDATA_NRELOC
190 uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
191#endif
182 192
183 sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection); 193 sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
184 194
@@ -192,22 +202,29 @@ void emit_peobj(BuildCtx *ctx)
192 /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ 202 /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
193 pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS; 203 pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
194 204
195#if LJ_TARGET_X64 205#ifdef PEOBJ_PDATA_NRELOC
196 memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1); 206 memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
197 pesect[PEOBJ_SECT_PDATA].ofs = sofs; 207 pesect[PEOBJ_SECT_PDATA].ofs = sofs;
198 sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4); 208 sofs += (pesect[PEOBJ_SECT_PDATA].size = PEOBJ_PDATA_NRELOC*4);
199 pesect[PEOBJ_SECT_PDATA].relocofs = sofs; 209 pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
200 sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE; 210 sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = PEOBJ_PDATA_NRELOC) * PEOBJ_RELOC_SIZE;
201 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ 211 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
202 pesect[PEOBJ_SECT_PDATA].flags = 0x40300040; 212 pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
203 213
204 memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1); 214 memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
205 pesect[PEOBJ_SECT_XDATA].ofs = sofs; 215 pesect[PEOBJ_SECT_XDATA].ofs = sofs;
206 sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */ 216 sofs += (pesect[PEOBJ_SECT_XDATA].size = PEOBJ_XDATA_SIZE); /* See below. */
207 pesect[PEOBJ_SECT_XDATA].relocofs = sofs; 217 pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
208 sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; 218 sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
209 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ 219 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
210 pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; 220 pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
221#elif LJ_TARGET_X86
222 memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1);
223 pesect[PEOBJ_SECT_SXDATA].ofs = sofs;
224 sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4);
225 pesect[PEOBJ_SECT_SXDATA].relocofs = sofs;
226 /* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */
227 pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240;
211#endif 228#endif
212 229
213 memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); 230 memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
@@ -231,8 +248,8 @@ void emit_peobj(BuildCtx *ctx)
231 */ 248 */
232 nrsym = ctx->nrelocsym; 249 nrsym = ctx->nrelocsym;
233 pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; 250 pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
234#if LJ_TARGET_X64 251#ifdef PEOBJ_PDATA_NRELOC
235 pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */ 252 pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */
236#endif 253#endif
237 254
238 /* Write PE object header and all sections. */ 255 /* Write PE object header and all sections. */
@@ -242,15 +259,8 @@ void emit_peobj(BuildCtx *ctx)
242 /* Write .text section. */ 259 /* Write .text section. */
243 host_endian.u = 1; 260 host_endian.u = 1;
244 if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) { 261 if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
245#if LJ_TARGET_PPC
246 uint32_t *p = (uint32_t *)ctx->code;
247 int n = (int)(ctx->codesz >> 2);
248 for (i = 0; i < n; i++, p++)
249 *p = lj_bswap(*p); /* Byteswap .text section. */
250#else
251 fprintf(stderr, "Error: different byte order for host and target\n"); 262 fprintf(stderr, "Error: different byte order for host and target\n");
252 exit(1); 263 exit(1);
253#endif
254 } 264 }
255 owrite(ctx, ctx->code, ctx->codesz); 265 owrite(ctx, ctx->code, ctx->codesz);
256 for (i = 0; i < ctx->nreloc; i++) { 266 for (i = 0; i < ctx->nreloc; i++) {
@@ -263,7 +273,6 @@ void emit_peobj(BuildCtx *ctx)
263 273
264#if LJ_TARGET_X64 274#if LJ_TARGET_X64
265 { /* Write .pdata section. */ 275 { /* Write .pdata section. */
266 uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
267 uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */ 276 uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
268 PEreloc reloc; 277 PEreloc reloc;
269 pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0; 278 pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
@@ -312,6 +321,100 @@ void emit_peobj(BuildCtx *ctx)
312 reloc.type = PEOBJ_RELOC_ADDR32NB; 321 reloc.type = PEOBJ_RELOC_ADDR32NB;
313 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); 322 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
314 } 323 }
324#elif LJ_TARGET_ARM64
325 /* https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling */
326 { /* Write .pdata section. */
327 uint32_t pdata[4];
328 PEreloc reloc;
329 pdata[0] = 0;
330 pdata[1] = 0;
331 pdata[2] = fcofs;
332 pdata[3] = 4+24+4;
333 owrite(ctx, &pdata, sizeof(pdata));
334 /* Start of .text and start of .xdata. */
335 reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
336 reloc.type = PEOBJ_RELOC_ADDR32NB;
337 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
338 reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2;
339 reloc.type = PEOBJ_RELOC_ADDR32NB;
340 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
341 /* Start of vm_ffi_call and start of second part of .xdata. */
342 reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2+2+1;
343 reloc.type = PEOBJ_RELOC_ADDR32NB;
344 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
345 reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2;
346 reloc.type = PEOBJ_RELOC_ADDR32NB;
347 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
348 }
349 { /* Write .xdata section. */
350 uint32_t u32;
351 uint8_t *p, uwc[24];
352 PEreloc reloc;
353
354#define CBE16(x) (*p = ((x) >> 8) & 0xff, p[1] = (x) & 0xff, p += 2)
355#define CALLOC_S(s) (*p++ = ((s) >> 4)) /* s < 512 */
356#define CSAVE_FPLR(o) (*p++ = 0x40 | ((o) >> 3)) /* o <= 504 */
357#define CSAVE_REGP(r,o) CBE16(0xc800 | (((r) - 19) << 6) | ((o) >> 3))
358#define CSAVE_REGS(r1,r2,o1) do { \
359 int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_REGP(r, o); \
360} while (0)
361#define CSAVE_REGPX(r,o) CBE16(0xcc00 | (((r) - 19) << 6) | (~(o) >> 3))
362#define CSAVE_FREGP(r,o) CBE16(0xd800 | (((r) - 8) << 6) | ((o) >> 3))
363#define CSAVE_FREGS(r1,r2,o1) do { \
364 int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_FREGP(r, o); \
365} while (0)
366#define CADD_FP(s) CBE16(0xe200 | ((s) >> 3)) /* s < 8*256 */
367#define CODE_NOP 0xe3
368#define CODE_END 0xe4
369#define CEND_ALIGN do { \
370 *p++ = CODE_END; \
371 while ((p - uwc) & 3) *p++ = CODE_NOP; \
372} while (0)
373
374 /* Unwind codes for .text section with handler. */
375 p = uwc;
376 CADD_FP(192); /* +2 */
377 CSAVE_REGS(19, 28, 176); /* +5*2 */
378 CSAVE_FREGS(8, 15, 96); /* +4*2 */
379 CSAVE_FPLR(192); /* +1 */
380 CALLOC_S(208); /* +1 */
381 CEND_ALIGN; /* +1 +1 -> 24 */
382
383 u32 = ((24u >> 2) << 27) | (1u << 20) | (fcofs >> 2);
384 owrite(ctx, &u32, 4);
385 owrite(ctx, &uwc, 24);
386
387 u32 = 0; /* Handler RVA to be relocated at 4 + 24. */
388 owrite(ctx, &u32, 4);
389
390 /* Unwind codes for vm_ffi_call without handler. */
391 p = uwc;
392 CADD_FP(16); /* +2 */
393 CSAVE_FPLR(16); /* +1 */
394 CSAVE_REGPX(19, -32); /* +2 */
395 CEND_ALIGN; /* +1 +2 -> 8 */
396
397 u32 = ((8u >> 2) << 27) | (((uint32_t)ctx->codesz - fcofs) >> 2);
398 owrite(ctx, &u32, 4);
399 owrite(ctx, &uwc, 8);
400
401 reloc.vaddr = 4 + 24; reloc.symidx = 1+2+nrsym+2+2;
402 reloc.type = PEOBJ_RELOC_ADDR32NB;
403 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
404 }
405#elif LJ_TARGET_X86
406 /* Write .sxdata section. */
407 for (i = 0; i < nrsym; i++) {
408 if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) {
409 uint32_t symidx = 1+2+i;
410 owrite(ctx, &symidx, 4);
411 break;
412 }
413 }
414 if (i == nrsym) {
415 fprintf(stderr, "Error: extern lj_err_unwind_win not used\n");
416 exit(1);
417 }
315#endif 418#endif
316 419
317 /* Write .rdata$Z section. */ 420 /* Write .rdata$Z section. */
@@ -330,11 +433,13 @@ void emit_peobj(BuildCtx *ctx)
330 emit_peobj_sym(ctx, ctx->relocsym[i], 0, 433 emit_peobj_sym(ctx, ctx->relocsym[i], 0,
331 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); 434 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
332 435
333#if LJ_TARGET_X64 436#ifdef PEOBJ_PDATA_NRELOC
334 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); 437 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
335 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); 438 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
336 emit_peobj_sym(ctx, "lj_err_unwind_win64", 0, 439 emit_peobj_sym(ctx, "lj_err_unwind_win", 0,
337 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); 440 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
441#elif LJ_TARGET_X86
442 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA);
338#endif 443#endif
339 444
340 emit_peobj_sym(ctx, ctx->beginsym, 0, 445 emit_peobj_sym(ctx, ctx->beginsym, 0,
diff --git a/src/host/genlibbc.lua b/src/host/genlibbc.lua
new file mode 100644
index 00000000..3eb1b827
--- /dev/null
+++ b/src/host/genlibbc.lua
@@ -0,0 +1,234 @@
1----------------------------------------------------------------------------
2-- Lua script to dump the bytecode of the library functions written in Lua.
3-- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT.
4----------------------------------------------------------------------------
5-- Copyright (C) 2005-2026 Mike Pall. All rights reserved.
6-- Released under the MIT license. See Copyright Notice in luajit.h
7----------------------------------------------------------------------------
8
9local ffi = require("ffi")
10local bit = require("bit")
11local vmdef = require("jit.vmdef")
12local bcnames = vmdef.bcnames
13
14local format = string.format
15
16local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1)
17
18local function usage(arg)
19 io.stderr:write("Usage: ", arg and arg[0] or "genlibbc",
20 " [-o buildvm_libbc.h] lib_*.c\n")
21 os.exit(1)
22end
23
24local function parse_arg(arg)
25 local outfile = "-"
26 if not (arg and arg[1]) then
27 usage(arg)
28 end
29 if arg[1] == "-o" then
30 outfile = arg[2]
31 if not outfile then usage(arg) end
32 table.remove(arg, 1)
33 table.remove(arg, 1)
34 end
35 return outfile
36end
37
38local function read_files(names)
39 local src = ""
40 for _,name in ipairs(names) do
41 local fp = assert(io.open(name))
42 src = src .. fp:read("*a")
43 fp:close()
44 end
45 return src
46end
47
48local function transform_lua(code)
49 local fixup = {}
50 local n = -30000
51 code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var)
52 n = n + 1
53 fixup[n] = { "CHECK", tp }
54 return format("%s=%d", var, n)
55 end)
56 code = string.gsub(code, "PAIRS%((.-)%)", function(var)
57 fixup.PAIRS = true
58 return format("nil, %s, 0x4dp80", var)
59 end)
60 return "return "..code, fixup
61end
62
63local function read_uleb128(p)
64 local v = p[0]; p = p + 1
65 if v >= 128 then
66 local sh = 7; v = v - 128
67 repeat
68 local r = p[0]
69 v = v + bit.lshift(bit.band(r, 127), sh)
70 sh = sh + 7
71 p = p + 1
72 until r < 128
73 end
74 return p, v
75end
76
77-- ORDER LJ_T
78local name2itype = {
79 str = 5, func = 9, tab = 12, int = 14, num = 15
80}
81
82local BC, BCN = {}, {}
83for i=0,#bcnames/6-1 do
84 local name = bcnames:sub(i*6+1, i*6+6):gsub(" ", "")
85 BC[name] = i
86 BCN[i] = name
87end
88local xop, xra = isbe and 3 or 0, isbe and 2 or 1
89local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3
90
91local function fixup_dump(dump, fixup)
92 local buf = ffi.new("uint8_t[?]", #dump+1, dump)
93 local p = buf+5
94 local n, sizebc
95 p, n = read_uleb128(p)
96 local start = p
97 p = p + 4
98 p = read_uleb128(p)
99 p = read_uleb128(p)
100 p, sizebc = read_uleb128(p)
101 local startbc = tonumber(p - start)
102 local rawtab = {}
103 for i=0,sizebc-1 do
104 local op = p[xop]
105 if op == BC.KSHORT then
106 local rd = p[xrc] + 256*p[xrb]
107 rd = bit.arshift(bit.lshift(rd, 16), 16)
108 local f = fixup[rd]
109 if f then
110 if f[1] == "CHECK" then
111 local tp = f[2]
112 if tp == "tab" then rawtab[p[xra]] = true end
113 p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE
114 p[xrb] = 0
115 p[xrc] = name2itype[tp]
116 else
117 error("unhandled fixup type: "..f[1])
118 end
119 end
120 elseif op == BC.TGETV then
121 if rawtab[p[xrb]] then
122 p[xop] = BC.TGETR
123 end
124 elseif op == BC.TSETV then
125 if rawtab[p[xrb]] then
126 p[xop] = BC.TSETR
127 end
128 elseif op == BC.ITERC then
129 if fixup.PAIRS then
130 p[xop] = BC.ITERN
131 end
132 end
133 p = p + 4
134 end
135 local ndump = ffi.string(start, n)
136 -- Fixup hi-part of 0x4dp80 to LJ_KEYINDEX.
137 ndump = ndump:gsub("\x80\x80\xcd\xaa\x04", "\xff\xff\xf9\xff\x0f")
138 return { dump = ndump, startbc = startbc, sizebc = sizebc }
139end
140
141local function find_defs(src, mode)
142 local defs = {}
143 for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
144 local tcode, fixup = transform_lua(code)
145 local func = assert(load(tcode, "", mode))
146 defs[name] = fixup_dump(string.dump(func, mode), fixup)
147 defs[#defs+1] = name
148 end
149 return defs
150end
151
152local function gen_header(defs32, defs64)
153 local t = {}
154 local function w(x) t[#t+1] = x end
155 w("/* This is a generated file. DO NOT EDIT! */\n\n")
156 w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n")
157 for j,defs in ipairs{defs64, defs32} do
158 local s, sb = "", ""
159 for i,name in ipairs(defs) do
160 local d = defs[name]
161 s = s .. d.dump
162 sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1)
163 .. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc)
164 .. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4)
165 end
166 if j == 1 then
167 w("static const uint8_t libbc_code[] = {\n#if LJ_FR2\n")
168 else
169 w("\n#else\n")
170 end
171 local n = 0
172 for i=1,#s do
173 local x = string.byte(s, i)
174 local xb = string.byte(sb, i)
175 if xb == 255 then
176 local name = BCN[x]
177 local m = #name + 4
178 if n + m > 78 then n = 0; w("\n") end
179 n = n + m
180 w("BC_"); w(name)
181 else
182 local m = x < 10 and 2 or (x < 100 and 3 or 4)
183 if xb == 0 then
184 if n + m > 78 then n = 0; w("\n") end
185 else
186 local name = defs[xb]:gsub("_", ".")
187 if n ~= 0 then w("\n") end
188 w("/* "); w(name); w(" */ ")
189 n = #name + 7
190 end
191 n = n + m
192 w(x)
193 end
194 w(",")
195 end
196 end
197 w("\n#endif\n0\n};\n\n")
198 w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
199 local m32, m64 = 0, 0
200 for i,name in ipairs(defs32) do
201 assert(name == defs64[i])
202 w('{"'); w(name); w('",'); w(m32) w('},\n')
203 m32 = m32 + #defs32[name].dump
204 m64 = m64 + #defs64[name].dump
205 assert(m32 == m64)
206 end
207 w("{NULL,"); w(m32); w("}\n};\n\n")
208 return table.concat(t)
209end
210
211local function write_file(name, data)
212 if name == "-" then
213 assert(io.write(data))
214 assert(io.flush())
215 else
216 local fp = io.open(name)
217 if fp then
218 local old = fp:read("*a")
219 fp:close()
220 if data == old then return end
221 end
222 fp = assert(io.open(name, "w"))
223 assert(fp:write(data))
224 assert(fp:close())
225 end
226end
227
228local outfile = parse_arg(arg)
229local src = read_files(arg)
230local defs32 = find_defs(src, "Wdts")
231local defs64 = find_defs(src, "Xdts")
232local hdr = gen_header(defs32, defs64)
233write_file(outfile, hdr)
234