Files
Mergen/ARCHITECTURE.md
2026-04-05 23:33:30 +03:00

4.7 KiB

Architecture Reference

Key Constants

Constant Value Defined in
STACKP_VALUE 0x14FEA0 lifter/core/Includes.h
Stack reserve min 0x1000 lifter/memory/MemoryPolicySetup.hpp (configureDefaultMemoryPolicy)
Stack reserve max 0x100000 lifter/memory/MemoryPolicySetup.hpp (configureDefaultMemoryPolicy)

Pipeline Order

# Function File Purpose
1 createRuntimeImageContext lifter/core/RuntimeImageContext.hpp Validates PE headers, builds RuntimeImageContext
2 createConfiguredLifterForRuntime lifter/core/LifterStages.hpp Calls loadFile, parses PE exports, auto-outlines export addresses
3 configureDefaultMemoryPolicy lifter/memory/MemoryPolicySetup.hpp Sets memoryPolicy (SYMBOLIC default, CONCRETE for PE sections + stack), clamps stackReserve to [0x1000, 0x100000]
4 prepareRuntimePagedMemory lifter/core/LifterPipelineStages.hpp Marks pageMap intervals for mapped memory regions
5 runSignatureStage lifter/core/LifterPipelineStages.hpp Signature-based analysis
6 Lift loop lifter/core/LiftDriver.hpp Main lifting of instructions to LLVM IR
7 run_opts lifter/core/MergenPB.hpp Fixpoint optimization (see below)

run_opts Fixpoint Loop

loop {
    O1 pipeline
    GEPLoadPass
    ReplaceTruncWithLoadPass
    PromotePseudoStackPass
    PromotePseudoMemory
} until instruction count stabilizes (delta == 0)

Final O2 pipeline (runs once after fixpoint)

Termination: the loop compares instruction count before and after each iteration. When the count stops changing, the fixpoint is reached.

Custom Pass Summary

Pass Filters on Produces Description
GEPLoadPass memory-base GEPs where: getPointerOperand() == mem, !isSymbolic, address_to_mapped_address != 0, isIntegerTy(), readMemory succeeds Constant integer values folded from PE image Folds constant loads from the PE image through memory-base GEPs
ReplaceTruncWithLoadPass trunc(load wide, ptr) patterns load narrow, ptr Rewrites wide-load-then-truncate into narrow load; valid on little-endian
PromotePseudoStackPass memory-base GEPs in [STACKP_VALUE - reserve, STACKP_VALUE + reserve] via isStackAddress() stackmemory alloca GEPs Replaces pseudo-stack memory accesses with real stack alloca operations
PromotePseudoMemory Remaining memory-base GEPs (not handled by above passes) inttoptr Converts leftover pseudo-memory GEPs to raw pointer operations

Pass order matters: GEPLoadPass must run before PromotePseudoMemory, otherwise concrete PE loads get converted to inttoptr and are lost.

InlinePolicy

  • CRTP framework: default policy inlines everything.
  • Outline set: addAddress(va) registers a VA for outlining (i.e., not inlined).
  • Check site: Semantics_ControlFlow.ipp:202 — when a call target is constant-resolved, the inline policy is consulted.
  • CLI: --outline <addrs> accepts comma-separated hex addresses, parsed in Utils.cpp, stored in ParseResult::outlineAddresses.
  • PE export auto-outline: export addresses are automatically added to the outline set in createConfiguredLifterForRuntime. Forwarded exports are filtered out by checking if the RVA falls within the export directory range.

Memory Subsystem

FileReader

CRTP base with concrete implementations x86FileReader and x86_64FileReader.

Method Returns Failure value
RvaToFileOffset file offset 0
readMemory bool false
address_to_mapped_address mapped address 0

MemoryPolicy

Region Policy
Default SYMBOLIC
PE sections CONCRETE
Stack CONCRETE

Set by configureDefaultMemoryPolicy in lifter/memory/MemoryPolicySetup.hpp.

pageMap

std::map<uint64_t, uint64_t> — interval map of paged memory regions.

  • markMemPaged(start, end) — inserts an interval.
  • isMemPaged — uses upper_bound then decrements iterator to check containment.

stackReserve

Set by configureDefaultMemoryPolicy, clamped to [0x1000, 0x100000]. Consumed by:

  • PromotePseudoStackPass — defines the stack address window around STACKP_VALUE
  • prepareRuntimePagedMemory — marks the stack region in pageMap

PE Parsing

  • Header types come from the linuxpe library.
  • RvaToFileOffset returns 0 on failure — callers must check before using the offset.
  • Export directory is parsed in createConfiguredLifterForRuntime; forwarded exports are detected by checking if the export RVA falls within the export directory VA range.
  • RuntimeImageContext is validated in createRuntimeImageContext (step 1 of the pipeline).