From a6e73ca73c391b466b11e2211972f6b4eab8cd5a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 28 Nov 2023 22:49:01 +0100 Subject: [PATCH] Handle serialization endianness transparently (#152) Change JS_WriteObject() and JS_WriteObject2() to write little-endian data and update JS_ReadObject() to byte-swap data when running on a big-endian system. Obsoletes the JS_WRITE_OBJ_BSWAP flag, it is now a no-op. Fixes: https://github.com/quickjs-ng/quickjs/issues/125 --- doc/quickjs.texi | 3 --- qjsc.c | 13 ++----------- quickjs.c | 36 +++++++++++++++--------------------- quickjs.h | 2 +- 4 files changed, 18 insertions(+), 36 deletions(-) diff --git a/doc/quickjs.texi b/doc/quickjs.texi index c3e6930..8d8fdd7 100644 --- a/doc/quickjs.texi +++ b/doc/quickjs.texi @@ -167,9 +167,6 @@ find the name of the dynamically loaded modules. Add initialization code for an external C module. See the @code{c_module} example. -@item -x -Byte swapped output (only used for cross compilation). - @item -flto Use link time optimization. The compilation is slower but the executable is smaller and faster. This option is automatically set diff --git a/qjsc.c b/qjsc.c index 65f3448..930b83f 100644 --- a/qjsc.c +++ b/qjsc.c @@ -51,7 +51,6 @@ static namelist_t cname_list; static namelist_t cmodule_list; static namelist_t init_module_list; static FILE *outfile; -static BOOL byte_swap; static const char *c_ident_prefix = "qjsc_"; @@ -152,11 +151,8 @@ static void output_object_code(JSContext *ctx, { uint8_t *out_buf; size_t out_buf_len; - int flags; - flags = JS_WRITE_OBJ_BYTECODE; - if (byte_swap) - flags |= JS_WRITE_OBJ_BSWAP; - out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); + + out_buf = JS_WriteObject(ctx, &out_buf_len, obj, JS_WRITE_OBJ_BYTECODE); if (!out_buf) { js_std_dump_error(ctx); exit(1); @@ -322,7 +318,6 @@ void help(void) "-m compile as Javascript module (default=autodetect)\n" "-D module_name compile a dynamically loaded module or worker\n" "-M module_name[,cname] add initialization code for an external C module\n" - "-x byte swapped output\n" "-p prefix set the prefix of the generated C names\n" "-S n set the maximum stack size to 'n' bytes (default=%d)\n", JS_GetVersion(), @@ -352,7 +347,6 @@ int main(int argc, char **argv) output_type = OUTPUT_C; cname = NULL; module = -1; - byte_swap = FALSE; verbose = 0; stack_size = 0; memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); @@ -399,9 +393,6 @@ int main(int argc, char **argv) case 'D': namelist_add(&dynamic_module_list, optarg, NULL, 0); break; - case 'x': - byte_swap = TRUE; - break; case 'v': verbose++; break; diff --git a/quickjs.c b/quickjs.c index 0f9d2d0..c139360 100644 --- a/quickjs.c +++ b/quickjs.c @@ -31664,18 +31664,11 @@ typedef enum BCTagEnum { BC_TAG_OBJECT_REFERENCE, } BCTagEnum; -#define BC_BASE_VERSION 2 -#define BC_BE_VERSION 0x40 -#ifdef WORDS_BIGENDIAN -#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION) -#else -#define BC_VERSION BC_BASE_VERSION -#endif +#define BC_VERSION 3 typedef struct BCWriterState { JSContext *ctx; DynBuf dbuf; - BOOL byte_swap : 8; BOOL allow_bytecode : 8; BOOL allow_sab : 8; BOOL allow_reference : 8; @@ -31717,6 +31710,15 @@ static const char * const bc_tag_str[] = { }; #endif +static inline BOOL is_be(void) +{ + union { + uint16_t a; + uint8_t b; + } u = {0x100}; + return u.b; +} + static void bc_put_u8(BCWriterState *s, uint8_t v) { dbuf_putc(&s->dbuf, v); @@ -31724,21 +31726,21 @@ static void bc_put_u8(BCWriterState *s, uint8_t v) static void bc_put_u16(BCWriterState *s, uint16_t v) { - if (s->byte_swap) + if (is_be()) v = bswap16(v); dbuf_put_u16(&s->dbuf, v); } static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v) { - if (s->byte_swap) + if (is_be()) v = bswap32(v); dbuf_put_u32(&s->dbuf, v); } static void bc_put_u64(BCWriterState *s, uint64_t v) { - if (s->byte_swap) + if (is_be()) v = bswap64(v); dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v)); } @@ -31908,7 +31910,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s, pos += len; } - if (s->byte_swap) + if (is_be()) bc_byte_swap(bc_buf, bc_len); dbuf_put(&s->dbuf, bc_buf, bc_len); @@ -32405,15 +32407,10 @@ static int JS_WriteObjectAtoms(BCWriterState *s) JSRuntime *rt = s->ctx->rt; DynBuf dbuf1; int i, atoms_size; - uint8_t version; dbuf1 = s->dbuf; js_dbuf_init(s->ctx, &s->dbuf); - - version = BC_VERSION; - if (s->byte_swap) - version ^= BC_BE_VERSION; - bc_put_u8(s, version); + bc_put_u8(s, BC_VERSION); bc_put_leb128(s, s->idx_to_atom_count); for(i = 0; i < s->idx_to_atom_count; i++) { @@ -32446,8 +32443,6 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, memset(s, 0, sizeof(*s)); s->ctx = ctx; - /* XXX: byte swapped output is untested */ - s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0); s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0); s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0); s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0); @@ -33531,7 +33526,6 @@ static int JS_ReadObjectAtoms(BCReaderState *s) if (bc_get_u8(s, &v8)) return -1; - /* XXX: could support byte swapped input */ if (v8 != BC_VERSION) { JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)", v8, BC_VERSION); diff --git a/quickjs.h b/quickjs.h index b018bad..8b8b384 100644 --- a/quickjs.h +++ b/quickjs.h @@ -838,7 +838,7 @@ JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); /* Object Writer/Reader (currently only used to handle precompiled code) */ #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ -#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ +#define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */ #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to encode arbitrary object