diff --git CMakeLists.txt CMakeLists.txt
index a76caf1..607bb47 100644
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -78,6 +78,37 @@ if(NOT CMAKE_BUILD_TYPE)
     set(CMAKE_BUILD_TYPE "Release")
 endif()
 
+# QuickJS ships pre-generated bytecode (the builtin-*.h headers compiled into the
+# library, and the gen/*.c blobs used by the CLI and examples). Bytecode is stored
+# in native endianness and validated by an embedded checksum at load time (see
+# bc_csum()/put_u32() in quickjs.c), so the committed little-endian files fail with
+# a "checksum error" on big-endian hosts. On a native big-endian build we regenerate
+# them from source with a freshly built qjsc, which emits native-endian bytecode.
+#
+# Cross-compilation cannot do this (qjsc would be built for the target and cannot run
+# on the build machine), so we only enable it for native builds. Cross-compiling to
+# a big-endian target still requires pre-generating the files with `make codegen` using
+# a matching-endianness toolchain.
+# QJS_REGEN_BYTECODE_FORCE forces regeneration regardless of detected endianness
+# (useful to exercise the codegen path, or if detection is ever wrong). It has no
+# effect when cross-compiling, where qjsc cannot be run on the build machine.
+option(QJS_REGEN_BYTECODE_FORCE "Always regenerate bytecode from source with qjsc" OFF)
+set(QJS_REGEN_BYTECODE OFF)
+if(NOT CMAKE_CROSSCOMPILING)
+    include(TestBigEndian)
+    test_big_endian(QJS_IS_BIG_ENDIAN)
+    if(QJS_IS_BIG_ENDIAN OR QJS_REGEN_BYTECODE_FORCE)
+        set(QJS_REGEN_BYTECODE ON)
+        message(STATUS "Bytecode will be regenerated from source with qjsc")
+    endif()
+elseif(DEFINED CMAKE_C_BYTE_ORDER AND CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+    message(WARNING
+        "Cross-compiling to a big-endian target: the committed bytecode "
+        "(builtin-*.h and gen/*.c) is little-endian and will fail at runtime "
+        "with a \"checksum error\". Pre-generate it with a matching-endianness "
+        "qjsc (see the `codegen` target in the Makefile) before building.")
+endif()
+
 message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode")
 message(STATUS "Building with ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} on ${CMAKE_SYSTEM}")
 
@@ -304,7 +335,100 @@ if(M_LIBRARIES OR CMAKE_C_COMPILER_ID STREQUAL "TinyCC")
     list(APPEND qjs_libs m)
 endif()
 
-add_library(qjs ${qjs_sources})
+# Bytecode regeneration (big-endian native builds only; see QJS_REGEN_BYTECODE above)
+#
+# The engine embeds three builtin bytecode blobs via #include (builtin-*.h) that are
+# evaluated lazily (Array.fromAsync, Iterator.zip, Iterator.zipKeyed), plus the CLI
+# and examples embed gen/*.c blobs. All must match the host endianness. We regenerate
+# them into the build tree with a bootstrap qjsc and have the real qjs (and the CLI,
+# examples, etc.) pick up the regenerated copies.
+set(qjs_gen_dir ${CMAKE_CURRENT_BINARY_DIR}/gen)
+set(qjs_real_sources ${qjs_sources})
+if(QJS_REGEN_BYTECODE)
+    # Self-contained bootstrap library + compiler, built from the *committed*
+    # (possibly wrong-endian) headers. Compiling JS to bytecode never touches the
+    # lazily-evaluated builtins, so a wrong-endian bootstrap engine generates correct
+    # native-endian bytecode even though it could not itself run that bytecode. Kept
+    # entirely separate from the real qjs so there is no build dependency cycle.
+    #
+    # qjsc.c pulls in quickjs-libc.h (js_std_dump_error, the module loader), so the
+    # bootstrap library must always include quickjs-libc.c to be self-contained. It is
+    # already part of qjs_sources when QJS_BUILD_LIBC is ON, so only add it otherwise.
+    set(qjs_bootstrap_sources ${qjs_sources})
+    if(NOT QJS_BUILD_LIBC)
+        list(APPEND qjs_bootstrap_sources quickjs-libc.c)
+    endif()
+    add_library(qjs_bootstrap STATIC EXCLUDE_FROM_ALL ${qjs_bootstrap_sources})
+    target_compile_definitions(qjs_bootstrap PRIVATE ${qjs_defines})
+    target_include_directories(qjs_bootstrap PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+    target_link_libraries(qjs_bootstrap PUBLIC ${qjs_libs})
+
+    add_executable(qjsc_bootstrap EXCLUDE_FROM_ALL qjsc.c)
+    target_compile_definitions(qjsc_bootstrap PRIVATE ${qjs_defines})
+    target_link_libraries(qjsc_bootstrap PRIVATE qjs_bootstrap)
+
+    # Regenerate one bytecode file into the build tree with the bootstrap compiler.
+    # The generated C symbol name derives from the input .js path, so we keep the
+    # same inputs and flags as the `codegen` target in the Makefile. -o must precede
+    # the input file: qjsc stops option scanning at the first non-option argument.
+    function(qjs_regen out_var relpath)
+        set(gen_out ${qjs_gen_dir}/${relpath})
+        get_filename_component(gen_out_dir ${gen_out} DIRECTORY)
+        add_custom_command(
+            OUTPUT ${gen_out}
+            COMMAND ${CMAKE_COMMAND} -E make_directory ${gen_out_dir}
+            COMMAND qjsc_bootstrap -o ${gen_out} ${ARGN}
+            DEPENDS qjsc_bootstrap
+            COMMENT "Regenerating ${relpath} (native endianness)"
+            VERBATIM
+        )
+        set(${out_var} ${gen_out} PARENT_SCOPE)
+    endfunction()
+
+    # -n sets the script name embedded in the bytecode (used in stack traces); we
+    # match the committed files' names so the output is a byte-for-byte drop-in and
+    # the build-tree absolute path does not leak into the binary.
+    qjs_regen(gen_builtin_fromasync builtin-array-fromasync.h
+        -C -ss -n builtin-array-fromasync.js
+        ${CMAKE_CURRENT_SOURCE_DIR}/builtin-array-fromasync.js)
+    qjs_regen(gen_builtin_zip builtin-iterator-zip.h
+        -C -ss -n builtin-iterator-zip.js
+        ${CMAKE_CURRENT_SOURCE_DIR}/builtin-iterator-zip.js)
+    qjs_regen(gen_builtin_zip_keyed builtin-iterator-zip-keyed.h
+        -C -ss -n builtin-iterator-zip-keyed.js
+        ${CMAKE_CURRENT_SOURCE_DIR}/builtin-iterator-zip-keyed.js)
+
+    # The builtin-*.h headers are #included by quickjs.c with quoted includes, which
+    # the compiler resolves relative to quickjs.c's own directory before any -I path.
+    # To make the regenerated headers win without mutating the source tree, we compile
+    # a copy of quickjs.c placed next to them in the build tree; its other quoted
+    # includes fall through to -I ${CMAKE_CURRENT_SOURCE_DIR}.
+    set(qjs_quickjs_copy ${qjs_gen_dir}/quickjs.c)
+    add_custom_command(
+        OUTPUT ${qjs_quickjs_copy}
+        COMMAND ${CMAKE_COMMAND} -E copy_if_different
+                ${CMAKE_CURRENT_SOURCE_DIR}/quickjs.c ${qjs_quickjs_copy}
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/quickjs.c
+                ${gen_builtin_fromasync} ${gen_builtin_zip} ${gen_builtin_zip_keyed}
+        COMMENT "Staging quickjs.c with regenerated builtin bytecode"
+        VERBATIM
+    )
+    list(REMOVE_ITEM qjs_real_sources quickjs.c)
+    list(APPEND qjs_real_sources ${qjs_quickjs_copy})
+endif()
+
+# Resolve a gen/*.c bytecode source to the committed file, or a regenerated copy
+# (in the build tree) on big-endian native builds.
+function(qjs_bytecode_source out_var relpath)
+    if(NOT QJS_REGEN_BYTECODE)
+        set(${out_var} ${relpath} PARENT_SCOPE)
+        return()
+    endif()
+    qjs_regen(gen_out ${relpath} ${ARGN})
+    set(${out_var} ${gen_out} PARENT_SCOPE)
+endfunction()
+
+add_library(qjs ${qjs_real_sources})
 target_compile_definitions(qjs PRIVATE ${qjs_defines})
 target_include_directories(qjs PUBLIC
     $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
@@ -378,9 +502,13 @@ target_link_libraries(qjsc PRIVATE qjs)
 # QuickJS CLI
 #
 
+qjs_bytecode_source(qjs_gen_repl gen/repl.c
+    -ss -m -n repl.js ${CMAKE_CURRENT_SOURCE_DIR}/repl.js)
+qjs_bytecode_source(qjs_gen_standalone gen/standalone.c
+    -ss -m -n standalone.js ${CMAKE_CURRENT_SOURCE_DIR}/standalone.js)
 add_executable(qjs_exe
-    gen/repl.c
-    gen/standalone.c
+    ${qjs_gen_repl}
+    ${qjs_gen_standalone}
     qjs.c
 )
 add_qjs_libc_if_needed(qjs_exe)
@@ -473,8 +601,10 @@ add_executable(unicode_gen EXCLUDE_FROM_ALL
 )
 target_compile_definitions(unicode_gen PRIVATE ${qjs_defines})
 
+qjs_bytecode_source(qjs_gen_function_source gen/function_source.c
+    -e -n tests/function_source.js ${CMAKE_CURRENT_SOURCE_DIR}/tests/function_source.js)
 add_executable(function_source
-    gen/function_source.c
+    ${qjs_gen_function_source}
 )
 add_qjs_libc_if_needed(function_source)
 target_include_directories(function_source PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
@@ -494,16 +624,20 @@ if(QJS_BUILD_EXAMPLES)
         )
     endif()
 
+    qjs_bytecode_source(qjs_gen_hello gen/hello.c
+        -e -n examples/hello.js ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello.js)
     add_executable(hello
-        gen/hello.c
+        ${qjs_gen_hello}
     )
     add_qjs_libc_if_needed(hello)
     target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
     target_compile_definitions(hello PRIVATE ${qjs_defines})
     target_link_libraries(hello PRIVATE qjs)
 
+    qjs_bytecode_source(qjs_gen_hello_module gen/hello_module.c
+        -e -m -n examples/hello_module.js ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello_module.js)
     add_executable(hello_module
-        gen/hello_module.c
+        ${qjs_gen_hello_module}
     )
     add_qjs_libc_if_needed(hello_module)
     target_include_directories(hello_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
@@ -528,8 +662,10 @@ if(QJS_BUILD_EXAMPLES)
         target_link_options(point PRIVATE -undefined dynamic_lookup)
     endif()
 
+    qjs_bytecode_source(qjs_gen_test_fib gen/test_fib.c
+        -e -m -n examples/test_fib.js ${CMAKE_CURRENT_SOURCE_DIR}/examples/test_fib.js)
     add_executable(test_fib
-        gen/test_fib.c
+        ${qjs_gen_test_fib}
     )
     add_qjs_libc_if_needed(test_fib)
     target_include_directories(test_fib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
