Files
2026-05-12 04:22:34 +02:00

1494 lines
60 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding llvm-nanobind | Interactive Learning Guide</title>
<style>
:root {
--bg: #1a1a2e;
--bg-light: #16213e;
--bg-card: #0f3460;
--accent: #e94560;
--accent-light: #ff6b6b;
--text: #eaeaea;
--text-dim: #a0a0a0;
--success: #4ecca3;
--warning: #ffc107;
--code-bg: #0d1117;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
padding: 0;
}
/* Navigation */
nav {
position: fixed;
top: 0;
left: 0;
width: 280px;
height: 100vh;
background: var(--bg-light);
padding: 20px;
overflow-y: auto;
border-right: 1px solid var(--bg-card);
z-index: 100;
}
nav h2 {
color: var(--accent);
font-size: 1.1rem;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid var(--bg-card);
}
nav ul {
list-style: none;
}
nav li {
margin: 8px 0;
}
nav a {
color: var(--text-dim);
text-decoration: none;
font-size: 0.9rem;
transition: color 0.2s;
display: block;
padding: 5px 10px;
border-radius: 4px;
}
nav a:hover, nav a.active {
color: var(--accent);
background: rgba(233, 69, 96, 0.1);
}
nav .section-title {
color: var(--text);
font-weight: 600;
margin-top: 20px;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Progress bar */
.progress-container {
margin: 20px 0;
padding: 15px;
background: var(--bg-card);
border-radius: 8px;
}
.progress-bar {
height: 8px;
background: var(--bg);
border-radius: 4px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--accent), var(--accent-light));
width: 0%;
transition: width 0.5s ease;
}
.progress-text {
font-size: 0.8rem;
color: var(--text-dim);
margin-top: 8px;
}
/* Main content */
main {
margin-left: 280px;
padding: 40px 60px;
max-width: 1000px;
}
h1 {
font-size: 2.5rem;
color: var(--text);
margin-bottom: 10px;
}
.subtitle {
color: var(--text-dim);
font-size: 1.2rem;
margin-bottom: 40px;
}
h2 {
font-size: 1.8rem;
color: var(--accent);
margin: 50px 0 20px;
padding-top: 20px;
border-top: 1px solid var(--bg-card);
}
h3 {
font-size: 1.3rem;
color: var(--text);
margin: 30px 0 15px;
}
p {
margin: 15px 0;
color: var(--text);
}
/* Code blocks */
pre {
background: var(--code-bg);
padding: 20px;
border-radius: 8px;
overflow-x: auto;
margin: 20px 0;
border: 1px solid var(--bg-card);
}
code {
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.9rem;
}
pre code {
color: #e6e6e6;
}
.keyword { color: #ff79c6; }
.string { color: #f1fa8c; }
.comment { color: #6272a4; }
.function { color: #50fa7b; }
.number { color: #bd93f9; }
.type { color: #8be9fd; }
/* Cards */
.card {
background: var(--bg-card);
border-radius: 12px;
padding: 25px;
margin: 25px 0;
border-left: 4px solid var(--accent);
}
.card.success {
border-left-color: var(--success);
}
.card.warning {
border-left-color: var(--warning);
}
.card h4 {
color: var(--accent);
margin-bottom: 10px;
font-size: 1.1rem;
}
.card.success h4 { color: var(--success); }
.card.warning h4 { color: var(--warning); }
/* Interactive Quiz */
.quiz {
background: var(--bg-light);
border-radius: 12px;
padding: 30px;
margin: 30px 0;
}
.quiz h4 {
color: var(--accent);
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.quiz-question {
font-size: 1.1rem;
margin-bottom: 20px;
}
.quiz-options {
display: flex;
flex-direction: column;
gap: 10px;
}
.quiz-option {
background: var(--bg-card);
border: 2px solid transparent;
border-radius: 8px;
padding: 15px 20px;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 12px;
}
.quiz-option:hover {
border-color: var(--accent);
transform: translateX(5px);
}
.quiz-option.selected {
border-color: var(--accent);
background: rgba(233, 69, 96, 0.2);
}
.quiz-option.correct {
border-color: var(--success);
background: rgba(78, 204, 163, 0.2);
}
.quiz-option.incorrect {
border-color: #e74c3c;
background: rgba(231, 76, 60, 0.2);
}
.option-letter {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--bg);
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 0.85rem;
}
.quiz-feedback {
margin-top: 20px;
padding: 20px;
border-radius: 8px;
display: none;
}
.quiz-feedback.show {
display: block;
}
.quiz-feedback.correct {
background: rgba(78, 204, 163, 0.15);
border: 1px solid var(--success);
}
.quiz-feedback.incorrect {
background: rgba(231, 76, 60, 0.15);
border: 1px solid #e74c3c;
}
/* Expandable sections */
.expandable {
background: var(--bg-light);
border-radius: 8px;
margin: 15px 0;
overflow: hidden;
}
.expandable-header {
padding: 15px 20px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: background 0.2s;
}
.expandable-header:hover {
background: var(--bg-card);
}
.expandable-header h4 {
margin: 0;
color: var(--text);
font-size: 1rem;
}
.expandable-icon {
transition: transform 0.3s;
color: var(--accent);
}
.expandable.open .expandable-icon {
transform: rotate(180deg);
}
.expandable-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.expandable.open .expandable-content {
max-height: 2000px;
}
.expandable-inner {
padding: 0 20px 20px;
}
/* Diagram container */
.diagram {
background: var(--code-bg);
border-radius: 12px;
padding: 30px;
margin: 25px 0;
overflow-x: auto;
font-family: 'Fira Code', monospace;
font-size: 0.85rem;
line-height: 1.4;
white-space: pre;
}
.diagram .highlight {
color: var(--accent);
}
.diagram .dim {
color: var(--text-dim);
}
.diagram .success {
color: var(--success);
}
/* Tabs */
.tabs {
margin: 25px 0;
}
.tab-buttons {
display: flex;
gap: 5px;
border-bottom: 2px solid var(--bg-card);
padding-bottom: 0;
}
.tab-button {
background: none;
border: none;
color: var(--text-dim);
padding: 12px 24px;
cursor: pointer;
font-size: 0.95rem;
transition: all 0.2s;
position: relative;
bottom: -2px;
border-bottom: 2px solid transparent;
}
.tab-button:hover {
color: var(--text);
}
.tab-button.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.tab-content {
display: none;
padding: 25px 0;
}
.tab-content.active {
display: block;
}
/* Table */
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid var(--bg-card);
}
th {
background: var(--bg-card);
color: var(--accent);
font-weight: 600;
}
tr:hover {
background: rgba(233, 69, 96, 0.05);
}
/* Checklist */
.checklist {
list-style: none;
margin: 20px 0;
}
.checklist li {
padding: 10px 0;
display: flex;
align-items: flex-start;
gap: 12px;
}
.checklist input[type="checkbox"] {
width: 20px;
height: 20px;
accent-color: var(--accent);
margin-top: 3px;
}
.checklist label {
cursor: pointer;
}
.checklist .checked {
color: var(--text-dim);
text-decoration: line-through;
}
/* Interactive diagram - SVG based */
.interactive-diagram {
background: var(--bg-light);
border-radius: 12px;
padding: 20px;
margin: 25px 0;
}
.interactive-diagram svg {
width: 100%;
max-width: 700px;
display: block;
margin: 0 auto;
}
.interactive-diagram .node {
cursor: pointer;
transition: all 0.2s;
}
.interactive-diagram .node:hover rect {
fill: var(--accent);
}
.interactive-diagram .node:hover text {
fill: white;
}
.diagram-tooltip {
position: absolute;
background: var(--bg-card);
color: var(--text);
padding: 15px;
border-radius: 8px;
font-size: 0.9rem;
max-width: 300px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
z-index: 1000;
}
.diagram-tooltip.show {
opacity: 1;
}
/* Score display */
.score-display {
position: fixed;
top: 20px;
right: 20px;
background: var(--bg-card);
padding: 15px 25px;
border-radius: 12px;
box-shadow: 0 5px 20px rgba(0,0,0,0.3);
z-index: 100;
}
.score-display .label {
font-size: 0.8rem;
color: var(--text-dim);
text-transform: uppercase;
}
.score-display .score {
font-size: 1.5rem;
font-weight: bold;
color: var(--accent);
}
/* Mobile responsive */
@media (max-width: 900px) {
nav {
width: 100%;
height: auto;
position: relative;
}
main {
margin-left: 0;
padding: 20px;
}
.score-display {
position: static;
margin-bottom: 20px;
}
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-in {
animation: fadeIn 0.4s ease forwards;
}
/* Print styles */
@media print {
nav, .score-display { display: none; }
main { margin-left: 0; }
}
</style>
</head>
<body>
<nav>
<h2>Learning Guide</h2>
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill" id="progress-fill"></div>
</div>
<div class="progress-text"><span id="progress-text">0%</span> complete</div>
</div>
<ul>
<li class="section-title">Foundations</li>
<li><a href="#intro">Introduction</a></li>
<li><a href="#problem">The Problem</a></li>
<li><a href="#llvm-ir">LLVM IR Basics</a></li>
<li class="section-title">The Bindings</li>
<li><a href="#architecture">Architecture</a></li>
<li><a href="#api-design">API Design</a></li>
<li><a href="#quirks">Quirks & Gotchas</a></li>
<li class="section-title">Transformations</li>
<li><a href="#pattern">The Pattern</a></li>
<li><a href="#mba">MBA Substitution</a></li>
<li><a href="#cff">Control Flow Flattening</a></li>
<li class="section-title">Critique</li>
<li><a href="#evaluation">Critical Evaluation</a></li>
<li><a href="#improvements">Improvements</a></li>
<li><a href="#final-quiz">Final Assessment</a></li>
</ul>
</nav>
<div class="score-display">
<div class="label">Quiz Score</div>
<div class="score"><span id="score">0</span>/<span id="total">0</span></div>
</div>
<main>
<h1>Understanding llvm-nanobind</h1>
<p class="subtitle">An interactive guide to the transformation API</p>
<!-- Introduction -->
<section id="intro">
<h2>Why This Guide Exists</h2>
<div class="card">
<h4>The Core Insight</h4>
<p>"Human review as the bottleneck for AI work" suggests an education problem. If you understand deeply, you can review quickly and contribute better ideas.</p>
</div>
<p>This guide aims to take you from "I can read the diff" to "I can critique the design and suggest improvements." It's structured as a journey, not a reference.</p>
<h3>What You'll Learn</h3>
<ul class="checklist">
<li><input type="checkbox" id="c1"><label for="c1">What LLVM IR is and how it's structured</label></li>
<li><input type="checkbox" id="c2"><label for="c2">How the Python bindings work</label></li>
<li><input type="checkbox" id="c3"><label for="c3">The transformation pattern all passes follow</label></li>
<li><input type="checkbox" id="c4"><label for="c4">MBA and CFF obfuscation techniques</label></li>
<li><input type="checkbox" id="c5"><label for="c5">How to critically evaluate API design</label></li>
</ul>
</section>
<!-- The Problem -->
<section id="problem">
<h2>The Problem We're Solving</h2>
<p><strong>LLVM</strong> is a compiler infrastructure. It represents programs in a language-agnostic form called IR (Intermediate Representation):</p>
<div class="diagram">
<span class="dim">Source Code</span> <span class="dim">LLVM IR</span> <span class="dim">Machine Code</span>
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ C/C++ │ │ │ │ x86 │
│ Rust │ ──────▶ │ IR │ ──────▶ │ ARM │
│ Swift │ │ │ │ WASM │
└─────────┘ └─────────┘ └─────────┘
<span class="highlight">Front-end</span> <span class="highlight">Middle-end</span> <span class="highlight">Back-end</span></div>
<div class="card success">
<h4>The Key Insight</h4>
<p>If you can <em>modify</em> the IR, you can transform programs: optimize them, obfuscate them, instrument them, or translate them to different targets.</p>
</div>
<h3>The Traditional Pain</h3>
<p>LLVM's API is C++. To write transformations, you need:</p>
<ul>
<li>C++ expertise and build system complexity</li>
<li>Long compile times</li>
<li>Manual memory management</li>
</ul>
<p><strong>The solution:</strong> Python bindings let you write transformations in a high-level language. Faster iteration, easier experimentation.</p>
<div class="quiz" data-correct="2">
<h4>🧠 Quick Check</h4>
<p class="quiz-question">Why might someone <em>not</em> want to use Python for LLVM work?</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span>Python doesn't support compiler concepts</span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span>Python is ~100x slower; some APIs aren't exposed</span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span>LLVM doesn't work on systems with Python</span>
</div>
</div>
<div class="quiz-feedback">
<strong>Right!</strong> Performance and completeness are the trade-offs. Python is great for prototyping, research, and one-off tools, but production compiler passes typically stay in C++.
</div>
</div>
</section>
<!-- LLVM IR -->
<section id="llvm-ir">
<h2>LLVM IR Basics</h2>
<p>LLVM IR is like a typed, structured assembly language. Understanding its structure is essential.</p>
<div class="tabs">
<div class="tab-buttons">
<button class="tab-button active" data-tab="structure">Structure</button>
<button class="tab-button" data-tab="ssa">SSA Form</button>
<button class="tab-button" data-tab="example">Example</button>
</div>
<div class="tab-content active" data-tab="structure">
<div class="diagram">
<span class="highlight">MODULE</span>
├── Target Triple, Data Layout
├── <span class="success">GLOBALS</span> (@global_var, @string_constant)
├── <span class="success">DECLARATIONS</span> (declare @printf, @malloc)
└── <span class="success">DEFINITIONS</span>
└── define @main() {
├── <span class="highlight">BASIC BLOCK</span>: entry
│ ├── %x = alloca i32 <span class="dim">← instruction</span>
│ ├── store i32 42, ptr %x <span class="dim">← instruction</span>
│ └── br label %loop <span class="dim">← TERMINATOR</span>
└── <span class="highlight">BASIC BLOCK</span>: loop
├── %i = phi i32 [...] <span class="dim">← PHI node</span>
├── ...
└── ret i32 0 <span class="dim">← TERMINATOR</span>
}</div>
<p><strong>Key invariant:</strong> Every basic block ends with exactly ONE terminator instruction.</p>
</div>
<div class="tab-content" data-tab="ssa">
<p><strong>SSA = Static Single Assignment.</strong> Every value is assigned exactly once.</p>
<pre><code><span class="comment">; NOT valid (same variable twice):</span>
%x = <span class="keyword">add</span> <span class="type">i32</span> <span class="number">1</span>, <span class="number">2</span>
%x = <span class="keyword">add</span> <span class="type">i32</span> %x, <span class="number">3</span> <span class="comment">; ERROR!</span>
<span class="comment">; Valid (different names):</span>
%x = <span class="keyword">add</span> <span class="type">i32</span> <span class="number">1</span>, <span class="number">2</span>
%y = <span class="keyword">add</span> <span class="type">i32</span> %x, <span class="number">3</span> <span class="comment">; OK</span></code></pre>
<div class="card warning">
<h4>Why SSA Matters for You</h4>
<p>You can't "change" a value. You create a <em>new</em> value and <em>replace uses</em> of the old one. This is why <code>replace_all_uses_with()</code> is fundamental.</p>
</div>
</div>
<div class="tab-content" data-tab="example">
<pre><code><span class="keyword">define</span> <span class="type">i32</span> <span class="function">@factorial</span>(<span class="type">i32</span> %n) {
<span class="string">entry:</span>
%cmp = <span class="keyword">icmp</span> sle <span class="type">i32</span> %n, <span class="number">1</span>
<span class="keyword">br</span> <span class="type">i1</span> %cmp, <span class="keyword">label</span> %base, <span class="keyword">label</span> %recurse
<span class="string">base:</span>
<span class="keyword">ret</span> <span class="type">i32</span> <span class="number">1</span>
<span class="string">recurse:</span>
%sub = <span class="keyword">sub</span> <span class="type">i32</span> %n, <span class="number">1</span>
%call = <span class="keyword">call</span> <span class="type">i32</span> <span class="function">@factorial</span>(<span class="type">i32</span> %sub)
%mul = <span class="keyword">mul</span> <span class="type">i32</span> %n, %call
<span class="keyword">ret</span> <span class="type">i32</span> %mul
}</code></pre>
<p>Three basic blocks: <code>entry</code>, <code>base</code>, <code>recurse</code>. Each ends with a terminator (<code>br</code> or <code>ret</code>).</p>
</div>
</div>
<div class="quiz" data-correct="1">
<h4>🧠 Quick Check</h4>
<p class="quiz-question">What is a PHI node used for?</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span>Performing floating-point arithmetic</span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span>Selecting a value based on which predecessor block we came from</span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span>Declaring function parameters</span>
</div>
</div>
<div class="quiz-feedback">
<strong>Correct!</strong> PHI nodes handle control flow merges in SSA form. <code>%result = phi i32 [ %x, %block1 ], [ %y, %block2 ]</code> means: "use %x if we came from block1, %y if from block2."
</div>
</div>
</section>
<!-- Architecture -->
<section id="architecture">
<h2>Architecture</h2>
<p>Understanding the layers helps you know what's possible and where limitations come from.</p>
<div class="interactive-diagram">
<svg viewBox="0 0 600 400">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:#e94560;stop-opacity:1" />
<stop offset="100%" style="stop-color:#ff6b6b;stop-opacity:1" />
</linearGradient>
</defs>
<!-- Layer 1: Python Code -->
<g class="node" data-tooltip="Your transformation code. Uses with statements, iterates over functions/blocks, builds new IR.">
<rect x="50" y="20" width="500" height="60" rx="8" fill="#0f3460"/>
<text x="300" y="55" text-anchor="middle" fill="#eaeaea" font-size="14">Your Python Code</text>
</g>
<!-- Layer 2: llvm-nanobind -->
<g class="node" data-tooltip="Python classes (Module, Function, Builder), memory safety via validity tokens, context managers for lifetime.">
<rect x="50" y="100" width="500" height="60" rx="8" fill="#16213e"/>
<text x="300" y="135" text-anchor="middle" fill="#eaeaea" font-size="14">llvm-nanobind (This Project)</text>
</g>
<!-- Layer 3: nanobind -->
<g class="node" data-tooltip="C++/Python bridge. Handles type conversions, exception translation, reference counting.">
<rect x="50" y="180" width="500" height="60" rx="8" fill="#0f3460"/>
<text x="300" y="215" text-anchor="middle" fill="#eaeaea" font-size="14">nanobind (C++/Python Bridge)</text>
</g>
<!-- Layer 4: LLVM C API -->
<g class="node" data-tooltip="Stable C functions: LLVMBuildAdd, LLVMParseIR, etc. Some functions NOT YET BOUND (like LLVMReplaceAllUsesWith).">
<rect x="50" y="260" width="500" height="60" rx="8" fill="#16213e"/>
<text x="300" y="295" text-anchor="middle" fill="#eaeaea" font-size="14">LLVM C API</text>
<text x="480" y="295" text-anchor="middle" fill="#e94560" font-size="10">gaps here!</text>
</g>
<!-- Layer 5: LLVM Core -->
<g class="node" data-tooltip="The actual compiler infrastructure. ~3.5 million lines of C++. Optimizations, code generation, analysis.">
<rect x="50" y="340" width="500" height="50" rx="8" fill="url(#grad1)"/>
<text x="300" y="370" text-anchor="middle" fill="white" font-size="14" font-weight="bold">LLVM C++ Core</text>
</g>
<!-- Arrows -->
<path d="M300 80 L300 100" stroke="#4ecca3" stroke-width="2" marker-end="url(#arrow)"/>
<path d="M300 160 L300 180" stroke="#4ecca3" stroke-width="2"/>
<path d="M300 240 L300 260" stroke="#4ecca3" stroke-width="2"/>
<path d="M300 320 L300 340" stroke="#4ecca3" stroke-width="2"/>
</svg>
</div>
<div class="diagram-tooltip" id="diagram-tooltip"></div>
<div class="card">
<h4>Key Insight</h4>
<p>When you find a missing feature, ask: "Does the LLVM C API expose this?" If yes, we can add it. If no, we'd need a C wrapper first.</p>
</div>
</section>
<!-- API Design -->
<section id="api-design">
<h2>API Design</h2>
<p>The bindings try to be Pythonic while staying close to LLVM's model.</p>
<h3>The Good Parts</h3>
<pre><code><span class="comment"># Context managers prevent leaks</span>
<span class="keyword">with</span> llvm.create_context() <span class="keyword">as</span> ctx:
<span class="keyword">with</span> ctx.parse_ir(ir_text) <span class="keyword">as</span> mod:
<span class="comment"># Module auto-disposed on exit</span>
<span class="comment"># Pythonic iteration</span>
<span class="keyword">for</span> func <span class="keyword">in</span> mod.functions:
<span class="keyword">for</span> bb <span class="keyword">in</span> func.basic_blocks:
<span class="keyword">for</span> inst <span class="keyword">in</span> bb.instructions:
...
<span class="comment"># Clean builder API</span>
builder.add(a, b, <span class="string">"sum"</span>) <span class="comment"># not CreateAdd</span>
builder.br(target_bb) <span class="comment"># not CreateBr</span></code></pre>
<h3>The Quirks</h3>
<table>
<tr>
<th>What You Try</th>
<th>What Happens</th>
<th>Correct Form</th>
</tr>
<tr>
<td><code>ctx.types.ptr</code></td>
<td>Gets bound method, not type!</td>
<td><code>ctx.types.ptr()</code></td>
</tr>
<tr>
<td><code>inst.parent</code></td>
<td>AttributeError</td>
<td><code>inst.block</code></td>
</tr>
<tr>
<td><code>for op in inst.operands:</code></td>
<td>AttributeError</td>
<td><code>for i in range(inst.num_operands):</code></td>
</tr>
<tr>
<td><code>inst.delete_instruction()</code></td>
<td>LLVM crash!</td>
<td><code>inst.remove_from_parent()</code> first</td>
</tr>
</table>
</section>
<!-- Quirks -->
<section id="quirks">
<h2>Quirks & Gotchas</h2>
<div class="expandable">
<div class="expandable-header">
<h4>Two-Step Instruction Deletion</h4>
<span class="expandable-icon"></span>
</div>
<div class="expandable-content">
<div class="expandable-inner">
<pre><code><span class="comment"># WRONG - will crash!</span>
inst.delete_instruction()
<span class="comment"># CORRECT - unlink first, then delete</span>
inst.remove_from_parent()
inst.delete_instruction()
<span class="comment"># The plan proposes:</span>
inst.erase_from_parent() <span class="comment"># Does both atomically</span></code></pre>
</div>
</div>
</div>
<div class="expandable">
<div class="expandable-header">
<h4>Manual Replace All Uses With</h4>
<span class="expandable-icon"></span>
</div>
<div class="expandable-content">
<div class="expandable-inner">
<pre><code><span class="comment"># The C API has LLVMReplaceAllUsesWith</span>
<span class="comment"># But it's NOT BOUND! Must implement manually:</span>
<span class="keyword">def</span> <span class="function">replace_all_uses_with</span>(old_val, new_val):
uses = <span class="keyword">list</span>(old_val.uses) <span class="comment"># snapshot!</span>
<span class="keyword">for</span> use <span class="keyword">in</span> uses:
user = use.user
<span class="keyword">for</span> i <span class="keyword">in</span> <span class="keyword">range</span>(user.num_operands):
<span class="keyword">if</span> user.get_operand(i) == old_val:
user.set_operand(i, new_val)</code></pre>
<p>This is error-prone and slower than the native version.</p>
</div>
</div>
</div>
<div class="expandable">
<div class="expandable-header">
<h4>UTF-8 String Encoding Bug</h4>
<span class="expandable-icon"></span>
</div>
<div class="expandable-content">
<div class="expandable-inner">
<pre><code><span class="comment"># You want bytes [0xFF, 0x80, 0x42]</span>
encrypted = <span class="keyword">bytes</span>([<span class="number">0xFF</span>, <span class="number">0x80</span>, <span class="number">0x42</span>]).decode(<span class="string">'latin-1'</span>)
const = ctx.const_string(encrypted)
<span class="comment"># Expected: [3 x i8]</span>
<span class="comment"># Actual: [5 x i8] (UTF-8 encoded!)</span></code></pre>
<p><strong>This blocks string encryption entirely.</strong> It's a Priority 1 issue.</p>
</div>
</div>
</div>
<div class="quiz" data-correct="2">
<h4>🧠 Quick Check</h4>
<p class="quiz-question">To iterate over all operands of an instruction, you use:</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span><code>for op in inst.operands:</code></span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span><code>for op in inst:</code></span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span><code>for i in range(inst.num_operands): op = inst.get_operand(i)</code></span>
</div>
</div>
<div class="quiz-feedback">
<strong>Yes!</strong> There's no <code>.operands</code> iterator. This is listed as a missing convenience in the improvement plan.
</div>
</div>
</section>
<!-- The Pattern -->
<section id="pattern">
<h2>The Transformation Pattern</h2>
<p>Almost every transformation follows this structure:</p>
<div class="diagram">
┌──────────────────────────────────────────────────────────────┐
<span class="highlight">1. TRAVERSE</span>
<span class="dim">for bb in func.basic_blocks:</span>
<span class="dim">for inst in bb.instructions:</span>
└────────────────────────────┬─────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
<span class="highlight">2. IDENTIFY</span>
<span class="dim">if inst.opcode == llvm.Opcode.Sub:</span>
<span class="dim">to_transform.append(inst)</span>
└────────────────────────────┬─────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
<span class="highlight">3. BUILD</span>
<span class="dim">builder.position_before(inst)</span>
<span class="dim">new_val = builder.add(xor_result, mul_result)</span>
└────────────────────────────┬─────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
<span class="highlight">4. REPLACE</span>
<span class="dim">replace_all_uses_with(inst, new_val)</span>
└────────────────────────────┬─────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
<span class="highlight">5. CLEAN UP</span>
<span class="dim">inst.remove_from_parent()</span>
<span class="dim">inst.delete_instruction()</span>
<span class="dim">assert mod.verify()</span>
└──────────────────────────────────────────────────────────────┘</div>
</section>
<!-- MBA -->
<section id="mba">
<h2>MBA Substitution</h2>
<p><strong>Mixed Boolean Arithmetic</strong> uses the fact that arithmetic and bitwise operations are related.</p>
<div class="card">
<h4>The Identity</h4>
<p style="font-size: 1.3rem; font-family: monospace; text-align: center; padding: 15px;">
X - Y = (X ⊕ -Y) + 2×(X ∧ -Y)
</p>
</div>
<div class="expandable open">
<div class="expandable-header">
<h4>Proof by Example</h4>
<span class="expandable-icon"></span>
</div>
<div class="expandable-content">
<div class="expandable-inner">
<pre><code>X = 7, Y = 3
Expected: 7 - 3 = <span class="number">4</span>
<span class="comment">Step 1: Compute -Y (two's complement)</span>
-Y = -3 = <span class="number">1111_1101</span> (8-bit)
<span class="comment">Step 2: X XOR -Y</span>
0000_0111 (7)
⊕ 1111_1101 (-3)
─────────
1111_1010 = <span class="number">-6</span> (signed)
<span class="comment">Step 3: X AND -Y</span>
0000_0111 (7)
∧ 1111_1101 (-3)
─────────
0000_0101 = <span class="number">5</span>
<span class="comment">Step 4: 2 × (X AND -Y)</span>
2 × 5 = <span class="number">10</span>
<span class="comment">Step 5: Add them</span>
-6 + 10 = <span class="success">4</span></code></pre>
</div>
</div>
</div>
<h3>Why It Works as Obfuscation</h3>
<p>Decompilers pattern-match <code>sub</code> to <code>-</code>. But they don't recognize <code>(x ^ neg_y) + 2*(x & neg_y)</code> as subtraction. It looks like arbitrary bitwise soup.</p>
<div class="quiz" data-correct="1">
<h4>🧠 Quick Check</h4>
<p class="quiz-question">The MBA pass randomly chooses between multiple equivalent XOR formulas. Why?</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span>To test which one is fastest</span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span>Polymorphism defeats pattern matching</span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span>Some formulas only work with certain inputs</span>
</div>
</div>
<div class="quiz-feedback">
<strong>Exactly!</strong> If all XORs became the same pattern, a reverse engineer could write a pattern matcher to undo them. Variety makes automated deobfuscation harder.
</div>
</div>
</section>
<!-- CFF -->
<section id="cff">
<h2>Control Flow Flattening</h2>
<p>CFF hides the program's control flow structure by introducing a state-machine dispatcher.</p>
<div class="tabs">
<div class="tab-buttons">
<button class="tab-button active" data-tab="before">Before</button>
<button class="tab-button" data-tab="after">After</button>
<button class="tab-button" data-tab="how">How It Works</button>
</div>
<div class="tab-content active" data-tab="before">
<div class="diagram">
┌─────────┐
│ entry │
└────┬────┘
<span class="dim">if (cond)</span>
┌─────┴─────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ block_A │ │ block_B │
└────┬─────┘ └────┬─────┘
└──────┬─────┘
┌──────────┐
│ exit │
└──────────┘
<span class="dim">Clear if/else structure visible to analysis</span></div>
</div>
<div class="tab-content" data-tab="after">
<div class="diagram">
┌─────────┐
│ entry │
<span class="highlight">state = A</span>
└────┬────┘
┌─────────────┐◄──────────────┐
<span class="highlight">dispatcher</span> │ │
│switch(state)│ │
└──────┬──────┘ │
┌───────────┼───────────┐ │
▼ ▼ ▼ │
┌──────────┐ ┌──────────┐ ┌───────┐ │
│ block_A │ │ block_B │ │ exit │ │
<span class="highlight">state = ?</span>│ │<span class="highlight">state = ?</span>│ │ ret │ │
└────┬─────┘ └────┬─────┘ └───────┘ │
└────────────┴──────────────────────┘
<span class="dim">All paths go through dispatcher</span></div>
</div>
<div class="tab-content" data-tab="how">
<ol style="margin-left: 20px;">
<li><strong>Demote PHI nodes</strong> to stack variables (PHIs encode predecessor info, lost after flattening)</li>
<li><strong>Create state variable</strong> in entry block</li>
<li><strong>Assign random state values</strong> to each block</li>
<li><strong>Create dispatcher</strong> that branches based on state</li>
<li><strong>Rewrite terminators</strong> to update state + jump to dispatcher</li>
</ol>
<div class="card warning">
<h4>PHI Demotion is Critical</h4>
<p>PHI nodes say "if we came from block1, use %x". After flattening, we always come from the dispatcher! So we convert PHIs to explicit memory (alloca → store → load).</p>
</div>
</div>
</div>
</section>
<!-- Evaluation -->
<section id="evaluation">
<h2>Critical Evaluation Framework</h2>
<p>Use these lenses to critique the work:</p>
<div class="card">
<h4>Lens 1: Consistency</h4>
<p>Can you predict the name of something you haven't used? If not, there's an inconsistency.</p>
<table>
<tr><th>Expected</th><th>Actual</th><th>Consistent?</th></tr>
<tr><td><code>.parent</code></td><td><code>.block</code></td><td></td></tr>
<tr><td><code>.operands</code></td><td>(doesn't exist)</td><td></td></tr>
<tr><td><code>.ptr</code></td><td><code>.ptr()</code></td><td></td></tr>
</table>
</div>
<div class="card success">
<h4>Lens 2: Pit of Success</h4>
<p>Does the easy path lead to correct code? Or does it lead to crashes?</p>
<p>Example: <code>inst.delete_instruction()</code> looks natural but crashes. The API should make the safe path obvious.</p>
</div>
<div class="card warning">
<h4>Lens 3: Completeness</h4>
<p>Can you do everything you need? The porting guide rates: "7/10 for code generation, 5/10 for transforms."</p>
<p>Transforms need RAUW, block splitting, instruction movement—mostly missing.</p>
</div>
</section>
<!-- Improvements -->
<section id="improvements">
<h2>Planned Improvements</h2>
<div class="tabs">
<div class="tab-buttons">
<button class="tab-button active" data-tab="p1">P1: Critical</button>
<button class="tab-button" data-tab="p2">P2: Consistency</button>
<button class="tab-button" data-tab="p3">P3: Convenience</button>
</div>
<div class="tab-content active" data-tab="p1">
<p>These <strong>block use cases entirely</strong>:</p>
<ul class="checklist">
<li><input type="checkbox"><label>Raw bytes support (blocks string encryption)</label></li>
<li><input type="checkbox"><label>Bind <code>LLVMReplaceAllUsesWith</code> (core SSA operation)</label></li>
<li><input type="checkbox"><label>Add <code>split_basic_block</code> (blocks some transforms)</label></li>
<li><input type="checkbox"><label>Add <code>erase_from_parent</code> (error-prone two-step)</label></li>
</ul>
</div>
<div class="tab-content" data-tab="p2">
<p>These cause <strong>confusion and bugs</strong>:</p>
<ul class="checklist">
<li><input type="checkbox"><label>Make <code>ptr</code> a property (like <code>i32</code>)</label></li>
<li><input type="checkbox"><label>Consistent setter patterns</label></li>
<li><input type="checkbox"><label>Add <code>.parent</code> alias for <code>.block</code></label></li>
<li><input type="checkbox"><label>Rename <code>.is_terminator_inst</code> to <code>.is_terminator</code></label></li>
</ul>
</div>
<div class="tab-content" data-tab="p3">
<p>These make the API <strong>more Pythonic</strong>:</p>
<ul class="checklist">
<li><input type="checkbox"><label>Add <code>.operands</code> iterator</label></li>
<li><input type="checkbox"><label>Add instruction movement (<code>move_before</code>, <code>move_after</code>)</label></li>
<li><input type="checkbox"><label>Add <code>.clone()</code> for instructions</label></li>
<li><input type="checkbox"><label>Add <code>.num_successors</code> property</label></li>
</ul>
</div>
</div>
</section>
<!-- Final Quiz -->
<section id="final-quiz">
<h2>Final Assessment</h2>
<p>Test your understanding with these synthesis questions:</p>
<div class="quiz" data-correct="1">
<h4>Question 1</h4>
<p class="quiz-question">Which improvement has the HIGHEST priority?</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span>Adding an <code>.operands</code> iterator</span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span>Binding <code>LLVMReplaceAllUsesWith</code></span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span>Making <code>ptr</code> a property</span>
</div>
</div>
<div class="quiz-feedback">
<strong>Correct!</strong> RAUW is Priority 1 (Critical Blocker). The iterator is P3 (Convenience), and ptr consistency is P2 (API Consistency).
</div>
</div>
<div class="quiz" data-correct="1">
<h4>Question 2</h4>
<p class="quiz-question">Why does CFF demote PHI nodes before flattening?</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span>PHI nodes are too slow</span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span>PHI nodes encode predecessor info that's lost after flattening</span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span>The LLVM API doesn't support PHI nodes</span>
</div>
</div>
<div class="quiz-feedback">
<strong>Yes!</strong> PHI nodes say "if we came from block1, use %x". After flattening, we always come from the dispatcher—the predecessor info is meaningless. Converting to memory operations preserves semantics.
</div>
</div>
<div class="quiz" data-correct="0">
<h4>Question 3</h4>
<p class="quiz-question">What happens if you access a Module after exiting its <code>with</code> block?</p>
<div class="quiz-options">
<div class="quiz-option" data-index="0">
<span class="option-letter">A</span>
<span>Clean Python exception (validity tokens)</span>
</div>
<div class="quiz-option" data-index="1">
<span class="option-letter">B</span>
<span>Segmentation fault</span>
</div>
<div class="quiz-option" data-index="2">
<span class="option-letter">C</span>
<span>Returns garbage data</span>
</div>
</div>
<div class="quiz-feedback">
<strong>Right!</strong> The bindings use validity tokens to track object lifetime. When the context manager exits, children are marked invalid, and accessing them raises a clean exception instead of undefined behavior.
</div>
</div>
<div id="final-score" style="display: none; margin-top: 40px;">
<div class="card success">
<h4>Your Results</h4>
<p id="final-score-text"></p>
</div>
</div>
</section>
<footer style="margin-top: 60px; padding: 40px 0; border-top: 1px solid var(--bg-card); color: var(--text-dim); text-align: center;">
<p>Built to help you understand, not just verify.</p>
<p style="font-size: 0.85rem; margin-top: 10px;">The goal is that you can now critique this work—and contribute better ideas.</p>
</footer>
</main>
<script>
// Quiz handling
let score = 0;
let total = 0;
let completedSections = new Set();
document.querySelectorAll('.quiz').forEach(quiz => {
const correct = parseInt(quiz.dataset.correct);
const options = quiz.querySelectorAll('.quiz-option');
const feedback = quiz.querySelector('.quiz-feedback');
let answered = false;
options.forEach((option, index) => {
option.addEventListener('click', () => {
if (answered) return;
answered = true;
total++;
options.forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
if (index === correct) {
option.classList.add('correct');
feedback.classList.add('correct');
score++;
} else {
option.classList.add('incorrect');
options[correct].classList.add('correct');
feedback.classList.add('incorrect');
}
feedback.classList.add('show');
updateScore();
updateProgress();
});
});
});
function updateScore() {
document.getElementById('score').textContent = score;
document.getElementById('total').textContent = total;
// Show final score if on last section
if (total >= 6) {
const finalScore = document.getElementById('final-score');
const finalText = document.getElementById('final-score-text');
finalScore.style.display = 'block';
const pct = Math.round((score / total) * 100);
let message = '';
if (pct >= 80) {
message = `You scored ${score}/${total} (${pct}%). Excellent! You're ready to review and critique the work.`;
} else if (pct >= 60) {
message = `You scored ${score}/${total} (${pct}%). Good foundation. Consider reviewing the sections where you missed questions.`;
} else {
message = `You scored ${score}/${total} (${pct}%). Consider re-reading the guide before diving into code review.`;
}
finalText.textContent = message;
}
}
// Tab handling
document.querySelectorAll('.tab-button').forEach(button => {
button.addEventListener('click', () => {
const tabGroup = button.closest('.tabs');
const tabName = button.dataset.tab;
tabGroup.querySelectorAll('.tab-button').forEach(b => b.classList.remove('active'));
tabGroup.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
button.classList.add('active');
tabGroup.querySelector(`.tab-content[data-tab="${tabName}"]`).classList.add('active');
});
});
// Expandable sections
document.querySelectorAll('.expandable-header').forEach(header => {
header.addEventListener('click', () => {
header.parentElement.classList.toggle('open');
});
});
// Progress tracking
function updateProgress() {
const sections = document.querySelectorAll('section');
const totalSections = sections.length;
// Track completed via checklist and quizzes
const checkboxes = document.querySelectorAll('.checklist input:checked').length;
const totalCheckboxes = document.querySelectorAll('.checklist input').length;
const answeredQuizzes = document.querySelectorAll('.quiz-feedback.show').length;
const totalQuizzes = document.querySelectorAll('.quiz').length;
const progress = Math.round(((checkboxes + answeredQuizzes) / (totalCheckboxes + totalQuizzes)) * 100);
document.getElementById('progress-fill').style.width = progress + '%';
document.getElementById('progress-text').textContent = progress + '%';
}
// Checklist persistence
document.querySelectorAll('.checklist input').forEach(checkbox => {
checkbox.addEventListener('change', () => {
updateProgress();
if (checkbox.checked) {
checkbox.nextElementSibling.classList.add('checked');
} else {
checkbox.nextElementSibling.classList.remove('checked');
}
});
});
// Interactive diagram tooltips
const tooltip = document.getElementById('diagram-tooltip');
document.querySelectorAll('.interactive-diagram .node').forEach(node => {
node.addEventListener('mouseenter', (e) => {
const text = node.dataset.tooltip;
if (text) {
tooltip.textContent = text;
tooltip.classList.add('show');
}
});
node.addEventListener('mousemove', (e) => {
tooltip.style.left = (e.pageX + 10) + 'px';
tooltip.style.top = (e.pageY + 10) + 'px';
});
node.addEventListener('mouseleave', () => {
tooltip.classList.remove('show');
});
});
// Smooth scroll for nav
document.querySelectorAll('nav a').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const target = document.querySelector(link.getAttribute('href'));
target.scrollIntoView({ behavior: 'smooth' });
document.querySelectorAll('nav a').forEach(l => l.classList.remove('active'));
link.classList.add('active');
});
});
// Highlight current section in nav
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.id;
document.querySelectorAll('nav a').forEach(link => {
link.classList.toggle('active', link.getAttribute('href') === '#' + id);
});
}
});
}, { threshold: 0.3 });
document.querySelectorAll('section').forEach(section => {
observer.observe(section);
});
</script>
</body>
</html>