Files
naci 5708deef54 lifter: allow resolved indirect jumps to participate in structured loop generalization (#98)
* docs: sync rewrite workflow guidance

* docs: drop machine-local pointers and fix stale README branch link

* lifter: allow resolved indirect jumps to participate in structured loop generalization

When a register-indirect jmp has already been resolved to a concrete target via solvePath (ConstantInt or solver), it's no longer speculative. If the target also points backward at a visited block, treat it as a loop back-edge for generalization purposes, the same way a direct or conditional jump would be treated.

Introduces currentPathSolveAllowsStructuredLoopGeneralizationForResolvedTarget() alongside the existing narrow predicate. canGeneralizeStructuredLoopHeader gains an opt-in targetResolvedConcretely parameter that routes through the widened check. getLiftedBackedgeBB uses the widened variant so back-edge reuse fires for resolved indirect jumps. resolveTargetBlock passes targetResolvedConcretely=true (its entry condition requires a concrete destination) and extends stackBypassGeneralizedLoopAddresses to include IndirectJump-context inserts.

Ret-path contexts remain excluded. Tests updated: the old runLoopGeneralizationIndirectJumpBlocked splits into runLoopGeneralizationIndirectJumpBlockedWhenUnresolved (unchanged semantics) and runLoopGeneralizationIndirectJumpAllowedWhenResolved (new). runPendingGeneralizedLoopBlockedByContext becomes runPendingGeneralizedLoopByContext with an expectReuse parameter; Ret still expects no reuse, IndirectJump with a resolved target now expects reuse.

---------

Co-authored-by: yusufcanislek <yusuf.canislek@meetdandy.com>
2026-04-19 05:36:45 +03:00

3.5 KiB

Building Mergen

This file owns build and toolchain setup. For pipeline details, use ARCHITECTURE.md. For rewrite/test workflows, use docs/REWRITE_BASELINE.md.

Preferred Development Flow

Mergen is developed and CI-tested primarily on Windows with Ninja, clang-cl, and LLVM 18.

Prerequisites

  • CMake on PATH
  • Ninja on PATH
  • Visual Studio C++ toolchain installed (the scripts rely on clang-cl finding MSVC headers/libs; they do not call VsDevCmd.bat)
  • LLVM_DIR pointing at LLVM 18 CMake config, or a local ../llvm18-install/lib/cmake/llvm
  • Rust/Cargo on PATH for the default iced backend

Default iced backend

cmd /c scripts\dev\configure_iced.cmd
cmd /c scripts\dev\build_iced.cmd

Outputs:

  • build_iced/lifter.exe
  • build_iced/rewrite_microtests.exe

Alternate Zydis-only backend

Use this only when you need the fallback lane or backend-specific debugging.

cmd /c scripts\dev\configure_zydis.cmd
cmd /c scripts\dev\build_zydis.cmd

Verify After Building

Primary checks:

The rewrite gate's sample-build lane is stricter than the core CMake build. CI requires a pinned clang-cl via CLANG_CL_EXE, CMAKE_C_COMPILER, or LLVM_DIR; for local python test.py quick / all runs, set CLANG_CL_EXE=C:\Program Files\LLVM\bin\clang-cl.exe when you want the same sample-build compiler resolution as CI instead of relying on local fallback discovery.

python test.py quick
python test.py all

Useful targeted checks:

python test.py baseline
python test.py micro --check-flags
python test.py negative
python test.py vmp

Use python test.py vmp for larger control-flow/semantics/inlining changes when you want a quick sanity pass over the local VMProtect targets without making it part of the default quick gate. Required 3.8.x targets must finish with blocks_completed > 0; the older VMP 3.6 sample remains best-effort only.

Useful Environment Variables

  • LLVM_DIR — points CMake at LLVMConfig.cmake
  • MERGEN_BUILD_JOBS — overrides build parallelism (default 4)
  • CMAKE_C_COMPILER / CMAKE_CXX_COMPILER — optional compiler override for the configure scripts
  • CLANG_CL_EXE — optional local override for the rewrite gate's sample-build path; set it to the pinned clang-cl when you want local python test.py quick / all runs to match CI compiler resolution

Example:

set CLANG_CL_EXE=C:\Program Files\LLVM\bin\clang-cl.exe
set MERGEN_BUILD_JOBS=8
cmd /c scripts\dev\build_iced.cmd
python test.py quick

Secondary Flows

Docker

The checked-in Dockerfile is primarily a build/export container: its default CMD copies the built lifter binary to /output/lifter.

docker build . -t mergen
mkdir -p output
docker run --rm -v "$PWD/output":/output mergen

If you want to run the built lifter inside the container instead of exporting it, override the command explicitly:

docker run --rm -v "$PWD":/work mergen /root/Mergen/build/lifter /work/target.exe 0x123456789

Manual CMake

Use direct CMake only when debugging cmkr/CMake behavior. Day-to-day development should go through scripts/dev/*.cmd.

cmake -G Ninja -S . -B build_iced -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR="..."
cmake --build build_iced --config Release --parallel 4

Build Configuration Boundaries

  • cmake.toml is the source of truth.
  • CMakeLists.txt is generated from cmake.toml; do not hand-edit it.
  • build*/ directories are generated outputs, not source-controlled configuration.