# --- T2-COPYRIGHT-BEGIN --- # t2/package/*/mesa/hotfix-x32.patch # Copyright (C) 2026 The T2 SDE Project # SPDX-License-Identifier: GPL-2.0 or patched project license # --- T2-COPYRIGHT-END --- On x32 the gallivm JIT emitted i386 objects and crashed on the first shader: "JITed object file architecture i386 is not compatible with target architecture i386:x64-32". llvm::sys::getProcessTriple() reduces LLVM_HOST_TRIPLE to the pointer-size variant based on sizeof(void *) alone, and Triple::get32BitArchVariant() maps x86_64 to plain x86 regardless of the environment, so x32 ends up as i386. MCJIT reaches that via EngineBuilder::selectTarget(), since the module has no target triple set outside Windows. --- mesa-26.1.5/src/gallium/auxiliary/gallivm/lp_bld_misc.h.vanilla 2026-07-15 22:03:19.000000000 +0200 +++ mesa-26.1.5/src/gallium/auxiliary/gallivm/lp_bld_misc.h 2026-07-26 12:38:40.458396035 +0200 @@ -104,6 +104,9 @@ lp_build_fill_mattrs(std::vector &MAttrs); +std::string +lp_build_jit_triple(void); + } #endif --- mesa-26.1.5/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp.vanilla 2026-07-26 12:40:22.401743006 +0200 +++ mesa-26.1.5/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp 2026-07-26 12:38:36.764375593 +0200 @@ -460,6 +460,29 @@ lp_build_dump_mattrs(std::vector MAttrs; --- mesa-26.1.5/src/gallium/auxiliary/gallivm/lp_bld_init_orc.cpp.vanilla 2026-07-26 12:40:22.401812599 +0200 +++ mesa-26.1.5/src/gallium/auxiliary/gallivm/lp_bld_init_orc.cpp 2026-07-26 12:38:47.355435507 +0200 @@ -391,7 +391,7 @@ llvm::orc::JITTargetMachineBuilder LPJit * llvm::sys::getProcessTriple() is bogus. It returns the host LLVM was * compiled on. Be careful when doing cross compilation */ - JITTargetMachineBuilder JTMB((Triple(sys::getProcessTriple()))); + JITTargetMachineBuilder JTMB((Triple(lp_build_jit_triple()))); #endif TargetOptions options; vk_cmd_queue: size command entries by offsetof(), not sizeof(base) vk_cmd_queue_type_sizes[] sizes every enqueued command as sizeof(struct vk_cmd_) + sizeof(struct vk_cmd_queue_entry_base) which silently assumes offsetof(struct vk_cmd_queue_entry, u) equals sizeof(struct vk_cmd_queue_entry_base). That holds where the two happen to agree, but not on x32: ABI sizeof(base) offsetof(entry, u) x86-64 24 24 i386 12 12 x32 12 16 x32 is the odd one out because it combines 4-byte pointers with the x86-64 alignment rules, so struct list_head plus the type enum end at 12 while the union - which holds uint64_t members such as VkDeviceSize and the non-dispatchable handles, 8-byte aligned - only starts at 16. Every command entry is therefore allocated four bytes too small and the union member is written past the end of the object. linear_alloc_child() rounds to 8, so those four bytes are the start of the next sub-allocation. vk_enqueue_cmd_pipeline_barrier2() lays that out as: cmd = linear_alloc_child(ctx, 16); /* needs 20 */ dep = linear_alloc_child(ctx, 36); /* placed at cmd + 16 */ cmd->u.pipeline_barrier2.pDependencyInfo = dep; /* writes at cmd + 16 */ memcpy(dep, pDependencyInfo, sizeof(*dep)); /* overwrites it again */ so reading the field back yields dep->sType, i.e. 1000314003, and the next store through it faults: mov %edx,0x10(%r14d) 0 0xf6ef17c0 in ?? () from /usr/libx32/libvulkan_lvp.so vkcube reaches this through vk_common_CmdPipelineBarrier(). Use offsetof(struct vk_cmd_queue_entry, u) for the commands that have a union member, and keep the bare base size for the parameterless ones. offsetof() is available via util/list.h, which the generated header already includes. Signed-off-by: René Rebe --- mesa-26.1.5/src/vulkan/util/vk_cmd_queue_gen.py.vanilla +++ mesa-26.1.5/src/vulkan/util/vk_cmd_queue_gen.py @@ -249,9 +249,11 @@ size_t vk_cmd_queue_type_sizes[] = { #ifdef ${c.guard} % endif % if len(c.params) > 1: - sizeof(struct ${to_struct_name(c.name)}) + -% endif + offsetof(struct vk_cmd_queue_entry, u) + + sizeof(struct ${to_struct_name(c.name)}), +% else: sizeof(struct vk_cmd_queue_entry_base), +% endif % if c.guard is not None: #endif // ${c.guard} % endif