<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"  xml:base="https://dridi.fedorapeople.org/">
  <channel>
    <title>Digressive Developer</title>
    <link>https://dridi.fedorapeople.org/</link>
    <description>Recent content on Digressive Developer</description>
    <language>en-us</language><copyright>Copyright (c) Dridi Boukelmoune, all rights reserved</copyright>
    <lastBuildDate>Sun, 27 Oct 2024</lastBuildDate>
    <atom:link href="https://dridi.fedorapeople.org/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>I almost made a 10x optimization</title>
      <link>https://dridi.fedorapeople.org/post/i-almost-made-a-10x-optimization/</link>
      <pubDate>Sun, 27 Oct 2024</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/i-almost-made-a-10x-optimization/</guid>
        <description>&lt;h2 id=&#34;working-on-a-high-performance-web-accelerator&#34;&gt;Working on a high-performance Web accelerator&lt;/h2&gt;
&lt;p&gt;I have been working on &lt;a href=&#34;https://dridi.fedorapeople.org/projects/varnish/&#34;&gt;Varnish Cache&lt;/a&gt; for
a decade and from day one former colleagues of mine persuaded themselves that
from then on I was dealing with arcane performance topics on a daily basis so
explaining that it was not the case puzzled them for a while.&lt;/p&gt;
&lt;p&gt;As it turns out, Varnish Cache is a very small project, and yet there is
plenty of variety in the project. Working on Varnish means that you can work
on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;networking sockets&lt;/li&gt;
&lt;li&gt;networking protocols&lt;/li&gt;
&lt;li&gt;multi-threading&lt;/li&gt;
&lt;li&gt;IPC of various kinds, including shared memory&lt;/li&gt;
&lt;li&gt;terminal-based interfaces (TUI applications)&lt;/li&gt;
&lt;li&gt;a programming language compiler (VCL)&lt;/li&gt;
&lt;li&gt;a programming language interpreter (VTC)&lt;/li&gt;
&lt;li&gt;a homemade test framework&lt;/li&gt;
&lt;li&gt;libraries&lt;/li&gt;
&lt;li&gt;gzip&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that is only what comes off the top of my head. There are so many things
going on for such a small project that amazingly, after a decade, there are
still several parts of the code base I never worked on, some of them I never
even read.&lt;/p&gt;
&lt;p&gt;I eventually worked on a performance bottleneck that almost resulted in a 10x
speed increase, significantly reducing the time it would take me to perform
certain tasks. It also turned out to be very similar to the first optimization
I remember making in a professional setting.&lt;/p&gt;
&lt;h2 id=&#34;working-on-a-low-performance-web-application&#34;&gt;Working on a low-performance Web application&lt;/h2&gt;
&lt;p&gt;Almost two decades ago, I ported a PHP application to Java, because I had
joined a company doing everything in Java, and nobody was competent to work on
this small internal PHP application. I was tasked to rewrite it from scratch
in Java, and that would serve as a training vector to familiarize myself with
the stack I would use next, on a regular Java project.&lt;/p&gt;
&lt;p&gt;The result was a slow, slow, slow mess of an application universally hated by
everyone who had to use it in the company, which was pretty much everyone.
There were several reasons why it was so slow, and this was the opportunity to
discover the art of profiling.&lt;/p&gt;
&lt;p&gt;For the first problem I solved, I decided to blame Java for being magic and
not warning me about the dangers of my ways.&lt;/p&gt;
&lt;h3 id=&#34;the-exception-to-the-simplicity-rule&#34;&gt;The exception to the simplicity rule&lt;/h3&gt;
&lt;p&gt;Back then, Java 5 was brand new, and it came with &amp;ldquo;amazing&amp;rdquo; features like
for-each loops, generics, and other quality-of-life features. The language was
verbose and complicated, but it was also mostly unambiguous. It was almost
always possible to figure immediately what was what in a code snippet.&lt;/p&gt;
&lt;p&gt;Despite being a complicated language, as far as I could observe, &lt;code&gt;javac&lt;/code&gt; had
always been a simple piece of the tool chain. It ingested Java code and turned
it into Java bytecode in such a way that most of the bytecode I have seen had
a 1-1 correspondence to its Java code.&lt;/p&gt;
&lt;p&gt;The beauty of &lt;code&gt;javac&lt;/code&gt;&amp;rsquo;s straightforward translation of the Java code, without
extensive optimization passes, was that the runtime would instead be in charge
of optimizations taking advantage of the host system capabilities. In other
words, &lt;code&gt;javac&lt;/code&gt; could remain simple because the complexity was pushed at the
edge. My assumption (that I&amp;rsquo;m not attempting to verify because at this point I
no longer care) is that aggressive optimizations at compile time could have
prevented better optimizations at run time, but I digress.&lt;/p&gt;
&lt;h3 id=&#34;isolating-the-performance-hot-spot&#34;&gt;Isolating the performance hot spot&lt;/h3&gt;
&lt;p&gt;For the first performance problem I solved, I wrote a reproducer for the naive
code that ended up eating a significant amount of cycles:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;Concat&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;	&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(String...&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;cat&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;arg:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;cat&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;arg;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;System.&lt;span style=&#34;color:#4070a0&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#4070a0&#34;&gt;println&lt;/span&gt;(cat);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;	&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This program loops over its command line arguments to build a comma-separated
representation of them. It&amp;rsquo;s also branch-less, so the separator is handled as
a string instead of, for example, a boolean.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s compile it to bytecode for Java 5:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ javac -source 5 -target 5 Concat.java
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: [options] bootstrap class path not set in conjunction with -source 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error: Source option 5 is no longer supported. Use 8 or later.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error: Target option 5 is no longer supported. Use 8 or later.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately this is no longer possible with OpenJDK 21, so let&amp;rsquo;s try again
with Java 8 as suggested by the error message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ javac -source 8 -target 8 Concat.java
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: [options] bootstrap class path not set in conjunction with -source 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: [options] source value 8 is obsolete and will be removed in a future release
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: [options] target value 8 is obsolete and will be removed in a future release
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 warnings
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And let&amp;rsquo;s just make sure that it works as advertised:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ javac Concat.java
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ java Concat a b c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a, b, c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-curious-case-of-the-magic-bytecode&#34;&gt;The curious case of the magic bytecode&lt;/h3&gt;
&lt;p&gt;Looking at the loop, the problem was not obvious. It looked straightforward
and nothing hinted at ill-advised operations in a tight loop. I eventually
decided to look at the bytecode because that made me look competent, and at
least busy and actively working on the problem.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s still trivial today with OpenJDK:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ javap -c Concat.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Compiled from &amp;#34;Concat.java&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;public class Concat {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  public Concat();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Code:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       0: aload_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       // Method Object.&amp;#34;&amp;lt;init&amp;gt;&amp;#34;:()V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       1: invokespecial #1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       4: return
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  public static void main(String...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Code:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       0: ldc           #7                  // String
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       2: astore_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       3: ldc           #7                  // String
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       5: astore_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       6: aload_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       7: astore_3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       8: aload_3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       9: arraylength
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      10: istore        4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      12: iconst_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      13: istore        5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      15: iload         5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      17: iload         4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      19: if_icmpge     61
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      22: aload_3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      23: iload         5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      25: aaload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      26: astore        6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // class StringBuilder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      28: new           #9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      31: dup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Method StringBuilder.&amp;#34;&amp;lt;init&amp;gt;&amp;#34;:()V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      32: invokespecial #11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      35: aload_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Method StringBuilder.append:(LString;)LStringBuilder;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      40: invokevirtual #12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      39: aload_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Method StringBuilder.append:(LString;)LStringBuilder;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      40: invokevirtual #12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      43: aload         6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Method StringBuilder.append:(LString;)LStringBuilder;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      45: invokevirtual #12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Method StringBuilder.toString:()LString;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      48: invokevirtual #16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      51: astore_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      52: ldc           #20                 // String ,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      54: astore_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      55: iinc          5, 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      58: goto          15
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Field System.out:Ljava/io/PrintStream;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      61: getstatic     #22
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      64: aload_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      // Method java/io/PrintStream.println:(LString;)V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      65: invokevirtual #28
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      68: return
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I was really taken by surprise when I realized that the bytecode was not at
all looking like a 1-1 translation of the Java code. My loop (much larger back
then) was full of objects and instructions that appeared out of nowhere. And I
really hate magic. I can&amp;rsquo;t reason about magic, I need my code to do what it&amp;rsquo;s
told and not do anything that wasn&amp;rsquo;t explicitly said, otherwise I can&amp;rsquo;t build
a reliable mental model.&lt;/p&gt;
&lt;p&gt;To help myself reason about this bytecode, I manually decompiled it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;Concat&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;	&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(String...&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;cat&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;arg:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;StringBuilder&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;tmp&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;new&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;StringBuilder();&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;tmp.&lt;span style=&#34;color:#4070a0&#34;&gt;append&lt;/span&gt;(cat);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;tmp.&lt;span style=&#34;color:#4070a0&#34;&gt;append&lt;/span&gt;(sep);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;tmp.&lt;span style=&#34;color:#4070a0&#34;&gt;append&lt;/span&gt;(arg);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;cat&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;tmp.&lt;span style=&#34;color:#4070a0&#34;&gt;toString&lt;/span&gt;();&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;System.&lt;span style=&#34;color:#4070a0&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#4070a0&#34;&gt;println&lt;/span&gt;(cat);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;	&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And from then on the problem was obvious. The &amp;lsquo;+&amp;rsquo; operator for the &lt;code&gt;String&lt;/code&gt;
class was backed by a &lt;code&gt;StringBuilder&lt;/code&gt;. I&amp;rsquo;m saying &amp;ldquo;was&amp;rdquo; here because OpenJDK
uses a different backend for string concatenation in Java 21. Because &lt;code&gt;javac&lt;/code&gt;
makes a straightforward translation of the Java code, we end up with a lot of
churn inside the tight loop, creating and discarding one &lt;code&gt;StringBuilder&lt;/code&gt; per
iteration.&lt;/p&gt;
&lt;p&gt;In my performance problem, I remember seeing several string builders being
created and deleted in the same loop, as its body was doing a lot more. This
was the occasion to discover that Java strings are immutable and what it
means in practice. One conclusion I drew was that the runtime was not able
to optimize this case at all. Even with other mechanisms like generational
garbage collectors, these short-lived string builders slowed the application
down to a crawl. I have no idea what OpenJDK 21 is capable of these days, and
I will probably not find out.&lt;/p&gt;
&lt;h3 id=&#34;time-for-performance-wizardry&#34;&gt;Time for performance wizardry&lt;/h3&gt;
&lt;p&gt;Seeing what the &amp;lsquo;+&amp;rsquo; and &amp;lsquo;+=&amp;rsquo; operators were doing to the generated bytecode
the solution was rather simple. If string concatenation is backed by a string
builder, we can avoid the needless churn by moving the string builder out of
the loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;Concat&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;	&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(String...&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;StringBuilder&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;cat&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;new&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;StringBuilder();&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;arg:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;cat.&lt;span style=&#34;color:#4070a0&#34;&gt;append&lt;/span&gt;(sep);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;cat.&lt;span style=&#34;color:#4070a0&#34;&gt;append&lt;/span&gt;(arg);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;			&lt;/span&gt;sep&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;		&lt;/span&gt;System.&lt;span style=&#34;color:#4070a0&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#4070a0&#34;&gt;println&lt;/span&gt;(cat);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;	&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And with a similar change in the code base, this hot spot no longer registered
in the profiler. The rest of the hot spots had similar churn problems that
became obvious after learning to identify them. From then on that pattern was
burned into my brain and I would quickly spot it, taking action immediately to
prevent it from turning into a bottleneck.&lt;/p&gt;
&lt;h2 id=&#34;spotting-this-pattern-in-varnish&#34;&gt;Spotting this pattern in Varnish&lt;/h2&gt;
&lt;p&gt;Fast forward years later, as of today also a few years ago, I find myself in a
delicate position trying to understand a dramatic performance problem observed
by a customer. Varnish is performing exceptionally poorly and they can prove
it reliably, and repeatedly. It&amp;rsquo;s so bad that I end up traveling to work on it
in person and on site with them.&lt;/p&gt;
&lt;p&gt;Every time they run their benchmark, it results in more than 20GB of logs, and
it takes me forever to collect data. I was using my own personal project
&lt;a href=&#34;https://git.sr.ht/~dridi/varnishplot&#34;&gt;varnishplot&lt;/a&gt; to automate the creation
of latency graphs. It would take me forever to conclude that Varnish was
reporting very low processing times. Being very attentive to the pitfall I
first ran into as a Java developer, I had already noticed the likelihood of a
similar occurrences in Varnish logs two years prior, when I initiated my work
on &lt;code&gt;varnishplot&lt;/code&gt;, and on the spot I decided to have a shot at it.&lt;/p&gt;
&lt;h3 id=&#34;the-varnish-shared-memory-log&#34;&gt;The Varnish Shared Memory Log&lt;/h3&gt;
&lt;p&gt;To summarize briefly how logs work in Varnish, we have on one end &lt;code&gt;varnishd&lt;/code&gt;
creating a memory-mapped file per shared memory segment. On the other end we
have programs that can map the same files in memory. Addressing them via the
file system is how they become shared memory segments. This particular segment
I am interested in is called VSL for Varnish Shared Log, also referred to as
shared memory log, or &lt;em&gt;shmlog&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The VSL segment is itself split into several parts inside which actual logs
are written. Logs have a structured binary representation, and &lt;code&gt;varnishd&lt;/code&gt; will
cycle through segments as it writes to them. Inside &lt;code&gt;varnishd&lt;/code&gt;, there can be a
large amount of threads logging concurrently, so long-running tasks log in a
local buffer and ideally flush everything at once at the end of the task.&lt;/p&gt;
&lt;p&gt;The circular nature of the live VSL means that consumers like &lt;code&gt;varnishlog&lt;/code&gt; or
&lt;code&gt;varnishncsa&lt;/code&gt; may be overrun by &lt;code&gt;varnishd&lt;/code&gt;. Grouping transactions increases
the risk of being overtaken. As a result VSL consumers may make copies of log
records to keep them available until a complete transaction or transaction
group is ready to be processed. In terms of coordination, &lt;code&gt;varnishd&lt;/code&gt; threads
use a mutex to publish log records, and consumers synchronize in wait-free
fashion with memory barriers.&lt;/p&gt;
&lt;p&gt;Log consumers can also feed from regular files, written by &lt;code&gt;varnishlog -w&lt;/code&gt;.
This offers the ability to perform queries and filtering on structured binary
logs at rest. This is essentially how I was processing logs from benchmark
runs to plot latency histograms.&lt;/p&gt;
&lt;p&gt;That should be it for the short digression, back to the problem now.&lt;/p&gt;
&lt;h3 id=&#34;pushing-the-cursor&#34;&gt;Pushing the cursor&lt;/h3&gt;
&lt;p&gt;The logs consumption itself is abstracted behind a cursor interface (VSLC or
Varnish Shared Log Cursor). There is a VSM (Varnish Shared Memory) cursor for
live logs and a file cursor for VSL files written down to disk. The churn
pattern described with the Java anecdote does not appear as clearly as in the
Java bytecode, but after asking the author of the current VSL implementation a
dozen times when I started having my doubts two years before my benchmark woes
I was fairly certain that the same scenario was happening.&lt;/p&gt;
&lt;p&gt;The sequence of events was different, but is actually quite similar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the file cursor opens a file&lt;/li&gt;
&lt;li&gt;it reads data in a local buffer&lt;/li&gt;
&lt;li&gt;it parses log records
&lt;ul&gt;
&lt;li&gt;copies are made to outlive the buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;once a transaction group is processed, copies are freed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The thing that was bothering me was the need to allocate copies at rest, so I
made the hypothesis that regular files could be mapped in memory to work with
them directly in place.&lt;/p&gt;
&lt;p&gt;In other words, this would take the best of both worlds, working &amp;ldquo;live&amp;rdquo; on a
memory buffer like the VSM cursor, without the fear of being overtaken like
the file cursor. As an added bonus, the code for the &lt;code&gt;mmap&lt;/code&gt; cursor ended up
being the simplest of the three. A simple design often is a good foundation
for good performance.&lt;/p&gt;
&lt;h2 id=&#34;almost-10x&#34;&gt;Almost 10x&lt;/h2&gt;
&lt;p&gt;With the new &lt;code&gt;mmap&lt;/code&gt; cursor I was able to iterate much faster on large dumps of
logs from benchmark runs. On my workstation the speed to process logs jumped
to 6x faster for transaction groups and 9x for raw log records.&lt;/p&gt;
&lt;p&gt;Faster iterations meant that I processed benchmark results more efficiently
from this point on, and soon after the answer became obvious: all client
requests came from a very small set of file descriptors.&lt;/p&gt;
&lt;p&gt;There was a proxy in front of Varnish that would serve several purposes, but
it was configured to open two connections to Varnish per client IP address.
In this very synthetic benchmark, that proxy was funneling thousands of HTTP
requests per second over a handful of TCP connections. Lifting that limit
solved the problem and that was the end of a wild goose chase.&lt;/p&gt;
&lt;p&gt;Soon after I
&lt;a href=&#34;https://github.com/varnishcache/varnish-cache/pull/3429&#34;&gt;submitted&lt;/a&gt; my change
and all was well that ended well. I was hoping that reflecting on this would
help me understand another ongoing performance problem, but no luck so far. At
this rate I might write something up about the current problem in 2028&amp;hellip;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Initial verdict on Hare safety</title>
      <link>https://dridi.fedorapeople.org/post/initial-verdict-on-hare-safety/</link>
      <pubDate>Mon, 20 May 2024</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/initial-verdict-on-hare-safety/</guid>
        <description>&lt;p&gt;Note: this post was written in early March and supposed to be published then.
It was extended with further observations after the closing words to make up
for this unfortunate oversight.&lt;/p&gt;
&lt;h2 id=&#34;managing-resources-is-a-solved-problem&#34;&gt;Managing resources is a solved problem&lt;/h2&gt;
&lt;p&gt;In my &lt;a href=&#34;https://dridi.fedorapeople.org/post/introducing-tsess/&#34;&gt;tsess introduction&lt;/a&gt; I rambled
on Hare and how it fares against C, Rust and Go. The answer was pretty well
and &lt;code&gt;tsess-0.2&lt;/code&gt; is good occasion to revisit this.&lt;/p&gt;
&lt;p&gt;As the project probably already covers 120% of my needs, there will be little
to add besides small features I have in mind that only add convenience to a
utility I already find more than good enough on a daily basis. These features
will be a good excuse to explore a little more of Hare. That excuse has been
the main driver for the initial attempt to write tsess in Rust and the current
success in Hare.&lt;/p&gt;
&lt;p&gt;As stated &lt;a href=&#34;https://dridi.fedorapeople.org/post/cross-compiling-tsess-on-fedora/&#34;&gt;previously&lt;/a&gt;
Valgrind found leaks in &lt;code&gt;tsess&lt;/code&gt; so safety in Hare is already a failure. After
all, Rust solved this with its ownership model enforced by its borrow checker.
But the same borrow checker reached its limit when I tried to fit a single
allocation model for the configuration file with parsing in place. This was a
different kind of failure, either on Rust for not being able to get a &lt;code&gt;&amp;amp;&amp;amp;str&lt;/code&gt;
from a &lt;code&gt;Box&amp;lt;str&amp;gt;&lt;/code&gt; or on me for not figuring out how.&lt;/p&gt;
&lt;p&gt;Needless to say, I wouldn&amp;rsquo;t have this problem in C (although I would have a
different problem called null-terminated strings) and I didn&amp;rsquo;t have this
problem with Hare. But nevertheless, I leaked resources.&lt;/p&gt;
&lt;h2 id=&#34;revisiting-tsess-leaks&#34;&gt;Revisiting tsess leaks&lt;/h2&gt;
&lt;p&gt;Since I&amp;rsquo;m too lazy to either go back in Git history before the commits that
plugged leaks, restoring the tool chain I was using then, I will simply revert
the bug fixes to revisit the leaks. Fortunately, so far, I made leaks easy to
find from commit messages alone.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git revert --no-commit --no-edit $(git log --grep Plug --format=%H)
Auto-merging bin/tsess/config/env.ha
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Interesting fact, so far I only fixed leaks in &lt;code&gt;env.ha&lt;/code&gt;, and what&amp;rsquo;s is not
visible is that two leaks were plugged.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s ask Valgrind about problems, but let&amp;rsquo;s do it as it used to, from a
statically linked &lt;code&gt;tsess&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After running the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;valgrind --tool=memcheck --leak-check=full --track-fds=all ./tsess list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I get the following report from Valgrind, after cleaning it up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FILE DESCRIPTORS: 4 open (3 std) at exit.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open file descriptor 3: /home/dridi/.config/tsess/example.tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x8006BB1: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x8003721: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x80166FD: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x801657C: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x8011C8E: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x8012ED9: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x805421A: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x8053928: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x80531E2: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x80507EA: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x806241E: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open file descriptor 2: /dev/pts/6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;lt;inherited from parent&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open file descriptor 1: /dev/pts/6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;lt;inherited from parent&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open file descriptor 0: /dev/pts/6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;lt;inherited from parent&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEAP SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    in use at exit: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;All heap blocks were freed -- no leaks are possible
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;For lists of detected and suppressed errors, rerun with: -s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Despite the lack of a useful stack trace, it was easy to find the source of
the leak since there is only one place in the code that opens files. The bug
fix is a one-liner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git show 8d525d563f13c3ce995471e23fa1078bb90fe8e9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit 8d525d563f13c3ce995471e23fa1078bb90fe8e9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config: Plug file leak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Spotted by Valgrind.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;diff --git a/bin/tsess/config/env.ha b/bin/tsess/config/env.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;index cf21695..7449318 100644
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- a/bin/tsess/config/env.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++ b/bin/tsess/config/env.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -74,6 +74,7 @@ fn file_size(h: io::handle) (size | io::error) = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fn file_load(path: str) ([]u8 | error) = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        let file = os::open(path)?;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+       defer io::close(file)!;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        if (file_size(file)? == 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                return errors::unsupported: io::error;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the only file leak plugged, it&amp;rsquo;s time to look at memory leaks. I know for
a fact that there are more than zero allocations, and I also know for a fact
that Valgrind could find them if &lt;code&gt;tsess&lt;/code&gt; was dynamically linked.&lt;/p&gt;
&lt;h2 id=&#34;memory-leaks&#34;&gt;Memory leaks&lt;/h2&gt;
&lt;p&gt;Since version 0.2, &lt;code&gt;tsess&lt;/code&gt; is dynamically linked by default. It is however
still possible to statically link it at build time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ make tsess_LDFLAGS=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_cmd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/cli/gen/cmd.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_env
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/env_vars.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_prop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/prop_defs.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file * | grep ELF
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_cmd:        ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_env:        ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_prop:       ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tsess:          ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Side note, the invocation eventually changed to &lt;code&gt;make tsess_LIBS=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My rationale to dynamically link by default is that libc may provide certain
services based on the system configuration. For example, a system user or
group lookup could be done from &lt;code&gt;/etc/passwd&lt;/code&gt; or &lt;code&gt;/etc/group&lt;/code&gt;, or from an NSS
module.&lt;/p&gt;
&lt;p&gt;This can only work if the Hare runtime is implemented with fall-backs to libc
functions. There is at least one service from libc that will be used, and it&amp;rsquo;s
the memory allocator. This probably means that we can also use a different
&lt;code&gt;malloc&lt;/code&gt; implementation, for example linking to &lt;code&gt;jemalloc&lt;/code&gt; for its profiling
capabilities among other things, but I digress.&lt;/p&gt;
&lt;p&gt;So, once I dynamically link &lt;code&gt;tsess&lt;/code&gt;, let&amp;rsquo;s look at memory leaks. After running
the same Valgrind command I get the following suggestion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reachable blocks (those to which a pointer was found) are not shown.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;To see them, rerun with: --leak-check=full --show-leak-kinds=all
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since I was able to confirm that the file leak was plugged, I ran this command
instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./tsess list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And I get the following report, once again cleaned up to keep the essentials:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEAP SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    in use at exit: 16,472 bytes in 5 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  total heap usage: 102 allocs, 97 frees, 62,379 bytes allocated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;12 bytes in 1 blocks are indirectly lost in loss record 1 of 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x41844D: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x42B9C6: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x42B3DA: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x430182: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x47F907: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x47D2D5: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x48F631: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408738: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4897149: (below main) (libc_start_call_main.h:58)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;19 bytes in 1 blocks are still reachable in loss record 2 of 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x418A85: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4824E6: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x482667: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x482794: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408D51: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408733: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4897149: (below main) (libc_start_call_main.h:58)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;25 bytes in 1 blocks are still reachable in loss record 3 of 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x418A85: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x482A67: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408D51: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408733: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4897149: (below main) (libc_start_call_main.h:58)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;44 (32 direct, 12 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484A074: realloc (vg_replace_malloc.c:1690)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F0B: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x402075: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x42B3FC: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x430182: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x47F907: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x47D2D5: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x48F631: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408738: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4897149: (below main) (libc_start_call_main.h:58)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;16,384 bytes in 1 blocks are definitely lost in loss record 5 of 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4602A1: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408D51: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408733: ??? (in /home/dridi/src/tsess/tsess)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4897149: (below main) (libc_start_call_main.h:58)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LEAK SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   definitely lost: 16,416 bytes in 2 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   indirectly lost: 12 bytes in 1 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     possibly lost: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   still reachable: 44 bytes in 2 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        suppressed: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;For lists of detected and suppressed errors, rerun with: -s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main reason why I didn&amp;rsquo;t dive straight away in memory leaks is the
uselessness of this report. From the stack trace I can easily infer which
lines are inside &lt;code&gt;tsess&lt;/code&gt;&amp;rsquo; &lt;code&gt;main()&lt;/code&gt; function but after that, I wasn&amp;rsquo;t going to
follow all the paths that could lead to an allocation after &amp;ldquo;that many&amp;rdquo;
function calls for each leak. Especially since that would also mean following
paths into the standard library. I&amp;rsquo;d rather have a computer do this repetitive
work for me.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also worried about this 16kB allocation. What did I do so wrong to leak
16kB of memory when this Valgrind experiments loads one configuration file
that has a size below 1kB? Did I forget to free a buffer for buffered I/O?
That&amp;rsquo;s highly unlikely since &lt;code&gt;tsess&lt;/code&gt; is very conservative with allocations.
The reason why the Rust experiment failed was caused by my insistence in
having one allocation per configuration file, and working with in-place
substrings.&lt;/p&gt;
&lt;p&gt;There should be no such buffer.&lt;/p&gt;
&lt;p&gt;I was also wondering where the two reachable memory outstanding allocations
came from. I was well-aware of one source of allocations that could be held
until completion, and it happens to be again in &lt;code&gt;env.ha&lt;/code&gt;: the configuration
directory is the expansion of &lt;code&gt;${XDG_CONFIG_HOME}/tsess&lt;/code&gt; and this is done
during startup by an &lt;code&gt;@init&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;let tsess_dir = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@init fn env_init() void = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        env_args.dir = arg_resolve(env_vars.dir, env_defs.dir);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        env_args.tmux = arg_resolve(env_vars.tmux, env_defs.tmux);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        env_args.tmpdir = arg_resolve(env_vars.tmpdir, env_defs.tmpdir);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tsess_dir = strings::concat(env_args.dir: str, &amp;#34;/tsess&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It could even fall back to an expansion of &lt;code&gt;${HOME}/.config&lt;/code&gt; with the result
expanded to &lt;code&gt;${HOME}/.config/tsess&lt;/code&gt;, leading to two reachable outstanding
allocations instead of one. But based on the environment in which Valgrind was
running, I had an explanation for only one reachable remain in the report.&lt;/p&gt;
&lt;p&gt;My initial initial verdict on Hare safety was that it really sucked to have
bugs in your code, and I was looking forward to proper debug symbols. Except
that at the time I first looked at memory leaks I had proper DWARF support in
my Hare tool chain, and I found how to take advantage of it by accident.&lt;/p&gt;
&lt;h2 id=&#34;preparing-the-second-release&#34;&gt;Preparing the second release&lt;/h2&gt;
&lt;p&gt;As I was heading towards a &lt;code&gt;tsess-0.2&lt;/code&gt; release, planets aligned and I was able
to upgrade to Hare 0.24.0 with as little effort as I was planning to invest.
The &lt;code&gt;qbe&lt;/code&gt; package was already a snapshot of &amp;ldquo;almost qbe 1.2&amp;rdquo; and the &lt;code&gt;harec&lt;/code&gt;
package got upgraded to 0.24.0 so with a minimal change in my local packaging
I was able to rebuild an up-to-date &lt;code&gt;hare&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;tsess-0.2&lt;/code&gt; release I toyed with the &lt;code&gt;-R&lt;/code&gt; option for &lt;code&gt;hare build&lt;/code&gt; and
eventually left a build tree configured in release mode. Once I finally got
motivated to revisit the Valgrind report, but this time I got this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEAP SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    in use at exit: 88 bytes in 4 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  total heap usage: 101 allocs, 97 frees, 45,995 bytes allocated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;12 bytes in 1 blocks are indirectly lost in loss record 1 of 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: rt.malloc (malloc+libc.ha:7)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4146BD: strings.dup (dup.ha:15)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x42DC60: fs.dirent_dup (types.ha:168)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x42D674: fs.readdir (util.ha:93)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x430E8C: os.readdir (os.ha:32)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4633E3: bin.tsess.config.env_load (env.ha:119)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x460DB1: bin.tsess.config.list (list.ha:16)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x47A413: .main (tsess.ha:42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408738: main (start+libc.ha:20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;19 bytes in 1 blocks are still reachable in loss record 2 of 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: rt.malloc (malloc+libc.ha:7)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x414CF5: strings.concat (concat.ha:10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x465FC2: bin.tsess.config.arg_expand (env.ha:39)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x466143: bin.tsess.config.arg_resolve (env.ha:29)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x466270: initfunc.0 (env.ha:18)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408D51: rt.init (initfini.ha:9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408733: main (start+libc.ha:19)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;25 bytes in 1 blocks are still reachable in loss record 3 of 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484280F: malloc (vg_replace_malloc.c:442)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F22: rt.malloc (malloc+libc.ha:7)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x414CF5: strings.concat (concat.ha:10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x466543: initfunc.0 (env.ha:21)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408D51: rt.init (initfini.ha:9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408733: main (start+libc.ha:19)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;44 (32 direct, 12 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   at 0x484A074: realloc (vg_replace_malloc.c:1690)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x401F0B: rt.realloc (malloc+libc.ha:21)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x402075: rt.ensure (ensure.ha:24)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x42D696: fs.readdir (util.ha:93)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x430E8C: os.readdir (os.ha:32)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x4633E3: bin.tsess.config.env_load (env.ha:119)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x460DB1: bin.tsess.config.list (list.ha:16)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x47A413: .main (tsess.ha:42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   by 0x408738: main (start+libc.ha:20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LEAK SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   definitely lost: 32 bytes in 1 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   indirectly lost: 12 bytes in 1 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     possibly lost: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   still reachable: 44 bytes in 2 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        suppressed: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One things stands out immediately: the report becomes actionable with proper
stack traces. It becomes apparent that my initial assessment on the reachable
bits was wrong: one was the expansion of &lt;code&gt;${HOME}/.config&lt;/code&gt; and the other one
was the one I identified. That left only one direct memory leak, with no trace
of the 16kB leak. Since the &lt;code&gt;-R&lt;/code&gt; option omits the &lt;code&gt;debug&lt;/code&gt; package, I can only
come to the conclusion that the remaining leaks were in the standard library.&lt;/p&gt;
&lt;h2 id=&#34;plugging-the-final-leak&#34;&gt;Plugging the final leak&lt;/h2&gt;
&lt;p&gt;The bug fix for this second leak looks a lot like the fix from the first one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git show --format=short 74c8d4cf5c94be9c41ef2615e1421b7f1d27809c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit 74c8d4cf5c94be9c41ef2615e1421b7f1d27809c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config: Plug leak spotted by Valgrind
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;diff --git a/bin/tsess/config/env.ha b/bin/tsess/config/env.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;index de1b1d2..aa05b8a 100644
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- a/bin/tsess/config/env.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++ b/bin/tsess/config/env.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -122,6 +122,7 @@ export fn env_load(sess: *[]sess) (void | src_error) = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        case let d: []fs::dirent =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                yield d;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+       defer fs::dirents_free(list);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        for (let i = 0z; i &amp;lt; len(list); i += 1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                if (!fs::isfile(list[i].ftype))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        continue;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem with this one-liner is that I distinctly remember adding this line
when I first started listing files from the configuration directory. But prior
to this commit there are no traces of it. My only explanation is a Vim or Git
accident, most likely an undo operation (simply pressing &amp;lsquo;u&amp;rsquo;) that flew under
my radar.&lt;/p&gt;
&lt;p&gt;This is a shiny example of something that wouldn&amp;rsquo;t have happened in Rust. I
would likely never had freed that resource and simply relied on the fact that
&lt;code&gt;list&lt;/code&gt; would have been dropped at the end of its scope.&lt;/p&gt;
&lt;p&gt;A quick check of memory leaks, without worrying about reachable memory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;valgrind --tool=memcheck --leak-check=full ./tsess list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And as expected, I get a clean report:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEAP SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    in use at exit: 44 bytes in 2 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  total heap usage: 101 allocs, 99 frees, 45,995 bytes allocated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LEAK SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   definitely lost: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   indirectly lost: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     possibly lost: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   still reachable: 44 bytes in 2 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        suppressed: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;closing-words&#34;&gt;Closing words&lt;/h2&gt;
&lt;p&gt;The key takeaways in my opinion are first that the only mistakes I made were
the same: I forgot to immediately free resources with the &lt;code&gt;defer&lt;/code&gt; keyword just
after allocating them. I need to grow this reflex of planning a deferred free
on the very next statement following an allocation. Even though in one case I
did, but did not notice its absence during a review. Second, Hare leaves me to
my own devices when it comes to resource management, but unlike C it offers a
precious &lt;code&gt;defer&lt;/code&gt; keyword that deals with multipath pitfalls. Third, as proven
with Valgrind, I have some tricks up my sleeves to mitigate the inevitable
mistakes I make. Fourth, the Hare model appears to be a successful recipe, as
I was able to limit actual leaks to two spots for approximately 3000 lines of
Hare code. And my last key takeaway is that despite learning Hare, I don&amp;rsquo;t
remember ever wondering what I was doing with memory, unlike my experience
with Go.&lt;/p&gt;
&lt;p&gt;I need to mention that static linking has a benefit that dynamic linking lacks
out of the box. At some point I tried to both defer a free and manually do it.
Hare&amp;rsquo;s allocator warned me about a potential double free, and was of course
spot on.&lt;/p&gt;
&lt;p&gt;My actual initial verdict on Hare safety is very positive.&lt;/p&gt;
&lt;p&gt;Or is it?&lt;/p&gt;
&lt;h2 id=&#34;fast-forwarding-to-version-04&#34;&gt;Fast forwarding to version 0.4&lt;/h2&gt;
&lt;p&gt;A couple releases later, &lt;code&gt;tsess&lt;/code&gt; is still lacking a test suite. Thus, there
has been no attempt at systematizing safety checks. As a result, another leak
was introduced, unsurprisingly.&lt;/p&gt;
&lt;p&gt;This is not a problem for several reasons, ranked by importance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tsess&lt;/code&gt; is designed for short-lived executions, no lingering leaks&lt;/li&gt;
&lt;li&gt;once the testing strategy is in place, it will include safety checks&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tsess&lt;/code&gt; has not reached 1.0, whether in scope or quality&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This time the leak was not a missing &lt;code&gt;defer&lt;/code&gt; statement, so I can maybe claim
that this reflex is settling in. It is probably too soon to tell anyway.&lt;/p&gt;
&lt;p&gt;I also extended my safety checks to more than listing configurations and
found new worrying complaints from Valgrind.&lt;/p&gt;
&lt;p&gt;Not having time to focus on all of them I narrowed the easiest one down:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat unsafe.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use fmt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use unix;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export fn main() void = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	let unsafe: (rune | void) = &amp;#39;\n&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unix::getuid() != 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		unsafe = void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unsafe == &amp;#39;\n&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		fmt::println(&amp;#34;ERROR&amp;#34;)!;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hare build -qR -lc -o unsafe unsafe.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ valgrind --tool=memcheck --leak-check=full ./unsafe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== Memcheck, a memory error detector
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== Copyright (C) 2002-2024, and GNU GPL&amp;#39;d, by Julian Seward et al.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== Command: ./unsafe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== Conditional jump or move depends on uninitialised value(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==    at 0x44628B: .main (unsafe.ha:8)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==    by 0x408738: main (start+libc.ha:20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== HEAP SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==     in use at exit: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== All heap blocks were freed -- no leaks are possible
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== Use --track-origins=yes to see where uninitialised values come from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== For lists of detected and suppressed errors, rerun with: -s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==601071== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing that surprised me when I looked at my code was that it made a direct
comparison between a tagged union type &lt;code&gt;(rune | void)&lt;/code&gt; with a &lt;code&gt;rune&lt;/code&gt; instead
of using a &lt;code&gt;match&lt;/code&gt; expression to decompose it. I read the Hare specification
but it took me months and I do not remember the rules allowing expressions
involving a union with one of its types without a &lt;code&gt;match&lt;/code&gt;, a cast or the &lt;code&gt;as&lt;/code&gt;
keyword. I don&amp;rsquo;t even remember from reading the specification that it was
possible in the first place, so I probably forgot that I was dealing with a
tagged union when I did that.&lt;/p&gt;
&lt;p&gt;The good news is that this is probably a false positive, at least as far as
Hare is concerned. (Future me says no.) My assumption is that the offending
&lt;code&gt;if&lt;/code&gt; expression reads more than the type tag for its comparison, but at least
it does not print an error so we get the expected behavior. (Future me says
no.) Valgrind will stop complaining if the second &lt;code&gt;if&lt;/code&gt; expression is turned
into a &lt;code&gt;match&lt;/code&gt; so there is still something amiss. (Future me shouts YES!)&lt;/p&gt;
&lt;p&gt;The first &lt;code&gt;if&lt;/code&gt; expression checks the PID to make sure the second assignment is
not optimized away.&lt;/p&gt;
&lt;h2 id=&#34;how-do-tagged-union-types-actually-work&#34;&gt;How do tagged union types actually work?&lt;/h2&gt;
&lt;p&gt;I explored several aspects of Hare as I was learning it, like for example how
the moving parts of the build system are articulated. From my recollection of
the Hare specification, the layout of tagged union types is an implementation
detail, but how does the reference implementation manage them?&lt;/p&gt;
&lt;p&gt;I tried to look at the generated assembly code to figure this out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rm -rf ~/.cache/hare/tmp/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hare build -vvR -lc -o unsafe unsafe.ha 2&amp;gt;&amp;amp;1 | grep &amp;#39;unsafe\.ha/.*\.s$&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;as -o /home/dridi/.cache/hare/tmp/tmp.qYgG01hZNn/unsafe.ha/896798450034f4518c1b81f1230065157390a134955ec9fc76f91d699574c45b.o.tmp /home/dridi/.cache/hare/tmp/tmp.qYgG01hZNn/unsafe.ha/c3dd2ba88647977896af5bed73e7cbfb2ab8560fc3652a21996b94efcd048d45.s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since this is the assembly code generated by &lt;code&gt;qbe&lt;/code&gt;, it uses the AT&amp;amp;T notation
I&amp;rsquo;m &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-3/&#34;&gt;not familiar&lt;/a&gt; with. This is
hopefully trivial enough for me&amp;hellip; I mean, it can hardly be more trivial, can
it? I digress.&lt;/p&gt;
&lt;p&gt;And with that, let&amp;rsquo;s look at the beginning of the &lt;code&gt;main()&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;.main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;pushq&lt;/span&gt; &lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;movq&lt;/span&gt; &lt;span style=&#34;color:#bb60d5&#34;&gt;%rsp&lt;/span&gt;, &lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;subq&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;$112&lt;/span&gt;, &lt;span style=&#34;color:#bb60d5&#34;&gt;%rsp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#4070a0&#34;&gt;.loc&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;25&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#4070a0&#34;&gt;.loc&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;movl&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;$1737287038&lt;/span&gt;, -&lt;span style=&#34;color:#40a070&#34;&gt;56&lt;/span&gt;(&lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#4070a0&#34;&gt;.loc&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;movl&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;$10&lt;/span&gt;, -&lt;span style=&#34;color:#40a070&#34;&gt;52&lt;/span&gt;(&lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second &lt;code&gt;movl&lt;/code&gt; is for the &lt;code&gt;&#39;\n&#39;&lt;/code&gt; assignment, a &lt;code&gt;rune&lt;/code&gt; is a 32bit integer.
My logical conclusion is that &lt;code&gt;1737287038&lt;/code&gt; is the tag for the &lt;code&gt;rune&lt;/code&gt; type
either in Hare in general, in this program, or for this specific tagged union
type &lt;code&gt;(rune | void)&lt;/code&gt;. After all, they both refer to line 5 where the variable
is declared and first assigned.&lt;/p&gt;
&lt;p&gt;If there is indeed an access to uninitialized memory, does it mean that the
&amp;ldquo;value&amp;rdquo; for &lt;code&gt;void&lt;/code&gt; is stored separately? Let&amp;rsquo;s skip ahead to line 7:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#4070a0&#34;&gt;.loc&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;movl&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;$3650376889&lt;/span&gt;, -&lt;span style=&#34;color:#40a070&#34;&gt;112&lt;/span&gt;(&lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#4070a0&#34;&gt;.loc&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;movq&lt;/span&gt; -&lt;span style=&#34;color:#40a070&#34;&gt;112&lt;/span&gt;(&lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;), &lt;span style=&#34;color:#bb60d5&#34;&gt;%rax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06287e&#34;&gt;movq&lt;/span&gt; &lt;span style=&#34;color:#bb60d5&#34;&gt;%rax&lt;/span&gt;, -&lt;span style=&#34;color:#40a070&#34;&gt;56&lt;/span&gt;(&lt;span style=&#34;color:#bb60d5&#34;&gt;%rbp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we write the new tag &lt;code&gt;3650376889&lt;/code&gt; for the &lt;code&gt;void&lt;/code&gt; type in some scratch
space on the stack. Then we copy 64bits to &lt;code&gt;RAX&lt;/code&gt; and finally we copy the tag
and the &lt;code&gt;void&lt;/code&gt; &amp;ldquo;value&amp;rdquo; where the &lt;code&gt;unsafe&lt;/code&gt; variable is stored.&lt;/p&gt;
&lt;p&gt;If we check the beginning of the &lt;code&gt;main()&lt;/code&gt; function again, and the code I&amp;rsquo;m
omitting, we can confirm that we copied 4 initialized bytes for the tag along
with 4 uninitialized bytes in &lt;code&gt;RAX&lt;/code&gt;, and then smuggled them in &lt;code&gt;unsafe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So I can make a few observations. As usual, Valgrind was correctly complaining
about uninitialized memory and I didn&amp;rsquo;t expect to prove it wrong. The layout
of a tagged union type appears to be a 32bit tag followed by what looks like a
C union. This was at least what I remembered from the presentation linked in
this &lt;a href=&#34;https://harelang.org/blog/2022-04-25-announcing-hare/&#34;&gt;blog post&lt;/a&gt; (but I
don&amp;rsquo;t have time for a rewatch).&lt;/p&gt;
&lt;p&gt;I think that what&amp;rsquo;s happening is that a tag is set in the scratch space and
that the &lt;code&gt;void&lt;/code&gt; type has a zero size. So we end up with an uninitialized read
because the assignment will copy the total union size. And finally, because
the scratch space appears to be reserved at the beginning of the stack for the
&lt;code&gt;main()&lt;/code&gt; function, one tagged assignment could initialize this space and turn
this into a false negative from Valgrind.&lt;/p&gt;
&lt;p&gt;Another obvious consequence is that the &lt;code&gt;rune&lt;/code&gt; check could accidentally match
a 32bit uninitialized value already present on the stack.&lt;/p&gt;
&lt;h2 id=&#34;checking-the-spurious-match-hypothesis&#34;&gt;Checking the spurious match hypothesis&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s tweak the program to see whether we can display &amp;ldquo;ERROR&amp;rdquo; in the standard
output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat spurious.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use fmt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use unix;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export fn main() void = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	let unsafe: (rune | void) = &amp;#39;\0&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unix::getuid() != 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		unsafe = void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unsafe == &amp;#39;\0&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		fmt::println(&amp;#34;ERROR&amp;#34;)!;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hare build -qR -o spurious spurious.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./spurious
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hypothesis confirmed.&lt;/p&gt;
&lt;h2 id=&#34;checking-the-false-negative-hypothesis&#34;&gt;Checking the false negative hypothesis&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s tweak the program to see whether we can silence Valgrind without solving
the actual problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat smuggle.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use fmt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use unix;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export fn main() void = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	let unsafe: (rune | void) = &amp;#39;\0&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	let unrelated: (rune | void) = void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unix::getpid() != 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		unrelated = &amp;#39;u&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unix::getuid() != 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		unsafe = void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	if (unsafe == &amp;#39;u&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		fmt::println(&amp;#34;ERROR&amp;#34;)!;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hare build -qR -lc -o smuggle smuggle.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ valgrind --tool=memcheck --leak-check=full ./smuggle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== Memcheck, a memory error detector
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== Copyright (C) 2002-2024, and GNU GPL&amp;#39;d, by Julian Seward et al.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== Command: ./smuggle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== HEAP SUMMARY:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695==     in use at exit: 0 bytes in 0 blocks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== All heap blocks were freed -- no leaks are possible
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695==
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== For lists of detected and suppressed errors, rerun with: -s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==606695== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hypothesis confirmed.&lt;/p&gt;
&lt;p&gt;Not only did the &lt;code&gt;unrelated&lt;/code&gt; variable assignment hide the uninitialized
access, it also managed to smuggle the &lt;code&gt;&#39;u&#39;&lt;/code&gt; character in the &lt;code&gt;unsafe&lt;/code&gt;
variable, even tagged as &lt;code&gt;void&lt;/code&gt;. It was smuggled in the sense that the
offending &lt;code&gt;if&lt;/code&gt; expression doesn&amp;rsquo;t seem to check the tag and take this
&lt;code&gt;rune&lt;/code&gt; at face value.&lt;/p&gt;
&lt;h2 id=&#34;initial-verdict-on-hare-safety&#34;&gt;Initial verdict on Hare safety&lt;/h2&gt;
&lt;p&gt;My initial verdict on Hare safety was very positive, and I can&amp;rsquo;t retroactively
change that.&lt;/p&gt;
&lt;p&gt;Did my new findings change my opinion on Hare safety? Not really. This finding
was &lt;em&gt;really&lt;/em&gt; interesting to dive into, being both &lt;em&gt;really&lt;/em&gt; small and &lt;em&gt;really&lt;/em&gt;
trivial (emphasis on &lt;em&gt;really&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;I think that the &lt;code&gt;(void | rune) == rune&lt;/code&gt; comparison should be a compile error,
and I should probably submit a bug report. Valgrind is complaining about other
things that are a little more worrying, but I already burnt a lot of my spare
time looking into this one and writing about it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not too fond of the shared scratch space for tagged (and possibly other)
assignments, but there are probably constraints I&amp;rsquo;m not aware of that lead to
this design. I&amp;rsquo;m also not really familiar to how other compilers deal with
their stack.&lt;/p&gt;
&lt;p&gt;It should be noted that I found this with
&lt;a href=&#34;https://harelang.org/blog/2024-02-16-hare-0.24.0-released/&#34;&gt;Hare 0.24.0&lt;/a&gt;, and
even though the project is already quite advanced, it&amp;rsquo;s probably fair to say
that Hare is still somewhat in its infancy. And I don&amp;rsquo;t expect 1.0 to somehow
turn the reference implementation into perfect software. Software implies bugs
and that&amp;rsquo;s a fact of life. Hare still offers me an interesting alternative to
C without the complications of Rust (that I see more as a &lt;code&gt;C++&lt;/code&gt; alternative).&lt;/p&gt;
&lt;p&gt;While Rust&amp;rsquo;s compiler has to behave like a static analyzer out of the box, I
also believe that Hare generally leaves much less opportunities to lose track
of the flow of a program, so writing a static analyzer for Hare would likely
allow more accurate results than what state-of-the-art static analyzers for C
can manage based on my unscientific wet-finger estimate, but I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;My verdict is still very positive.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Cross compiling tsess on Fedora</title>
      <link>https://dridi.fedorapeople.org/post/cross-compiling-tsess-on-fedora/</link>
      <pubDate>Sun, 25 Feb 2024</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/cross-compiling-tsess-on-fedora/</guid>
        <description>&lt;h2 id=&#34;updating-my-hare-tool-chain&#34;&gt;Updating my Hare tool chain&lt;/h2&gt;
&lt;p&gt;Considering the amount of spare time I can allocate to various projects I
decided early on to build my own
&lt;a href=&#34;https://copr.fedorainfracloud.org/coprs/dridi/&#34;&gt;hare package&lt;/a&gt;
and only that to learn Hare by rewriting my long-gestated
&lt;a href=&#34;https://dridi.fedorapeople.org/projects/tsess/&#34;&gt;tsess&lt;/a&gt; project. Both
&lt;a href=&#34;https://c9x.me/compile/&#34;&gt;qbe&lt;/a&gt; and &lt;code&gt;harec&lt;/code&gt; were available on Fedora, the
latter as a snapshot.&lt;/p&gt;
&lt;p&gt;Only recently we finally had a
&lt;a href=&#34;https://harelang.org/blog/2024-02-16-hare-0.24.0-released/&#34;&gt;0.24.0&lt;/a&gt; release
of &lt;code&gt;hare&lt;/code&gt; and &lt;code&gt;harec&lt;/code&gt;, and the long-awaited 1.2 release of &lt;code&gt;qbe&lt;/code&gt;. And &lt;code&gt;qbe&lt;/code&gt; is
the reason why I stuck for so long on an ancient commit for my &lt;code&gt;hare&lt;/code&gt; package.
With limited time to track local packages, I had to draw the line somewhere or
I would otherwise end up eating too much of my spare time on a regular basis.&lt;/p&gt;
&lt;p&gt;Before the formal releases for the Hare tool chain, a release candidate of
&lt;code&gt;harec&lt;/code&gt; landed in Fedora Rawhide (currently f40), but relying on a snapshot
of &lt;code&gt;qbe&lt;/code&gt; in the absence of a proper release for features needed by &lt;code&gt;harec&lt;/code&gt;.
Luckily both &lt;code&gt;qbe&lt;/code&gt; and &lt;code&gt;harec&lt;/code&gt; packages would install just fine on Fedora 39
and after updating my local &lt;code&gt;hare&lt;/code&gt; packaging I was ready to update &lt;code&gt;tsess&lt;/code&gt;
to &amp;ldquo;modern&amp;rdquo; Hare.&lt;/p&gt;
&lt;h2 id=&#34;cross-compiling-hare-code&#34;&gt;Cross compiling Hare code&lt;/h2&gt;
&lt;p&gt;Cross compilation is really easy when it comes to the &lt;code&gt;hare build&lt;/code&gt; command.
When I started learning Hare it was only a matter of adding a &lt;code&gt;-t&lt;/code&gt; option to
define the target architecture. Early on, I made my automake configuration
build upon autoconf&amp;rsquo;s &lt;code&gt;--host&lt;/code&gt; option. The configure script for &lt;code&gt;tsess&lt;/code&gt; would
look for a GCC tool chain for that architecture and fall back to a regular C
compiler.&lt;/p&gt;
&lt;p&gt;It does not matter since the Hare tool chain produces static binaries, right?&lt;/p&gt;
&lt;p&gt;I already covered &lt;a href=&#34;https://dridi.fedorapeople.org/post/introducing-tsess/&#34;&gt;this&lt;/a&gt; earlier&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;dynamic-linking-of-hare-programs&#34;&gt;Dynamic linking of Hare programs&lt;/h2&gt;
&lt;p&gt;Hare offers C interoperability, which sounds like a requirement in the systems
programming landscape. In that case it becomes possible to link with &lt;code&gt;libc&lt;/code&gt;
and use a variety of services it provides, ranging from its memory allocator
to the resolution of domain or service names. To my knowledge, &lt;code&gt;tsess&lt;/code&gt; would
benefit from none of such services as of today, but it still creates new
opportunities.&lt;/p&gt;
&lt;p&gt;With dynamic linking it becomes possible to find memory leaks with Valgrind
for example. And unfortunately, I found some, but haven&amp;rsquo;t studied them yet.&lt;/p&gt;
&lt;p&gt;It is rather easy to compile a dynamically linked &lt;code&gt;tsess&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./configure HAREFLAGS=-lc &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_cmd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/cli/gen/cmd.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_env
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/env_vars.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_prop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/prop_defs.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7/7 tasks completed (100%)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file * | awk -F &amp;#39;[:,] *&amp;#39; &amp;#39;$2 ~ &amp;#34;ELF&amp;#34; {printf &amp;#34;%s: %s, %s, %s\n&amp;#34;, $1, $3, $5, $6}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_cmd: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_env: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_prop: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tsess: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cross compilation of &lt;code&gt;tsess&lt;/code&gt; with dynamic linking is a little more involved,
but not difficult on Fedora.&lt;/p&gt;
&lt;h2 id=&#34;cross-compilation-on-fedora&#34;&gt;Cross compilation on Fedora&lt;/h2&gt;
&lt;p&gt;It is amazing to see how today&amp;rsquo;s tooling is making cross compilation so much
easier. From package managers to emulation, it does not take much effort to
get a working cross compilation environment on Fedora.&lt;/p&gt;
&lt;p&gt;The first thing needed for cross compilation is a tool chain. As I stated
before, by default the configure script will fall back to a regular C compiler
which would work for Clang, but not GCC:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./configure --host=aarch64-unknown-linux-gnu &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ grep ^CC= config.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CC=&amp;#39;gcc&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After installing the &lt;code&gt;gcc-aarch64-linux-gnu&lt;/code&gt; package the configure script will
find the right compiler out of the box:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./configure --host=aarch64-unknown-linux-gnu &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ grep ^CC= config.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CC=&amp;#39;aarch64-linux-gnu-gcc&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order to link with glibc, I need it installed in the tool chain&amp;rsquo;s sysroot,
and the cross compiler has one configured by default:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc --print-sysroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ aarch64-linux-gnu-gcc --print-sysroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/usr/aarch64-linux-gnu/sys-root
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are wondering what the package ships in its sysroot, the answer is
nothing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rpm -ql gcc-aarch64-linux-gnu | grep sys-root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/usr/aarch64-linux-gnu/sys-root
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;sys-root/&lt;/code&gt; directory is empty, I need to populate it.&lt;/p&gt;
&lt;h2 id=&#34;creating-a-fedora-sysroot-on-fedora&#34;&gt;Creating a Fedora sysroot on Fedora&lt;/h2&gt;
&lt;p&gt;At the heart of Fedora we find several critical components, several of them
constitute its software distribution tool chain. Fedora is an RPM-based Linux
distribution, and the actual software distribution is operated by DNF. DNF
introduces the notion of remote package repositories. I would install the
&lt;code&gt;gcc-aarch64-linux-gnu&lt;/code&gt; package with DNF if it wasn&amp;rsquo;t a dependency of my
homemade &lt;code&gt;hare&lt;/code&gt; package in the first place.&lt;/p&gt;
&lt;p&gt;On top of it, another package called &lt;code&gt;mock&lt;/code&gt; can be used to &amp;ldquo;take source RPMs
and build them in a &lt;code&gt;chroot&lt;/code&gt;&amp;rdquo;. Mock does a lot more but that&amp;rsquo;s literally how
it is described today:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rpm -q --qf &amp;#39;%{description}\n&amp;#39; mock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Mock takes an SRPM and builds it in a chroot.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mock can help set up a sysroot for a limited number of architectures. As of
today that would be aarch64, i686, ppc64le, s390x and of course x86-64. As the
description suggests, mock is backed by the &lt;code&gt;chroot&lt;/code&gt; facility (not sure which
one between the &lt;code&gt;chroot(2)&lt;/code&gt; system call and &lt;code&gt;chroot(1)&lt;/code&gt; program). Or rather,
it was backed by &lt;code&gt;chroot&lt;/code&gt; also known as its &amp;ldquo;simple&amp;rdquo; isolation backend. It now
defaults to &lt;code&gt;systemd-nspawn&lt;/code&gt; and can perform the bootstrap from an OCI image
with &lt;code&gt;podman&lt;/code&gt; (instead of installing all the packages from scratch).&lt;/p&gt;
&lt;p&gt;In addition to this, DNF can work with packages on different architectures
with the help of QEMU.&lt;/p&gt;
&lt;p&gt;In other words, I can create a Fedora sysroot with a single command line
thanks to &lt;code&gt;mock&lt;/code&gt;. In fact, I can even create sysroots for other RPM-based
distributions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls /etc/mock/templates/ | awk -F- &amp;#39;{print $1}&amp;#39; | sort | uniq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;almalinux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;amazonlinux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;anolis
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;centos
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;circlelinux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;custom
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;epel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;eurolinux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fedora
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mageia
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;navy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openeuler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openmandriva
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opensuse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;oraclelinux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rhel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rocky
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can imagine the amount of work it used to require to create and maintain a
sysroot when we didn&amp;rsquo;t have such well-integrated tools.&lt;/p&gt;
&lt;p&gt;For the sake of the exercise, I wanted to link &lt;code&gt;tsess&lt;/code&gt; to both &lt;code&gt;libc&lt;/code&gt; and
&lt;code&gt;libcurl&lt;/code&gt;. There is nothing in &lt;code&gt;tsess&lt;/code&gt; requiring anything from &lt;code&gt;libcurl&lt;/code&gt;, but
it shows how easy it is to bring up, and how fast it happens:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo rm -rf /var/*/mock/fedora-39-aarch64*/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ time mock -r fedora-39-aarch64 --install glibc-devel curl-devel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INFO: Unable to build arch aarch64 natively on arch x86_64. Setting forcearch to use software emulation.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INFO:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Finish: run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;real	4m59.646s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user	4m45.281s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sys	0m13.513s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I couldn&amp;rsquo;t find how to really remove the OCI image with &lt;code&gt;podman&lt;/code&gt;, it appeared
to still be present after removing and pruning it, but regardless, in a few
minutes I have a working sysroot. Most of the time spent was on downloading
metadata and packages, on a DSL connection.&lt;/p&gt;
&lt;p&gt;I ended up with a sysroot after next to no manual operations.&lt;/p&gt;
&lt;p&gt;The only problems I have with the package management tool chain on Fedora is
its lack of good and meaningful names. RPM is fine, it used to carry meaning
before being turned into a backronym, but by that time it was well&amp;hellip; well
known? Then Yum, meaningless, but established. Why did DNF (is meaninglesser
a word?) not keep the Yum name? Why is it still called Yum on RHEL? I don&amp;rsquo;t
need an answer, that was a rhetorical question. And mock? Who calls a piece of
software that has no relation to software testing mock? Probably somebody who
wants to make sure it does not show up in search engine results.&lt;/p&gt;
&lt;p&gt;I get it though, naming things is pretty damn hard, but it&amp;rsquo;s really a shame
because as demonstrated, mock is a powerful tool.&lt;/p&gt;
&lt;p&gt;Then again, it seems that meaningless names are the norm when it comes to
package managers. Either that, or I don&amp;rsquo;t have the reference. The outcome is
the same. See for example apt/aptitude, sbuild, pacman and zypper&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;cross-compiling-tsess&#34;&gt;Cross compiling tsess&lt;/h2&gt;
&lt;p&gt;Now if I want to compile &lt;code&gt;tsess&lt;/code&gt; for aarch64 on my x86-64 laptop I need to
shoehorn my sysroot into my build system somehow. I could do it at configure
time, and I actually documented how to do this. My preferred solution is to
populate &lt;code&gt;/usr/aarch64-linux-gnu/sys-root&lt;/code&gt; directly.&lt;/p&gt;
&lt;p&gt;However, I treat &lt;code&gt;/usr&lt;/code&gt; as immutable, so I don&amp;rsquo;t want to add anything inside.
The simplest solution I found requires privileges, but is otherwise free of
friction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls -1 /usr/aarch64-linux-gnu/sys-root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo mount --bind /var/lib/mock/fedora-39-aarch64/root /usr/aarch64-linux-gnu/sys-root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls -1 /usr/aarch64-linux-gnu/sys-root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;afs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;boot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builddir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;home
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;installation-homedir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lib64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;media
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mnt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;proc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sbin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;srv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;var
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m now ready to build a &lt;code&gt;tsess&lt;/code&gt; dynamically linked to both &lt;code&gt;libc&lt;/code&gt; and
&lt;code&gt;libcurl&lt;/code&gt;, even though only &lt;code&gt;libc&lt;/code&gt; is relevant:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./configure --host=aarch64-unknown-linux-gnu HAREFLAGS=&amp;#39;-lc -lcurl&amp;#39; &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_cmd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/cli/gen/cmd.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_env
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/env_vars.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_prop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/prop_defs.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;13/13 tasks completed (100%)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file * | awk -F &amp;#39;[:,] *&amp;#39; &amp;#39;$2 ~ &amp;#34;ELF&amp;#34; {printf &amp;#34;%s: %s, %s, %s\n&amp;#34;, $1, $3, $5, $6}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_cmd: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_env: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_prop: x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tsess: ARM aarch64, dynamically linked, interpreter /lib/ld-linux-aarch64.so.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Only &lt;code&gt;tsess&lt;/code&gt; is built for the aarch64 target because the other programs are
executed during the build.&lt;/p&gt;
&lt;p&gt;We can easily check that the Hare flags were honored:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ readelf --dynamic tsess | grep NEEDED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0x0000000000000001 (NEEDED)             Shared library: [libcurl.so.4]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;wrapping-up&#34;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;In the end, I find amazing how easy it is to cross compile a dynamically
linked &lt;code&gt;tsess&lt;/code&gt;, so easy it feels like cheating. It really boils down to a
handful of commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mock&lt;/li&gt;
&lt;li&gt;mount&lt;/li&gt;
&lt;li&gt;configure&lt;/li&gt;
&lt;li&gt;make&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that&amp;rsquo;s really it! It could have been a very short post, but I couldn&amp;rsquo;t
help sprinkle a little digression here and there.&lt;/p&gt;
&lt;p&gt;This apparent simplicity builds upon a huge pile of complications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the autotools (autoconf, automake and libtool in this case)&lt;/li&gt;
&lt;li&gt;years of RPM history (the whole tool chain, including pieces I omitted)&lt;/li&gt;
&lt;li&gt;years of packaging refinement for cross GCC tool chains&lt;/li&gt;
&lt;li&gt;years of Linux kernel history (everything &lt;code&gt;podman&lt;/code&gt; relies on)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The effective simplicity comes from some degree of cohesion between all the
moving parts. Catch me on a bad day and I will describe it as a high degree of
coupling between components poorly cobbled together, but the cohesion is still
there regardless.&lt;/p&gt;
&lt;p&gt;For example, on my machine RPM ships with a &lt;code&gt;%configure&lt;/code&gt; macro that takes care
of applying system-wide configure flags recognized by any package relying on
the autotools. I greatly suspect that the packaging of cross compilers evolved
following autoconf&amp;rsquo;s conventions, and probably influenced autoconf in return.&lt;/p&gt;
&lt;p&gt;The bottom line is that for this use case I only need to configure the bare
minimum at each step:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tell mock to install my build dependencies in an aarch64 root&lt;/li&gt;
&lt;li&gt;bind the aarch64 root directory to the cross compiler sysroot&lt;/li&gt;
&lt;li&gt;tell the &lt;code&gt;configure&lt;/code&gt; script to target aarch64&lt;/li&gt;
&lt;li&gt;tell &lt;code&gt;hare&lt;/code&gt; to link with &lt;code&gt;libc&lt;/code&gt; (and for fun, &lt;code&gt;libcurl&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And once again, that&amp;rsquo;s really it!&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s amazing to see how our tools evolved and to see the concrete effect of
iterative refinements. The Hare tool chain is still young but it is already
quite usable and it shows that lessons from the past were effectively learned.
It also didn&amp;rsquo;t take too much effort from me to find a crowbar and retrofit it
in my familiar ecosystem, and just like that I can rebuild &lt;code&gt;tsess&lt;/code&gt; in mere
minutes and deploy it to the ARM board I occasionally SSH into.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s a wrap for a yak that won&amp;rsquo;t need a shaving for a while.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Revisiting hare_build.sh</title>
      <link>https://dridi.fedorapeople.org/post/revisiting-hare-build-sh/</link>
      <pubDate>Sun, 07 Jan 2024</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/revisiting-hare-build-sh/</guid>
        <description>&lt;h2 id=&#34;previously-on-digressive-developer&#34;&gt;Previously on Digressive Developer&lt;/h2&gt;
&lt;p&gt;In my &lt;a href=&#34;https://dridi.fedorapeople.org/post/introducing-tsess/&#34;&gt;previous post&lt;/a&gt; introducing my
new &lt;a href=&#34;https://dridi.fedorapeople.org/projects/tsess/&#34;&gt;tsess&lt;/a&gt; project I spent much more time
exploring the Hare language and reference implementation tool chain than the
actual introduction.&lt;/p&gt;
&lt;p&gt;This was not an exploration in depth of Hare, but more like a wide surface
look at everything that stuck in my mind in my &lt;code&gt;tsess&lt;/code&gt; journey. One thing in
particular failed, and if I had paid attention it shouldn&amp;rsquo;t have.&lt;/p&gt;
&lt;h2 id=&#34;sorting-out-dependencies&#34;&gt;Sorting out dependencies&lt;/h2&gt;
&lt;p&gt;In order to find dependencies the script contained the following function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find_mods&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;echo&lt;/span&gt; rt &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# always built&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hare deps -T +linux+x86_64 -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;$2 == &amp;#34;-&amp;gt;&amp;#34; {print $3 &amp;#34; &amp;#34; $1}&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# &amp;#34;foo&amp;#34;; &amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tr -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#34;;&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# foo bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Fv .ha | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# only modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -wv rt | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# already built first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tsort
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It lists dependencies in the &lt;a href=&#34;https://graphviz.org/doc/info/lang.html&#34;&gt;dot&lt;/a&gt;
format and arrange the output to be processed by &lt;code&gt;tsort&lt;/code&gt;. With this simple
trick I can build dependencies in the right order.&lt;/p&gt;
&lt;p&gt;Notice however how the dependency order is reversed with the &lt;code&gt;awk&lt;/code&gt; script
printing the dependency first and the dependent next. I reversed this order
because initially I ran into a missing dependency doing it in the right order
and I used &lt;code&gt;tac&lt;/code&gt; to reverse the order:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find_mods&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;echo&lt;/span&gt; rt &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# always built&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hare deps -T +linux+x86_64 -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;$2 == &amp;#34;-&amp;gt;&amp;#34; {print $1 &amp;#34; &amp;#34; $3}&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# &amp;#34;foo&amp;#34;; &amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tr -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#34;;&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# foo bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Fv .ha | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# only modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -wv rt | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# already built first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tsort |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tac
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And this would result in this output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hare_build.sh hello-print.ha &amp;amp;&amp;amp; ./hello-print
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod types
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod bytes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod encoding::utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod math
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod strings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Could not open module &amp;#39;encoding::utf8&amp;#39;: typedef variable $HARE_TD_encoding::utf8 not set
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s when I noticed that I was exporting &lt;code&gt;HARE_TD_encoding_utf8&lt;/code&gt; and trying
to export the expected variable would not work. I was also not too fond of
using &lt;code&gt;tac&lt;/code&gt; so I ended up reversing the &lt;code&gt;tsort&lt;/code&gt; input with &lt;code&gt;awk&lt;/code&gt; instead of
its output with &lt;code&gt;tac&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So when I got this result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hare_build.sh hello-print.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod encoding::utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod errors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod types
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod math
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod bytes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Could not open module &amp;#39;linux::vdso&amp;#39;: typedef variable $HARE_TD_linux::vdso not set
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My reaction should not have been to conclude that I had run into the wrong
environment variable being exported (&lt;code&gt;HARE_TD_linux_vdso&lt;/code&gt;) but really to ask
myself where the devil this module comes from and why it wasn&amp;rsquo;t listed as a
dependency.&lt;/p&gt;
&lt;p&gt;I should have known that, because I tried to submit a &lt;code&gt;tsort&lt;/code&gt; format for the
&lt;code&gt;hare deps&lt;/code&gt; subcommand but it got postponed until after a large update to the
build driver. And I knew then that the dependencies listing is not recursive,
I was &lt;a href=&#34;https://lists.sr.ht/~sircmpwn/hare-dev/patches/41087&#34;&gt;planning&lt;/a&gt; to send
a patch series eventually with it.&lt;/p&gt;
&lt;p&gt;I tweaked the script to incrementally add missing dependencies as I was trying
to sort them out and eventually managed to manually link my &lt;code&gt;hello-print.ha&lt;/code&gt;
program. One thing that bothered me though, was the somewhat specific order of
&lt;code&gt;.a&lt;/code&gt; files on the &lt;code&gt;ld&lt;/code&gt; command line to get a result.&lt;/p&gt;
&lt;h2 id=&#34;exporting-problems&#34;&gt;Exporting problems&lt;/h2&gt;
&lt;p&gt;One thing that is not possible in a POSIX shell but that can be done from a
POSIX shell is exporting variables like &lt;code&gt;HARE_TD_encoding::utf8&lt;/code&gt; to the
environment.&lt;/p&gt;
&lt;p&gt;It can&amp;rsquo;t be done in the shell&amp;rsquo;s environment, but it can be done for &lt;code&gt;harec&lt;/code&gt;&amp;rsquo;s
environment. I attempted just that with the help of the &lt;code&gt;env&lt;/code&gt; command, and it
worked.&lt;/p&gt;
&lt;p&gt;I ended up using a construct I&amp;rsquo;m not fond of:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;env &lt;span style=&#34;color:#bb60d5&#34;&gt;$HARE_TD&lt;/span&gt; harec -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa -N &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_ns &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -t &lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;.td &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_src &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; ha&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;...&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;HARE_TD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$HARE_TD&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt; HARE_TD_&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.td&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But it had the merit to work.&lt;/p&gt;
&lt;h2 id=&#34;putting-everything-together&#34;&gt;Putting everything together&lt;/h2&gt;
&lt;p&gt;At this point I wasn&amp;rsquo;t sure whether compiling all modules would be enough to
successfully link the program. The dependencies listing ended up looking like
this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find_mods&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; mod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hare deps -T +linux+x86_64 -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$mod&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;$2 == &amp;#34;-&amp;gt;&amp;#34; {print $1 &amp;#34; &amp;#34; $3}&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# &amp;#34;foo&amp;#34; &amp;#34;bar&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tr -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#34;;&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# foo bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tsort |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Fv &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# only dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead of giving &lt;code&gt;rt&lt;/code&gt; a special treatment here, the only thing to filter out
is the module itself, the &lt;code&gt;$1&lt;/code&gt; parameter. The topological sort as populated by
&lt;code&gt;awk&lt;/code&gt; is back to the &amp;ldquo;natural&amp;rdquo; order.&lt;/p&gt;
&lt;p&gt;The complete script looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;set&lt;/span&gt; -u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tag_filter&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Pv &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;\+(?!linux|x86_64)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_dir&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;printf&lt;/span&gt; %s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;/usr/src/hare/stdlib/&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;s|::|/|g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_ns&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;printf&lt;/span&gt; %s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;s|::|.|g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_td&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;printf&lt;/span&gt; %s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;s|::|_|g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_src&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;dir&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_dir &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;ext&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	find &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$dir&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; -name &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;*.&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$ext&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; -type f |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -v &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$dir&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;/[^+-].*/&amp;#34;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# do not enter submodules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tag_filter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find_mods&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; mod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hare deps -T +linux+x86_64 -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$mod&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;$2 == &amp;#34;-&amp;gt;&amp;#34; {print $1 &amp;#34; &amp;#34; $3}&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# &amp;#34;foo&amp;#34; &amp;#34;bar&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tr -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#34;;&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# foo bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tsort |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Fv &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# only dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;build_mod&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_td &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;test&lt;/span&gt; -f &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.td&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; mod in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;find_mods &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		build_mod &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$mod&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Building mod &lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_td &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	env &lt;span style=&#34;color:#bb60d5&#34;&gt;$HARE_TD&lt;/span&gt; harec -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa -N &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_ns &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -t &lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;.td &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_src &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; ha&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	qbe -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	as -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; s in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_src &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; s&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		as -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;basename &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$s&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; .s&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.o&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$s&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ar -r -c &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.a &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;*.o
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;HARE_TD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$HARE_TD&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt; HARE_TD_&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.td&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -f -- *.td *.ssa *.s *.o *.a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;HARE_TD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; mod in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;find_mods &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	build_mod &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$mod&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;prog&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;basename &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; .ha&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;env &lt;span style=&#34;color:#bb60d5&#34;&gt;$HARE_TD&lt;/span&gt; harec -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qbe -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;as -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ld.lld -T /usr/src/hare/stdlib/rt/hare.sc -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.o *.a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To solve the &lt;code&gt;*.a&lt;/code&gt; ordering problem I tried other linkers. The default was
&lt;code&gt;bfd&lt;/code&gt;, &lt;code&gt;gold&lt;/code&gt; had the same problem, and &lt;code&gt;lld&lt;/code&gt; appeared to do just fine so I
picked the latter and never tried to find the right command line options to
ask the other linkers to unconfuse themselves.&lt;/p&gt;
&lt;p&gt;Lo and behold, it works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hare_build.sh hello-print.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod errors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod types
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod bytes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod encoding::utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod strings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod io
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod memio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod path
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod format::elf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod linux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod types::c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod linux::vdso
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod math
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod fs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod bufio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod os
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod ascii
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod strconv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod fmt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hello-print
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When I linked the program manually I was able to get away with less modules,
but that made a difference of only 1kB on the final binary. If I add the
&lt;code&gt;--gc-sections&lt;/code&gt; option I get the exact same file size for both manual and
scripted linking, but the programs are not identical.&lt;/p&gt;
&lt;p&gt;I will not go down this rabbit hole, but I&amp;rsquo;m happy to report that it is
possible to emulate the Hare tool chain with a shell script (and all the
transparency that comes with it). I could probably also emulate &lt;code&gt;hare deps&lt;/code&gt;
instead of invoking it but I was merely interested in the build pipeline here.&lt;/p&gt;
&lt;p&gt;Simple and accessible.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Introducing tsess</title>
      <link>https://dridi.fedorapeople.org/post/introducing-tsess/</link>
      <pubDate>Sat, 06 Jan 2024</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/introducing-tsess/</guid>
        <description>&lt;h2 id=&#34;best-wishes-for-the-new-years&#34;&gt;Best wishes for the new year(s)&lt;/h2&gt;
&lt;p&gt;2024 is finally here, and a new entry in this blog was long overdue. It&amp;rsquo;s not
that I had nothing to write about, I always have something silly in store I
could mention here. I simply had little time to spare, and chose to do other
things on my spare time.&lt;/p&gt;
&lt;p&gt;In these last three and a half years I have kept up to date with many things,
which is an implicit requirement when choosing Fedora as an operating system
but one thing I failed to uphold was the maintenance of this blog. It was a
little bit painful to deal with updates to Hugo and the Jane theme, but I
somehow succeeded.&lt;/p&gt;
&lt;p&gt;Since January is the time for new year&amp;rsquo;s resolution, this years I made up two
for myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;migrate my development workflow to &lt;a href=&#34;https://dridi.fedorapeople.org/projects/tsess/&#34;&gt;tsess&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;write at least one blog post per year&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m so good at upholding resolutions that I already succeeded both. I can go
back to extreme procrastination with a good conscience. See you next year.&lt;/p&gt;
&lt;h2 id=&#34;introducing-tsess&#34;&gt;Introducing tsess?&lt;/h2&gt;
&lt;p&gt;In 2023 I discovered the &lt;a href=&#34;https://harelang.org/&#34;&gt;Hare&lt;/a&gt; programming language
when a FOSDEM presentation was brought to my attention, although admittedly I
don&amp;rsquo;t remember how. I suspect it was from
&lt;a href=&#34;https://harelang.org/blog/2022-04-25-announcing-hare/&#34;&gt;LWN&lt;/a&gt; because I was
lagging far behind on this feed, and nowadays I&amp;rsquo;m not even trying to follow
it, but I digress.&lt;/p&gt;
&lt;p&gt;My first reaction was of course to compare it to
&lt;a href=&#34;https://www.rust-lang.org/&#34;&gt;Rust&lt;/a&gt;, a language I have been following since
version 0.4 as a serious contender for C. The philosophy behind Hare matches
many opinions I forged over time, and as it turned out, more than Rust. So I
started reading about Hare and playing with it until it was time, six months
later, to have a &amp;ldquo;real&amp;rdquo; project to effectively learn it.&lt;/p&gt;
&lt;p&gt;I started musing about this &lt;code&gt;tsess&lt;/code&gt; project when the
&lt;a href=&#34;https://github.com/tmuxinator/tmuxinator&#34;&gt;tmuxinator&lt;/a&gt; package was orphaned in
Fedora and eventually removed from the repositories. In late 2022, two years
after maintaining my own RPMs for tmuxinator and its dependencies outside of
Fedora, I started &lt;code&gt;tsess&lt;/code&gt; in Rust and failed in the context of self-imposed
constraints. In August 2023 I decided to try again in Hare.&lt;/p&gt;
&lt;p&gt;In 2023 I also authored my first &lt;a href=&#34;https://go.dev/&#34;&gt;Go&lt;/a&gt; project for work and
among other things it involved crafting a simple parser, which is most of what
I have done in Rust so far. The Hare tool chain shows similarities with Go&amp;rsquo;s
and the Hare language itself looks like C enhanced by concepts found in both
Rust and Go. Rewriting &lt;code&gt;tsess&lt;/code&gt; in Hare became all the more interesting for me
in that context.&lt;/p&gt;
&lt;p&gt;And in the common Internet tradition, I have to explain why Vim is better than
Emacs, or the other way around.&lt;/p&gt;
&lt;h2 id=&#34;the-rust-go-hare-showdown&#34;&gt;The Rust-Go-Hare showdown&lt;/h2&gt;
&lt;h3 id=&#34;rust&#34;&gt;Rust&lt;/h3&gt;
&lt;p&gt;I have been following Rust&amp;rsquo;s evolution for years now but never worked on a
real project doing actual work in production somewhere. I really love Rust so
all the negative things I&amp;rsquo;m going to say about it must be framed in this
context: I really love Rust.&lt;/p&gt;
&lt;p&gt;In a nutshell, Rust is to me a language that encodes resource management in
its type system (and to some extent its standard library) and effectively
turns the compiler into a static analyzer. For forcing me to think harder
about ownership I am forever grateful.&lt;/p&gt;
&lt;p&gt;Rust also has relatively straightforward C interoperability but despite
starting as a C-like language like so many others it embraces functional
programming constructs. The standard library is by design wide, providing a
lot of variants for a lot of features. Likewise, the syntax sometimes offers
several ways radically different to achieve the same thing and interestingly
the Clippy linter will steer you towards certain constructs.&lt;/p&gt;
&lt;p&gt;Rust forces you to handle return values, elegantly generalizes null handling
with its &lt;code&gt;Option&lt;/code&gt; type and offers a pleasant higher-level error management
with the &lt;code&gt;Result&lt;/code&gt; type. It is also expression-oriented, which is refreshing
coming from C.&lt;/p&gt;
&lt;p&gt;In comparison, C is a simple statement-oriented imperative language. The
simplicity of C is downright impressive, but the language is sometimes too
simplistic and overall plagued with undefined behavior. Rust on the other
hand is too complicated. I call it an &lt;em&gt;imperacryptive&lt;/em&gt; language and my
inability to fit it in my head is a problem, even assisted by tools. Mind
you, there are some bits of C equally cryptic like the rules for &lt;code&gt;struct&lt;/code&gt;
layouts or the mere ability to come up with Duff&amp;rsquo;s device but the things
difficult to remember (for me) about C are things I rarely need or actively
avoid (unfortunately you can&amp;rsquo;t just look away from undefined behavior).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also not in line with the Rust community philosophy of having many crates
&amp;ldquo;doing one thing and doing it well&amp;rdquo; à la UNIX™. I don&amp;rsquo;t like that &lt;code&gt;cargo&lt;/code&gt; is
both a dependency manager and a build system, this is the main ingredient in
the recipe for supply chain attacks and generally a lack of separation of two
critical concerns. Cargo also poorly composes with polyglot projects, like any
language&amp;rsquo;s self-centered all-encompassing tool chain. This is true of Go and
Hare as well, but to a lesser extent for the latter. I became familiar with
this problem in a past life working on Java projects built with the Maven
build system, but don&amp;rsquo;t get me started on this one or I will dial digressions
up to eleven.&lt;/p&gt;
&lt;h3 id=&#34;go&#34;&gt;Go&lt;/h3&gt;
&lt;p&gt;Go in comparison is much simpler than Rust, and has an overall pleasant look
and feel. Rust has a rather heavily ceremonial syntax and in comparison Go
is very straightforward.&lt;/p&gt;
&lt;p&gt;Like Rust, Go has very interesting design choices, but my main problem is the
amount of magic that goes behind the scenes. Rust is certainly not devoid of
magic constructs but in general I know what I&amp;rsquo;m doing or trying to do. With Go
most of the time all bets are off, as far as I&amp;rsquo;m concerned. It should be noted
that I never tried to formally learn either Rust or Go, unlike Hare. In Go&amp;rsquo;s
defense, before this first work project I had spent much less time looking at
it than say, Rust.&lt;/p&gt;
&lt;p&gt;Error handling in Go is interesting too, but not to my liking. Still, I tried
to adhere to the coding standard and do things the Go way because I was going
to ultimately hand over this code to someone else for future maintenance, but
then I ran into exotic error handling in the &lt;code&gt;text/scanner&lt;/code&gt; package I relied
on for my parser. Navigating the standard library was not always trivial. For
example do I use &lt;code&gt;net&lt;/code&gt; package to work with CIDRs? What about the &lt;code&gt;net/netip&lt;/code&gt;
package?&lt;/p&gt;
&lt;p&gt;The Go tool chain is clearly the worst of the three in my ranking. The way Go
manages dependencies as Git repositories is horrendous. At least Cargo works
with actual &amp;ldquo;crates&amp;rdquo; repositories. I understand some of the constraints behind
the source-only compilation of mostly-statically-linked programs for both Rust
and Go (and Hare!) but it doesn&amp;rsquo;t mean that I approve. At least Rust solves
source code incompatibilities with an interesting system of editions. In Go,
the resulting dependency hell appears to be universally solved with vendoring,
and well, to me this is only adding one circle to this inferno. This is giving
a license to software maintainers to not carefully design interfaces. Can&amp;rsquo;t
just upgrade to the latest version of X, or need a specific patch? Lock your
dependency or vendor it.&lt;/p&gt;
&lt;p&gt;Oh, and I don&amp;rsquo;t like ending up with a hello world weighing as much as a web
browser once compiled. I may be exaggerating a little here, but man, Go
programs are anything but lean.&lt;/p&gt;
&lt;h3 id=&#34;hare&#34;&gt;Hare&lt;/h3&gt;
&lt;p&gt;Now Hare is a beast of its own, but one I found incredibly easy to tame. Hare
looks like C, with Rust-like type decomposition, a Go-like tool chain, and
everything pretty much toned down.&lt;/p&gt;
&lt;p&gt;Hare is expression-oriented like Rust, and unlike Go. While the syntax looks
ceremonial, with for example code blocks delimited by curly braces requiring a
semi-colon after the closing brace, once you realize the block is just another
expression it makes sense. So far Hare has the most consistent syntax of the
three.&lt;/p&gt;
&lt;p&gt;In fact, Hare comes with a formal
&lt;a href=&#34;https://harelang.org/specification/&#34;&gt;specification&lt;/a&gt; that I spent a lot of
time reading on an on and off basis. In the roughly six month between the time
I discovered Hare and the time I started writing &lt;code&gt;tsess&lt;/code&gt; I had probably read
half of the document. I&amp;rsquo;m not sure whether this is me being more mature, the
Hare specification being more accessible (than say, the ISO C standards) or a
case of all of the above, but it was instrumental helping me fit Hare in my
brain.&lt;/p&gt;
&lt;p&gt;Between the specification and overall consistency of the language design, Hare
managed to enter my slow brain faster than any other programming language I
can remember learning. I found one minor inconsistency not worth mentioning,
but I may revisit it in the future.&lt;/p&gt;
&lt;p&gt;While consistency probably plays a role, my favorite aspect of Hare is the
emphasis on simplicity. I feel that nowadays simplicity is underappreciated in
the software landscape. Making and keeping a non-trivial system simple is no
small fit. In that regard Rust failed utterly, keeping the core language small
and simple, but not the language we see, the internal representation, the one
the compiler &amp;ldquo;desugars&amp;rdquo; actual Rust code to. I think I eventually had a sugar
overdose that distanced myself from Rust. On the other hand of the spectrum C
is so simple it tips over to being too simplistic in some areas. Meanwhile, Go
has too much magic and I wasn&amp;rsquo;t able to get a good grasp on all the code I
wrote.&lt;/p&gt;
&lt;p&gt;Hare appears to draw inspiration from Rust in the error handling department.
But instead of forcing an arbitrary &lt;code&gt;Result&lt;/code&gt; type down our throat, it enables
any type to become an error by suffixing it with a &lt;code&gt;!&lt;/code&gt; character. Like Rust,
Hare requires error handling. Unlike Hare, Rust is explicit about handling
everything (I mentioned &lt;code&gt;Option&lt;/code&gt; already). Suffixing an expression with &lt;code&gt;!&lt;/code&gt;
tells the compiler that it should be fail-safe, or otherwise abort. The &lt;code&gt;?&lt;/code&gt;
suffix tells the compiler to return from the function if the return value is
an error.&lt;/p&gt;
&lt;p&gt;One thing I would like to see added is a &lt;code&gt;_&lt;/code&gt; suffix to ignore the value of an
expression, and by extension the error cases, effectively casting it to &lt;code&gt;void&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (something &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; wrong) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	fmt&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;fprint&lt;/span&gt;(os&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;stderr, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Something went wrong!&lt;/span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)_;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	os&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;exit&lt;/span&gt;(STATUS_SOMETHING_WRONG);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ignoring a potential failure to write the error message would ensure that the
programs exits with the desired status, instead of aborting.&lt;/p&gt;
&lt;p&gt;This can be done like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;let ign &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; fmt&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;fprint&lt;/span&gt;(os&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;stderr, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Something went wrong!&lt;/span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I&amp;rsquo;m not sure whether the specification will evolve in a stricter direction
where for example you can&amp;rsquo;t have unused variables. The problem with the PDF
specification draft is the lack of git commit to review changes since the
revision I downloaded. I can probably infer it to roughly a year back.&lt;/p&gt;
&lt;p&gt;It also becomes unwieldy to ignore multiple expressions in the same scope,
something that a &lt;code&gt;_&lt;/code&gt; suffix could elegantly solve while still being explicit.
Something you would catch in a code review to dispute or argue.&lt;/p&gt;
&lt;p&gt;Now here is something to watch, I just had an idea and I need to follow my
intuition right now. I will be back soon:&lt;/p&gt;
&lt;img src=&#34;https://dridi.fedorapeople.org/post/introducing-tsess/hypnotoad.gif&#34; alt=&#34;Please be patient&#34; /&gt;

&lt;p&gt;I&amp;rsquo;m back, thank you for your patience. Complaining about the unwieldiness of
the construct above and my suggestion to make &lt;code&gt;_&lt;/code&gt; cast away to &lt;code&gt;void&lt;/code&gt; gave me
the idea to try just that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fmt&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;fprint&lt;/span&gt;(os&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;stderr, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Something went wrong!&lt;/span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And well, it does what I need the way I suggested it without polluting the
code, so I think I have no further complaints about error handling.&lt;/p&gt;
&lt;p&gt;Damn.&lt;/p&gt;
&lt;p&gt;Moving on, another &amp;ldquo;problem&amp;rdquo; with Hare is that it&amp;rsquo;s still under development,
so things change. I have been there since Rust 0.4, but I&amp;rsquo;m also stuck on an
ancient version of Hare because I decided to use the
&lt;a href=&#34;https://c9x.me/compile/&#34;&gt;qbe&lt;/a&gt; package available on Fedora.&lt;/p&gt;
&lt;p&gt;One concrete example is &lt;code&gt;@noreturn&lt;/code&gt; functions, or in more recent versions of
Hare, functions returning &lt;code&gt;never&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fn &lt;span style=&#34;color:#06287e&#34;&gt;some_function&lt;/span&gt;(&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;arg&lt;/span&gt;: some_type) (&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt; error) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	let obj &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; foo&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;allocate&lt;/span&gt;(arg);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	defer foo&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;finish&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;obj);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	bar&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;do_some&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;obj)&lt;span style=&#34;color:#666&#34;&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	bar&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;do_more&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;obj)&lt;span style=&#34;color:#666&#34;&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	bar&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;prepare&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;obj)&lt;span style=&#34;color:#666&#34;&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	os&lt;span style=&#34;color:#666&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;exec&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;obj.cmd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;defer&lt;/code&gt; keyword (inspired by Go?) ensures that &lt;code&gt;obj&lt;/code&gt; is freed if one of
the three functions from the &lt;code&gt;bar&lt;/code&gt; module fails. The problem is that it also
ensures that it is freed before calling &lt;code&gt;os::exec()&lt;/code&gt; that is not supposed to
return. I haven&amp;rsquo;t been able to ponder this much, but I can see cases where a
&lt;code&gt;defer&lt;/code&gt; expression should be evaluated even when the program will not return,
but I don&amp;rsquo;t know what kind of syntax could express both cases in a meaningful
way. Maybe an &lt;code&gt;always&lt;/code&gt; keyword to match the &lt;code&gt;never&lt;/code&gt; type?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;defer&lt;/span&gt; foo::&lt;span style=&#34;color:#06287e&#34;&gt;rm_tmp_dir&lt;/span&gt;(): always;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing I love in Hare is the parity between logical and bitwise boolean
operators. There are gaps like this or the lack of explicit endianness support
in the C standards that I find surprising to still have to this day. There is
however one boolean operator that does not have a counterpart:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (res is error) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// do something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is a &lt;code&gt;match&lt;/code&gt; keyword similar to Rust&amp;rsquo;s, not as ergonomic, but still very
usable. Sometimes it is simpler to go with the &lt;code&gt;is&lt;/code&gt; operator and &lt;code&gt;match&lt;/code&gt; is
arguably overkill. I understand that &lt;code&gt;is&lt;/code&gt; composes just fine with &lt;code&gt;!&lt;/code&gt; but for
this very case I would arbitrate in favor of a little duplication:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666&#34;&gt;!&lt;/span&gt;(this is less_readable)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// do something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// vs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (expr not convoluted) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// do something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also really like that &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt; keywords only operate on loops,
and it&amp;rsquo;s probably for the best that falling through &lt;code&gt;switch&lt;/code&gt; or &lt;code&gt;match&lt;/code&gt; cases
is not possible. The multi-modal &lt;code&gt;for&lt;/code&gt; loop is bold, but so far there has
always been a mode that fits my needs. There&amp;rsquo;s just one thing that irritates
me about both Rust, Go and Hare: what is wrong about the do-while style of
loops? I&amp;rsquo;d love to see a single-mode &lt;code&gt;do expression for ( expression )&lt;/code&gt; kind
of loop.&lt;/p&gt;
&lt;p&gt;While I could complain about the Hare tool chain for being of the kind I do
not like, I would rather point out that the &lt;code&gt;hare&lt;/code&gt; command, unlike &lt;code&gt;go&lt;/code&gt; and
&lt;code&gt;cargo&lt;/code&gt; is a build driver without dependency management. It will only discover
Hare modules and not endeavor to fetch them or introduce a new &amp;ldquo;standard&amp;rdquo; form
of repository. And this is not by accident or lack of implementation so far,
this is a
&lt;a href=&#34;https://harelang.org/blog/2022-04-25-announcing-hare/#introducing-hare&#34;&gt;stated&lt;/a&gt;
design choice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dependencies&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have a module system!&lt;/li&gt;
&lt;li&gt;But no package manager&lt;/li&gt;
&lt;li&gt;Use your distro&amp;rsquo;s package manager&lt;/li&gt;
&lt;li&gt;Choose your dependencies conservatively&lt;/li&gt;
&lt;li&gt;stdlib gets you most of the way there&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;How refreshing!&lt;/p&gt;
&lt;p&gt;If I had to pick one word to summarize Hare, it would be &lt;em&gt;thoughtful&lt;/em&gt;. I could
go on praising or complaining about Hare, but at this rate I would never say a
thing about &lt;code&gt;tsess&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After this small digression it shouldn&amp;rsquo;t come as a surprise that Hare wins
this showdown by a wide margin. I still love Rust and never really liked Go,
but Hare was a major discovery for me in 2023, as big as Git and Varnish a
little more than a decade ago.&lt;/p&gt;
&lt;h2 id=&#34;introducing-tmuxinator&#34;&gt;Introducing tmuxinator&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s rewind back forever ago, after I started using Linux as my main
operating system. It was Ubuntu, and it was a mixture of pleasantness and
frustration because I never really like the &lt;code&gt;apt&lt;/code&gt; ecosystem. I knew about
Fedora but so many things were missing, a different kind of frustration, and
yet I eventually bit the bullet. I became a Fedora contributor the day I
realized I had all the skills needed to maintain some packages I was lacking,
but I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;At some point in my Linux journey, I settled on a terminal emulator called
terminator that I think was unmaintained at the time. It appears to exist as
&lt;a href=&#34;https://gnome-terminator.org/&#34;&gt;Gnome Terminator&lt;/a&gt; today. The whole deal is
to have multiple terminals in the same window, and do interesting things with
them.&lt;/p&gt;
&lt;p&gt;At some point in my current day job, a former colleague tried to convince me
to use &lt;a href=&#34;https://github.com/tmux/tmux/wiki&#34;&gt;tmux&lt;/a&gt; by repeatedly telling me to
use it. I eventually got tired of it and started looking, and that&amp;rsquo;s when I
ran into tmuxinator. I can only assume the name was a reference to both tmux
and terminator but I can&amp;rsquo;t tell for sure. After setting up tmux key bindings
to manage tmux panes almost like terminator terminals (I couldn&amp;rsquo;t use the Alt
key for keyboard shortcuts) I had a close enough setup to replace my previous
one. And on top of that my colleague would no longer bother me about tmux.&lt;/p&gt;
&lt;p&gt;Once the muscle memory was successfully rewired, it was an overall win.&lt;/p&gt;
&lt;p&gt;What does tmuxinator bring to the table? The management of tmux sessions from
a declarative configuration read from YAML files that happen to also be
&lt;a href=&#34;https://github.com/ruby/erb&#34;&gt;ERB&lt;/a&gt; templates, via a command line interface.&lt;/p&gt;
&lt;p&gt;I had been a happy tmuxinator user until it disappeared from the Fedora
repositories. To bring it back on my machine I had to make an RPM and two more
for Ruby gems that also went away. I have no Ruby programming experience and
felt really unfit for maintenance on behalf of Fedora (even though it proved
to be relatively low maintenance).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not particularly interested in Ruby. Interpreted languages are generally
not my vibe and I run away from systems prone to &amp;ldquo;magic&amp;rdquo; constructs and my
understanding is that Ruby is a very dynamic language that encourages magic
syntax tricks.&lt;/p&gt;
&lt;h2 id=&#34;meeting-the-hare-tool-chain&#34;&gt;Meeting the hare tool chain&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;hare&lt;/code&gt; command I already mentioned mainly coordinates operations performed
by other utilities, including the &lt;code&gt;harec&lt;/code&gt; compiler that turns Hare code into
QBE&amp;rsquo;s intermediate language. The &lt;code&gt;hare&lt;/code&gt; command maintains a cache of build
artifacts, its way of dealing with incremental rebuilds.&lt;/p&gt;
&lt;p&gt;The pipeline goes like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;harec&lt;/code&gt; translates &lt;code&gt;.ha&lt;/code&gt; files to a &lt;code&gt;.ssa&lt;/code&gt; file
&lt;ul&gt;
&lt;li&gt;it may also produce a &amp;ldquo;typedef&amp;rdquo; &lt;code&gt;.td&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;qbe&lt;/code&gt; translates the &lt;code&gt;.ssa&lt;/code&gt; file to a &lt;code&gt;.s&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;as&lt;/code&gt; compiles the &lt;code&gt;.s&lt;/code&gt; file to a &lt;code&gt;.o&lt;/code&gt; object file
&lt;ul&gt;
&lt;li&gt;the module may ship &lt;code&gt;.s&lt;/code&gt; files too&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ar&lt;/code&gt; may collect object files into a &lt;code&gt;.a&lt;/code&gt; archive&lt;/li&gt;
&lt;li&gt;rinse next module and repeat&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ld&lt;/code&gt; links &lt;code&gt;.o&lt;/code&gt; and &lt;code&gt;.a&lt;/code&gt; archives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;.td&lt;/code&gt; file could be compared to a &lt;code&gt;.h&lt;/code&gt; file in C, it&amp;rsquo;s just a Hare file
containing the module exported types and symbols.&lt;/p&gt;
&lt;p&gt;If the Hare program is linking to shared objects, &lt;code&gt;cc&lt;/code&gt; is used in place of
&lt;code&gt;ld&lt;/code&gt; for linking.&lt;/p&gt;
&lt;p&gt;And finally, &lt;code&gt;harec&lt;/code&gt; may compile multiple &lt;code&gt;.ha&lt;/code&gt; files into a single &lt;code&gt;.ssa&lt;/code&gt;
(and &lt;code&gt;.td&lt;/code&gt;) file because a translation unit in Hare is a module, so all the
module files must be compiled at once. The &lt;code&gt;hare&lt;/code&gt; program does a little bit
more than just the above, it also manages a system of tags similar to Rust
conditional compilation with the &lt;code&gt;#[cfg_attr]&lt;/code&gt; attribute or &lt;code&gt;cfg!&lt;/code&gt; macro,
except that it takes the form of directories named after tag names, or files
(Hare or assembly) suffixed with tag names.&lt;/p&gt;
&lt;p&gt;To illustrate the process, let&amp;rsquo;s write a &lt;code&gt;hare_build.sh&lt;/code&gt; script with
hard-coded tags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;set&lt;/span&gt; -u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tag_filter&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Pv &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;\+(?!linux|x86_64)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_dir&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;printf&lt;/span&gt; %s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;/usr/src/hare/stdlib/&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;s|::|/|g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_ns&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;printf&lt;/span&gt; %s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;s|::|.|g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_td&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;printf&lt;/span&gt; %s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;s|::|_|g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mod_src&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;dir&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_dir &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;ext&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	find &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$dir&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; -name &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;*.&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$ext&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; -type f |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -v &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$dir&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;/[^+-].*/&amp;#34;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# do not enter sub-modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tag_filter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;build_mod&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#bb60d5&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_td &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	harec -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa -N &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_ns &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -t &lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;.td &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_src &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; ha&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	qbe -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	as -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; s in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;mod_src &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; s&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		as -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;basename &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$s&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; .s&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.o&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$s&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ar -r -c &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.a &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;*.o
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;export &amp;#39;HARE_TD_&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$td&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.td&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find_mods&lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;echo&lt;/span&gt; rt &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# always built&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hare deps -T +linux+x86_64 -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;$2 == &amp;#34;-&amp;gt;&amp;#34; {print $3 &amp;#34; &amp;#34; $1}&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# &amp;#34;foo&amp;#34;; &amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tr -d &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#34;;&amp;#39;&lt;/span&gt; | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# foo bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -Fv .ha | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# only modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grep -wv rt | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# already built first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tsort
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -f -- *.td *.ssa *.s *.o *.a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; mod in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;find_mods &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Building mod &lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$mod&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	build_mod &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$mod&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;prog&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;basename &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; .ha&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;harec -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qbe -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.ssa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;as -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ld -T /usr/src/hare/stdlib/rt/hare.sc -o &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$prog&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;.o *.a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I still relied on &lt;code&gt;hare deps&lt;/code&gt; to collect modules, but otherwise tried to
decompose the logic to better illustrate how the build system is glued
together, for the static linking case. It doesn&amp;rsquo;t honor the &lt;code&gt;HAREPATH&lt;/code&gt; and
probably a lot of other things expected from &lt;code&gt;hare build&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see it in action with a basic program that does nothing, possibly the
smallest legal Hare program:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat hello-void.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export fn main() void = void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hare_build.sh hello-void.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hello-void &amp;amp;&amp;amp; echo OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, let&amp;rsquo;s try a program that writes hello to its standard output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat hello-write.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use rt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;let msg: []u8 = [&amp;#39;h&amp;#39;, &amp;#39;e&amp;#39;, &amp;#39;l&amp;#39;, &amp;#39;l&amp;#39;, &amp;#39;o&amp;#39;, &amp;#39;\n&amp;#39;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export fn main() void = rt::write(1, &amp;amp;msg[0], len(msg))!: void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hare_build.sh hello-write.ha &amp;amp;&amp;amp; ./hello-write
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, let&amp;rsquo;s see it in action with the &lt;code&gt;fmt&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat hello-print.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use fmt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export fn main() void = fmt::print(&amp;#34;hello\n&amp;#34;)!: void;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./hare_build.sh hello-print.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod rt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod encoding::utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod errors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod types
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod math
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod bytes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building mod time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Could not open module &amp;#39;linux::vdso&amp;#39;: typedef variable $HARE_TD_linux::vdso not set
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This shell experiment only goes so far. For modules below the top level it
appears that &lt;code&gt;harec&lt;/code&gt; expects environment variables with &lt;code&gt;::&lt;/code&gt; in their names,
which is not legal for shell variables. At least not possible with a portable
POSIX shell script. Expecting &lt;code&gt;HARE_TD_linux_vdso&lt;/code&gt; would be cleaner, but also
conflict with a top-level module called &lt;code&gt;linux_vdso&lt;/code&gt;. I don&amp;rsquo;t see an obvious
solution to this besides forbidding underscores in module names.&lt;/p&gt;
&lt;p&gt;Overall the tool chain is very lean. I can build the QBE compiler backend in
less than a minute on my machine, including the time needed to browse to its
web site and download a release archive.&lt;/p&gt;
&lt;p&gt;Most of the stack is standard off-the-shelf tools, and the &lt;code&gt;hare&lt;/code&gt; command
takes care of coordinating everything. The directory nature of translation
units make this harder to integrate in a Makefile, compared to the POSIX way
of building C programs and libraries for example.&lt;/p&gt;
&lt;p&gt;I even contributed a couple minor patches as I was playing with it and
building my own RPM for &lt;code&gt;hare&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Still, I proudly managed to commit the unforgivable in that department.&lt;/p&gt;
&lt;h2 id=&#34;the-gnu-build-system&#34;&gt;The GNU build system&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;Autotools&lt;/em&gt; are a widely-hated set of tools that make up the GNU build
system, and operate on top of the venerable &lt;code&gt;make&lt;/code&gt; command. This is a radical
departure from the general simplicity of the Hare ecosystem.&lt;/p&gt;
&lt;p&gt;I wouldn&amp;rsquo;t be surprised if the autotools weren&amp;rsquo;t welcome in the Hare community
after witnessing hostility towards them left and right over the last decade.&lt;/p&gt;
&lt;p&gt;While I share a lot of grievances regarding the autotools, I stand by my
choice. Even good old &lt;code&gt;make&lt;/code&gt; has its share of problems but to this day, &lt;code&gt;make&lt;/code&gt;
is what offers the best level of abstraction for me. And &lt;code&gt;automake&lt;/code&gt; has the
best integration with its underlying &lt;code&gt;make&lt;/code&gt; backend.&lt;/p&gt;
&lt;p&gt;On top of that, it offers many services ranging from the installation of files
of different natures, a decent test driver, and a form of standardization over
a set of &lt;code&gt;make&lt;/code&gt; targets. This is also the only build system I know that erases
itself for distribution, requiring only a shell and &lt;code&gt;make&lt;/code&gt; on top of the
package&amp;rsquo;s tool chain for downstream consumers. Such downstream consumers can
be your operating system&amp;rsquo;s package manager, and for example it integrates out
of the box in an RPM spec.&lt;/p&gt;
&lt;p&gt;I just wish it wasn&amp;rsquo;t oh so complicated underneath.&lt;/p&gt;
&lt;p&gt;When I wrote my first &lt;a href=&#34;https://git.sr.ht/~dridi/vclpp&#34;&gt;toy project&lt;/a&gt; in Rust I
decided to use the autotools and I was happy about the result, but I was also
constantly fighting the Rust tool chain. For &lt;code&gt;tsess&lt;/code&gt; I decided to throw the
towel and use &lt;code&gt;cargo&lt;/code&gt;, I&amp;rsquo;d figure the non-Rust bits later, but I never reached
that point.&lt;/p&gt;
&lt;p&gt;When I rebooted &lt;code&gt;tsess&lt;/code&gt; in Hare, I ended up using the unholy trinity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/autoconf/&#34;&gt;Autoconf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/automake/&#34;&gt;Automake&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/libtool/&#34;&gt;Libtool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;autoconf&#34;&gt;Autoconf&lt;/h3&gt;
&lt;p&gt;There isn&amp;rsquo;t much to say here. The Hare tool chain only brings a handful of
dependencies, and I bring &lt;code&gt;automake&lt;/code&gt;, &lt;code&gt;libtool&lt;/code&gt;, &lt;code&gt;hare&lt;/code&gt; and
&lt;a href=&#34;https://drewdevault.com/2018/05/13/scdoc.html&#34;&gt;scdoc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wrote my own Autoconf macros for Hare configuration, but nothing worth
dwelling on, besides maybe the creation of a &lt;code&gt;HARE_ENV&lt;/code&gt; variable for the
&lt;code&gt;hare&lt;/code&gt; and &lt;code&gt;harec&lt;/code&gt; commands, and the injection of the VPATH into &lt;code&gt;HAREPATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One thing that is not easy to do is deriving the default &lt;code&gt;HAREPATH&lt;/code&gt; from the
&lt;code&gt;hare&lt;/code&gt; command. For the ancient Hare tool chain I&amp;rsquo;m using, &lt;code&gt;hare version -v&lt;/code&gt;
does not inspire confidence and I considered submitting a &lt;code&gt;hare config&lt;/code&gt;
subcommand inspired by &lt;code&gt;pkg-config&lt;/code&gt; to probe the Hare tool chain:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;DEFAULT_HAREPATH&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;hare config harepath&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I will wait until QBE 1.2 is released and &lt;code&gt;qbe&lt;/code&gt;/&lt;code&gt;harec&lt;/code&gt; packages are
updated on Fedora. I&amp;rsquo;m not interested in maintaining more packages locally.&lt;/p&gt;
&lt;h3 id=&#34;libtool&#34;&gt;Libtool&lt;/h3&gt;
&lt;p&gt;Likewise, there isn&amp;rsquo;t much to say about Libtool except that once included it
changes how Automake rules are put together, and incorporating the Libtool
behemoth is what made the rest simpler.&lt;/p&gt;
&lt;p&gt;How ironic.&lt;/p&gt;
&lt;h3 id=&#34;automake&#34;&gt;Automake&lt;/h3&gt;
&lt;p&gt;Normally one would declare a list of programs or binaries, then exhaustively
list its sources, and in theory things just work. Things may only just work
when languages are known to Autoconf, which is obviously not the case here.&lt;/p&gt;
&lt;p&gt;I managed to keep the complications for &lt;code&gt;tsess&lt;/code&gt; relatively under control:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-make&#34; data-lang=&#34;make&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;HARE_BUILD&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; env &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;HARE_ENV&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;HARE&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;LINK&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;HARE_BUILD&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;HAREFLAGS&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -t &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;host_cpu&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$($(&lt;/span&gt;@&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;_HAREFLAGS&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -o &lt;span style=&#34;color:#bb60d5&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;bin_PROGRAMS&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;tsess_SOURCES&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/attach/attach.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/cli/cli.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/config/env.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/config/error.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/config/list.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/config/prop.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/config/sess.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/lexer/lex.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/lexer/tok.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/parser/parse.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/parser/rule.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/text/pos.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/text/scan.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/text/text.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/tmux/proc.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/main.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;nodist_tsess_SOURCES&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/cli/gen/cmd.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	bin/tsess/config/gen/env_vars.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;tsess_DEPENDENCIES&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;tsess_SOURCES&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;nodist_tsess_SOURCES&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;tsess_HAREFLAGS&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	-D &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;TSESS_STRING=&amp;#34;$(PACKAGE_STRING)&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;	-D &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;TSESS_VERSION=&amp;#34;$(PACKAGE_VERSION)&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;tsess_LDADD&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;srcdir&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;/bin/tsess/main.ha
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With Libtool the build is normally driven by &lt;code&gt;COMPILE&lt;/code&gt; and &lt;code&gt;LINK&lt;/code&gt; variables,
and in turn they rely on the configured &lt;code&gt;CC&lt;/code&gt; and &lt;code&gt;CCLD&lt;/code&gt; variables. But if
&lt;code&gt;tsess_SOURCES&lt;/code&gt; contained &lt;code&gt;.c&lt;/code&gt; files instead it would implicitly populate
&lt;code&gt;tsess_OBJECTS&lt;/code&gt; with their &lt;code&gt;.o&lt;/code&gt; counterparts.&lt;/p&gt;
&lt;p&gt;As illustrated earlier, a Hare build is not as straightforward as turning
individual C files into object files and linking them together, so nothing
picks up the &lt;code&gt;.ha&lt;/code&gt; files. This is why &lt;code&gt;tsess_DEPENDENCIES&lt;/code&gt; has to reference
the sources explicitly, to trigger &lt;code&gt;$(LINK)&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;And so only the &lt;code&gt;LINK&lt;/code&gt; variable is overridden to invoke &lt;code&gt;hare build&lt;/code&gt;, and it
appears in the output as a &lt;code&gt;CCLD&lt;/code&gt; operation, which is not inaccurate. This
means that a &lt;code&gt;Makefile.am&lt;/code&gt; file cannot contain rules for both Hare code and
another language managed by the autotools like C, but it is still possible to
have both in the same project in separate Makefiles.&lt;/p&gt;
&lt;p&gt;It would be that simple if it weren&amp;rsquo;t for the &lt;code&gt;nodist_tsess_SOURCES&lt;/code&gt;. Hare
does not have a macro system like C or Rust and encourages code generation
instead, so I decided to find a reason to justify having some.&lt;/p&gt;
&lt;h3 id=&#34;vpath-hell&#34;&gt;VPATH hell&lt;/h3&gt;
&lt;p&gt;At this point it should be mentioned that many things that are not strictly
necessary in &lt;code&gt;tsess&lt;/code&gt; are there for learning purposes. For code generation,
it&amp;rsquo;s not so clear cut as I wanted to avoid disconnecting the documentation
from the code.&lt;/p&gt;
&lt;p&gt;With Automake the &lt;code&gt;make&lt;/code&gt; VPATH contains the build directory and the source
directory. They can be the same directory, which is usually the case when
&lt;code&gt;./configure&lt;/code&gt; is executed. When the configure script is invoked from a
different directory like &lt;code&gt;../tsess/configure&lt;/code&gt; it results in &lt;code&gt;$srcdir&lt;/code&gt; having a
different value than &lt;code&gt;$builddir&lt;/code&gt; and in this example &lt;code&gt;../tsess&lt;/code&gt;. This is why
&lt;code&gt;$(srcdir)&lt;/code&gt; is added escaped to the &lt;code&gt;HAREPATH&lt;/code&gt; so it&amp;rsquo;s expanded by &lt;code&gt;make&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know what &lt;code&gt;$builddir&lt;/code&gt; can be besides &lt;code&gt;.&lt;/code&gt; and I suspect it only exists
for parity. There are others &amp;ldquo;abs&amp;rdquo; and &amp;ldquo;top&amp;rdquo; variants of the VPATH components.&lt;/p&gt;
&lt;p&gt;This means that for a single source tree there can be multiple concurrent
build trees. For example one building with GCC and another with Clang. It also
means that a &amp;ldquo;dist&amp;rdquo; archive, once unpacked, can be mounted read-only and not
dirtied in a continuous integration environment (or fail the build if that
happens).&lt;/p&gt;
&lt;p&gt;Unfortunately there are some gotchas in the VPATH department. For example if
we consider the following suffix rule:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-make&#34; data-lang=&#34;make&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;SUFFIXES&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; .1.scd .1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;.1.scd.1&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;SCDOC&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &amp;lt;$&amp;lt; &amp;gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the source lives in the VPATH outside of the current directory, &lt;code&gt;gmake&lt;/code&gt;
will create the target in the current directory, but &lt;code&gt;bmake&lt;/code&gt; will create it
in the same directory as the source. If the source tree is read-only, or in
general with Automake&amp;rsquo;s model, &lt;code&gt;bmake&lt;/code&gt;&amp;rsquo;s behavior is a problem.&lt;/p&gt;
&lt;p&gt;This is also a problem with tools that don&amp;rsquo;t support searching files from a
&lt;a href=&#34;https://github.com/sphinx-doc/sphinx/issues/5491&#34;&gt;PATH&lt;/a&gt;. In &lt;code&gt;scdoc&lt;/code&gt;&amp;rsquo;s case
there isn&amp;rsquo;t an include feature in the first place, so I used Autoconf instead
to reconstruct the manuals from multiple fragments.&lt;/p&gt;
&lt;p&gt;The downside of this approach is that as far as &lt;code&gt;make&lt;/code&gt; is concerned, the
&lt;code&gt;.scd&lt;/code&gt; files are always seen as updated after the configure step so manual
pages always need to be rebuilt. So even when building from a &amp;ldquo;dist&amp;rdquo; archive
&lt;code&gt;scdoc&lt;/code&gt; fails to erase itself like the rest of the autotools and there is no
actual benefit of shipping the man pages.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s still possible for end users to erase &lt;code&gt;scdoc&lt;/code&gt; at configure time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar xf tsess-0.1.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#007020&#34;&gt;cd&lt;/span&gt; tsess-0.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./configure &lt;span style=&#34;color:#bb60d5&#34;&gt;SCDOC&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;/bin/true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or at least it would be if &lt;code&gt;scdoc&lt;/code&gt; didn&amp;rsquo;t strictly work with standard input
and output. The result of &lt;code&gt;$(SCDOC) &amp;lt;$&amp;lt; &amp;gt;$@&lt;/code&gt; would result in an empty manual.
If it was possible to run &lt;code&gt;$(SCDOC) -o $@ $&amp;lt;&lt;/code&gt; instead, then that would have
been possible. I think this is a concrete example of too much simplicity
making a system simplistic.&lt;/p&gt;
&lt;p&gt;To work around these limitations, I wrote a script called &lt;code&gt;mkmissing&lt;/code&gt; that
rebuilds target based on the checksum of sources. So unless some &lt;code&gt;scd&lt;/code&gt; file
is patched, &lt;code&gt;scdoc&lt;/code&gt; should never be needed during a downstream build from a
release archive.&lt;/p&gt;
&lt;p&gt;And I didn&amp;rsquo;t just wing it, I carefully crafted &lt;code&gt;mkmissing&lt;/code&gt;. For some reason I
really enjoy shell scripting, I can&amp;rsquo;t help it&amp;hellip;&lt;/p&gt;
&lt;p&gt;Other tools like &lt;code&gt;hare&lt;/code&gt; can work with VPATH builds, but the way &lt;code&gt;HAREPATH&lt;/code&gt;
works adds a limitation: a module cannot be split across multiple components
of the &lt;code&gt;HAREPATH&lt;/code&gt;. This is why generated files land in &lt;code&gt;gen&lt;/code&gt; sub-modules:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-make&#34; data-lang=&#34;make&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;nodist_tsess_SOURCES&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;        bin/tsess/cli/gen/cmd.ha &lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;&lt;/span&gt;        bin/tsess/config/gen/env_vars.ha
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thankfully &lt;code&gt;hare&lt;/code&gt; doesn&amp;rsquo;t enforce that sub-modules be sub-directories of their
&amp;ldquo;parent&amp;rdquo; modules. There doesn&amp;rsquo;t seem to be a relationship beyond a logical
hierarchy.&lt;/p&gt;
&lt;p&gt;The idea here is to generate the model for environment variables and the
command line interface based on what the manual says. This way the manual is
authoritative and changes to the documentation are immediately effective, or
at least actionable. The &lt;code&gt;getopt&lt;/code&gt; module (as far as my ancient Hare goes) has
poor ergonomics but an excellent design, so I was able to implement a thin
wrapper on top to get my desired result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tsess -h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Usage: tsess [-h] [-q|-v]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List available subcommands.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Options:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -h              Print usage and exit.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -q              Quiet mode.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -v              Verbose mode.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Subcommands:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  attach          Attach to a session.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  list            List available sessions.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  version         Display the version number.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tsess -h attach
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Usage: tsess attach [-L|-S] &amp;lt;name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Attach to a session.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Options:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -L socket-name  Alternative socket name of the tmux server.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -S socket-path  Alternative socket path to the tmux server.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Parameters:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name            The name of the session.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Throwaway Hare programs generate the Hare sources from the manual fragments,
and that became a problem from cross compilation.&lt;/p&gt;
&lt;h3 id=&#34;cross-compiling-tsess&#34;&gt;Cross compiling tsess&lt;/h3&gt;
&lt;p&gt;Hare currently supports Linux and FreeBSD, and apparently OpenBSD is being
worked on. It also targets the three architectures supported by QBE: x86_64,
aarch64 and riscv64.&lt;/p&gt;
&lt;p&gt;Cross compiling &lt;code&gt;tsess&lt;/code&gt; is incredibly easy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./configure --host=riscv64-unknown-linux-gnu &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_cmd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/cli/gen/cmd.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     gen_env
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      bin/tsess/config/gen/env_vars.ha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CCLD     tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GEN      man/tsess.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file gen_cmd gen_env tsess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_cmd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen_env: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tsess:   ELF 64-bit LSB executable, UCB RISC-V, double-float ABI, version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That alone is quite the payoff.&lt;/p&gt;
&lt;p&gt;I think that it even is easier than cross compiling a C project with a mix
of programs for the build and host architectures.&lt;/p&gt;
&lt;p&gt;Part of this is solved by my local RPM packaging of Hare. In order to build
Hare a &lt;code&gt;config.mk&lt;/code&gt; file is needed to specify the various commands for normal
and cross builds. In the &lt;code&gt;%prep&lt;/code&gt; step of the RPM build I generate the right
configuration on the fly based on the target architecture with a Lua macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;%prep
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;%autosetup -p1 -n %{name}-%{shortcommit}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tee config.mk &amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PREFIX = %{_prefix}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BINDIR = %{_bindir}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MANDIR = %{_mandir}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SRCDIR = %{_usrsrc}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;STDLIB = $(SRCDIR)/hare/stdlib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PLATFORM = %{_host_os}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARCH = %{_arch}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HAREC = harec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HAREFLAGS =
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;QBE = qbe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AS = %{__as}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AR = %{__ar}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LD = %{__ld}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SCDOC = scdoc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HARECACHE = .cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BINOUT = .bin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;%{lua:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;for arch in string.gmatch(macros.hare_arches, &amp;#39;%S+&amp;#39;) do
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local host = arch..&amp;#34;-linux-gnu-&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local host_as = &amp;#34;as&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local host_ar = &amp;#34;ar&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local host_cc = &amp;#34;cc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local host_ld = &amp;#34;ld&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    if arch == macros._arch then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        host = &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        host_as = macros.__as
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        host_ar = macros.__ar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        host_cc = macros.__cc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        host_ld = macros.__ld
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    end
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(string.upper(arch)..&amp;#34;_AS = &amp;#34;..host..host_as..&amp;#34;\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(string.upper(arch)..&amp;#34;_AR = &amp;#34;..host..host_ar..&amp;#34;\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(string.upper(arch)..&amp;#34;_CC = &amp;#34;..host..host_cc..&amp;#34;\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(string.upper(arch)..&amp;#34;_LD = &amp;#34;..host..host_ld..&amp;#34;\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So all I need is to target the host architecture when &amp;ldquo;linking&amp;rdquo; Hare programs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-make&#34; data-lang=&#34;make&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;LINK&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;HARE_BUILD&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;HAREFLAGS&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -t &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;host_cpu&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$($(&lt;/span&gt;@&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;_HAREFLAGS&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt; -o &lt;span style=&#34;color:#bb60d5&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And code generators can override it with their hare flags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-make&#34; data-lang=&#34;make&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bb60d5&#34;&gt;gen_cmd_HAREFLAGS&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; -t &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;$(&lt;/span&gt;build_cpu&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way, there&amp;rsquo;s no need to worry about treating code generation like manual
page generation. The Hare tool chain is a requirement anyway, unlike &lt;code&gt;scdoc&lt;/code&gt;
that I made optional with the help of &lt;code&gt;mkmissing&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;testing&#34;&gt;Testing&lt;/h3&gt;
&lt;p&gt;Hare, like Go and Rust, comes with native support for unit testing in the form
of a &lt;code&gt;@test&lt;/code&gt; attribute that is part of the language specification. I&amp;rsquo;m not
planning to use the &lt;code&gt;@test&lt;/code&gt; attribute in this project.&lt;/p&gt;
&lt;p&gt;As a matter of fact, the 0.1 release of &lt;code&gt;tsess&lt;/code&gt; ships with no automated tests.
I could spend an entire post on why I don&amp;rsquo;t engage in unit testing and prefer
to focus on functional testing and why the proverbial test pyramid should be
considered harmful, but I&amp;rsquo;m already spending an entire post on introducing
&lt;code&gt;tsess&lt;/code&gt; and I believe that so far it still hasn&amp;rsquo;t been formally introduced.&lt;/p&gt;
&lt;p&gt;The bottom line is that I actually have plans for testing and I figured about
fifty percent of the testing architecture. What&amp;rsquo;s certain is that it will rely
on Automake&amp;rsquo;s default test driver.&lt;/p&gt;
&lt;p&gt;For all its flaws, I&amp;rsquo;m convinced that adopting the GNU build system for
&lt;code&gt;tsess&lt;/code&gt; brought more value than liabilities.&lt;/p&gt;
&lt;h2 id=&#34;from-zero-to-zero-dot-one&#34;&gt;From zero to zero dot one&lt;/h2&gt;
&lt;p&gt;The development of &lt;code&gt;tsess&lt;/code&gt; happened in small bursts. It took me much less than
a week&amp;rsquo;s worth of full time work to get to the first release. Except of course
that if I had tried to do everything in one go it would likely have taken more
time. Between bursts I would read or reread parts of the spec, read more code
from the standard library or contribute trivial patches to the project. So I
had time to let whatever I learned sink in or perform some experiments before
putting them in practice on the &lt;code&gt;tsess&lt;/code&gt; code base:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;August 23rd, one evening, built a working lexer&lt;/li&gt;
&lt;li&gt;August 27th, one evening, built a working parser&lt;/li&gt;
&lt;li&gt;Septenber 2nd, one evening, ended up shaving the &lt;code&gt;mkmissing&lt;/code&gt; yak&lt;/li&gt;
&lt;li&gt;October 5th, a train ride, started modeling configuration&lt;/li&gt;
&lt;li&gt;November 23rd, one evening, more work on configuration, first codegen&lt;/li&gt;
&lt;li&gt;December 4th, one evening, command line interface, more codegen&lt;/li&gt;
&lt;li&gt;December 14th, one afternoon, added a &lt;code&gt;tmux&lt;/code&gt; controller&lt;/li&gt;
&lt;li&gt;December 15th, one morning, a minimum viable &lt;code&gt;tmuxinator&lt;/code&gt; replacement&lt;/li&gt;
&lt;li&gt;December 31th, &lt;code&gt;tsess&lt;/code&gt; 0.1 released&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well, most of it happened in December, and of course this project had to start
with a parser.&lt;/p&gt;
&lt;h3 id=&#34;parsing-the-configuration-file&#34;&gt;Parsing the configuration file&lt;/h3&gt;
&lt;p&gt;I enjoy writing parsers. For my day job I worked on several occasions on the
&lt;a href=&#34;https://varnish-cache.org/docs/7.4/reference/vcl.html&#34;&gt;VCL&lt;/a&gt; parser and my
first Rust project was a &lt;a href=&#34;https://git.sr.ht/~dridi/vclpp&#34;&gt;VCL preprocessor&lt;/a&gt; to
experiment with the VCL syntax.&lt;/p&gt;
&lt;p&gt;Why make up my own configuration file format when I could reuse an established
format like &lt;code&gt;tmuxinator&lt;/code&gt; did? The answer is two-fold: I wanted a configuration
format really tailored to the user experience for &lt;code&gt;tsess&lt;/code&gt; and it was a very
good opportunity to evaluate Hare since I worked on more parsers than I can
remember.&lt;/p&gt;
&lt;p&gt;Here is for example the &lt;code&gt;tmuxinator&lt;/code&gt; configuration of my Fedora &amp;ldquo;workspace&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#062873;font-weight:bold&#34;&gt;name&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;fedora&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#062873;font-weight:bold&#34;&gt;root&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;~/fedora&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#062873;font-weight:bold&#34;&gt;windows&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&amp;lt;% for pkg in [&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;haproxy&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;libslz&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;makeself&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;numatop&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;python-funcparserlib&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;python-webcolors&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;ShellCheck&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;tiptop&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;vcsh&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;vmod-querystring&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;]&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;%&amp;gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;- &amp;lt;%= &amp;#34;#{pkg}&amp;#34; %&amp;gt;:&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#062873;font-weight:bold&#34;&gt;layout&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;main-horizontal&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#062873;font-weight:bold&#34;&gt;root&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;~/fedora/&amp;lt;%= &amp;#34;#{pkg}&amp;#34; %&amp;gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#062873;font-weight:bold&#34;&gt;panes&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;- vim &amp;lt;%= &amp;#34;#{pkg}&amp;#34; %&amp;gt;.spec&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;- git status&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&amp;lt;% end %&amp;gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reminder, it&amp;rsquo;s an ERB template producing YAML.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;tsess&lt;/code&gt; my configuration file looks like this instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;fedora&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;~/fedora&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[@pkg@]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;layout&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;main-horizontal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;@pkg@&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;pane.editor.send-keys&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;vim @pkg@.spec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;pane.prompt.send-keys&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;git status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:haproxy]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:libslz]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:makeself]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:numatop]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:python-funcparserlib]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:python-webcolors]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:ShellCheck]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:tiptop]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:vcsh]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:vmod-querystring]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at my needs I took the problem from the other end. Instead of enabling
a programmatic definition of my repetitive windows and panes, I opted for a
window template called &lt;code&gt;pkg&lt;/code&gt; and applied the template to all my windows. It
just so happens that I don&amp;rsquo;t need to further configure individual windows, but
I could do something like this for example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;[pkg:special]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;pane.prompt.split&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In theory I should be able to write this and still send an implicit &lt;code&gt;C-m&lt;/code&gt; key
at the end:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;pane.editor.send-keys&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;vim @pkg@.spec&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the distinction between single- and multi-line properties is missing from
the 0.1 release. So instead I&amp;rsquo;m using the here-document syntax. It&amp;rsquo;s also
possible to use single-quoted strings and here-documents to disable template
expansion.&lt;/p&gt;
&lt;p&gt;This is arguably over-engineered, but again learning purposes&amp;hellip; Also, it&amp;rsquo;s
overall much less engineering than ERB templating (that can embed Ruby code)
and as long as it is not YAML, probably anything is better.&lt;/p&gt;
&lt;p&gt;The configuration format is decently documented in the &lt;code&gt;tsess(5)&lt;/code&gt; manual. The
&lt;code&gt;tsess(1)&lt;/code&gt; manual documents &lt;code&gt;~/.config/tsess/*.tsess&lt;/code&gt; as the default location
for configuration files, but the &lt;code&gt;tsess/&lt;/code&gt; directory is currently omitted.&lt;/p&gt;
&lt;h3 id=&#34;working-with-tmux&#34;&gt;Working with tmux&lt;/h3&gt;
&lt;p&gt;Another thing that inspired &lt;code&gt;tsess&lt;/code&gt; a long time ago happened by accident one
day, innocently running &lt;code&gt;ps&lt;/code&gt;. There, I found quite the unexpected line, with a
single process from the &lt;code&gt;ps&lt;/code&gt; output filling my entire terminal.&lt;/p&gt;
&lt;p&gt;Its command line started like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;sh -c #!/bin/bash  # Clear rbenv variables before starting tmux
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;After collecting the actual shell script with its new line characters present,
I could witness the translation of the YAML configuration into &lt;code&gt;tmux&lt;/code&gt; commands
and shell &lt;code&gt;if&lt;/code&gt; statements. I started looking at the &lt;code&gt;os::exec&lt;/code&gt; module and it
didn&amp;rsquo;t take long to find my marks. Like the &lt;code&gt;getopt&lt;/code&gt; module it is very well
designed, but unlike the &lt;code&gt;getopt&lt;/code&gt; module it also has excellent ergonomics, so
I was ready to move on in no time.&lt;/p&gt;
&lt;p&gt;When it was finally time to start interacting with a &lt;code&gt;tmux&lt;/code&gt; server, I read the
manual and found the control mode, that uses a simple text protocol to issue
commands. Emphasis on simple!&lt;/p&gt;
&lt;p&gt;Hare is one of those languages like Rust that only works with UTF-8 strings,
so using &lt;code&gt;tmux&lt;/code&gt; in control mode would be really no fun if there wasn&amp;rsquo;t a &lt;code&gt;-u&lt;/code&gt;
option to guarantee UTF-8 encoding. Thanks to that it becomes really trivial
to work with off-the-shelf goodies from the &lt;code&gt;strings&lt;/code&gt; and &lt;code&gt;bufio&lt;/code&gt; modules.&lt;/p&gt;
&lt;h3 id=&#34;working-with-strings&#34;&gt;Working with strings&lt;/h3&gt;
&lt;p&gt;Another reason to start my &lt;code&gt;tsess&lt;/code&gt; project was that I was increasingly itching
to work on a parser that would not need to duplicate strings per token. I gave
up quickly when I wrote my VCL preprocessor, as a Rust beginner. Writing my
parser in Rust was incredibly pleasant, besides this failure.&lt;/p&gt;
&lt;p&gt;To explain what I mean by not duplicating strings, consider the following
contents to parse:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;property = &amp;#39;value&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The self-imposed constraint I insisted on keeping was to load the contents
just once (&lt;code&gt;&amp;quot;property = &#39;value&#39;\n&amp;quot;&lt;/code&gt;) and reference tokens in place. In C
that&amp;rsquo;s impossible with null-terminated &lt;code&gt;char *&lt;/code&gt; strings.&lt;/p&gt;
&lt;p&gt;In Varnish Cache, we use the following data structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;e;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} txt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A token has some data, and a &lt;code&gt;txt&lt;/code&gt; field to track the base and end of its text
in the loaded source. In other words, a token would reference a substring of
the source being parsed, in-place. The important thing is of course that a
token must not outlive its source material.&lt;/p&gt;
&lt;p&gt;If C leaves me to my own devices, Rust on the other hand has the ability to
express lifetimes of types in relation to others. So I decided that I wanted
to parse &lt;code&gt;tsess&lt;/code&gt;&amp;rsquo;s configuration in Rust with a single heap allocation.&lt;/p&gt;
&lt;p&gt;I hit my head pretty hard several times on the advanced lifetimes wall, but I
made progress. Approximately a year ago, I read this documentation page on
&lt;a href=&#34;https://doc.rust-lang.org/stable/book/2018-edition/ch19-02-advanced-lifetimes.html&#34;&gt;advanced lifetime&lt;/a&gt;
and that was the breakthrough I needed.&lt;/p&gt;
&lt;p&gt;Here is the commit message I wrote to myself back then:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;lexer: Let lexer::Eval reference its text&lt;/p&gt;
&lt;p&gt;The reason why the first attempt failed was the single lexer lifetime.
Working with a &amp;amp;&amp;amp;str reference allows a distinction between the string
lifetime and the shorter lexer lifetime.&lt;/p&gt;
&lt;p&gt;In fact, an Eval&amp;lt;&amp;rsquo;s&amp;gt; should now be able to outlive the lexer that made
it in the first place, since it&amp;rsquo;s only bound to the source&amp;rsquo;s lifetime.&lt;/p&gt;
&lt;p&gt;The Eval implementation of the Display trait is replaced with Debug, and
now that it carries its own text, it can escape it by itself.&lt;/p&gt;
&lt;p&gt;As a result the main loop now looks like what it was meant to look like
from the beginning, this time with great success.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here is the diff of the main loop in this commit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fn main() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-    for eval in lexer::Lexer::from(SRC) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-        match eval.input {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-            Ok(_) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-                print!(&amp;#34;{} &amp;#39;&amp;#34;, eval);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-                for c in eval.text(SRC).chars() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-                    print!(&amp;#34;{}&amp;#34;, c.escape_default())
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-                }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-                print!(&amp;#34;&amp;#39;\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-            }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-            Err(_) =&amp;gt; println!(&amp;#34;{}&amp;#34;, eval),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;-        };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a00000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;+    for eval in lexer::Lexer::from(&amp;amp;SRC) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;+        println!(&amp;#34;{eval:?}&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;&lt;/span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thank you past me for holding the hand of your future self, me, I couldn&amp;rsquo;t
remember this without you. And I agree with you, the main loop became slightly
more readable.&lt;/p&gt;
&lt;p&gt;So after becoming a master of &lt;code&gt;&#39;a, &#39;b: &#39;a&lt;/code&gt; lifetimes I completed the lexical
analyzer and the parser. Eventually, when it was time to load configuration
files and stop working with a hard-coded &lt;code&gt;str&lt;/code&gt;, I could not figure how to get
a &lt;code&gt;&amp;amp;&amp;amp;str&lt;/code&gt; from a &lt;code&gt;Box&amp;lt;str&amp;gt;&lt;/code&gt; to apply my mighty advanced lifetime scheme.&lt;/p&gt;
&lt;p&gt;I tried many things and they all failed, and that&amp;rsquo;s when I heard about Hare
for the first time. Hare is not as nice as Rust when it comes to massaging
strings to do things with them, but Hare also doesn&amp;rsquo;t have half a dozen types
to represent strings under various circumstances like Rust. I&amp;rsquo;m exaggerating
on purpose here, but this typically the kind of complications that make Rust
hard to fit into one brain without daily practice.&lt;/p&gt;
&lt;p&gt;Hare works with UTF-8 strings. The &lt;code&gt;str&lt;/code&gt; type is just a &lt;code&gt;[]u8&lt;/code&gt; (slice of 8 bit
unsigned integers) in disguise with the promise that it is valid UTF-8. Hare
insists for the most part to work with iterators when it comes to strings. I&amp;rsquo;m
surprised because it was my understanding that UTF-8 ensures that you always
know whether you are at the boundary of a code point, but using indices to get
substrings is not common practice. At least the &lt;code&gt;[]&lt;/code&gt; operator is not available
for &lt;code&gt;str&lt;/code&gt; but we can find byte-wise and rune-wise indexing in the &lt;code&gt;strings&lt;/code&gt;
module.&lt;/p&gt;
&lt;p&gt;The preferred way to work with strings appear to be iterators. I wrote my own
&lt;code&gt;text&lt;/code&gt; module to implement functions like C&amp;rsquo;s &lt;code&gt;strcspn()&lt;/code&gt; on top of iterators
and in general whatever convenience would make sense for the parser. I used it
for the code generators as well.&lt;/p&gt;
&lt;h3 id=&#34;the-first-release&#34;&gt;The first release&lt;/h3&gt;
&lt;p&gt;I struggled with a couple things, like Vim rendering mangled during startup
and until a pane is resized and it looks like a &lt;code&gt;SIGWINCH&lt;/code&gt; was enough. When I
first successfully attached to my &lt;code&gt;fedora&lt;/code&gt; session, it was only a matter of
minutes to migrate my other sessions from &lt;code&gt;tmuxinator&lt;/code&gt; to &lt;code&gt;tsess&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The reason why I took care of a couple &lt;em&gt;TODOs&lt;/em&gt; in the documentation and
performed the release on December 31th was simply to say that this journey to
publishing my first Hare project belonged exclusively to 2023. Yes, I&amp;rsquo;m quite
vain.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not expecting anyone to use it, but I will continue &lt;code&gt;tsess&lt;/code&gt;&amp;rsquo; development
and reach the scope I have in mind before cutting a 1.0 release. Just in case,
you may find it on &lt;a href=&#34;https://git.sr.ht/~dridi/tsess/refs/tsess-0.1&#34;&gt;Sourcehut&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;closing-words&#34;&gt;Closing words&lt;/h2&gt;
&lt;p&gt;As for Hare, I find it to be an interesting language striking an excellent
balance in a spectrum going from C to Rust. I find the cursor between safety
and agency to be where I want it most of the time, possibly where I should
want it if I knew better. I just regret for now the lack of support for macros
because code generation is one thing, but there are other use cases. This is
for one may shoehorn generics in C, but I digress. Just like Rust, I will keep
an eye on Hare, but unlike Rust I may play with Hare on a more regular basis,
starting with exploring &lt;code&gt;tsess&lt;/code&gt; until I can agree to make a 1.0 release.&lt;/p&gt;
&lt;p&gt;I still haven&amp;rsquo;t formally introduced &lt;code&gt;tsess&lt;/code&gt;, but I will assume that you can
get the gist of it after seeing a configuration example and the command line
usage. You can also Read The Fancy Manuals to learn more, but not much more.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>POSIX interactive stupidity</title>
      <link>https://dridi.fedorapeople.org/post/posix-interactive-stupidity/</link>
      <pubDate>Tue, 14 Jul 2020</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/posix-interactive-stupidity/</guid>
        <description>&lt;h2 id=&#34;good-old-unix-bashing&#34;&gt;Good old UNIX bashing&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m a Fedora user, and Fedora is a GNU/Linux system. While GNU stands for
&amp;ldquo;GNU&amp;rsquo;s Not UNIX&amp;rdquo; it is definitely a UNIX-like system and Linux is definitely a
UNIX-like kernel. There are other UNIX-like systems in the wild, and there is
even POSIX: the Portable Operating System Interface. Don&amp;rsquo;t ask me where the X
fits in that acronym, my guess would be to rhyme with UNIX since POSIX is a
UNIX-like family of standards that still carries stupid UNIX limitations from
a different time in computing. POSIX had decades to fix those limitations,
therefore I blame POSIX for the one I will cover today.&lt;/p&gt;
&lt;p&gt;But before that, let&amp;rsquo;s digress a bit.&lt;/p&gt;
&lt;h2 id=&#34;my-stupid-dial-up-modem&#34;&gt;My stupid dial-up modem&lt;/h2&gt;
&lt;p&gt;I already &lt;a href=&#34;https://dridi.fedorapeople.org/post/hardware-tinkering/#wrapping-up&#34;&gt;mentioned&lt;/a&gt; that my
dial-up modem is built on Fedora and coming from me that sounds amazing. The
sad reality is that like most hardware, my modem&amp;rsquo;s firmware is crap.&lt;/p&gt;
&lt;h3 id=&#34;bullshitware&#34;&gt;Bullshitware&lt;/h3&gt;
&lt;p&gt;I can see without a problem the difference between hardware and software. For
technical terms it&amp;rsquo;s a rare occurrence but I find the French equivalent even
better. The French word &amp;ldquo;logiciel&amp;rdquo; is constructed like &amp;ldquo;logicware&amp;rdquo;, which to
me is more expressive than software. But software works for me regardless.&lt;/p&gt;
&lt;p&gt;Then you have different &amp;ldquo;kinds&amp;rdquo; of software, like free software or open source
as defined respectively by the Free Software Foundation (FSF) and the Open
Source Initiative (OSI). The rest to me is bullshitware.&lt;/p&gt;
&lt;p&gt;I suppose it was a trend from the last century to name varieties of software
somethingware: freeware (of course not to be confused with free software, I
mean, who would fall for that?) or shareware. Then there are more legitimate
entries that still register high on my bullshit-o-meter: malware, ransomware
or even bloatware.&lt;/p&gt;
&lt;p&gt;Finally, my personal (least) favorite is firmware. Firmware is software that
controls hardware. I would probably need a whole post to explain why firmware
is bullshit, but in one sentence it&amp;rsquo;s simply software that pretends to be
special.&lt;/p&gt;
&lt;h3 id=&#34;my-modems-firmware&#34;&gt;My modem&amp;rsquo;s firmware&lt;/h3&gt;
&lt;p&gt;My modem was unusable when I unpacked it. It failed to fulfill its main job,
which was to connect me to the internet. I had to call the manufacturer to be
redirected to their unmaintained (likely on purpose) support system, to be
provided with a firmware update.&lt;/p&gt;
&lt;p&gt;The firmware binary is hosted with sources and build instructions. Everything
is present except the vendor&amp;rsquo;s web interface. You can see severely outdated
and vulnerable packages. You can even see build instructions, and that&amp;rsquo;s where
it gets really ugly for me: you need Fedora 5 to cross-compile the firmware.&lt;/p&gt;
&lt;p&gt;When that particular model was released, I can assure you that Fedora already
had two digits in its version numbers. So that is likely an unmaintained tool
chain that they keep reusing from model to model. And don&amp;rsquo;t get me wrong, I&amp;rsquo;m
not complaining about the act of reusing.&lt;/p&gt;
&lt;h3 id=&#34;stupid-self-hosting&#34;&gt;Stupid self-hosting&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m going to need a new firmware update soon, and sadly there is nothing I can
do besides hoping for the vendor to provide a patched firmware. My gut feeling
tells me that this is a bug I could fix myself if I had access to the source
code and the tool chain.&lt;/p&gt;
&lt;p&gt;I wanted to self-host a service that turns out to also get a high stupidity
rating but one full-blown digression is enough. After all this is a post about
something POSIX, I could spend ages before getting to the point.&lt;/p&gt;
&lt;p&gt;After some efforts and a lot of complaining I finally have a hosting setup
that is almost satisfying. I try to access it from a remote location, and it
looks fine. When I try from my laptop I get an invalid TLS certificate.&lt;/p&gt;
&lt;p&gt;I configured the modem to forward TCP packets to ports 80 and 443 to the host
where my service is installed, so what went wrong?&lt;/p&gt;
&lt;h3 id=&#34;stupid-firmware&#34;&gt;Stupid firmware&lt;/h3&gt;
&lt;p&gt;Much like any &amp;ldquo;modern&amp;rdquo; modem or set-top box, the modem can be configured via a
web interface available on the gateway&amp;rsquo;s address. From there I can configure
the DSL connexion, DNS resolvers, some aspects of the router like port
forwarding or DHCP leases.&lt;/p&gt;
&lt;p&gt;The DHCP customizations offered are way too simplistic and I had to configure
the server with a fixed IP address, opting out of DHCP, to even enable port
forwarding reliably.&lt;/p&gt;
&lt;p&gt;The thing I didn&amp;rsquo;t expect was that port forwarding wasn&amp;rsquo;t based on the IP
address but on which side of the modem the request comes from. So inside my
network any request to the public IP address is handled as if the gateway IP
address was used. I checked the packets with &lt;code&gt;tcpdump&lt;/code&gt; and Wireshark.&lt;/p&gt;
&lt;p&gt;So when I try to reach my self-hosted service from inside my private network
I&amp;rsquo;m presented with the TLS certificate of the modem&amp;rsquo;s web interface.&lt;/p&gt;
&lt;h3 id=&#34;working-around-stupidity&#34;&gt;Working around stupidity&lt;/h3&gt;
&lt;p&gt;As I am waiting for my new shiny support ticket to find a solution, I worked
around the problem with &lt;code&gt;iptables&lt;/code&gt;. It&amp;rsquo;s not pretty, but it works. It works,
but I don&amp;rsquo;t want to manually enable or disable the workaround every time I
switch to a different network.&lt;/p&gt;
&lt;p&gt;It was a no-brainer for me that the solution would be a shell script, that I
would manage as a systemd unit. Since systemd has a tight integration with
DBus I thought it would be possible to have a unit that would be triggered by
DBus messages. I couldn&amp;rsquo;t find anything of the sort, but I didn&amp;rsquo;t search hard.&lt;/p&gt;
&lt;p&gt;Then I looked at how to integrate with DBus from a shell script that would
monitor certain messages: if systemd can&amp;rsquo;t trigger executions for me I might
as well have a simple service where the shell scripts listens to the events
I&amp;rsquo;m interested in. What I could find looked too complicated for my taste so
instead of listening to NetworkManager&amp;rsquo;s DBus API I simply used &lt;code&gt;nmcli&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also not too fond of &lt;code&gt;nmcli&lt;/code&gt;, for example &lt;code&gt;nmcli connection monitor NAME&lt;/code&gt;
won&amp;rsquo;t tell me when I connect to or disconnect from NAME. It tells me nothing
when disconnected and only tells me this three times when the connection is
established:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NAME: connection profile changed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not very useful for what I&amp;rsquo;m trying to do&amp;hellip;&lt;/p&gt;
&lt;p&gt;Poking at &lt;code&gt;nmcli&lt;/code&gt; I finally find a combination of two commands to capture the
events I&amp;rsquo;m interested in. First, &lt;code&gt;nmcli connection show --active&lt;/code&gt; lets me know
the current status, and &lt;code&gt;nmcli device monitor wlp2s0&lt;/code&gt; gives me &lt;code&gt;connected&lt;/code&gt; and
&lt;code&gt;disconnected&lt;/code&gt; events for my wireless device.&lt;/p&gt;
&lt;p&gt;At this point I&amp;rsquo;m still playing in my terminal and it&amp;rsquo;s trivial to process the
output of both commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# wireless (dis)connected events&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nmcli device monitor wlp2s0 | grep connected
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# active NAME connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nmcli connection show --active | grep -q &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;^NAME\s&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that it works I put a script together for my systemd service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nmcli device monitor wlp2s0 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep connected |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;read&lt;/span&gt; line
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# disable iptables workaround&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; nmcli connection show --active | grep -q &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;^NAME\s&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# enable iptables workaround&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I start the service and play with my connection while monitoring &lt;code&gt;iptables&lt;/code&gt;
rules and then&amp;hellip; crickets. End of the longer-than-usual digression.&lt;/p&gt;
&lt;h2 id=&#34;interactive-buffering&#34;&gt;Interactive buffering&lt;/h2&gt;
&lt;p&gt;Finally, we can look at my POSIX peeve. Why is nothing happening? And why did
it work in my terminal emulator?&lt;/p&gt;
&lt;p&gt;It turns out to be a fairly easy answer that I knew but forgot after years of
not running into this use case. Writing to the standard output is always
buffered by default, and line-bufferred when writing to a tty. So what I was
seeing from my terminal was very responsive, while the script feeding the
&lt;code&gt;while&lt;/code&gt; loop was waiting for &lt;code&gt;grep&lt;/code&gt; to fill its buffer. It could have waited
for a long long time&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;conditional-buffering&#34;&gt;Conditional buffering&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s rather easy to reproduce in a terminal. I can create a small file and
feed it to grep along with my terminal input:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat &amp;gt;test.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^D
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat test.txt - | grep .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^D &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# hangs until I close cat&amp;#39;s standard input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#007020&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if the output of the &lt;code&gt;grep&lt;/code&gt; command is not a tty, events happen in a
different order:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat test.txt - | grep . | sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^D &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# hangs until I close cat&amp;#39;s standard input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#007020&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;grep&lt;/code&gt; command will perform full buffering since its output goes to the
&lt;code&gt;sed&lt;/code&gt; command&amp;rsquo;s input.&lt;/p&gt;
&lt;h3 id=&#34;standard-buffering&#34;&gt;Standard buffering&lt;/h3&gt;
&lt;p&gt;At this point I could come to the conclusion that &lt;code&gt;grep&lt;/code&gt; is a stupid utility
since it assumes that only a tty implies an interactive workload. My problem
with this assumption is that my workaround script sits in limbo because of
that.&lt;/p&gt;
&lt;p&gt;That conclusion would be slightly incorrect because this assumption is made by
the C runtime. There is a function called &lt;code&gt;setvbuf()&lt;/code&gt; to control the buffering
behavior and the defaults for the &lt;code&gt;stdout&lt;/code&gt; stream are line-buffered for a tty
and fully buffered otherwise.&lt;/p&gt;
&lt;p&gt;I can even verify it with a simple program that will pipe &lt;code&gt;stdin&lt;/code&gt; to &lt;code&gt;stdout&lt;/code&gt;
line by line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#define _POSIX_C_SOURCE 200809L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;line &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;size_t&lt;/span&gt; n &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#06287e&#34;&gt;getline&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;line, &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;n, stdin) &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt;, line);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;free&lt;/span&gt;(line);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#06287e&#34;&gt;ferror&lt;/span&gt;(stdin)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;getline&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (EXIT_FAILURE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (EXIT_SUCCESS);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I will call this program &lt;code&gt;stupidcat&lt;/code&gt; to stay on brand and it will behave like
&lt;code&gt;grep&lt;/code&gt; regarding output buffering:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ c99 -o stupidcat stupidcat.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat test.txt - | ./stupidcat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^D &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# hangs until I close cat&amp;#39;s standard input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat test.txt - | ./stupidcat | sed &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^D &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# hangs until I close cat&amp;#39;s standard input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#007020&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So as it stands, my &lt;code&gt;stupidcat&lt;/code&gt; is as stupid as &lt;code&gt;grep&lt;/code&gt;, but I could add an
interactive mode that would enforce a specific buffering mode and not rely
on defaults. That would slightly increase the amount of code in &lt;code&gt;stupidcat.c&lt;/code&gt;
but nothing scary or groundbreaking.&lt;/p&gt;
&lt;h3 id=&#34;when-sensible-defaults-turn-stupid&#34;&gt;When sensible defaults turn stupid&lt;/h3&gt;
&lt;p&gt;My &lt;code&gt;stupidcat&lt;/code&gt; is stupid by design, but it&amp;rsquo;s only here to illustrate that this
behavior is not &lt;code&gt;grep&lt;/code&gt;&amp;rsquo;s fault. So all I need now is to tell &lt;code&gt;grep&lt;/code&gt; to do line
buffering for my non-tty interactive needs.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s where things become really unpleasant. There is no such option, and
to be fair not only &lt;code&gt;grep&lt;/code&gt; but also &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt; have this problem. Of all
the standard utilities I have used so far only &lt;code&gt;cat&lt;/code&gt; has a &lt;code&gt;-u&lt;/code&gt; option (which
I assume stands for unbuffered).&lt;/p&gt;
&lt;p&gt;Oddly enough, GNU &lt;code&gt;cat&lt;/code&gt; defaults to unbuffered mode and as a result the &lt;code&gt;-u&lt;/code&gt;
options is only supported to be ignored:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat test.txt - | cat | cat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^D &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# hangs until I close the leftmost cat&amp;#39;s standard input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#007020&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While I tend to be unhappy about GNU extensions because they hurt portability,
I&amp;rsquo;m also not surprised that GNU &lt;code&gt;grep&lt;/code&gt; has a &lt;code&gt;--line-buffered&lt;/code&gt; option, nor am
I surprised that GNU &lt;code&gt;sed&lt;/code&gt; has a &lt;code&gt;-u&lt;/code&gt; option (sounds familiar) aliased to
&lt;code&gt;--unbuffered&lt;/code&gt; (sounds familiar) and in that case I have to be in the GNU camp
even though more often than not I am in GNU&amp;rsquo;s camp, but I digress.&lt;/p&gt;
&lt;p&gt;What appals me, is that POSIX 2017 still doesn&amp;rsquo;t have an option for &lt;code&gt;grep&lt;/code&gt; and
&lt;code&gt;sed&lt;/code&gt;, and that the FUTURE DIRECTIONS section of the manuals simply says none.
There might be other pipeline-friendly commands lacking the ability to change
the buffering behavior, there is one that I know of that I will mention later.&lt;/p&gt;
&lt;h3 id=&#34;a-pseudo-solution&#34;&gt;A pseudo solution&lt;/h3&gt;
&lt;p&gt;Another solution would be to have a program that pretends to be a tty to make
other commands buffer on a line-by-line basis. Such a program could &lt;code&gt;openpty&lt;/code&gt;
or &lt;code&gt;forkpty&lt;/code&gt; a pseudoterminal and answer yes to the existential &lt;code&gt;isatty&lt;/code&gt;
question.&lt;/p&gt;
&lt;p&gt;In other words my script could instead look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nmcli device monitor wlp2s0 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep connected |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pty | &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# this line was added&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;read&lt;/span&gt; line
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# disable iptables workaround&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; nmcli connection show --active | grep -q &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;^NAME\s&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# enable iptables workaround&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It turns out though that such solutions exist like GNU &lt;code&gt;stdbuf&lt;/code&gt; or the
&lt;code&gt;unbuffer&lt;/code&gt; command from the &lt;a href=&#34;https://core.tcl.tk/expect/index&#34;&gt;expect&lt;/a&gt; project
but suddenly you need a &lt;a href=&#34;http://tcl.sourceforge.net/&#34;&gt;TCL&lt;/a&gt; runtime. I&amp;rsquo;m not
saying that those programs solve this by pretending to be a tty, but I&amp;rsquo;m
definitely saying that I didn&amp;rsquo;t find a standard POSIX utility to solve this
problem.&lt;/p&gt;
&lt;p&gt;To solve this stupid problem, I can use &lt;code&gt;grep --line-buffered connected&lt;/code&gt; and
be done with it, but what if I want a portable solution to the general problem
of interactive workloads not involving a tty?&lt;/p&gt;
&lt;h2 id=&#34;an-awkward-solution&#34;&gt;An awk(ward) solution&lt;/h2&gt;
&lt;p&gt;A discussion on shell utilities mentioning &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; wouldn&amp;rsquo;t be
complete if &lt;code&gt;awk&lt;/code&gt; wasn&amp;rsquo;t somehow also covered given the overlap that can exist
between the three commands, to which I will promptly remedy.&lt;/p&gt;
&lt;p&gt;As promised, I found another utility that suffers from full buffering if its
output is not a tty, and that command is &lt;code&gt;awk&lt;/code&gt;. While &lt;code&gt;awk&lt;/code&gt; is very different
from &lt;code&gt;grep&lt;/code&gt; and less but still quite different from &lt;code&gt;sed&lt;/code&gt;, my solution was to
emulate my &lt;code&gt;grep&lt;/code&gt; command with a small &lt;code&gt;awk&lt;/code&gt; script.&lt;/p&gt;
&lt;h3 id=&#34;the-wtf-moment&#34;&gt;The WTF moment&lt;/h3&gt;
&lt;p&gt;A quick search quickly led me to the GNU &lt;code&gt;awk&lt;/code&gt; documentation, and as usual you
can always count on &lt;code&gt;awk&lt;/code&gt; when a utility lets you down. According to the docs
all my problems can be solved with the &lt;code&gt;fflush()&lt;/code&gt; function:&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4 id=&#34;fflushfilename&#34;&gt;fflush([filename])&lt;/h4&gt;
&lt;p&gt;Flush any buffered output associated with filename, which is either a file
opened for writing or a shell command for redirecting output to a pipe or
coprocess.&lt;/p&gt;
&lt;p&gt;[&amp;hellip;]&lt;/p&gt;
&lt;p&gt;POSIX standardizes &lt;code&gt;fflush()&lt;/code&gt; as follows: if there is no argument, or if the
argument is the null string (&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;), then &lt;code&gt;awk&lt;/code&gt; flushes the buffers for all
open output files and pipes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wondering why searching for the &amp;ldquo;buf&amp;rdquo; pattern in the POSIX &lt;code&gt;awk&lt;/code&gt; manual yields
nothing this time I look for &amp;ldquo;flush&amp;rdquo; and still no result. I&amp;rsquo;m not sure where
the GNU &lt;code&gt;awk&lt;/code&gt; folks got the idea that this was in POSIX, maybe it was
discussed and strongly considered, but it&amp;rsquo;s not in the POSIX 2017 docs.&lt;/p&gt;
&lt;h3 id=&#34;more-awkwardness&#34;&gt;More awkwardness&lt;/h3&gt;
&lt;p&gt;Since I was in the neighborhood I kept reading to find what knobs I had to
control the standard output and quickly came across a very awkward section:&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4 id=&#34;output-statements&#34;&gt;Output Statements&lt;/h4&gt;
&lt;p&gt;Both &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;printf&lt;/code&gt; statements shall write to standard output by
default. The output shall be written to the location specified by
&lt;code&gt;output_redirection&lt;/code&gt; if one is supplied, as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt; expression&amp;gt;&amp;gt; expression| expression&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In all cases, the expression shall be evaluated to produce a string that is
used as a pathname into which to write (for &lt;code&gt;&#39;&amp;gt;&#39;&lt;/code&gt; or &lt;code&gt;&amp;quot;&amp;gt;&amp;gt;&amp;quot;&lt;/code&gt;) or as a command
to be executed (for &lt;code&gt;&#39;|&#39;&lt;/code&gt; ).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Despite the weird formatting on the POSIX end, I sensed that I was onto
something so I check GNU &lt;code&gt;awk&lt;/code&gt; and &lt;code&gt;nawk&lt;/code&gt; manuals to come to the conclusion
that I could emulate my &lt;code&gt;grep&lt;/code&gt; statement like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;/connected/ {print | &amp;#34;cat&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In other words, for each line from the &lt;code&gt;nmcli&lt;/code&gt; output &lt;code&gt;awk&lt;/code&gt; forks a shell to
execute the &lt;code&gt;cat&lt;/code&gt; command and the &lt;code&gt;cat&lt;/code&gt; command will naturally flush its
output when it exits. And with that the cat is out of the bag, there is no
global solution with &lt;code&gt;awk&lt;/code&gt; and if you script has multiple &lt;code&gt;print&lt;/code&gt; statements
you&amp;rsquo;ll need to pipe them all! (or wrap that in a function.)&lt;/p&gt;
&lt;h2 id=&#34;closing-words&#34;&gt;Closing words&lt;/h2&gt;
&lt;p&gt;I can&amp;rsquo;t remember when I last ran into buffering problems with a shell script,
it must have been at least a few years. The difference between then and now is
that nowadays I try to stick to portable code even when portability is not a
requirement because I can always learn or rediscover something.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a lot of waste to fork a shell and a &lt;code&gt;cat&lt;/code&gt; process to emulate &lt;code&gt;fflush(3)&lt;/code&gt;
but that doesn&amp;rsquo;t bother me. The shell script doesn&amp;rsquo;t run a tight &lt;code&gt;while&lt;/code&gt; loop
and connecting to or disconnecting from a wireless network is not something
that happens continuously. I also love how mentioning in a casual discussion
that to solve a silly networking problem I forked a cat from shell in an awk
script: it sounds like nonsensical plain English you could find in something
like Alice in Wonderland, but I digress.&lt;/p&gt;
&lt;p&gt;The GNU &lt;code&gt;awk&lt;/code&gt; manual also states that forking a shell should be enough to
flush:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;awk &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;/connected/ {print; system(&amp;#34;&amp;#34;)}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even though &lt;code&gt;nawk&lt;/code&gt; behaves similarly, and GNU &lt;code&gt;awk&lt;/code&gt; flushes without forking a
shell for maximum efficiency, I see nothing of the sorts in the POSIX &lt;code&gt;awk&lt;/code&gt;
manual, so I&amp;rsquo;ll stick to my guns and ignore this claim.&lt;/p&gt;
&lt;p&gt;Lessons learned: non free firmwares are to be avoided like a plague and much
like a plague it&amp;rsquo;s kinda hard to avoid, you can&amp;rsquo;t always gawk at a manual and
trust what it says, and POSIX 2017 failed to identify a decades old common
pitfall that can trap even experienced shell script authors.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Hardware tinkering</title>
      <link>https://dridi.fedorapeople.org/post/hardware-tinkering/</link>
      <pubDate>Sat, 30 May 2020</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/hardware-tinkering/</guid>
        <description>&lt;h2 id=&#34;hacking-hardware&#34;&gt;Hacking hardware&lt;/h2&gt;
&lt;p&gt;I have never been a hardware person, I may find my way around software but
when it comes to hardware I have forgotten most of everything I learned about
materials and electronics. It&amp;rsquo;s a shame because I had a knack for the latter.&lt;/p&gt;
&lt;p&gt;And so I have never really hacked hardware or even software dealing directly
with hardware, at best I may tinker with hardware. And even when hardware
embeds some form of software, it&amp;rsquo;s so closed that today it&amp;rsquo;s most likely
impossible to get any kind of hardware appliance loaded with 100% free (as in
freedom) software.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve had a couple recent hardware incidents that I feel are relevant to the
topic of free software. This is the story of computers on my head, in my
pocket, in a purse or on my desk and their unimpressive replacements despite
the constant march of progress. The story of how hard it is to keep a working
computer running.&lt;/p&gt;
&lt;h2 id=&#34;the-computer-on-my-head&#34;&gt;The computer on my head&lt;/h2&gt;
&lt;p&gt;The sad thing about computing today is the diligent work from the market to
remove computing from any computing discussion. Take the cloud for example, a
weatherly word for hosting, probably coined because the word hosting was
tainted by the collective idea that it has to suck, with FTP deployments of
PHP files in a web server users have little control over.&lt;/p&gt;
&lt;p&gt;You will see the media talk about digital and algorithms but not often about
computers. Billions of computers were sold as phones, and yet such phones can
run general purpose operating systems and often do. Everyday I wear a computer
on my head, but we call that a bluetooth headphone.&lt;/p&gt;
&lt;h3 id=&#34;the-best-worst-bluetooth-headphone&#34;&gt;The best worst bluetooth headphone&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m usually not fond of naming and shaming but interactions Philips&amp;rsquo; customer
support were bitter at best. I own a Philips Fidelio M2BTBK headphone, I have
used it for years to my satisfaction. It&amp;rsquo;s supposedly a beefier version of the
Fidelio M1BT, twice as expensive, and yet the ear pads turned out to be a bit
too fragile. Quick search, found some online, not too hard to change after
seeing a video tutorial (you need take a leap of faith to remove them without
breaking anything) and all is well that ends well.&lt;/p&gt;
&lt;p&gt;The next time it broke, quick search, found nothing, longer search, found
nothing. After a couple month ear pads were wearing out to the point where
wearing the headphone was starting to hurt the skin of my ears. One last ditch
effort, I ring the customer support and get a very helpful person on the line
who opens a support case and moves the discussion from phone to email.&lt;/p&gt;
&lt;p&gt;The support gives me a link to an online retailer selling ear pads, I order a
pair and a couple weeks later it found its way into my mailbox. To my dismay
it wasn&amp;rsquo;t even close to compatible with the headphone. The support&amp;rsquo;s answer
was condescending, barely apologizing and condescendingly pointing the
retailer&amp;rsquo;s return policy to me. This time, not one but two links to online
retailers with the correct ear pads. I order to pairs this time, because I
don&amp;rsquo;t want to run into this again next time they break, I want to secure an
advance of one pair.&lt;/p&gt;
&lt;p&gt;A couple weeks later, the new order makes it through again from China to my
mailbox, visiting customs on the way. They definitely look like the ones I
ordered myself the first time, and yet I fail to put them on. Looking closer
at the product description, it says that those ear pads are compatible with
M1BT headphones (and half a dozen other Philips headphones) but it
specifically mentions not being compatible with the M2BT. Time to look for a
new headphone.&lt;/p&gt;
&lt;h3 id=&#34;the-good-the-bad-and-the-fugly&#34;&gt;The good, the bad, and the fugly&lt;/h3&gt;
&lt;p&gt;I had been happy until then with my headphone because it was one of a kind: it
sounds decent, can fall back to wired audio, has great battery life, supports
audio and phone calls, and can pause and resume audio if interrupted by a
phone call. Nothing revolutionary, most recent competing products could do the
same so what set it apart for me was the ability to connect to several devices
concurrently. Pairing with several devices concurrently was the norm, but
connecting to several devices was only something I had seen with bluetooth
speakers so far.&lt;/p&gt;
&lt;p&gt;The first problem is that Philips stopped selling them, and while I can only
assume why, I&amp;rsquo;m convinced that this headphone has severe bugs. I used to have
my laptop and phone connected, so a phone call would pause and resume any
player running on my laptop. I achieved my custom setup using
&lt;a href=&#34;https://github.com/altdesktop/playerctl&#34;&gt;playerctl&lt;/a&gt;, but I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;I have witnessed bugs with the pause and resume feature, which I attribute to
pausing directly from the laptop, desynchronizing the &amp;ldquo;state&amp;rdquo; of the
headphone. My assumption is that it doesn&amp;rsquo;t base the state on whether the
device was transmitting audio, but keeps track of its own internal state
machine, via key presses to pause or play. I&amp;rsquo;m also convinced that software is
involved in the design of the headphone and that this logic is not implemented
100% in hardware. Unfortunately there is no way to my knowledge to debug the
alleged software, and no opportunity for firmware updates.&lt;/p&gt;
&lt;p&gt;Another thing I suspect is that the M2BTBK doesn&amp;rsquo;t scale. I can connect up to
8 concurrent devices, which really sounds (pun intended) overkill, and bugs
probably manifest themselves more often when more devices are competing: only
one device at a time can be audible.&lt;/p&gt;
&lt;p&gt;For a long time I also suspected the headphone to send spurious &amp;ldquo;back&amp;rdquo;
commands, sending the player back to the beginning of a media. But having
purchased a different product this is still happening to me on Android, which
is where it always happened with the M2BTBK. This is very frustrating when it
happens in the middle of a 2h podcast but again, I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;The worst part is probably that it has the same form factor as many Philips
headphones that all share the same ear pads, but for some reason they singled
this one out and gave it similar ear pads with incompatible connections. Even
the audio jack has a custom connector, that has annoyed me from day one,
worrying that if I lost it I would no longer be able to fall back to wired.&lt;/p&gt;
&lt;p&gt;Most bluetooth headphones on the market have the same problems, those are
locked down products that the average customer will never question. But
Philips went the extra mile to ensure that their high-end headphone would turn
into e-waste as soon as anything went wrong.&lt;/p&gt;
&lt;p&gt;Slow clap.&lt;/p&gt;
&lt;h3 id=&#34;the-unimpressive-replacement&#34;&gt;The unimpressive replacement&lt;/h3&gt;
&lt;p&gt;After giving up my perfectly working headphone for lack of ear pads, I looked
for a replacement and it looks like what made it unique back then still
applies today. I couldn&amp;rsquo;t find an alternative that would connect to multiple
devices simultaneously.&lt;/p&gt;
&lt;p&gt;Obviously a new factor in my quest was the ability to purchase spare ear pads
in addition to all the criteria I had from my Fidelio M2BTBK. I traded one
feature with the ability to easily (VERY easily) replace pads with Marshall&amp;rsquo;s
MID Active Noise Reduction headphone.&lt;/p&gt;
&lt;p&gt;I had to give up on connecting to multiple devices, which to this day is still
a pain in the ass since I frequently switch between devices when I use both
but I gained a couple new neat features.&lt;/p&gt;
&lt;p&gt;The first one is the ability to purchase ear pads directly from Marshall
Headphones, and I ordered a pair along with the headphone. Being able to get
them directly from the brand company gives more confidence than having to
search online. The first time I found pads produced by a Chinese company just
fine, the second time it had become impossible because Philips was no longer
selling that product. Why would that company still produce spare parts for a
discontinued product?&lt;/p&gt;
&lt;p&gt;One very interesting feature from the MID ANC is the ability to get input from
both bluetooth and jack audio simultaneously. I have yet to find a use case
for this but well, that&amp;rsquo;s neat. I assume this is a side effect of an actual
documented feature: the headphone can send the bluetooth audio via the jack
wire, for example to another headphone, someone sitting next to you.&lt;/p&gt;
&lt;p&gt;One thing I consider a smart improvement over my previous headphone is the
independence of the noise reduction system. It isn&amp;rsquo;t tied to bluetooth audio
and can be turned on or off even for jack audio. Noise reduction itself is not
impressive (but I have yet to see one that is) and it&amp;rsquo;s mostly good with white
noise, which might come in handy in plane, but I digress.&lt;/p&gt;
&lt;p&gt;On the other hand it has one major (obscure pun intended) anti feature: a
single knob controls everything. Pressing the button will turn the headphone
on or off. Tapping the button will trigger a play or pause command over
bluetooth. Pushing the button forward or backward will send backward and
forward (yes, they got it backwards!) commands and interestingly keeping
button in that direction will trigger fast backward or fast forward actions.
Finally pressing up or down will send commands to turn the volume up or down.&lt;/p&gt;
&lt;p&gt;The problem here is again, trying to change the volume in the middle of a 2h
podcast is a recipe for disaster so no, less isn&amp;rsquo;t always more, having more
controls on the headphone would have made it more usable. The worst part is
that those control don&amp;rsquo;t feel like up/down or forward/backward with the
headphone on but rather like diagonals, adding to the challenge, but I
digress.&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;m almost certain of is that this knob is the first thing that will
physically break. I&amp;rsquo;m not counting ear pads because I can replace those. And I
miss being able to play/pause with my shoulder when my hands aren&amp;rsquo;t free.&lt;/p&gt;
&lt;p&gt;One more feature is the ability to double tap the button to invoke Apple&amp;rsquo;s
stupid voice assistant, but on an Android phone (more on that later) it does
nothing. Again, I&amp;rsquo;m convinced that some kind of software is embedded in the
headphone and it would have been nice^Wdecent to have access to source code
and be able to patch something different in, but that&amp;rsquo;s never going to
happen&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;locked-all-the-way-down&#34;&gt;Locked all the way down&lt;/h3&gt;
&lt;p&gt;Unlike last time when I purchased my Fidelio M2BTBK (and I don&amp;rsquo;t buy a new
headphone every other year) I noticed that many manufacturers advertise high
fidelity audio with aptX. I can only assume that Qualcomm® is aggressively
marketing it since even my old headphone supports it and yet I never heard
about it back then.&lt;/p&gt;
&lt;p&gt;Digging a bit, it looks like Android supports it out of the box, but on my
laptop there is no way Fedora would allow the PulseAudio plugin to be
distributed. A quick search later I found the right package to install and my
laptop was finally able to sound as good as my phone via bluetooth.&lt;/p&gt;
&lt;p&gt;And at this point I can only assume (because I don&amp;rsquo;t care enough to verify)
that aptX is patented, which by definition means that the codec description is
publicly available and free software implementations can be distributed in
countries where software patents aren&amp;rsquo;t a thing, like mine.&lt;/p&gt;
&lt;p&gt;At this point I&amp;rsquo;m not sure whether I even own half of the headphone, but less
than a month after switching headphones another kind of lock down started
hitting the globe.&lt;/p&gt;
&lt;h2 id=&#34;the-computer-in-my-pocket&#34;&gt;The computer in my pocket&lt;/h2&gt;
&lt;p&gt;I often carry a special computer in my pocket. What&amp;rsquo;s so special about it?
Maybe the fact that it can make phone calls, or maybe the fact that it belongs
to one of the most locked down family of products:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;carriers may lock what kind of SIM card is accepted&lt;/li&gt;
&lt;li&gt;phone manufacturers may lock the bootloader&lt;/li&gt;
&lt;li&gt;the baseband processor runs its own operating system
&lt;ul&gt;
&lt;li&gt;sometimes to work around legal requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;the user-facing operating system doesn&amp;rsquo;t grant full privileges
&lt;ul&gt;
&lt;li&gt;and I&amp;rsquo;m not suggesting we need that for regular operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;it may not be possible to install third-party software&lt;/li&gt;
&lt;li&gt;it may not be possible to remove unessential applications&lt;/li&gt;
&lt;li&gt;the multimedia stack may enforce DRMs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And if you go the extra mile you might find that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;components trend toward not being removable
&lt;ul&gt;
&lt;li&gt;even batteries can no longer be replaced once they die&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MicroSD card slots are a thing of the past&lt;/li&gt;
&lt;li&gt;dedicated chips may prevent alternative OSs&lt;/li&gt;
&lt;li&gt;screws may be non standard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The list probably goes on much much further than I can think of, but the gist
of it remains the same even when after years it&amp;rsquo;s time to find a replacement.&lt;/p&gt;
&lt;h3 id=&#34;the-software-in-my-pocket&#34;&gt;The software in my pocket&lt;/h3&gt;
&lt;p&gt;It became apparent quite early in the commercial life of Android that things
weren&amp;rsquo;t looking good on the software front. Manufacturers would come up with
their own graphical layer on top of Android to set themselves apart from the
competition and at some point it became common wisdom (in my computing
circles at least) that only Nexus phones would offer you a proper experience
across the board.&lt;/p&gt;
&lt;p&gt;Besides fiddling with the OS itself they might also pre-install applications.
Carriers might add yet another layer of OS changes and even more applications,
and sometimes they would even deface preexisting applications. All that crap
would significantly increase delays for important software updates.&lt;/p&gt;
&lt;p&gt;I had an HTC Desire purchased via Orange at the time when I decided that my
next phone would be a Nexus. I was able to compare it to a stock HTC Desire
and that&amp;rsquo;s when I realized that the audio player was missing an important
feature that had been awkwardly be replaced by Orange&amp;rsquo;s online music store. I
did not hesitate to flash my phone with a stock HTC image to get rid of all
this crap.&lt;/p&gt;
&lt;p&gt;I also was able to compare it with a Nexus One (and Wikipedia tells me there
are more differences than I thought) but before I could even do that I left
Android for the not-so-happy world of Firefox OS.&lt;/p&gt;
&lt;h3 id=&#34;the-web-is-the-platform&#34;&gt;The web is the platform&lt;/h3&gt;
&lt;p&gt;A new contender on the mobile market took me by surprise, it was Mozilla. One
of those alternatives to Android and iOS that never survive, because most
popular applications are not free and not interested by free (still as in
freedom) platforms.&lt;/p&gt;
&lt;p&gt;This system ticks all the boxes that should have driven me away. The market
was already saturated by Google and Apple, leaving room for nobody else. The
whole operating system was basically a browser engine and the user space so to
speak was made of web applications (I refer to myself as a web hater). The
system itself was based on AOSP and thus very dependent on Android.&lt;/p&gt;
&lt;p&gt;And reviews were overall poor.&lt;/p&gt;
&lt;p&gt;Some people rightfully noted that while Mozilla was (legitimately) complaining
about iOS&amp;rsquo; arbitrary restriction that forced them to use a different browser
engine, they also built a competing system that made it impossible to even
have a different browser. The scariest thing Mozilla did was to reinforce the
idea that the web works hard at superseding the underlying operating system,
but I digress.&lt;/p&gt;
&lt;p&gt;Then a few things happened: I was able to take part of a hackathon at Mozilla
Paris&amp;rsquo; and play with a Firefox OS Flame phone. A Firefox OS emulator directly
available in the desktop browser turned out to be very usable. Even better, I
had a work laptop with a touch screen.&lt;/p&gt;
&lt;p&gt;So in 2014 my venerable HTC Desire was replaced by a Firefox OS Flame phone
which (to my surprise) I did appreciate. I wanted to believe in it, and I even
considered JavaScript development to build applications. That break from
Android was actually beneficial, I really enjoyed my time with my Flame phone
but eventually parts of the screen started to become unresponsive and Mozilla
announced the death of the project.&lt;/p&gt;
&lt;h3 id=&#34;nexus-pain&#34;&gt;Nexus pain&lt;/h3&gt;
&lt;p&gt;I needed a new phone but Firefox OS was no longer on the proverbial table, and
iOS never stood a chance in that regard. There were other systems then, but
nothing convincing enough to take another leap of faith. Back to Android then,
and finally back to the common wisdom of sticking to a Nexus phone.&lt;/p&gt;
&lt;p&gt;There was one problem though. The market kept moving to larger phones to the
point where &amp;ldquo;phablet&amp;rdquo; was coined: tablet-sized phones that had the unique
feature of turning a simple phone call into an awkward scene. While not as
ridiculous the Nexus 6 was larger than the Nexus 5 that was in turn larger
than the Nexus 4 that was in turn larger than my Firefox OS Flame, itself much
larger than my HTC Desire.&lt;/p&gt;
&lt;p&gt;I purchased a Nexus 4, only because I found one of the last new models. One
year later I ordered a very cheap refurbished Nexus 4, but let&amp;rsquo;s not jump
ahead too much.&lt;/p&gt;
&lt;p&gt;The main pain point besides finding a &amp;ldquo;pure&amp;rdquo; Android phone that is not too
large is simple: updates. Turning on an old phone for the first time, I had to
wait for several OS updates before I could start using the device. Thanks to a
new trend of catchy names for security vulnerabilities I was aware that my
device was affected by Stagefright and disabled MMS support. I also reviewed
past Android security bulletins and to keep track of future ones to  make sure
to disable as many things as possible.&lt;/p&gt;
&lt;p&gt;Going back to Android was already painful enough (which again, surprised me
considering Firefox OS&amp;rsquo; limitations) and having to deal with that kind of crap
didn&amp;rsquo;t help. Since my phone was no longer supported it was hard to tell most
of the time whether vulnerabilities were relevant or not. Then Blueborne was
too much, I needed to look at alternatives.&lt;/p&gt;
&lt;h3 id=&#34;android-in-wonderland&#34;&gt;Android in Wonderland&lt;/h3&gt;
&lt;p&gt;Alice wants to establish a secure connection with Bob, but both of them have
Android &amp;ldquo;smart&amp;rdquo; phones. What can they do about it? Nothing. The closest is to
keep devices up to date, but eventually they run out of support, incredibly
fast actually. Welcome to the world of non free software with a tint planned
obsolescence.&lt;/p&gt;
&lt;p&gt;But AOSP is free software, right?&lt;/p&gt;
&lt;p&gt;Indeed, but AOSP is not Android. And most manufacturers ship Android devices.
But AOSP is free software, so there are mostly-compatible alternatives to
Android. Unfortunately at the time CyanogenMod was in the middle of a storm
that gave birth to LineageOS and overall it didn&amp;rsquo;t feel like the right moment
to join either bandwagon.&lt;/p&gt;
&lt;p&gt;Around the same time, a new player based on AOSP appeared out of the blue.
Ubuntu Touch was a hybrid system that could turn phone into a desktop
workstation once plugged (wired or over the air) to an external display and a
keyboard. Canonical had &amp;ldquo;invented&amp;rdquo; the Convergence®©™ that everyone else was
already pitching as the future of mobile. And like Firefox OS this exercise in
futility didn&amp;rsquo;t last long.&lt;/p&gt;
&lt;p&gt;The prospect of flashing a different OS was quickly overtaken by events, and
not setting up an automated reminder didn&amp;rsquo;t help. To make matters worse,
Google threw the Nexus common wisdom down the shitter by replacing its Nexus
product line with Pixel devices. I&amp;rsquo;m not interested in high-end phones, only
usable ones with as little as custom software as possible and this was no
longer an option.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t remember how that happened, but I found a very cheap refurbished Nexus
4 as I mentioned earlier. The USB port on the phone was in a poor state, and I
had to bend the cable to help it recharge the battery. When I was offered with
a refund I changed my mind and decided to keep the spare phone for spare parts
just in case I&amp;rsquo;d keep the device alive a while longer.&lt;/p&gt;
&lt;p&gt;What a foolish reasoning&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;the-unimpressive-replacement-1&#34;&gt;The unimpressive replacement&lt;/h3&gt;
&lt;p&gt;As I was back to using an outdated Android system on my Nexus 4, I was looking
for a sustainable replacement from which I could squeeze years of mileage.&lt;/p&gt;
&lt;p&gt;Thanks to Greg Kroah-Hartman who brought one during a conference I was able to
look at concept device for Project Ara, a sort of pocket computer that would
work like a PC in which you could change parts as you wish, to some extent. An
interesting take on upgrading phone parts each at their own pace. The parts
were overall large and as I remember it the assembled phone was too big for my
tastes. I wanted to believe this project had a future but as far as I was
concerned the writing was on the wall, it would go nowhere. Sadly I was
apparently right.&lt;/p&gt;
&lt;p&gt;The other thing I was aware of was the Fairphone 2. I don&amp;rsquo;t think I had heard
of their first device but the second one made some heavy marketing noise and
partnered with iFixIt who gave them a 10/10 rating for their second device.
Fairphone, it turns out, is trying to change the electronics industry to move
towards longer-lived devices and a better treatment for all people involved in
the supply chain. So you essentially buy an expensive device, but instead of
paying with a bit of money and a lot of blood, you pay slightly more money
than a comparable device would cost with slightly less blood on the balance.&lt;/p&gt;
&lt;p&gt;There were rumours that a Fairphone 3 was around the corner but I bought a
Fairphone 2 nevertheless as my next device. I had a ton of updates that
brought me from Android 5 to Android 7, a huge leap forward, and since then I
have seen a handful of minor updates including security fixes. It&amp;rsquo;s far from
perfect and I had to remove the camera module to perform device encryption but
iFixIt didn&amp;rsquo;t lie: even with my crappy screwdrivers (two of them were enough
since most screws are the same) I was able to tear it down and build it up
again. Twice of course, to put the camera module back, and apparently my
reward for being late in the game was that I ended up with the enhanced second
version of the camera module but its kernel driver prevents the phone to reach
the needed state for the encryption process, and as usual I digress.&lt;/p&gt;
&lt;p&gt;Other than quirks that a technical savvy person like me can bear with, the
only real problem with this phone is that it&amp;rsquo;s even larger than the Nexus 6 I
thought was way too large&amp;hellip; The software issues the Fairphone 2 faces today
are mostly related to the lack of support from Qualcomm® that forces the team
supporting that device to operate blindly, or so I&amp;rsquo;m led to believe. But I
think this is to date the least closed computer I have put in my pocket.&lt;/p&gt;
&lt;p&gt;And by the way yes, Qualcomm®, the same company that makes the bluetooth chip
for the computer on my head. It&amp;rsquo;s a small world after all.&lt;/p&gt;
&lt;h2 id=&#34;the-computer-in-someone-elses-purse&#34;&gt;The computer in someone else&amp;rsquo;s purse&lt;/h2&gt;
&lt;p&gt;My girlfriend&amp;rsquo;s Android phone had been misbehaving for a while and when I
switched phones she considered buying one too. After leaving two lives before
and after my Firefox OS escapade I suggested that maybe it could start a third
cycle and lo and behold, she accepted.&lt;/p&gt;
&lt;p&gt;She could bear with all the crap I had diligently removed over the years
mostly because most of it was invisible, and because MMS didn&amp;rsquo;t matter since
she has Apps®©™ to send or receive pictures. She did notice that I had lent
her a phone with not many apps, mostly because I had disabled many of the
unremovable apps, including system apps. With Wi-Fi at home the lack of 4G
connectivity went unnoticed for a while. Overall a device that doesn&amp;rsquo;t crash
the foreground application every 10 minutes probably felt already like a huge
improvement.&lt;/p&gt;
&lt;p&gt;That reminds me that I was really not happy to see that I could no longer
disable system applications on my brand new Fairphone 2. I had gotten used to
removing a lot of cruft, but it turned out that they are no longer visible by
default and it&amp;rsquo;s easy to show them. As a result I have a very small list of
applications in the launcher, despite installing a few of them from F-Droid
(some of them replacing disabled applications). My phone doesn&amp;rsquo;t react if I
tell it &amp;ldquo;OK Google&amp;rdquo; and overall battery lasts a bit longer, but I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;Later on a few things happened: Fairphone released a third device, and half of
the human population (allegedly) went on lock down.&lt;/p&gt;
&lt;h3 id=&#34;smack-my-snitch-up&#34;&gt;Smack My Snitch Up&lt;/h3&gt;
&lt;p&gt;In the middle of its third life, my beloved Nexus 4 died after 6 years of
interrupted service. Its screen was accidentally smashed, and my initial
thought was that it was fine. I have seen many people use a phone with a
broken touch screen and it&amp;rsquo;s all right. Let me unlock the phone with my thumb,
why does this hurt? Why can I see small cuts on my skin? Oh, it&amp;rsquo;s as good as
dead.&lt;/p&gt;
&lt;p&gt;I treat my computers with a lot of respect. I would normally say care and
respect but I&amp;rsquo;m so clumsy that care would be an overstatement. While the
intent is here, I&amp;rsquo;d say I accidentally dropped that phone probably a hundred
times. My girlfriend drops it once after several months, only once, and she
breaks it. My luck probably beats my clumsiness, according to statistics.&lt;/p&gt;
&lt;p&gt;We quickly set contingency measures in motion, ordering a new phone and
pulling her old phone back from the grave. One problem though, we needed to
back up the contents of ThatOneApp™ and restore it on the active phone to
avoid losing StuffThatAppManages™ since it doesn&amp;rsquo;t support concurrent access
on multiple devices for a given account. Yes, that application is certainly
not free software, and not something I use myself.&lt;/p&gt;
&lt;p&gt;Cornered as I was, that&amp;rsquo;s when I remembered my spare Nexus 4 from which I
would salvage parts (like a screen) if something were to happen. She agreed to
stop using ThatOneApp™ for the time being and give me a chance to save the
day.&lt;/p&gt;
&lt;h3 id=&#34;ifeelstupid&#34;&gt;iFeelStupid&lt;/h3&gt;
&lt;p&gt;You don&amp;rsquo;t find guides to tear down all devices on iFixIt and that&amp;rsquo;s one more
advantage of Nexus or Pixel devices, they tend to be covered. The Nexus 4 has
a 7/10 rating for repairability, therefore it should be fine.&lt;/p&gt;
&lt;p&gt;Of course it is not.&lt;/p&gt;
&lt;p&gt;My crappy set of precision screwdrivers is really really crappy. There are
screws I can&amp;rsquo;t even remove. Compared to the Fairphone 2 the more the progress
the more I feel that I&amp;rsquo;m not going to make it. And of course there&amp;rsquo;s this
ominous comment from the guide:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The glass is fused to both the display and the display frame. So don&amp;rsquo;t crack
the glass unless you&amp;rsquo;re good with a heat gun, or you&amp;rsquo;re fond of replacing
the glass, display, and frame together ($$$).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I was sinking into moderate despair, I decided to take another leap of
faith. I would order screwdrivers from iFixIt and give it a try, which I found
a bit expensive. On the other hand they provided me with a free guide (not
counting the Fairphone 2 guide since the companies partnered) so I would bear
with it. On second thought I wouldn&amp;rsquo;t, for a few more euros I could get their
Essential Electronics Toolkit with all the individual tools I needed plus a
lot more.&lt;/p&gt;
&lt;h3 id=&#34;ifeelbetter&#34;&gt;iFeelBetter&lt;/h3&gt;
&lt;p&gt;Disclaimer: I&amp;rsquo;m not sponsored by anyone to praise iFixIt, I&amp;rsquo;m just a happy
customer.&lt;/p&gt;
&lt;p&gt;I would advise anyone unsure whether they could tear down an electronics
device to order at least that kit. Trying their screwdrivers I came to the
conclusion that my cheap kit was crappy. Tearing down the Nexus 4 became
trivial. The guide doesn&amp;rsquo;t say much about connectors, but in the end they were
easy to remove and put back. Based on my experience with a 10/10 and a 7/10
device I&amp;rsquo;m tempted to say that 6/10 is probably quite hard to deal with, at
least for someone like me.&lt;/p&gt;
&lt;p&gt;After a quick search in the basement I dug up my spare Nexus 4 and moved the
motherboard from one frame to the other and put everything back together. When
I tried to turn the phone on none of the batteries seemed to make a difference
and trying to charge the phone with either battery didn&amp;rsquo;t work. Only then did
I remember what was wrong with my spare device. Tear down again, then swap
daughterboards, rinse, repeat. Now it charges!&lt;/p&gt;
&lt;p&gt;Then the mixed feeling of relief and something hard to explain when the device
finally turned on, and we were able to solve the problem. The Nexus 4 was
brought back to life but remained undead with no real purpose. Had I known
that I would be able to do that, maybe we wouldn&amp;rsquo;t have purchased a new
device.&lt;/p&gt;
&lt;h3 id=&#34;the-unimpressive-replacement-2&#34;&gt;The unimpressive replacement&lt;/h3&gt;
&lt;p&gt;I managed to convince my girlfriend to get herself a Fairphone 3. While I
admire Fairphone for what they envision and want to congratulate them for what
they achieved so far, I was nonplussed by their latest entry.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s again larger, a trend that seems impossible to fight, and modules appear
not to be compatible with the previous device. I get that they have to source
components somewhere and chip manufacturers move on, but that&amp;rsquo;s a device even
more hungry for power than the Fairphone 2 and that&amp;rsquo;s disappointing. They make
very clear that the majority of resource consumption happens in the supply
chain for a device, but I would hope that they&amp;rsquo;d keep devices frugal. Also did
I mention how big it is?&lt;/p&gt;
&lt;p&gt;I can see that Android is making strides and the most noticeable change is the
update system that applies while the device is running and switches to the
update during the next boot. Other than that, I performed the ritual of
disabling all the things I would identify as unremovable crapware without
asking for permission and presented the device as ready to be used.&lt;/p&gt;
&lt;h2 id=&#34;the-undead-computer-on-my-desk&#34;&gt;The undead computer on my desk&lt;/h2&gt;
&lt;p&gt;Now that I had a working Nexus 4 in limbo I was wondering what to do with it.
The spare parts went back to the basement, in the box containing the HTC
Desire and the Firefox OS Flame. That&amp;rsquo;s when it occurred to me that I could
give a try to an alternative operating system.&lt;/p&gt;
&lt;h3 id=&#34;the-android-clone&#34;&gt;The Android clone&lt;/h3&gt;
&lt;p&gt;LineageOS is still alive and kicking, and only CyanogenMod appears to be
scarred by the controversy dating back to the hostile fork. Looking at the
latest LineageOS release, and the latest Nexus 4 build lagging what looks like
two major releases behind I was not feeling very confident. It would likely
improve the situation but also freeze it in time, not much of an improvement.&lt;/p&gt;
&lt;h3 id=&#34;the-flame-still-burns&#34;&gt;The Flame still burns&lt;/h3&gt;
&lt;p&gt;Firefox OS was abandoned, but from its ashes KaiOS was born. Let&amp;rsquo;s look at the
list of supported devices&amp;hellip; Oh, no Nexus 4, not even my Flame phone? Next.&lt;/p&gt;
&lt;h3 id=&#34;the-gnulinux-mad-house&#34;&gt;The GNU/Linux mad house&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s one &lt;a href=&#34;https://puri.sm/products/librem-5/&#34;&gt;phone&lt;/a&gt; designed to run a
general purpose Linux distribution, with specialized applications nevertheless
for the phone factor to my knowledge. However I&amp;rsquo;m pretty sure there are no
plans for PureOS to support the Nexus 4 hardware.&lt;/p&gt;
&lt;p&gt;The other mad scientist project is &lt;a href=&#34;https://postmarketos.org/&#34;&gt;PostmarketOS&lt;/a&gt;
and I really recognize myself in their pitch:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We are sick of not receiving updates shortly after buying new phones. Sick
of the walled gardens deeply integrated into Android and iOS. That&amp;rsquo;s why we
are developing a sustainable, privacy and security focused free software
mobile OS that is modeled after traditional Linux distributions. With
privilege separation in mind. Let&amp;rsquo;s keep our devices useful and safe until
they physically break!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course I don&amp;rsquo;t belong to the OS development part, but overall I agree with
their goals. The technical details are also very interesting and development
seems to bear much less overhead than what I expected. Oh and it works with
Nexus 4 hardware!&lt;/p&gt;
&lt;p&gt;Except that working is an overstatement, and it is not working with a mainline
Linux kernel. They seem to be stuck with whatever source code we had during
the device&amp;rsquo;s prime. It hasn&amp;rsquo;t reached the point where I could participate,
period.&lt;/p&gt;
&lt;p&gt;Not a GNU system, not a mainline Linux kernel, next.&lt;/p&gt;
&lt;p&gt;But hey, I want to see both PureOS and PostmarketOS succeed!&lt;/p&gt;
&lt;h3 id=&#34;the-impressive-replacement&#34;&gt;The impressive replacement&lt;/h3&gt;
&lt;p&gt;Last try: when Canonical pulled the plug on Ubuntu Touch, it seems that some
people really liked it and formed a community to continue its development. I
heard a lot about Ubuntu Touch when Canonical was trying to enter the market,
and the user interface sounded weird, but I never bothered to look at their
concept of scopes.&lt;/p&gt;
&lt;p&gt;The installation process was truly impressive. The installer is not available
in Fedora repositories but a Snap package is present and recommended. Snaps
had never worked for me on Fedora but maybe this time it would work. It did,
and the installer was able to detect the Nexus 4 without a glitch. It took me
around 5 minutes to install the &lt;code&gt;snapd&lt;/code&gt; RPM, install the UBports Installer
snap, flash my device and remove UBports installer and &lt;code&gt;snapd&lt;/code&gt; from my system.&lt;/p&gt;
&lt;p&gt;Truly impressive.&lt;/p&gt;
&lt;p&gt;The version of the system was OTA-11 (which I assume means Over The Air update
11) and while I don&amp;rsquo;t understand the scope concept that didn&amp;rsquo;t stop me from
installing applications and finding my way around. Navigation was a bit
confusing, but I&amp;rsquo;m fully aware that I was primed by Android experience. I
think it&amp;rsquo;s mostly fine, except that the back button is often around the top of
the screen which can put some strain on the thumb. Ubuntu Touch on my
Fairphone 2 would probably kill my hand on the spot.&lt;/p&gt;
&lt;p&gt;The system was very responsive and I haven&amp;rsquo;t seen a glitch yet. At the same
time that&amp;rsquo;s not my daily driver. But installing and updating applications
worked just fine.&lt;/p&gt;
&lt;p&gt;A couple weeks later I noticed that
&lt;a href=&#34;https://ubports.com/blog/ubports-blog-1/post/ubuntu-touch-ota-12-release-276&#34;&gt;OTA-12&lt;/a&gt;
was available but it showed up as &amp;ldquo;Version 10&amp;rdquo; in the settings. The upgrade
went smoothly, the only nitpick I have is the lack of information about what&amp;rsquo;s
happening besides 3 blinking dots. The changelog is impressive and apparently
scopes are gone, but I didn&amp;rsquo;t notice a major difference. I may never know what
the fuss was all about.&lt;/p&gt;
&lt;p&gt;I have yet to give the Convergence®©™ a try and for now my Nexus 4 will stay
undead but it might start its fourth life at some point. Everything I tried
worked like a charm, so finally this old device has up-to-date software. Or
does it? The device build description seems to imply that the Android kernel
was compiled in user debug mode, whatever that means, it dates back to 2016
and belongs to the 4.4 series.&lt;/p&gt;
&lt;p&gt;That doesn&amp;rsquo;t look reassuring and I couldn&amp;rsquo;t find a definitive answer after a
quick search, sigh. On the other hand I didn&amp;rsquo;t ask anyone from the project
mainly because I don&amp;rsquo;t want to waste anyone&amp;rsquo;s time with my petty questions
unless I&amp;rsquo;m planning to seriously ramp up my Ubuntu Touch usage which is not on
my agenda, yet.&lt;/p&gt;
&lt;p&gt;Oh and of course I had to download and try a game on the first day, and I was
able to get my best score ever on the first try:&lt;/p&gt;
&lt;img src=&#34;https://dridi.fedorapeople.org/post/hardware-tinkering/ubuntu-touch-2048.jpg&#34; alt=&#34;The protective film is still on the screen&#34; /&gt;

&lt;p&gt;I wish UBports the best, they seem to do an amazing work and I really feel
that Canonical was onto something with Ubuntu Touch.&lt;/p&gt;
&lt;h2 id=&#34;the-computer-in-my-closet&#34;&gt;The computer in my closet&lt;/h2&gt;
&lt;p&gt;If I managed to keep my Nexus 4 alive (though currently undead) for that long,
with great difficulty, I can&amp;rsquo;t say the same for the laptop in my closet. This
one didn&amp;rsquo;t get the basement treatment but it&amp;rsquo;s close enough.&lt;/p&gt;
&lt;h3 id=&#34;non-free-software-end-of-life&#34;&gt;Non free software end of life&lt;/h3&gt;
&lt;p&gt;My girlfriend has her own laptop, and it&amp;rsquo;s &amp;ldquo;powered&amp;rdquo; by Windows 7 (if you ask
me I&amp;rsquo;d rather say &amp;ldquo;crippled&amp;rdquo;). For almost a year now we were in parleys over
the incoming end of support and what to do next. She didn&amp;rsquo;t want to upgrade to
Windows 10, but it would also be hard to convince her to use &amp;ldquo;my Fedora
thing&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;In January when Windows 7 finally died we agreed to make an inventory of what
she currently uses on this computer (not much besides a web browser and an
office suite) and make sure the alternative OS would cover the current needs.
Then we&amp;rsquo;d try a live CD to check hardware support and if stars aligned the
next step would be a dual boot setup.&lt;/p&gt;
&lt;p&gt;Since she&amp;rsquo;s a teacher we decided to follow the plan during the next school
holidays, but before that could happen we&amp;rsquo;d have to deal with the COVID-19
pandemic. I didn&amp;rsquo;t have a contingency plan for that.&lt;/p&gt;
&lt;h3 id=&#34;the-impressive-replacement-1&#34;&gt;The impressive replacement&lt;/h3&gt;
&lt;p&gt;As she began to teach kids remotely problems started to crop up. The last
straw was a microphone problem I couldn&amp;rsquo;t solve: on battery everything would
be fine but once plugged a constant noise would be picked up by the microphone
and it apparently only happens for this remote teaching web application.&lt;/p&gt;
&lt;p&gt;Running out of ideas I had to resort to creative thinking again. I remembered
having my 2011 laptop computer in my closet, so maybe it was worth a shot?
Last time I had used it was around two years ago, so I had three major Fedora
upgrades to perform over one weekend. They took forever, the hard disk drive
is probably not going to last long but there is nothing important there. Since
this is not a Nexus 4 device replacing that part will be easy when push comes
to shove. On the next weekend I upgraded to Fedora 32, and for one week she
had access to a perfectly fine Fedora 31 system.&lt;/p&gt;
&lt;p&gt;Besides the slow, very slow hard disk, slowing down everything from boot to
packages updates or first launches of applications, it is very, very, very (I
insist) responsive. It might certainly not fit the bill for AAA gaming, and
none of my devices do but it otherwise works almost perfectly fine. The only
problem I encountered is the halting restart. Shutting down the computer works
fine, trying to restart it halts it, in a state waiting to be powered down
using the hardware switch. And of course it&amp;rsquo;s hard to get two hours of battery
life without doing anything productive, and while it&amp;rsquo;s removable I&amp;rsquo;m not sure
I can find a compatible replacement. Therefore this laptop can only be used
like a good old desktop computer, but at least it has none of the problems the
Windows laptop has.&lt;/p&gt;
&lt;p&gt;Shocking: none of the hardware is supported by &lt;a href=&#34;https://fwupd.org/&#34;&gt;LVFS&lt;/a&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Luckily for me, two years ago I installed &lt;a href=&#34;https://mate-desktop.org/&#34;&gt;MATE&lt;/a&gt; in
addition to &lt;a href=&#34;https://xfce.org/&#34;&gt;Xfce&lt;/a&gt; and left MATE as the default even though
Xfce is still my desktop environment of choice. And MATE seems to be intuitive
enough for her, at least for me it&amp;rsquo;s slicker than Xfce but somehow utterly
fails to convince me to switch. But I digress.&lt;/p&gt;
&lt;p&gt;Computing being computing, maybe installing Fedora on her laptop won&amp;rsquo;t make a
difference. Maybe some power chord is too close to the microphone&amp;rsquo;s cable and
it creates hardware interferences? Or maybe it&amp;rsquo;s a software problem since it
only happens with the remote teaching web application and not with other kinds
of audio or video conferencing software?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m willing to bet on Fedora, fully aware of my own bias. This laptop has
nothing really impressive for itself. What&amp;rsquo;s really impressive is that, who
would have guessed, computers can last and we don&amp;rsquo;t need to replace them too
often. Sadly laptop computers today are even harder to repair and have less
moving parts, less parts that can be individually replaced. One would argue
this is a requirement for very slim and light devices, but I think this is
only an excuse to justify more planned obsolescence. And as professional
dealing with servers we worry a lot more about hardware faults or bit rot and
tend to forget that devices with less intensive usage can last longer.&lt;/p&gt;
&lt;h2 id=&#34;wrapping-up&#34;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The positive result of my various hardware experiences of the past few month
is that I still have some degree of liberty for a small subset of my hardware
and I no longer need parleys to exorcise Windows from my home.&lt;/p&gt;
&lt;p&gt;I will keep an eye on Ubuntu Touch and PostmarketOS, but really I would prefer
to run Fedora on all my devices. We also have one more Windows device, a
netbook, more than ten years old. If it has an x86 32bit processor, Fedora (or
even any Linux-based system) might no longer be an option. We&amp;rsquo;ll see what we
do with the computer in the drawer, but not today.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll say it once more, if you think you might hypothetically need tools to
tinker with electronics devices in the future, don&amp;rsquo;t wait until midden lands
on the windmill. My recommendation goes to iFixIt for the quality of their
tools and the helpful repair guides, whether they originate from a partnership
or were authored by individuals not from the iFixIt staff.&lt;/p&gt;
&lt;p&gt;And this longest post (to date) was also the one that took me the longest to
write, over two months. As events unraveled I ended up with much more to tell
than initially planned. The smaller the device, the harder it is to keep it
alive over the years, and that&amp;rsquo;s the sad reality of computing today. Some
companies, under the cult of innovation even treat hardware as a commodity and
the market gives the same incentive to everyone else, but there are still a
few folks trying to reverse or slow down the trend. For this reason I&amp;rsquo;m also
keeping an eye on the &lt;a href=&#34;https://e.foundation/&#34;&gt;/e/&lt;/a&gt; project (but seriously next
time work on a better name) and it supports the Nexus 4 but like LineageOS it
seems to be stuck a couple major AOSP releases behind.&lt;/p&gt;
&lt;p&gt;And well, I could keep rambling on this topic so maybe next time I will talk
about the other computers on my desk like my NAS or my docking station that is
simply a computer in disguise, my bluetooth speaker that can take firmware
updates or my dial-up modem built on Fedora, or even my main and current
laptop. Spoiler alert, none of them are any less closed and I&amp;rsquo;ll probably use
the word crap or its variants as many times if not more.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xfce presentation mode</title>
      <link>https://dridi.fedorapeople.org/post/xfce-presentation-mode/</link>
      <pubDate>Fri, 04 Oct 2019</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xfce-presentation-mode/</guid>
        <description>&lt;h2 id=&#34;friendship&#34;&gt;Friendship&lt;/h2&gt;
&lt;p&gt;I remember from when I joined my current &lt;code&gt;$DAYJOB&lt;/code&gt;, the CTO looked me in the
eyes and explained that I could choose my own work environment with a caveat:
if I picked Windows the rest of the team would be instructed to always point a
finger in my direction and laugh whenever they see me.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t remember my exact reaction, but I was probably trying hard to suppress
a smile, maintaining a poker face and replying with what I hoped was a casual
&amp;ldquo;cool&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;m writing about one of those topics that can end a friendship like a
favorite operating system, text editor or desktop environment.&lt;/p&gt;
&lt;p&gt;So of course my favorite operating system is Fedora, but I&amp;rsquo;m not using Fedora
Workstation because Gnome 3 drives me mad whenever I get to use it. I started
with Gnome 2 and was very satisfied with it, but I would run into magic
corners and other features that weren&amp;rsquo;t compatible with me. I tried Unity and
actually enjoyed what they were pushing but again, small usability quirks that
didn&amp;rsquo;t work for me on a daily basis eventually led to an accumulation of
frustration that was unbearable for me. And incidentally I was using Unity at
a previous &lt;code&gt;$DAYJOB&lt;/code&gt; and didn&amp;rsquo;t have much of a choice.&lt;/p&gt;
&lt;p&gt;So instead I quickly settled for Xfce. It hardly gets in my way, it&amp;rsquo;s sort of
minimalist and yet featureful, and its overall architecture makes sense to me
on paper: I have no experience with desktop environment development. Except
that of course it also manages to drive me mad under certain very narrow
circumstances when I&amp;rsquo;m giving a presentation or training a team: when I press
&lt;code&gt;Alt+Tab&lt;/code&gt; to cycle between open windows it shows up on the presentation screen
or projector.&lt;/p&gt;
&lt;p&gt;Please note that any harsh words are not directed to a group of people, but
merely stating how I feel about software. Let&amp;rsquo;s stay on friendly terms, pretty
please 😊.&lt;/p&gt;
&lt;h2 id=&#34;my-xfce-in-fedora&#34;&gt;(My) Xfce in Fedora&lt;/h2&gt;
&lt;p&gt;While I&amp;rsquo;m a big fan of Xfce, I think that the stock experience leaves too much
to desire. Thankfully I have all I need on Fedora to fix everything I don&amp;rsquo;t
like. For example I use the
&lt;a href=&#34;https://gottcode.org/xfce4-whiskermenu-plugin/&#34;&gt;Whisker Menu&lt;/a&gt; and previously
used Docky to replace the dock-like panel from the stock setup until it went
defunct. Actually further than its retirement, I used it until it would block
a major Fedora upgrade. That&amp;rsquo;s when I discovered
&lt;a href=&#34;https://launchpad.net/plank&#34;&gt;Plank&lt;/a&gt; that thankfully worked as a drop-in
replacement. Despite my distaste for Gnome, I still prefer their display
manager over Xfce&amp;rsquo;s, so I happily take what works for me. I know, I&amp;rsquo;m praising
the same folks who make a desktop environment that &amp;ldquo;drives me mad&amp;rdquo; to quote
myself.&lt;/p&gt;
&lt;p&gt;I switch themes every couple years if I manage to get enough bored to look for
a new one so all in all Xfce despite a bad stock experience, it is with little
customization effort that I got myself a very serviceable desktop environment
that has pleased me for a while now, including some of the stock applications.&lt;/p&gt;
&lt;p&gt;A year ago I tried the MATE desktop and found it amazing and a lot more
polished than Xfce and yet it wasn&amp;rsquo;t enough to make me switch. I also ran into
a lot of bugs when the Xfce maintainer for Fedora polled our mailing list to
find whether we should follow the unstable 4.13 branch. A lot of bugs here
means a couple, because yes, even running into a few bugs is more than I&amp;rsquo;m
used to with Xfce. This was also their transition from GTK+ 2 to GTK+ 3, and
others on the mailing list were less lucky and ran into many severe bugs.&lt;/p&gt;
&lt;p&gt;But I digress here, now that Xfce 4.14 is available on Fedora 30, I&amp;rsquo;m saw
what&amp;rsquo;s on the other side of the 4.13 tunnel and while it was pleasant to get
the new features incrementally, I didn&amp;rsquo;t get one small change I&amp;rsquo;ve wanted for
a few years already. I had a short window of free time where I felt I could
look into that, and so I did.&lt;/p&gt;
&lt;h2 id=&#34;hacking-xfce-on-fedora&#34;&gt;Hacking Xfce (on Fedora)&lt;/h2&gt;
&lt;p&gt;To be clear, I&amp;rsquo;m mostly documenting this for myself just in case I revisit
Xfce in the future. If you find this helpful, don&amp;rsquo;t hesitate to let me know.&lt;/p&gt;
&lt;h3 id=&#34;trial-and-mostly-error&#34;&gt;Trial and (mostly) error&lt;/h3&gt;
&lt;p&gt;My first thought was to build my own RPM in &lt;code&gt;/usr/local&lt;/code&gt; and change some
systemd configuration to point to &lt;code&gt;/usr/local/bin/xfwm4&lt;/code&gt;. I could easily
revert that change without network access or further packaging update (likely
a downgrade) if I ended up bricking my desktop.&lt;/p&gt;
&lt;p&gt;In hindsight I&amp;rsquo;m really happy I couldn&amp;rsquo;t figure how my system knew which
window manager to pick (if you know, feel free to email me) so I decided to
look at Xfce&amp;rsquo;s documentation and found nothing really helpful. I did come
across &lt;a href=&#34;https://github.com/schuellerf/xfce-test&#34;&gt;xfce-test&lt;/a&gt; and besides being
in unfamiliar Ubuntu territory (I only realized later that a Fedora 29 branch
exists) it also was denied execution by the default SELinux policy. I might
shave this yak someday, but this was enough to convince me not to engage this
route: besides pleasing SELinux I ultimately needed to also learn how to write
automated tests.&lt;/p&gt;
&lt;p&gt;My next step was to try inside a virtual machine, something I for some reason
have trouble doing with a Fedora guest. I turned to my familiar tools, Vagrant
and Virtual Box. A quick search taught me how to start a VM with multiple
monitors (something I wasn&amp;rsquo;t even sure xfce-test supported) and looking
through Vagrant&amp;rsquo;s atlas I found official Fedora images hosted by the Fedora
Project itself (yay!) but the only one available was the Cloud (meh!) edition.&lt;/p&gt;
&lt;h3 id=&#34;first-success&#34;&gt;First success&lt;/h3&gt;
&lt;p&gt;I started a VM, struggled to install Xfce (more on that later), struggled
again to install my modified copy of xfwm4, and then checked that it contained
my modifications. At this point it was only an arbitrary string checked with
the &lt;code&gt;strings&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt; utilities. So far so good, time to reboot the VM and
check that this no-op change didn&amp;rsquo;t break everything. I&amp;rsquo;m prompted for a text
mode login, and from there I have no idea how to actually start Xfce (much
like I have no idea how xfwm4 is started). A quick search without leaving the
VM and I quickly find the magic incantation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start graphical.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And voilà, in my two VirtualBox windows the Xfce wallpaper shows up and after
a couple eternities the desktop is fully functional! Time to automate the
process, which is easily done with the following &lt;code&gt;Vagrantfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$install_xfce &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;lt;&amp;lt;-EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&lt;/span&gt;dnf &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;y upgrade &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# somehow fails&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dnf &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;y upgrade &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# succeeds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dnf &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;y group install &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;Xfce Desktop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60add5&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60add5&#34;&gt;Vagrant&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;configure(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;config&lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vm&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;box &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;fedora/30-cloud-base&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vm&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;provision &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#517918&#34;&gt;inline&lt;/span&gt;: $install_xfce, &lt;span style=&#34;color:#517918&#34;&gt;privileged&lt;/span&gt;: &lt;span style=&#34;color:#007020&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vm&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;provider &lt;span style=&#34;color:#517918&#34;&gt;:virtualbox&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;vb&lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		vb&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;gui &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		vb&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;customize &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;modifyvm&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#517918&#34;&gt;:id&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;--monitorcount&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may notice that I needed to upgrade the package set twice to bring my VM
up to speed. Initially I didn&amp;rsquo;t understand why, and I didn&amp;rsquo;t understand why I
couldn&amp;rsquo;t install my xfwm4 package. The answer was unpleasant.&lt;/p&gt;
&lt;h3 id=&#34;fedora-constrained&#34;&gt;Fedora constrained&lt;/h3&gt;
&lt;p&gt;I should probably mention that I was slightly sleep-deprived as I was spending
my first evening trying to crack this nut. I made my first visible change to
the window manager and still didn&amp;rsquo;t realize that something was very wrong:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNF crashed with a mere &amp;ldquo;Killed&amp;rdquo; in its output&lt;/li&gt;
&lt;li&gt;Xfce took forever to start default applications&lt;/li&gt;
&lt;li&gt;Once started the UI was functional but unresponsive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Several brain cycles later it occurred to me that the VM wasn&amp;rsquo;t fundamentally
slow, it was just swapping like hell. A quick inspection shows defaults of
512MB of RAM and a single CPU with that Vagrantfile.&lt;/p&gt;
&lt;p&gt;I find it sad that DNF is so resource hungry that it can&amp;rsquo;t both update its
index and compute a transaction with limited resources. I&amp;rsquo;m wondering how the
Fedora IoT project copes with that, maybe they use &lt;code&gt;rpm-ostree&lt;/code&gt; instead. One
more thing that happened with DNF is that I couldn&amp;rsquo;t install my modified
package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dnf upgrade /vagrant/xfm4*.rpm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No matter what I would try, it would crash. So instead I opted for &lt;code&gt;rpm -U&lt;/code&gt;
and it happened almost instantly. DNF is way too hungry, and I understand that
it adds value on top of RPM, but I can see the spectre of bloat looming above.
DNF is a black hole: when RPM transactions enter time flies around them and
resources get sucked in by its gravity.&lt;/p&gt;
&lt;h3 id=&#34;clunky-workflow&#34;&gt;Clunky workflow&lt;/h3&gt;
&lt;p&gt;Once I realized what was wrong, I was ready to start hacking in the source
code. I wrote a small shell script that would build a &lt;code&gt;make dist&lt;/code&gt; archive from
source, build an RPM, upload it to the VM using SSH and upgrade the package.
Then with a simple restart of the VM I could give a try to my changes. In this
case I made a change in a label, just to validate the workflow. I updated my
Vagrantfile to provision a usable system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$install_xfce &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;lt;&amp;lt;-EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&lt;/span&gt;dnf &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;y upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dnf &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;y group install &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;Xfce Desktop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60add5&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60add5&#34;&gt;Vagrant&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;configure(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;config&lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vm&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;box &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;fedora/30-cloud-base&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vm&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;provision &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#517918&#34;&gt;inline&lt;/span&gt;: $install_xfce, &lt;span style=&#34;color:#517918&#34;&gt;privileged&lt;/span&gt;: &lt;span style=&#34;color:#007020&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vm&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;provider &lt;span style=&#34;color:#517918&#34;&gt;:virtualbox&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;vb&lt;span style=&#34;color:#666&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		vb&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;gui &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		vb&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;memory &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2048&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		vb&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;cpus &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		vb&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;customize &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;modifyvm&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#517918&#34;&gt;:id&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;--monitorcount&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point I don&amp;rsquo;t need to ask for an upgrade twice&amp;hellip; I specifically don&amp;rsquo;t
enable the &lt;code&gt;graphical.target&lt;/code&gt; unit in systemd because I don&amp;rsquo;t know how to test
the changes without a restart, so for a given VM I get one free try without a
restart. In theory I only need to provision the VM once before I iterate with
my changes, but in practice I rebuilt it from scratch a couple times before
and after I was completely done.&lt;/p&gt;
&lt;p&gt;The only problem with this workflow is that VirtualBox&amp;rsquo;s Linux kernel modules
aren&amp;rsquo;t all part of the mainline releases, and because of Fedora&amp;rsquo;s policy on
out-of-tree modules I get VirtualBox from &lt;a href=&#34;https://rpmfusion.org/&#34;&gt;RPM Fusion&lt;/a&gt;
but I digress&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;working-with-xfwm4&#34;&gt;Working with xfwm4&lt;/h2&gt;
&lt;p&gt;This was not my first dive in the xfwm4 code base, I tried to look at this
problem a couple years ago and didn&amp;rsquo;t get anywhere. I never really had enough
spare time I was willing to allocate to this and it had already taken me some
time to figure which one of the Xfce projects was responsible for the
&lt;code&gt;Alt+Tab&lt;/code&gt; window. This time I was ready to give it all my spare time until the
problem was solved or until I&amp;rsquo;d throw the towel. After one evening spent on
setting up a test environment, I was pleasantly surprised that it would only
take me one evening to write a satisfying patch.&lt;/p&gt;
&lt;h3 id=&#34;all-out-war&#34;&gt;All out war&lt;/h3&gt;
&lt;p&gt;If a discussion about desktop environments or text editors can break a
friendship, arguing about code style can lead to war. Even simple questions as
indentation can become complicated beyond just spaces vs tabs, because I
mean&amp;hellip; How many spaces? Where do you align line continuations? For languages
with a C-like syntax, where do you open curly brackets? Some code styles like
FreeBSD&amp;rsquo;s simply troll you by having both spaces and tabs, open curly brackets
both on the same or next line etc&amp;hellip; And yet it&amp;rsquo;s the C code style I enjoy.&lt;/p&gt;
&lt;p&gt;Thankfully, xfwm4 doesn&amp;rsquo;t follow the GNU code style for C, which I find deeply
unreadable and that is probably a pain to write unless you have very good
support in your text editor. I&amp;rsquo;m not fond of xfwm4&amp;rsquo;s style, and especially the
inconsistencies across files, but it was fine.&lt;/p&gt;
&lt;h3 id=&#34;working-without-safety&#34;&gt;Working without safety&lt;/h3&gt;
&lt;p&gt;In recent years I have been spoiled by my &lt;code&gt;$DAYJOB&lt;/code&gt; where I work on a code
base with extensive functional testing, and between 5 to 10% of the code being
assertions shipped to production. This contributes to increasing my confidence
in making changes, because many mistakes tend to manifest themselves quickly
during the development process and in a helpful way. And of course once you
build enough domain knowledge it becomes easier to deal with an increasingly
familiar code base.&lt;/p&gt;
&lt;p&gt;So leaving my comfort zone to work on a window manager did not bring much
confidence to begin with. Building the code and then running &lt;code&gt;make check&lt;/code&gt;
doesn&amp;rsquo;t seem to do anything. One more reason why xfce-test wouldn&amp;rsquo;t help is
that even if I built an SELinux module to deal with the denial I wasn&amp;rsquo;t even
sure I could even deal with emulating multiple monitors.&lt;/p&gt;
&lt;p&gt;And yet&amp;hellip;&lt;/p&gt;
&lt;p&gt;The code wasn&amp;rsquo;t that hard to browse and adding this feature only took a second
evening, two in total. Working without my beloved seat belts (plenty of tests
and assertions) turned out to be fine even though the project was throwing a
lot of unfamiliar things at me: new code base, GTK+, Glade etc. In no time I
was able to piece things together with reasonable confidence in the absence of
automated and comprehensive testing. I need to stress this point: the GTK+
documentation was easy to browse (winking in the general direction of the
Varnish project) and I found all my answers on the first try. I think I
visited 3 pages of API descriptions in total, way to go!&lt;/p&gt;
&lt;h2 id=&#34;working-on-fedora&#34;&gt;Working on Fedora&lt;/h2&gt;
&lt;p&gt;One thing I love about Fedora is its packaging policy, and in general working
with tooling that allows me to easily build and install my own packages and
not feel that I&amp;rsquo;m throwing random files in random locations that I may forget
about after a couple days.&lt;/p&gt;
&lt;p&gt;I eventually installed the same RPM I was building for the development VM on
my own system and it just worked fine also on bare metal. After submitting the
patches &lt;a href=&#34;https://bugzilla.xfce.org/show_bug.cgi?id=15942&#34;&gt;upstream&lt;/a&gt; I decided
to build the xfwm4 RPM that Fedora ships and simply incorporate them in the
RPM spec. It didn&amp;rsquo;t work&amp;hellip;&lt;/p&gt;
&lt;p&gt;Being familiar with autotools, I quickly realized that a &lt;code&gt;make dist&lt;/code&gt; archive
wouldn&amp;rsquo;t consider the updated Glade files, since those are meant to be
processed by maintainers. The solution was to &lt;code&gt;--enable-maintainer-mode&lt;/code&gt; in
the &lt;code&gt;./configure&lt;/code&gt; invocation and bring in the missing build dependencies. The
point of processing them beforehand being that downstream maintainers don&amp;rsquo;t
have to bother with architecture-independent build dependencies.&lt;/p&gt;
&lt;p&gt;With that I was able to build a &lt;a href=&#34;https://copr.fedorainfracloud.org/&#34;&gt;COPR&lt;/a&gt;
repository and make it available for anyone to give it a try on Fedora very
easily. Unfortunately I collected no test feedback, and the patches have been
sitting in Bugzilla limbos ever since I submitted them, but it seems to be the
case for a lot of xfwm4 tickets.&lt;/p&gt;
&lt;h2 id=&#34;future-contributions&#34;&gt;Future contributions&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m still impressed by the tools we get for free and how it has become
possible to easily test a change to an operating system without risking to
brick a device. At least in this very case.&lt;/p&gt;
&lt;p&gt;Packaging software for Fedora has taken me outside of my comfort zone more
than I can remember, and after this first contact with Xfce code I think I may
attempt more drive-by contributions.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>TLS sandboxing</title>
      <link>https://dridi.fedorapeople.org/post/tls-sandboxing/</link>
      <pubDate>Wed, 28 Aug 2019</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/tls-sandboxing/</guid>
        <description>&lt;h2 id=&#34;reinventing-tls&#34;&gt;Reinventing TLS&lt;/h2&gt;
&lt;p&gt;After being a month away from &lt;code&gt;$DAYJOB&lt;/code&gt; I couldn&amp;rsquo;t help myself not thinking
about TLS sandboxing. But with limited spare time to give this proper thought
I had to come up with something easier to grasp and implement. And as such I
came up with my own &lt;code&gt;SOCK_STREAM&lt;/code&gt; secure layer called MXC.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s very simple: you first agree on a session key using &lt;code&gt;MUL&lt;/code&gt; operations, and
at the end of the handshake the client can send encrypted traffic using &lt;code&gt;XOR&lt;/code&gt;
operations. MXC stands for &lt;em&gt;Multiplication and eXclusive-or enCryption&lt;/em&gt;. I&amp;rsquo;m
waiting for a pending
&lt;a href=&#34;https://twitter.com/Au51in1/status/1090839642277060608&#34;&gt;security audit&lt;/a&gt; to
complete before I can submit MXC to a standards body. It might take some time
considering how long it took for TLS 1.3 to settle.&lt;/p&gt;
&lt;p&gt;Since this is a thought experiment, I also decided to skip error handling and
keep things to a minimum. So &lt;code&gt;assert(3)&lt;/code&gt; is used where it wouldn&amp;rsquo;t make sense
at all to make further progress outside the happy path, and otherwise return
values are ignored using a &lt;code&gt;(void)&lt;/code&gt; cast.&lt;/p&gt;
&lt;p&gt;The protocol primitives are implemented in a short C header library called
&lt;a href=&#34;mxcrypt.h&#34;&gt;mxcrypt.h&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Needless to say, this implementation has many shortcomings, and the handshake
won&amp;rsquo;t work unless both client and server share the same endianness, but I
digress.&lt;/p&gt;
&lt;h2 id=&#34;the-client&#34;&gt;The client&lt;/h2&gt;
&lt;p&gt;The protocol library was designed so that both clients and servers could
almost fit on a slide:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;&amp;#34;mxcrypt.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; argc, &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;argv)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; mxc_sess sess[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; buf[&lt;span style=&#34;color:#40a070&#34;&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;ssize_t&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;uint16_t&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; fd;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	fd &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_socket&lt;/span&gt;(argc, argv);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	port &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_port&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;connected via port %hu&amp;#34;&lt;/span&gt;, port);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_init&lt;/span&gt;(sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_client&lt;/span&gt;(sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_send&lt;/span&gt;(sess, fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_recv&lt;/span&gt;(sess, fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_key&lt;/span&gt;(sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;computed session key 0x%08x&amp;#34;&lt;/span&gt;, sess&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		len &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;read&lt;/span&gt;(STDIN_FILENO, buf, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt; buf);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(len &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_send&lt;/span&gt;(sess, fd, buf, len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	} &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;while&lt;/span&gt; (len &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The client is very straightforward: first it initializes a session and
generates a client hello for the handshake, then it sends its own hello to
the server and waits for the server hello in the reply. At this point the key
can be derived and the client proceeds to forward its standard input
encrypted over the network.&lt;/p&gt;
&lt;h2 id=&#34;the-server&#34;&gt;The server&lt;/h2&gt;
&lt;p&gt;Again, thanks to how the library was designed the server is equally
straightforward:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;&amp;#34;mxcrypt.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; argc, &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;argv)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; mxc_sess sess[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; buf[&lt;span style=&#34;color:#40a070&#34;&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;ssize_t&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;uint16_t&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; sock_fd, sess_fd;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sock_fd &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_socket&lt;/span&gt;(argc, argv);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	port &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_port&lt;/span&gt;(sock_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;listening to port %hu&amp;#34;&lt;/span&gt;, port);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sess_fd &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;accept&lt;/span&gt;(sock_fd, &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;, &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(sess_fd &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_init&lt;/span&gt;(sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_recv&lt;/span&gt;(sess, sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_server&lt;/span&gt;(sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_send&lt;/span&gt;(sess, sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;computed session key 0x%08x&amp;#34;&lt;/span&gt;, sess&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		len &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_recv&lt;/span&gt;(sess, sess_fd, buf, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt; buf);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(len &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;write&lt;/span&gt;(STDOUT_FILENO, buf, len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	} &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;while&lt;/span&gt; (len &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(sock_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It requires one additional socket compared to the client, one for the port it
is listening to and one for the single connection it will accept. Then it&amp;rsquo;s
almost the same dance as the client. Initialize the session and wait for the
client hello, then generate and send the server hello. At this point the key
was already derived, courtesy of the MXC implementation. Finally the server
decrypts the client&amp;rsquo;s contents and forwards them to its standard output.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Now that I have working client and server implementations of MXC I want to
improve the handshake by adding the possibility to present a certificate for
authentication purposes. But there is a little problem with the protocol so
far. Actually there are so many problems with both the protocol and
implementations that your average crypto person might already be suffering a
heart attack.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll focus on one problem though, and the astute reader may have already
guessed that this is going to be about sandboxing.&lt;/p&gt;
&lt;p&gt;The main problem here is that an MXC might do too many things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;require root privileges depending on which port it uses&lt;/li&gt;
&lt;li&gt;deal with the private key of the certificate during the handshake&lt;/li&gt;
&lt;li&gt;process untrusted input from potentially adversary parties&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first problem is technically not a problem. Unfortunately dropping
privileges is often a privilege, so sandboxing might be more effective with
system administration rights in the first place.&lt;/p&gt;
&lt;p&gt;The real problem is that currently if there is an application-level bug below
MXC, the &amp;ldquo;bug&amp;rdquo; is in the same address space as the certificate&amp;rsquo;s private key,
and could do its damage with the aforementioned root privileges.&lt;/p&gt;
&lt;h2 id=&#34;incremental-solutions&#34;&gt;Incremental solutions&lt;/h2&gt;
&lt;p&gt;There is one straightforward solution which consists in having a proxy that
terminates MXC traffic and forwards clear traffic to the application. It is
also not entirely satisfying as a solution because it requires twice as many
sockets on the system, and is both a resource and operational overhead. It
could also not be an operational overhead if it terminates MXC for multiple
services, but that still leaves one undesirable detail. Despite address space
isolation between processes we still end up sending CLEAR traffic between
them. We can mitigate the problem by co-locating the proxy and application on
the same system, and using a Unix-domain socket with proper permissions, but
then it becomes harder to amortize the operational overhead. The resource
overhead is however here to stay.&lt;/p&gt;
&lt;p&gt;If we end up with both the proxy and the application on the same host we can
get rid of the clear traffic problem. Unix-domain sockets have one interesting
property of inter-process communication, they can pass file descriptors from
one process to another. In order to do that, there needs to be a new protocol
between the proxy and the application so that forwarding the connection itself
instead of its traffic can happen.&lt;/p&gt;
&lt;p&gt;Next, we can solve the operational overhead by teaching the application how to
do the sandboxing. Much like we can create a &lt;code&gt;pipe(2)&lt;/code&gt; before forking a
process, we can also create a Unix-domain &lt;code&gt;socketpair(2)&lt;/code&gt; to create a private
channel before two processes.&lt;/p&gt;
&lt;h2 id=&#34;mxc-sandboxing&#34;&gt;MXC sandboxing&lt;/h2&gt;
&lt;p&gt;Now that I have a working implementation of a client and a server, I can write
a new server with sandboxing and check that it still works with the original
client.&lt;/p&gt;
&lt;h3 id=&#34;the-admin-process&#34;&gt;The admin process&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;main()&lt;/code&gt; function would look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; argc, &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;argv)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;pid_t&lt;/span&gt; acceptor_pid, server_pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;socketpair&lt;/span&gt;(PF_UNIX, SOCK_STREAM, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, pair_fd) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	acceptor_pid &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;fork&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (acceptor_pid &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;main_accept&lt;/span&gt;(argc, argv, pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(acceptor_pid &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	server_pid &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;fork&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (server_pid &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;main_serve&lt;/span&gt;(pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(server_pid &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(pair_fd[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;waitpid&lt;/span&gt;(acceptor_pid, &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; acceptor_pid);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;waitpid&lt;/span&gt;(server_pid, &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; server_pid);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each process gets one end of the socket pair, but unlike a &lt;code&gt;pipe(2)&lt;/code&gt; it is
bidirectional so care needs to be taken to make sure no privilege escalation
is possible between the server process (that receives application traffic) and
the acceptor process (that manipulates certificates and their private keys).&lt;/p&gt;
&lt;p&gt;The acceptor process takes the original command line arguments to figure which
port it will listen to while the server only gets the socket from which it
will receive MXC sessions.&lt;/p&gt;
&lt;h3 id=&#34;the-acceptor-process&#34;&gt;The acceptor process&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;main_accept()&lt;/code&gt; function is simple enough:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main_accept&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; argc, &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;argv, &lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; server_fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; msg_sess ms[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;uint16_t&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; sock_fd;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	sock_fd &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_socket&lt;/span&gt;(argc, argv);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	port &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_port&lt;/span&gt;(sock_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;listening to port %hu&amp;#34;&lt;/span&gt;, port);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;accept&lt;/span&gt;(sock_fd, &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;, &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_init&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_recv&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess, ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_server&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;mxc_hello_send&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess, ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;computed session key 0x%08x&amp;#34;&lt;/span&gt;, ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;send_msg_sess&lt;/span&gt;(ms, server_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(sock_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It does everything the previous server did up to the handshake, then it sends
the MXC session to the server and finishes. After getting a hold of the TCP
port and access to certificates, this process could drop many privileges. It
could even drop privileges prior to accessing certificates if they are made
available beforehand to a dedicated unprivileged user.&lt;/p&gt;
&lt;h3 id=&#34;the-server-process&#34;&gt;The server process&lt;/h3&gt;
&lt;p&gt;It should be easy to guess from the first server implementation and the
acceptor process what this one looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main_serve&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; acceptor_fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; msg_sess ms[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; buf[&lt;span style=&#34;color:#40a070&#34;&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;ssize_t&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;recv_msg_sess&lt;/span&gt;(ms, acceptor_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		len &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mxc_sess_recv&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess, ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd, buf, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt; buf);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(len &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;write&lt;/span&gt;(STDOUT_FILENO, buf, len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	} &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;while&lt;/span&gt; (len &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;close&lt;/span&gt;(ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This process could drop its privileges right away, unless the application
needs to acquire resources before that. In this example of course, we already
inherited the standard output so in theory we could drop everything at the
very beginning.&lt;/p&gt;
&lt;h3 id=&#34;passing-the-mxc-session&#34;&gt;Passing the MXC session&lt;/h3&gt;
&lt;p&gt;Passing a file descriptor between processes is only one thing we need to do.
We can see in the server process that we still need a valid session to decrypt
the traffic. Thankfully, it is possible to do this somewhat atomically: the
session can be serialized and sent as the payload whereas passing a file
descriptor to a unix-domain socket uses the control payload of a message.&lt;/p&gt;
&lt;p&gt;In this case, we use a private socket and the MXC session is self-contained so
it can be sent as its in-memory representation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;send_msg_sess&lt;/span&gt;(&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; msg_sess &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;ms, &lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; msghdr msg[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; cmsghdr &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;cmsg;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; iovec iov[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;union&lt;/span&gt; msg_buf buf[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	iov&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;iov_base &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	iov&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;iov_len &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt; ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;memset&lt;/span&gt;(msg, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt; msg);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	msg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;msg_iov &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; iov;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	msg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;msg_iovlen &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	msg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;msg_control &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; buf;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	msg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;msg_controllen &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(buf);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	cmsg &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;CMSG_FIRSTHDR&lt;/span&gt;(msg);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	cmsg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;cmsg_level &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; SOL_SOCKET;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	cmsg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;cmsg_type &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; SCM_RIGHTS;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	cmsg&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;cmsg_len &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;CMSG_LEN&lt;/span&gt;(&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	(&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#06287e&#34;&gt;memcpy&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;CMSG_DATA&lt;/span&gt;(cmsg), &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;assert&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;sendmsg&lt;/span&gt;(fd, msg, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;LOG&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;sent session for file descriptor %d&amp;#34;&lt;/span&gt;, ms&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;sess_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;struct msg_sess&lt;/code&gt; type conveniently carries both session state and the
file descriptor, in other words the data and control payloads:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; msg_sess {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; mxc_sess	sess[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt;		sess_fd;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;recv_msg_sess()&lt;/code&gt; function isn&amp;rsquo;t too interesting to look at at this point
because it mostly looks like &lt;code&gt;send_msg_sess()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;mxc-sandboxing-benefits&#34;&gt;MXC sandboxing benefits&lt;/h2&gt;
&lt;p&gt;This scheme greatly reduces the overall attack surface. The main &amp;ldquo;admin&amp;rdquo;
process very likely running as root doesn&amp;rsquo;t touch any application traffic in
this example. The acceptor process that would have access to certificates and
private keys if I were to extend the MXC protocol would have very limited
interactions with untrusted input, namely handshakes. And finally the actual
server implementing some sort of application logic would only have access to
the ephemeral session key.&lt;/p&gt;
&lt;p&gt;It would also have less overhead because with one program we may now both
terminate encrypted traffic and process it at the application level. We&amp;rsquo;d
still have three processes, but coming from the same executable file they&amp;rsquo;d
share more and waste less. Finally we don&amp;rsquo;t need more sockets on the host
system.&lt;/p&gt;
&lt;p&gt;One nice twist of the second server implementation is the unidirectional
traffic over the unix-domain socket pair. This way there is little risk of
having a compromised application send commands to the acceptor process to
leak MXC private keys (even though I didn&amp;rsquo;t implement certificates). This
only works if the protocol no longer needs the certificate once the handshake
completes. Otherwise one might design the sandbox differently, or have a
two-way dialog between the acceptor and the server.&lt;/p&gt;
&lt;p&gt;Also, in the likely event that the session state would not be of a fixed
size like the MXC protocol so far, the acceptor may have read data past the
handshake and should serialize any data in the pipeline along with session
state.&lt;/p&gt;
&lt;h2 id=&#34;tls-sandboxing&#34;&gt;TLS sandboxing&lt;/h2&gt;
&lt;p&gt;Circling back to &lt;code&gt;$DAYJOB&lt;/code&gt;, I sometimes start pondering the two times where
HTTPS support was considered in Varnish, which resulted in the
&lt;a href=&#34;https://hitch-tls.org&#34;&gt;Hitch&lt;/a&gt; TLS terminator proxy.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://varnish-cache.org/docs/trunk/phk/ssl.html&#34;&gt;first one&lt;/a&gt; says the
following that stuck in my head:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Will that be significantly different, performance wise, from running a SSL
proxy in separate process ?&lt;/p&gt;
&lt;p&gt;No, it will not, because the way varnish would have to do it would be to &amp;hellip;
start a separate process to do the SSL handling.&lt;/p&gt;
&lt;p&gt;There is no other way we can guarantee that secret krypto-bits do not leak
anywhere they should not, than by fencing in the code that deals with them in
a child process, so the bulk of varnish never gets anywhere near the
certificates, not even during a core-dump.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, if we wanted native HTTPS support in Varnish we would require
the kind of sandboxing implemented as a thought experiment for MXC.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://varnish-cache.org/docs/trunk/phk/ssl_again.html&#34;&gt;second take&lt;/a&gt;
points to a keyless TLS implementation that uses private keys stored remotely
during the handshake, validating the MXC sandboxing model and adding one more
layer of security. If the MXC (or at this point TLS) handshake can be
exploited, at least it will be significantly harder to steal private keys.&lt;/p&gt;
&lt;p&gt;A keyless handshake also makes the whole &lt;code&gt;fork(2)&lt;/code&gt; with &lt;code&gt;socketpair(2)&lt;/code&gt; dance
somewhat obsolete, but it reintroduces operational overhead: instead of a TLS
terminator proxy the application needs a key server and a new can of security
worms to deal with. On the other hand it can probably be amortized rapidly for
CDN setups, but I digress.&lt;/p&gt;
&lt;h2 id=&#34;openssl-sandboxing&#34;&gt;OpenSSL sandboxing&lt;/h2&gt;
&lt;p&gt;Now that TLS could hypothetically be sandboxed safely, allowing the handshake
to happen in a separate process, possibly using private keys remotely without
ever fetching them, comes the question of a TLS implementation.&lt;/p&gt;
&lt;p&gt;The obvious candidate for multiple reasons would be OpenSSL, but can it do
that as of today? It is possible to serialize a session to an ASN1 or base64
representation, so this could be passed alongside the file descriptor to the
cache process (Varnish&amp;rsquo;s &amp;ldquo;server&amp;rdquo; process). We already use this for session
resumption in Hitch, but can it be done for a live ongoing connection?&lt;/p&gt;
&lt;p&gt;If it is doable, is it portable across all the platforms we care about in the
Varnish project? Would the TLS handshake sandboxing create a new bottleneck?
My intuition tells me that an application would still perform better without a
separate proxy. But it comes with further challenges and may require that we
modularize more parts of Varnish like the acceptor subsystem. Would OpenSSL
integrate nicely in our delivery pipeline? Many questions I&amp;rsquo;m not covering for
a short thought experiment in the middle of the night.&lt;/p&gt;
&lt;h2 id=&#34;bonus-mxc-demo&#34;&gt;Bonus MXC demo&lt;/h2&gt;
&lt;p&gt;I wanted to give an interactive demo of the MXC PoC, so I looked at what was
available on Fedora and settled for &lt;a href=&#34;https://asciinema.org/&#34;&gt;asciinema&lt;/a&gt;. In
this scenario I build the client, the sandboxing server, and use a shell
script to create a man-in-the-middle proxy. The client passes a secret key to
the server and the netcat-based proxy dumps traffic on disk. In order to show
all three actors semi-simulteanously I used &lt;code&gt;tmux&lt;/code&gt; to split the terminal:&lt;/p&gt;
&lt;script&gt;
  function resizeAsciinemaIframe(obj) {
    obj.style.height = obj.contentWindow.document.body.scrollHeight + &#39;px&#39;;
  }
&lt;/script&gt;

&lt;iframe id=&#34;asciicast-iframe&#34;
  src=&#34;https://dridi.fedorapeople.org/post/tls-sandboxing/asciinema-player.html&#34;
  allowfullscreen frameborder=&#34;0&#34; scrolling=&#34;no&#34;
  onload=&#34;resizeAsciinemaIframe(this);&#34;&gt;&lt;/iframe&gt;

&lt;p&gt;You can see what the client and server are logging, and that the server logs
from two different PIDs. When the client and servers are rebuilt with the
&lt;code&gt;MXC_CLEAR&lt;/code&gt; macro defined, the traffic is sent non-encrypted and the MITM
proxy successfully intercepts the private payload.&lt;/p&gt;
&lt;p&gt;All the code is available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;mxcrypt.h&#34;&gt;mxcrypt.h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;mxcrypt-client.c&#34;&gt;mxcrypt-client.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;mxcrypt-server.c&#34;&gt;mxcrypt-server.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;mxcrypt-server2.c&#34;&gt;mxcrypt-server2.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;mitm-proxy.sh&#34;&gt;mitm-proxy.sh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, one last reason I was thinking about HTTPS support in Varnish is that
HTTP/3 will likely be based on QUIC and specified as secure-only so keyless or
not we may want to eventually sandbox handshakes. I think we should still
support a complete handshake and not force users to have a key server, like we
force Varnish users to use proxies for both TLS termination and tunneling
today in end-to-end HTTPS setups.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Taking reverse engineering to the next level</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-8/</link>
      <pubDate>Sun, 31 Mar 2019</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-8/</guid>
        <description>&lt;h2 id=&#34;learning-new-languages&#34;&gt;Learning new languages&lt;/h2&gt;
&lt;p&gt;Last October I &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-7/&#34;&gt;wrote&lt;/a&gt; about my progress
and the first release of &lt;a href=&#34;https://dridi.fedorapeople.org/projects/bjxa/&#34;&gt;bjxa&lt;/a&gt;. I published a
reference implementation of a BandJAM XA decoder in C able to reproduce
bit-for-bit the same audio output as &lt;code&gt;xa.exe&lt;/code&gt;. After that I reviewed
DTXMania&amp;rsquo;s code, which to this date I still can&amp;rsquo;t build completely on Linux
with Mono.&lt;/p&gt;
&lt;p&gt;I remember seeing years ago a piece of advice for developers, encouraging them
to learn one new language each year, to challenge their comfort zone. While I
never followed this advice, I think that learning a new language can be
counter-productive if their isn&amp;rsquo;t an actionable project to back the learning.
Porting bjxa to C# was a perfect excuse, since the scope is small enough and
the language is somewhat familiar to Java which I already know.&lt;/p&gt;
&lt;p&gt;My conclusions after conducting this work is that C# is indeed a much more
pleasant language than Java. I&amp;rsquo;m still not satisfied with the code I came up
with but it was enough to even challenge my C implementation and drive some
improvements.&lt;/p&gt;
&lt;p&gt;I then sent an email to the DTXMania maintainer in November to raise his
awareness of BJXA and was greeted with deafening silence. This was of course
my own fault for not creating an account and create a ticket on the project
tracker, but that&amp;rsquo;s a consequence of a distinct lack of confidence.&lt;/p&gt;
&lt;p&gt;That made me wonder about the languages I learned over the years and whether
the total amount would average around one per year. Here is a list I could
produce off the top of my head, in alphabetic order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWK&lt;/li&gt;
&lt;li&gt;Ada&lt;/li&gt;
&lt;li&gt;C#&lt;/li&gt;
&lt;li&gt;C99&lt;/li&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;Groovy&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;POSIX shell&lt;/li&gt;
&lt;li&gt;Perl&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Rust&lt;/li&gt;
&lt;li&gt;SED&lt;/li&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;li&gt;VCL&lt;/li&gt;
&lt;li&gt;m4&lt;/li&gt;
&lt;li&gt;vimscript&lt;/li&gt;
&lt;li&gt;x86 assembler (Intel syntax)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s a fair amount of languages, but I&amp;rsquo;m a beginner in most of them. For
some of them I only learned them to write exactly one program or library for a
transient need and never touched them again. Some I use out of necessity every
once in a while but never became proficient, but I digress&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;reverse-script-kidding&#34;&gt;Reverse script kidding&lt;/h2&gt;
&lt;p&gt;Tools keep making astonishing progress in all areas, and even a beginner can
get results pretty fast with the help of IDEs or similar tools. And yet, as I
settled in programming my personal trend was to move away from such tools and
instead learn underlying tools they tend to abstract away.&lt;/p&gt;
&lt;p&gt;Using IDEs is fine, learning the fundamental tools is critical. Keeping IDEs
despite being proficient with the underlying tools is also fine, although I
personally prefer to avoid IDEs.&lt;/p&gt;
&lt;p&gt;But as a beginner it is sometimes much easier to use graphical tools that try
to be more user friendly by hiding the dirty details. Despite my success in
uncovering the BJXA codec and documenting it
&lt;a href=&#34;https://git.sr.ht/~dridi/bjxa/tree/bjxa-0.4/item/bjxa.5.rst&#34;&gt;thoroughly&lt;/a&gt;
there are still unknown parts. The reverse engineering of &lt;code&gt;xadec.dll&lt;/code&gt; was easy
even for an x86 beginner because it came with a header file that gave a
significant head start. The fact that it was a shared library also gave me by
definition access in the assembly to all the public functions.&lt;/p&gt;
&lt;p&gt;Now to find the answers to the remaining mysteries of the codec I would need
to decompile &lt;code&gt;xa.exe&lt;/code&gt; but there is a catch: it&amp;rsquo;s a statically linked program
and the only starting point I have is the entry point of the program, which is
responsible for calling the &lt;code&gt;main()&lt;/code&gt; function of a C program. In addition it&amp;rsquo;s
a Win32 executable, which I&amp;rsquo;m not familiar with.&lt;/p&gt;
&lt;p&gt;Just when I decided to live with those mysteries, the NSA knocked on my
proverbial door and convinced me to give a try to their IDE.&lt;/p&gt;
&lt;h2 id=&#34;here-be-dragons&#34;&gt;Here be dragons&lt;/h2&gt;
&lt;p&gt;After decompiling &lt;code&gt;xadec.dll&lt;/code&gt; I was convinced that it was originally written
in C and I suspected &lt;code&gt;xa.exe&lt;/code&gt; would be too. Finding the &lt;code&gt;main()&lt;/code&gt; function
would in theory allow me to unravel the encoding code and see how it treats
the undefined behavior of the codec.&lt;/p&gt;
&lt;p&gt;Trying to use
&lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-5/#thinking-more-like-a-compiler&#34;&gt;retdec&lt;/a&gt;
didn&amp;rsquo;t work out because it failed to identify the calling convention and I
gave up (without reaching out for help) when I couldn&amp;rsquo;t figure out how to let
it know. The result was even worse with &lt;code&gt;xa.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Trying to decompile the assembly by hand resulted in a total failure to even
locate the &lt;code&gt;main()&lt;/code&gt; function. Even the knowledge of &lt;code&gt;xa.exe&lt;/code&gt;&amp;rsquo;s command line
arguments I failed to use a reference to the usage code and find my way back
to the &lt;code&gt;argv&lt;/code&gt; parsing:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ wine xa.exe
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
Usage  : xa.exe &amp;lt;option&amp;gt; [filename&amp;lt;.wav/.xa&amp;gt;]
Option : -e[n]    Encode[WAV-&amp;gt;XA](Default) / n:BitCount(4/6/8)
         -d       Decode[XA-&amp;gt;WAV]
         -p       Play File
         -o[dir]  Output Directory
         -u       Update
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then the NSA announced it would open source one of their reverse engineering
tools and eventually made it available, although the source code isn&amp;rsquo;t yet.
Ghidra is a graphical tool that is for reverse engineering the equivalent of
an IDE for development.&lt;/p&gt;
&lt;p&gt;In less than 2 minutes (I timed it!) I was able to find the &lt;code&gt;main()&lt;/code&gt; function
and confirm that it used a C-like signature taking the two famous arguments
&lt;code&gt;int argc&lt;/code&gt; and a &lt;code&gt;char **argv&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I think that Ghidra&amp;rsquo;s main advantage over retdec was its ability to find the
right calling convention from the get go. I managed to find the equivalent of
&lt;code&gt;xadec.dll&lt;/code&gt;&amp;rsquo;s &lt;code&gt;xaDecodeOpen&lt;/code&gt; by luck and found the decompiled code to be quite
elegant.&lt;/p&gt;
&lt;p&gt;Overall, I think the NSA deserves to be congrat&amp;hellip; to be cong&amp;hellip; I think the
NSA did an OK job.&lt;/p&gt;
&lt;h2 id=&#34;unfortunate-obfuscation&#34;&gt;Unfortunate obfuscation&lt;/h2&gt;
&lt;p&gt;One reason why I had a hard time finding the &lt;code&gt;main()&lt;/code&gt; function and its command
line parsing is again an incarnation of the robustness principle. With no hint
from the usage description I couldn&amp;rsquo;t guess that options were case-insensitive
and that they also supported the Windows style for options:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ wine xa.exe -d square-mono-8.xa
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
square-mono-8.xa -&amp;gt; square-mono-8.wav : 44100Hz / monaural / 8bits.
1 Files Decoded.
Completed.

$ wine xa.exe /d square-mono-8.xa
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
square-mono-8.xa -&amp;gt; square-mono-8.wav : 44100Hz / monaural / 8bits.
1 Files Decoded.
Completed.

$ wine xa.exe /D square-mono-8.xa
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
square-mono-8.xa -&amp;gt; square-mono-8.wav : 44100Hz / monaural / 8bits.
1 Files Decoded.
Completed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I also couldn&amp;rsquo;t have guessed that the command line parsing would intertwine
options parsing and a lot of processing. Thanks to Ghidra I have a semi-clean
&lt;code&gt;switch&lt;/code&gt; statement and was able to figure that while some processing is done
immediately when an option is identify, some checks are deferred until needed.
For example I can ask to encode something and ultimately say that I want to do
decoding instead and it won&amp;rsquo;t complain:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ wine xa.exe -e5 square-mono-8.wav
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
bitcount error.

$ wine xa.exe -e5 -d square-mono-8.xa
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
bitcount error.

$ wine xa.exe -e8 square-mono-8.wav
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
square-mono-8.wav -&amp;gt; square-mono-8.xa : 44100Hz / 16bit / monaural
1 Files Encoded.
Completed.

$ wine xa.exe -e8 -d square-mono-8.xa
WAV to XA v1.22 Copyright 2000-2001 bandjam.net
square-mono-8.xa -&amp;gt; square-mono-8.wav : 44100Hz / monaural / 8bits.
1 Files Decoded.
Completed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I also found an interesting undocumented &lt;code&gt;-l&lt;/code&gt; option and its effects are
puzzling to say the least&amp;hellip; Looking at the shape of the code, it looks as
though &lt;code&gt;xa.exe&lt;/code&gt; was written in C++ and if I&amp;rsquo;m right that&amp;rsquo;s probably Visual
C++.&lt;/p&gt;
&lt;p&gt;I hope to solve the remaining mysteries in the BandJAM XA codec with the help
of Ghidra and so far it looks much more within reach. Unfortunately that&amp;rsquo;s a
project I will have to shelve for later, but I digress.&lt;/p&gt;
&lt;h1 id=&#34;19-years-of-xadecdll&#34;&gt;19 years of xadec.dll&lt;/h1&gt;
&lt;p&gt;Eventually, I received a response from the DTXMania maintainer regarding my
struggles when it comes to running it on Linux using Wine, and especially the
problem of &lt;code&gt;xadec.dll&lt;/code&gt;. The response was overwhelmingly positive and I learned
that they were struggling too because of it and the fact that so many songs
playable for the game use that ancient codec.&lt;/p&gt;
&lt;p&gt;They wanted to maintain the capability to read BandJAM XA files, but that
prevented 64bit builds of the game. Out of nowhere came bjxa and it got them
closer to solving the problem for good (they still have an ancient OGG and MP3
decoder similar to &lt;code&gt;xadec.dll&lt;/code&gt;: no source code).&lt;/p&gt;
&lt;p&gt;I also learned in the process that the original DTXMania maintainer was
working on a DTXMania2 but unfortunately that one is even harder to run with
Wine. Without much help from my side they managed to integrate &lt;code&gt;libbjxa&lt;/code&gt; in
their &lt;a href=&#34;https://git.sr.ht/~dridi/bjxa/refs/bjxa-0.3&#34;&gt;projects&lt;/a&gt; and the fact
that &lt;code&gt;bjxa.exe&lt;/code&gt; was available to see how to use the library probably helped.&lt;/p&gt;
&lt;p&gt;When I got the first response, the maintainer was apologetic because it had
taken a couple months to reply to my inquiry. Working on free and open source
software I have experienced the demanding tone of some users. I have found
myself in demanding positions too, and have probably given that impression
more than once even when it wasn&amp;rsquo;t the case. I find it a bit sad though when
maintainers apologize when they shouldn&amp;rsquo;t and keep doing so even after being
told that all is fine, but I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;No matter how I thanked them they would thank me even more. I&amp;rsquo;d like to thank
them here once more and I hope to hit them hard with more demanding patches as
I hope to iron out the remaining problems inside Wine that I identified.&lt;/p&gt;
&lt;h1 id=&#34;19-years-of-buffer-overflows&#34;&gt;19 years of buffer overflows&lt;/h1&gt;
&lt;p&gt;I found two interesting classes of bugs in &lt;code&gt;xadec.dll&lt;/code&gt;, one of which could
lead to a security vulnerability. The first one is that most tainted pointer
dereferences are done without a proper null check. The second one is a buffer
overflow that can be triggered easily with a specially crafted XA file. Can it
result in arbitrary code execution? I don&amp;rsquo;t know and even if I managed to own
a DTXMania process running in Wine that wouldn&amp;rsquo;t prove that the same exploit
could be used on Windows and vice versa. And considering that I won&amp;rsquo;t install
Windows to run the game and introduced myself to reverse engineering just for
the sake of running the game on Fedora, I won&amp;rsquo;t shave that yak.&lt;/p&gt;
&lt;p&gt;If you would like to see what real reverse engineering looks like, I strongly
recommend this &lt;a href=&#34;https://www.youtube.com/watch?v=j-ZWHGSvY9Y&#34;&gt;conference&lt;/a&gt; from
people that could have probably done in minutes what initially took me hours.
My plan is to level up my game (all kinds of puns intended) by cheating. I
will rely on Ghidra, my new power tool, but before that I have other things to
tend to and hopefully I will write on other topics in the future.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Beating the reverse engineering game</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-7/</link>
      <pubDate>Sun, 07 Oct 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-7/</guid>
        <description>&lt;h2 id=&#34;reverse-motivation&#34;&gt;Reverse motivation&lt;/h2&gt;
&lt;p&gt;After &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-6/&#34;&gt;losing&lt;/a&gt; my annotated assembly
listings, it&amp;rsquo;s been hard to find motivation to take the most complicated part
of the code, reverse engineer it again and comment it here. And this is code I
really want to comment because there are interesting findings inside.&lt;/p&gt;
&lt;p&gt;So instead I decided to work on the actual project, that goes beyond the quick
and dirty reverse engineered code. One thing I learned over the years is that
it&amp;rsquo;s easier to start than finish things, for a given definition of finish. In
this case that would be a working decoder, a specification of the codec, all
that wrapped nicely inside a source repository, and a first release with all
the bells and whistles. And as such bjxa 0.1 was released, matching this
definition of &lt;em&gt;finish&lt;/em&gt; with some hidden fine prints.&lt;/p&gt;
&lt;p&gt;As a result I decided to open a &lt;a href=&#34;https://dridi.fedorapeople.org/projects/&#34;&gt;projects&lt;/a&gt; section
with the result of this reverse engineering self challenge as its &lt;a href=&#34;https://dridi.fedorapeople.org/projects/bjxa/&#34;&gt;first&lt;/a&gt; entry.&lt;/p&gt;
&lt;h2 id=&#34;thank-wine-again&#34;&gt;Thank Wine, again&lt;/h2&gt;
&lt;p&gt;In order to produce a decoder that would produce a byte for byte identical
WAVE file I needed to somehow run &lt;code&gt;xadec.dll&lt;/code&gt; but previous attempts at cross
compiling &lt;code&gt;sample.c&lt;/code&gt; to run it under Wine failed for reasons beyond my tinker
spirit.&lt;/p&gt;
&lt;p&gt;But since I found that &lt;code&gt;xa.exe&lt;/code&gt; program from the same author, I was able to
produce WAVE files that would infringe on nobody&amp;rsquo;s copyright, convert them to
XA and back again to WAVE. Giving me an XA to WAVE baseline to check my work.
Unsurprisingly Wine had no issues running this (statically linked) program.&lt;/p&gt;
&lt;p&gt;I studied the differences between the PCM samples produced by my code and the
PCM samples produced by &lt;code&gt;xa.exe&lt;/code&gt; and noticed that most PCM samples were very
much identical and when they were not, only the least significant byte of the
samples were different.&lt;/p&gt;
&lt;h2 id=&#34;double-wrong-means-not-so-wrong&#34;&gt;Double wrong means not so wrong&lt;/h2&gt;
&lt;p&gt;I have yet to disassemble that part again, and it was the hardest bit to
reverse engineer for me so it will take some time before I pull it off. But in
short, I was right. The fact that the BandJAM author had shipped an encoder
made me think that my assumption was wrong that this was not an original
codec. But I was actually correct after my initial 30 hours once I got a
working C decoder after my mental decompilation of the assembly: BandJAM XA is
CDROM XA, the same audio codec as the PlayStation!&lt;/p&gt;
&lt;p&gt;Why would I notice that in the first place? It&amp;rsquo;s a little embarrassing but
sometimes I get bored and read other people&amp;rsquo;s source code. As I said, I&amp;rsquo;m
probably a cat serial killer at this point because my curiosity extends to
such lengths that I would sometimes read the source code of things that look
magic to me and in this case an open source emulator, but I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;CDROM XA has the notion of a block profile and depending on the profile
chosen for a block, a gain may be added to the PCM samples of a block, and I
already determined in &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-5/&#34;&gt;part 5&lt;/a&gt; the size
of XA blocks.  And since the LSB of the decoded samples was sometimes off, I
tried to figure why they would stop being off.&lt;/p&gt;
&lt;p&gt;It turns out they&amp;rsquo;d stop diverging at block boundaries, and one of the
profiles doesn&amp;rsquo;t adjust the gain and as a result is not influenced by past
blocks. Quick check: yes, when PCM samples diverge, they converge again on
such blocks. Following my intuition I updated my code to decode CDROM XA
blocks and here goes nothing: the audio output is a perfect match!&lt;/p&gt;
&lt;h2 id=&#34;audio-and-unicorns&#34;&gt;Audio and unicorns&lt;/h2&gt;
&lt;p&gt;With this in mind, I have to revisit the decompilation of &lt;code&gt;xadec.dll&lt;/code&gt;. Either
I made some mistakes, or there is a bug in the library and I have reasons to
keep this as a possibility. Another reason could be that &lt;code&gt;xadec.dll&lt;/code&gt; doesn&amp;rsquo;t
use the same code as &lt;code&gt;xa.exe&lt;/code&gt;. Unfortunately, I lost that decompilation, but
I&amp;rsquo;m still planning to redo it once I find my lost motivation.&lt;/p&gt;
&lt;p&gt;This got me thinking: why would my code for CDROM XA work better than my
decompiled code, especially since the former uses floating point arithmetic
and the latter relies only on integers? I looked into this and found a rabbit
hole so big that I shouldn&amp;rsquo;t even start.&lt;/p&gt;
&lt;p&gt;Short story: you can find many of the CDROM specifications online and CDROM XA
also known as CDROM eXtended Architecture, also known as the Green Book. The
Green Book is an extension to the Yellow Book standard and apparently CDROM
folks love colors. There are other books and the collection is sometimes
referred to as the Rainbow Books.&lt;/p&gt;
&lt;p&gt;I found a copy of the Green Book
&lt;a href=&#34;http://www.icdia.co.uk/docs/funcspec.html&#34;&gt;online&lt;/a&gt; and it&amp;rsquo;s about 1000 pages
long. The quality of this book should humble most open source projects, I have
spent hours reading through. This is a very interesting read, you have been
warned.&lt;/p&gt;
&lt;h2 id=&#34;robust-size&#34;&gt;Robust size&lt;/h2&gt;
&lt;p&gt;The digression above was brought to you by amazing engineers from the 90s. I
believe I left off at the perfect match. Well, almost perfect: there is a bug
in the RIFF header generated by &lt;code&gt;xa.exe&lt;/code&gt;. So let&amp;rsquo;s start by decompiling the
&lt;code&gt;xaDecodeSize&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001140:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;esp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x4&lt;/span&gt;]        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ecx = hxas;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001144:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;                        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (hxas == NULL) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001146:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jne&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x1000114b&lt;/span&gt;                     &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001148:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;       eax = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000114&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;                                   &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;       return (0);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;                                                &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000114&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;esp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x8&lt;/span&gt;]        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = slen;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000114&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;                        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; edx = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001151:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;div&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x28&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax /= hxas-&amp;gt;blk_sz;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001154:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;esp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xc&lt;/span&gt;]        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ecx = pdlen;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001158:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;inc&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                            &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax++;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001159:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;shl&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0x6&lt;/span&gt;                        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax *= 64;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000115&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;],&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;            &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; *pdlen = eax;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000115&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0x1&lt;/span&gt;                        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = 1;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001163:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;                                   &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; return (1);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It can feel confusing to see that &lt;code&gt;div&lt;/code&gt; takes only one operand. It&amp;rsquo;s only a
matter of knowing that in this case the dividend is the combination of &lt;code&gt;eax&lt;/code&gt;
for the LSB and &lt;code&gt;edx&lt;/code&gt; for the MSB. This explains why &lt;code&gt;edx&lt;/code&gt; is zeroed out of
the blue.&lt;/p&gt;
&lt;p&gt;Considering the signature of the function, it can be decompiled as such:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BOOL
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeSize&lt;/span&gt;(HXASTREAM hxas, ULONG slen, ULONG &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;pdlen)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (hxas &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (FALSE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;pdlen &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;64&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; (&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; slen &lt;span style=&#34;color:#666&#34;&gt;/&lt;/span&gt; hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;blk_sz);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (TRUE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, progress here, we have a null check for &lt;code&gt;hxas&lt;/code&gt;. On the other hand we lack
a null check for &lt;code&gt;pdlen&lt;/code&gt; and the arithmetics look bonkers. The additional
increment (pun intended) is here to compensate partial blocks. This is that
kind of reasoning that leads to the RIFF header bug in &lt;code&gt;xa.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fortunately, audio players tend to be more robust than that and will agree to
play a broken WAVE file if it&amp;rsquo;s only that kind of corruption. Sure the RIFF
size is in most cases smaller than what ends up declared, so this means we can
safely ignore anything beyond the WAVE data.&lt;/p&gt;
&lt;p&gt;This, is a good example of the robustness principle:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Be conservative in what you do, be liberal in what you accept from others.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sure, let&amp;rsquo;s accept everyone else&amp;rsquo;s bugs or non standard extensions to the
point where we can&amp;rsquo;t move a protocol or file format forward without breaking
everyone&amp;rsquo;s code. This, is the sad reality of the Internet: a slow-moving
behemoth that nevertheless keeps on growing faster than it can move. But I
digress&amp;hellip;&lt;/p&gt;
&lt;h1 id=&#34;building-up-motivation&#34;&gt;Building up motivation&lt;/h1&gt;
&lt;p&gt;Another reason why I started this series has yet to come. I&amp;rsquo;m not teaching x86
assembly or how to reverse engineer code. But I hope it will show that it is
possible for someone to start that kind of endeavour by themselves. I was
lucky to find an old C library either too old to lose me in optimizations or
too simple to be aggressively optimized. And I found more than just code to
disassemble and decompile, as cheesy as it may sound. I hope to publish a
&lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-8/&#34;&gt;next post&lt;/a&gt; soon, I should only need a
couple more to cover everything I wanted to report.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Expanding the XA puzzle</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-6/</link>
      <pubDate>Sun, 12 Aug 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-6/</guid>
        <description>&lt;h2 id=&#34;the-reverse-engineering-games&#34;&gt;The reverse engineering games&lt;/h2&gt;
&lt;p&gt;This post should have started with the words &amp;ldquo;last week&amp;rdquo; but unfortunately I
was not able to follow the weekly cadence I had planned. Instead of just the
trivial matters I &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-5/&#34;&gt;announced then&lt;/a&gt; I
will also cover more topics than initially planned, going from a very short
entry to hopefully an entry that still qualifies as short.&lt;/p&gt;
&lt;p&gt;The reason why I started the &lt;code&gt;xadec.dll&lt;/code&gt; reverse engineering game was as I
said in the &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-1/&#34;&gt;first post&lt;/a&gt; of this series
the prospect of living in a bigger place with enough space to use my
electronic drum kit.  One thought led to another and I remembered the fun I
had playing GuitarFreaks and DrumMania. The reason why this post is late is
because in the process of moving my laptop was stolen.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not too worried about the contents of the laptop because it should be a
brick to anyone but me. Considering the current trend among politicians
against strong cryptography, I&amp;rsquo;m very glad to be in the other camp. However
having the laptop stolen is not the only reason for a whole month delay: I
also lost some of my backups, including the sources of this blog.&lt;/p&gt;
&lt;p&gt;I have a NAS at home for local backups, and copies online (or as the sheeps
say these days, in the cloud). Some of my things are inherently backed up,
because hosted online: emails, source code. Stuff that is not important tend
to live on only one device until I archive it just in case, that&amp;rsquo;s obviously
gone. The big bummer is a couple of local backups that fail to restore, a
procedure I usually test when I switch laptops (that is, not often enough) so
the local backups are useless and the on-device archives are gone.&lt;/p&gt;
&lt;p&gt;If you paid attention, source code should not be a problem, but I lost the
blog sources. I forgot for some reason to host a clone online and I had to
reverse engineer the HTML web site and figure all the changes I had made to
the theme to get it back. I guess I should talk about &lt;code&gt;vim&lt;/code&gt; in a future post
because it helped a lot in the process, but I digress&amp;hellip; And with that this
post is already longer than the original one I had in mind.&lt;/p&gt;
&lt;h2 id=&#34;the-music-games&#34;&gt;The music games&lt;/h2&gt;
&lt;p&gt;Anothernother reason for being so late is the fact that I eventually moved,
and this was the occasion to revisit my games collection.&lt;/p&gt;
&lt;img src=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-6/music-games-sample.jpg&#34; alt=&#34;Some of my music games&#34; /&gt;

&lt;p&gt;On this picture you should see the boxes containing the guitar controller I
ordered before Guitar Hero happened, the Guitar Hero controller I then bought
along with the first game, two original games from Japan and one more
controller. The Playstation 2 game is &lt;em&gt;GuitarFreaks and DrumMania V3&lt;/em&gt;, and
missing from that picture are the defunct drums controller, the defunct modded
Playstation 2 and the defunct modded Wii.&lt;/p&gt;
&lt;p&gt;So unless I manage to use those controllers on a PC beefy enough to emulate
those consoles and manage to run such an emulator, at best they can be seen as
geeky decoration, otherwise dead weight that belongs in the basement. But
surely, running those games using an emulator would be piracy, right?&lt;/p&gt;
&lt;h2 id=&#34;the-music-game&#34;&gt;The music game&lt;/h2&gt;
&lt;p&gt;The game I&amp;rsquo;m interested in (DTXMania) is officially a piece of software that
anyone can use to practice their Yamaha DTX electronic drum kits. If you look
closer though, it&amp;rsquo;s a DrumMania and GuitarFreaks clone, because yes you can
also play the guitar. But to be fair DTXMania goes beyond the arcade nature of
DrumMania and can support many more elements on a drum kit, and even elements
with multiple states such as a hi hat that can be either open or closed.&lt;/p&gt;
&lt;p&gt;Out of curiosity I looked at the source code beyond the presence of
&lt;code&gt;xadec.dll&lt;/code&gt; and found a well maintained copyright statement of its bundled
dependencies. It mentions that &lt;code&gt;xadec.dll&lt;/code&gt; can only be used free of charge, so
any paid for game would not be allowed to ship and use it. It&amp;rsquo;s a bit
challenging to find information in a code base maintained in Japanese, and
that goes for the web site too, but there are some English resources. In there
I found &lt;code&gt;xa.exe&lt;/code&gt; apparently also shipped by the BandJam developer, and still
accessible thanks to projects like DTXMania. &lt;code&gt;xa.exe&lt;/code&gt; can both encode and
decode this XA format, and I was probably wrong to think that the BandJam
author was not behind this format. Now the question is the following: should I
also reverse engineer the encoder?&lt;/p&gt;
&lt;h2 id=&#34;disassembly-of-a-static-program&#34;&gt;Disassembly of a static program&lt;/h2&gt;
&lt;p&gt;Unlike a library that needs an entry point for each public symbol of its API,
a quick try on &lt;code&gt;xa.exe&lt;/code&gt; gives no starting point. Worse, even though I
reinstalled the same OS, &lt;code&gt;objdump&lt;/code&gt; no longer gives me the useful all-in-one
output I was used to. That in itself is very puzzling.&lt;/p&gt;
&lt;p&gt;One thing I could hope is to find the &lt;code&gt;xadec.dll&lt;/code&gt; code in &lt;code&gt;xa.exe&lt;/code&gt; since it
can both encode and decode. The problem is that even if the code is virtually
the same with identical optimizations for a similar output, it is likely that
the choice of registers would differ, and it is even more likely that
addresses wouldn&amp;rsquo;t match.&lt;/p&gt;
&lt;p&gt;That would make an interesting coding exercise, trying to find the same code
in two binaries with possibly slight differences, but for now I have other
plans, like maybe playing some drums at some point, maybe?&lt;/p&gt;
&lt;h2 id=&#34;pouring-some-wine&#34;&gt;Pouring some wine&lt;/h2&gt;
&lt;p&gt;Finally, I got hold of older versions of DTXMania, and managed to run them! At
this point I should stop this reverse engineering game and fulfill my original
goal of playing the game with my electronic drum kit. But that would imply
sanity, a trait I do not claim. After all, when I initially tied to run the
game I naturally went for the latest builds to no avail. I searched online and
found that people tried to
&lt;a href=&#34;https://appdb.winehq.org/objectManager.php?sClass=version&amp;amp;iId=10120&#34;&gt;use&lt;/a&gt;
Wine
&lt;a href=&#34;https://appdb.winehq.org/objectManager.php?sClass=version&amp;amp;iId=15596&#34;&gt;before&lt;/a&gt;
and it failed miserably.&lt;/p&gt;
&lt;p&gt;Well, Wine today can run DTXMania 067b just fine, even the version 061. In
fact, those are versions that predate the open-sourcing of the game. And since
I fail to build it on Fedora, I can&amp;rsquo;t assess when things broke today&amp;rsquo;s Wine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ dnf info wine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Installed Packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name         : wine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Version      : 3.13
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Release      : 3.fc28
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Arch         : x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Size         : 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Source       : wine-3.13-3.fc28.src.rpm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Repo         : @System
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;From repo    : updates
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Summary      : A compatibility layer for windows applications
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;URL          : https://www.winehq.org/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;License      : LGPLv2+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description  : Wine as a compatibility layer for UNIX to run Windows applications. This
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             : package includes a program loader, which allows unmodified Windows
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             : 3.x/9x/NT binaries to run on x86 and x86_64 Unixes. Wine can use native system
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             : .dll files if they are available.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             :
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             : In Fedora wine is a meta-package which will install everything needed for wine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             : to work smoothly. Smaller setups can be achieved by installing some of the
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             : wine-* sub packages.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All I can say is that it broke somewhere between 067b and 087. Maybe in a
couple years Wine will catch up and run it like a champ! But I&amp;rsquo;m not here to
reverse engineer the Windows APIs, so in the &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-7/&#34;&gt;next&lt;/a&gt; post I will resume my report on &lt;code&gt;xadec.dll&lt;/code&gt; but I
don&amp;rsquo;t expect to stick to one post a week. While I still have my decompiled
source code, I lost the side-by-side decompilation with the assembly.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Starting the xadec.dll puzzle</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-5/</link>
      <pubDate>Sun, 08 Jul 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-5/</guid>
        <description>&lt;h2 id=&#34;thinking-like-a-compiler&#34;&gt;Thinking like a compiler&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-4/&#34;&gt;previous post&lt;/a&gt; I came to the
conclusion that &lt;code&gt;xadec.dll&lt;/code&gt; turns an XA file into a PCM stream and describes
that PCM stream with a &lt;code&gt;WAVEFORMATEX&lt;/code&gt; data structure. After looking at the
valuable insights present in &lt;code&gt;xadec.h&lt;/code&gt; it&amp;rsquo;s now time to look at the assembly
and for the first time encounter machine code that _really_ doesn&amp;rsquo;t look
like what a sane human being would come up with.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;xaDecodeOpen&lt;/code&gt; function does two main things: set up the decoder state and
fill the &lt;code&gt;WAVEFORMATEX&lt;/code&gt; structure. And that&amp;rsquo;s where the riddle begins: given
an opaque data structure, how to make sense of the values it holds?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001000:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001001:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001002:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;esp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xc&lt;/span&gt;]         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ebp = pxah; /* arg0 */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001006:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001007:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;cmp&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x0&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x3144574b&lt;/span&gt;  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (pxah-&amp;gt;id != _XAID)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000100&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jne&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x1000110a&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;         return (0); /* error */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001014:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#40a070&#34;&gt;0x34&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001016:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#40a070&#34;&gt;0x40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001018:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;call&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;ds&lt;/span&gt;:&lt;span style=&#34;color:#40a070&#34;&gt;0x10006010&lt;/span&gt;         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = GlobalAlloc(64, 52);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000101&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000101&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;call&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;ds&lt;/span&gt;:&lt;span style=&#34;color:#40a070&#34;&gt;0x1000600c&lt;/span&gt;         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = GlobalLock(eax); /* no-op */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001025:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ebx = eax; /* hxas = calloc(1, 52); */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001027:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (ebx == NULL)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001029:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;je&lt;/span&gt;     &lt;span style=&#34;color:#40a070&#34;&gt;0x1000110a&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;         return (0); /* error */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000102&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being completely new to this, and lacking any clear methodology I made things
up as I was making progress. I would for example call &lt;code&gt;arg0&lt;/code&gt; the first
argument to a function, or replace it with its name (if it&amp;rsquo;s known or I
understand its purpose). In this case &lt;code&gt;arg0&lt;/code&gt; is called &lt;code&gt;pxah&lt;/code&gt; in &lt;code&gt;xadec.h&lt;/code&gt; and
its &lt;code&gt;id&lt;/code&gt; field known, otherwise I would have called written down something
like &lt;code&gt;arg0-&amp;gt;dw0&lt;/code&gt; in the &lt;code&gt;if&lt;/code&gt; statement where &lt;code&gt;dw0&lt;/code&gt; means a 32-bit integer at
the offset &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I have yet to make sense of what the opaque data structure fields mean, but at
least I know its size: 52 octets. Yikes, that&amp;rsquo;s a lot of bytes to keep track
of.&lt;/p&gt;
&lt;p&gt;I note that a failing &lt;code&gt;GlobalLock&lt;/code&gt; after a succeeding &lt;code&gt;GlobalAlloc&lt;/code&gt; will leak
52 bytes of memory (plus the allocator&amp;rsquo;s overhead for alignment and tracking)
but I also note something interesting. I once read that the first rule of
compiler optimizations is that the compiler is smarter than you, and the
second rule is that the compiler is smarter than you. Apparently &lt;code&gt;xadec.dll&lt;/code&gt;
was either compiled without (much) optimizations or comes from a time where
compilers were less smart. In this case I&amp;rsquo;m not sure how moving &lt;code&gt;eax&lt;/code&gt;&amp;rsquo;s value
to &lt;code&gt;ebx&lt;/code&gt; helps. Testing a null &lt;code&gt;eax&lt;/code&gt; would have the same effect of unwinding
the stack and returning an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001104:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000110&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;                              &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000110&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;                              &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000110&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                          &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000110&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;                              &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000110&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;                                     &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; return (eax); /* error */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You could even save some processing by moving the &lt;code&gt;xor&lt;/code&gt; operation before the
other &lt;code&gt;pop&lt;/code&gt; operations and jump straight after the &lt;code&gt;xor&lt;/code&gt; when &lt;code&gt;GlobalLock&lt;/code&gt;
fails and &lt;code&gt;eax&lt;/code&gt; is already null. Unless &lt;code&gt;pop esi&lt;/code&gt; or &lt;code&gt;pop ebp&lt;/code&gt; has a side
effect I&amp;rsquo;m not aware of on &lt;code&gt;eax&lt;/code&gt;, which sounds highly unlikely to me. I&amp;rsquo;ve had
this idea for a while that most software problems can be reduced to graph
theory problems. The use (and reuse) of a limited set of registers is akin to
graph coloring and that&amp;rsquo;s a tough nut to crack, but I digress&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;thinking-more-like-a-compiler&#34;&gt;Thinking more like a compiler&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s move on and stay focused on what&amp;rsquo;s happening in the code. It&amp;rsquo;s already
complicated enough, and too early too think about optimizing anything. It is
more likely that I may have to mentally deoptimize code unless I&amp;rsquo;m lucky&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001029:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000102&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001031:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;al&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;BYTE&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xe&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = pxah-&amp;gt;nBits;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001034:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;sub&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0x4&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax -= 4;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001037:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;je&lt;/span&gt;     &lt;span style=&#34;color:#40a070&#34;&gt;0x10001063&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (eax == 0) goto 0x10001063;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001039:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;sub&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0x2&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax -= 2;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000103&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;je&lt;/span&gt;     &lt;span style=&#34;color:#40a070&#34;&gt;0x10001053&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (eax == 0) goto 0x10001053;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000103&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;sub&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0x2&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax -= 2;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001041:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jne&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x10001071&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (eax != 0) goto 0x10001071;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001043:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x28&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x21&lt;/span&gt;       &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw40 = 31;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000104&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x2c&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x10001450&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw44 = 0x10001450;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001051:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jmp&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x10001071&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; goto 0x10001071;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001053:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x28&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x19&lt;/span&gt;       &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw40 = 25;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000105&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x2c&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x100013e0&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw44 = 0x100013e0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001061:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jmp&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x10001071&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; goto 0x10001071;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001063:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x28&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x11&lt;/span&gt;       &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw40 = 17;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000106&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x2c&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x100013a0&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw44 = 0x100013a0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001071:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So now the compiler is outsmarting us for a greater good, unless &lt;code&gt;xadec.dll&lt;/code&gt;
was coded in this style which I highly doubt. It is commonly known that
computers are good at comparing things to zero and sometimes simply turning a
&lt;code&gt;for&lt;/code&gt; loop upside down so that it converges towards zero can provide a
noticeable performance boost. An explanation could be that some architectures
like x86 may set the zero flag (ZF) for instructions not primarily designed to
make comparisons. Arithmetic and bitwise operations set the flag if the result
is zero and unset it otherwise, and &lt;code&gt;sub&lt;/code&gt; can be followed by a conditional
jump.&lt;/p&gt;
&lt;p&gt;So conceptually we get this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt; nBits &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; pxah&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;nBits;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; ((nBits &lt;span style=&#34;color:#666&#34;&gt;-=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw40 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;31&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw44 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x10001450&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; ((nBits &lt;span style=&#34;color:#666&#34;&gt;-=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw40 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;25&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw44 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x100013e0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; ((nBits &lt;span style=&#34;color:#666&#34;&gt;-=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw40 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw44 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x100013a0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* hxas-&amp;gt;dw40 and hxas-&amp;gt;dw44 are both zero */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After a mental deoptimization I may write this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; xastream &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeOpen&lt;/span&gt;(&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; xaheader &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;pxah, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; waveformatex &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;wfx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; xastream &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;hxas &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (pxah&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;id &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; _XAID)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;calloc&lt;/span&gt;(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;52&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (hxas &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (pxah&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;nBits &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw40 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;31&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw44 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x10001450&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (pxah&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;nBits &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw40 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;25&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw44 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x100013e0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (pxah&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;nBits &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw40 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		hxas&lt;span style=&#34;color:#666&#34;&gt;-&amp;gt;&lt;/span&gt;dw44 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x100013a0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the other hand retdec ended up with something confusing, looking roughly
like this once stripped (really really) down:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// Address range: 0x10001000 - 0x1000110f
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeOpen&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; a1, &lt;span style=&#34;color:#902000&#34;&gt;int16_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; a2, &lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; a3) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; v1 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt;)a1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)a1 &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x3144574b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; v2 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;GlobalLock&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;GlobalAlloc&lt;/span&gt;(&lt;span style=&#34;color:#40a070&#34;&gt;64&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;52&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; pMem2 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt;)v2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (v2 &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#902000&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; v3 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(v1 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; v4 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; v3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (v3 &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (v4 &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(pMem2 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;40&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;25&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(pMem2 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;44&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x100013e0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (v4 &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(pMem2 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;40&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;33&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(pMem2 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;44&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x10001450&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)pMem2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(pMem2 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;40&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(pMem2 &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;44&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0x100013a0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)pMem2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may note the presence of a third argument, and this is likely a problem
caused by the lack of known calling convention and my inability to find how to
tell retdec which one it is. It also has the tendency to follow the assembly
too closely and for example when &lt;code&gt;pxah-&amp;gt;nBits&lt;/code&gt; is moved as a byte and then
computed as a dword, we end up with two distinct variables &lt;code&gt;v3&lt;/code&gt; and &lt;code&gt;v4&lt;/code&gt;. And
that&amp;rsquo;s when we&amp;rsquo;re lucky: not accounting for the &lt;code&gt;/* ... */&lt;/code&gt; code duplication
there were 12 other local variables and in total the library decompilation
grew 119 global variables.&lt;/p&gt;
&lt;h2 id=&#34;breaking-the-spell&#34;&gt;Breaking the spell&lt;/h2&gt;
&lt;p&gt;With a partial function decompilation we already end up with a handful of
magic numbers, so it&amp;rsquo;s best to start now. I&amp;rsquo;m leaving &lt;code&gt;0x3144574b&lt;/code&gt; out because
it was ostensibly waiting to be picked up in &lt;code&gt;xadec.h&lt;/code&gt; and seemed like the
first thing you&amp;rsquo;d check in a function called &lt;code&gt;xaDecodeOpen&lt;/code&gt;. Well, don&amp;rsquo;t mind
me, that would be the second thing to check, right? Did you notice the lack of
null check of &lt;code&gt;arg0&lt;/code&gt; aka &lt;code&gt;pxah&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Next, the mysterious numbers 17, 25 and 33. In order to understand their
meaning, I need to solve a couple equations and for the sake of brevity I will
mention when I get to that code what confirmed the supposed meaning.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f(x) = ???
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f(8) = 33
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f(6) = 25
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f(4) = 17
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It doesn&amp;rsquo;t take much time to notice the pattern, at least it didn&amp;rsquo;t take me long to realize that those figures were &amp;ldquo;almost&amp;rdquo; recognizable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;blockSize(nBits) = 4 * nBits + 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;blockSize(8) = 33
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;blockSize(6) = 25
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;blockSize(4) = 17
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Praise my mighty arithmetic powers!&lt;/p&gt;
&lt;p&gt;Next I need to make sense of &lt;code&gt;0x10001450&lt;/code&gt;, &lt;code&gt;0x100013e0&lt;/code&gt; and &lt;code&gt;0x100013a0&lt;/code&gt;. They
look awfully like function addresses, and tracking the use of this &lt;code&gt;44&lt;/code&gt; offset
confirms it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;100011&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c4:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;100011&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c5:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;100011&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c6:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;call&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;edi&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x2c&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One can assume that &lt;code&gt;nBits&lt;/code&gt; refers to the number of bits per samples, so the
addresses probably refer to callbacks that uncompress the samples, and it
looks like the callbacks take two arguments.&lt;/p&gt;
&lt;p&gt;Moving forward in the decompilation I find more magic numbers, but fortunately
less magic and more straightforward from now on:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000106&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001071:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001073:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;al&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;BYTE&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xf&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = pxah-&amp;gt;nChannels;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001076:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;dec&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax--;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001077:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;je&lt;/span&gt;     &lt;span style=&#34;color:#40a070&#34;&gt;0x10001085&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (eax == 0) goto 0x10001085;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001079:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;dec&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax--;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000107&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jne&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x1000108c&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (eax != 0) goto 0x1000108c;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000107&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x30&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x10001210&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw48 = 0x10001210;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001083:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jmp&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x1000108c&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; goto 0x1000108c;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001085:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x30&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x10001190&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; hxas-&amp;gt;dw48 = 0x10001190;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000108&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is quite similar to the &lt;code&gt;nBits&lt;/code&gt; callbacks, here we have what looks like
one callback for mono and one callback for stereo conversion. Again, using the
same trick with &lt;code&gt;dec&lt;/code&gt; instead of &lt;code&gt;sub&lt;/code&gt; to compare &lt;code&gt;pxah-&amp;gt;nChannels&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; and
&lt;code&gt;2&lt;/code&gt;. &lt;code&gt;xadec.dll&lt;/code&gt; is a 32bit library, so it&amp;rsquo;s no surprise to see function
pointers fit in a dword.&lt;/p&gt;
&lt;h2 id=&#34;boardom-is-bliss&#34;&gt;Boardom is bliss&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m a big fan of The IT Crowd, a silly British sitcom that manages to be
hilarious at times. There&amp;rsquo;s an episode on board games, and they make it really
sound like bored games, and sometimes boredom is the best thing that could
happen to you, but I digress. Thankfully at this point it&amp;rsquo;s all very boring.&lt;/p&gt;
&lt;p&gt;There is nothing complicated in this function and the decompilation is very
straightforward. Except maybe for a couple magic numbers that were easy to
understand, there was really only one surprising thing. The next boring step
is to check that we have both callbacks, so in other words a valid combination
of sample size and mono or stereo sound.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001085:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000108&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x2c&lt;/span&gt;]        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = hxas-&amp;gt;dw44;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000108&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (hxas-&amp;gt;dw44 == NULL)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001091:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;je&lt;/span&gt;     &lt;span style=&#34;color:#40a070&#34;&gt;0x100010f0&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;         goto 0x100010f0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001093:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x30&lt;/span&gt;]        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = hxas-&amp;gt;dw48;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001096:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (hxas-&amp;gt;dw48 == NULL)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001098:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;je&lt;/span&gt;     &lt;span style=&#34;color:#40a070&#34;&gt;0x100010f0&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;         goto 0x100010f0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000109&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m omitting the error handing at &lt;code&gt;0x100010f0&lt;/code&gt; but it is positioned just
before the bit I already decompiled and frees &lt;code&gt;hxas&lt;/code&gt; before returning zero
(aka an error in this case).&lt;/p&gt;
&lt;p&gt;Next is a bit of a surprise, although not puzzling. Thanks to prior exposure
to this construct I was able to follow the logic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001098:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000109&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;edi&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 16
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000109&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0x8&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ecx = 8;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a0:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esi = pxah
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a2:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;edi&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; edi = hxas
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a4:&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;rep&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;movs&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;es&lt;/span&gt;:[&lt;span style=&#34;color:#60add5&#34;&gt;edi&lt;/span&gt;],&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;ds&lt;/span&gt;:[&lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                 &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; memcpy(hxas, pxah, sizeof *pxah);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a6:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Copy 8 dwords (32 bytes) from &lt;code&gt;pxah&lt;/code&gt; to &lt;code&gt;hxas&lt;/code&gt;, in other words embed a copy of
the XA header in the opaque data structure, removing at once 32 bytes from the
52 bytes puzzle. What. A. Relief.&lt;/p&gt;
&lt;h2 id=&#34;surf-the-wave&#34;&gt;Surf the WAVE&lt;/h2&gt;
&lt;p&gt;Surf is one of those board games for which I wonder how it all started. At
some point someone thought it would be fun to ride waves, and turned out to be
correct. But how does such an idea come to someone&amp;rsquo;s mind? In a sense, this
reverse engineering journey is that kind of improbable idea, and after a poor
start I now feel like everything is going by itself according to plan. World
domination will ensue.&lt;/p&gt;
&lt;p&gt;The last bit of good news came from the last bit of decompiled code. At this
point where everything succeeded, all we need (barring one more missing null
check) is to fill in the wave file format:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a4:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;a6:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;esp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x18&lt;/span&gt;]        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ecx = wfx; /* arg1 */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;aa:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; edx = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;ac:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;edi&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;ad:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;ae:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x1&lt;/span&gt;              &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;wFormatTag = WAVE_FORMAT_PCM;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b3:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;movzx&lt;/span&gt;  &lt;span style=&#34;color:#60add5&#34;&gt;ax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;BYTE&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xf&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ax = pxah-&amp;gt;nChannels;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b8:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x2&lt;/span&gt;],&lt;span style=&#34;color:#60add5&#34;&gt;ax&lt;/span&gt;           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;nChannels = pxah-&amp;gt;nChannels;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;bc:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;dx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xc&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; dx = pxah-&amp;gt;nSamplesPerSec;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c0:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x4&lt;/span&gt;],&lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;nSamplesPerSec = pxah-&amp;gt;nSamplesPerSec;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c3:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; edx = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c5:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;movzx&lt;/span&gt;  &lt;span style=&#34;color:#60add5&#34;&gt;ax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;BYTE&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xf&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; ax = pxah-&amp;gt;nChannels;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;ca:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;shl&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;                           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax /= 2;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;cc:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xc&lt;/span&gt;],&lt;span style=&#34;color:#60add5&#34;&gt;ax&lt;/span&gt;           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;nBlockAlign = pxah-&amp;gt;nChannels / 2;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;d0:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;dx&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xc&lt;/span&gt;]           &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; dx = pxah-&amp;gt;nSamplesPerSec;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;d4:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;and&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;0xffff&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = ax; /* no prior xor */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;d9:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ebp&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;da:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;imul&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;edx&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = pxah-&amp;gt;nSamplesPerSec * pxah-&amp;gt;nChannels / 2;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;dd:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x8&lt;/span&gt;],&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;nAvgBytesPerSec = eax;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e0:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;                         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; eax = hxas;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e2:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0xe&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x10&lt;/span&gt;         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;wBitsPerSample = 16;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;e8:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;WORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;ecx&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x10&lt;/span&gt;],&lt;span style=&#34;color:#40a070&#34;&gt;0x0&lt;/span&gt;         &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; wfx-&amp;gt;cbSize = 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;ee:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;ebx&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;ef:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;                                    &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; return (hxas);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;100010&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f0:&lt;/span&gt; &lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The decoder always produces 16bit PCM at the same rate as the XA file, and
this code confirms that the &lt;code&gt;WAVEFORMATEX&lt;/code&gt; structure pointer is an &amp;ldquo;output&amp;rdquo;
argument, not a regular argument asking to produce &amp;ldquo;that kind of WAVE data&amp;rdquo;.
It means that the rest of the code should remain simple as well and that&amp;rsquo;s
quite motivating to follow this through the end.&lt;/p&gt;
&lt;h2 id=&#34;collecting-my-precious&#34;&gt;Collecting my precious&lt;/h2&gt;
&lt;p&gt;With all that, my first pieces of the puzzle:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; TODO &lt;span style=&#34;color:#06287e&#34;&gt;xa_inflate_f&lt;/span&gt;(TODO, TODO);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; TODO &lt;span style=&#34;color:#06287e&#34;&gt;xa_convert_f&lt;/span&gt;(TODO, TODO);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; xastream {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; xaheader hdr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#902000&#34;&gt;uint32_t&lt;/span&gt;        dw32;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#902000&#34;&gt;uint32_t&lt;/span&gt;        dw36;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#902000&#34;&gt;uint32_t&lt;/span&gt;        blk_sz; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* 40 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        xa_inflate_f    &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;inflate_cb; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* 44 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        xa_convert_f    &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;convert_cb; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* 48 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* 52 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately that uncovered more pieces, but most of the opaque structure is
known and that is a very significant progress. In the &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-6/&#34;&gt;next post&lt;/a&gt; I will take a step back and look at more trivial
matters.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>First contact with &#34;the&#34; XA codec</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-4/</link>
      <pubDate>Sun, 01 Jul 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-4/</guid>
        <description>&lt;h2 id=&#34;cracking-the-codec-open&#34;&gt;Cracking the codec open&lt;/h2&gt;
&lt;p&gt;I may have complained in a past blog post that retdec as a decompiler didn&amp;rsquo;t
produce readable or helpful code, I may have even said that the code was
horrible, but I also showed that it was rather good at figuring library calls.
So in order to understand that the four Windows function calls could be
reduced to a plain &lt;code&gt;free(3)&lt;/code&gt; call I had to both look at the decompiled code
for &lt;code&gt;xaDecodeOpen&lt;/code&gt; and documentation of the functions and their flags on the
MSDN.&lt;/p&gt;
&lt;p&gt;These days I&amp;rsquo;m way more comfortable with the &lt;code&gt;man&lt;/code&gt; utility, but in a sense I
also think that online docs are very important. In this regard, I always found
Microsoft&amp;rsquo;s MSDN a very good place to browse documentation. It has always been
a terrible place to start browsing though. If it weren&amp;rsquo;t for search engines, I
would never find the starting point.&lt;/p&gt;
&lt;p&gt;In order to &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-3/&#34;&gt;decompile&lt;/a&gt; &lt;code&gt;xaDecodeClose&lt;/code&gt;
I needed to look at &lt;code&gt;xaDecodeOpen&lt;/code&gt; to enumerate all memory management
functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GlobalAlloc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GlobalFree&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GlobalHandle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GlobalLock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GlobalUnlock&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In portable C code that can be safely reduced to &lt;code&gt;calloc(3)&lt;/code&gt; and &lt;code&gt;free(3)&lt;/code&gt;. No
big surprise here, it is the memory management of the opaque structure, the
“handle”. In other words, stuff hidden under the compiler rug that I will need
to uncover, gathering clues like a detective, trying to fit all the pieces
together. And that first clue was waiting there in the open to be picked up:
&lt;code&gt;xaDecodeOpen&lt;/code&gt;&amp;rsquo;s second argument.&lt;/p&gt;
&lt;h2 id=&#34;the-big-bad-wav-file&#34;&gt;The big bad WAV file&lt;/h2&gt;
&lt;p&gt;One misconception about WAV files is that they are big because uncompressed,
another is that they are WAV files. WAV files are really one kind of RIFF
file, a generic container that specialized in audio and video. A RIFF file is
made of chunks and a WAV file is a RIFF file with a WAVE chunk describing how
its audio data is encoded, and then a data chunk containing the aforementioned
audio data. You could for example use an MP3 codec in a WAV file, and you
would get a file approximately the same size as an MP3 file. It&amp;rsquo;s probably
even possible to add things like track information or subtitles to a RIFF
file, similar to MP3s ID3 tags but at this point, I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;The reason most WAV files are big is because of their number one (literally)
and probably most widely used codec: PCM or Pulse-Code Modulation. To keep it
short (or digression-free) the signal is represented with a fixed duration for
samples and each samples has a fixed value. In stereo mode, samples are
interleaved, with one left sample followed by one right sample for each point
in time. Interleaving is streaming-friendly as you may read the audio without
the need to jump back and forth in the audio stream and can avoid pseudo
random accesses. Arguably, picking the smallest granularity (individual
samples) may not be that efficient, but I can&amp;rsquo;t help it, I digress.&lt;/p&gt;
&lt;h2 id=&#34;from-xa-to-pcm&#34;&gt;From XA to PCM&lt;/h2&gt;
&lt;p&gt;Looking at &lt;code&gt;sample.c&lt;/code&gt;, &lt;code&gt;xadec.h&lt;/code&gt; and some MSDN documentation we roughly see
this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; _XAHEADER {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ULONG	id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ULONG	nDataLen;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ULONG	nSamples;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	USHORT	nSamplesPerSec;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	UCHAR	nBits;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	UCHAR	nChannels;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ULONG	nLoopPtr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	SHORT	befL[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	SHORT	befR[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	UCHAR	pad[&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} XAHEADER;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	WORD	wFormatTag;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	WORD	nChannels;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	DWORD	nSamplesPerSec;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	DWORD	nAvgBytesPerSec;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	WORD	nBlockAlign;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	WORD	wBitsPerSample;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	WORD	cbSize;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} WAVEFORMATEX;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	FILE &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;fp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	XAHEADER xah;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	WAVEFORMATEX wfx;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	XASTREAMHEADER xash;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	fp &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;fopen&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;sample.xa&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;fread&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;xah, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(XAHEADER), fp);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	hxas &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeOpen&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;xah, &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&lt;/span&gt;wfx);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point we could assume that &lt;code&gt;xadec.dll&lt;/code&gt; will turn an XA file into a WAV
file but no. While I claimed that this XA file format doesn&amp;rsquo;t look like
something the Bandjam author came up with, the use of &lt;code&gt;WAVEFORMATEX&lt;/code&gt; on the
other hand looks like a Windows-oriented choice in API design. The &lt;code&gt;wfx&lt;/code&gt;
structure is passed as an “output” parameter, only to neatly pack information
about the resulting audio in a single data structure. We technically already
have all we need in the &lt;code&gt;XAHEADER&lt;/code&gt; structure, provided that we know one more
secret about &lt;code&gt;xaDecodeOpen&lt;/code&gt; (hint: it&amp;rsquo;s hidden in the assembly.)&lt;/p&gt;
&lt;h2 id=&#34;the-xa-header&#34;&gt;The XA header&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fread(3)&lt;/code&gt; call gives us one vital piece of information: the XA header is
located at the beginning of the file and is serialized using little endian
integers. It means that at this point I&amp;rsquo;m able to dump the header of an XA and
keep track of how the header fields are used using their offset, and that
should help me dig further.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m always baffled that ISO C99 doesn&amp;rsquo;t offer anything to deal with the byte
order of a given architecture. The byte orders big and little endian define in
which order a “word” is laid out in memory. Confusingly enough, endian refers
to one end or the other of the “word” once broken down into octets, so in this
case values from the XA header &lt;em&gt;start&lt;/em&gt; from the little &lt;em&gt;end&lt;/em&gt;. It&amp;rsquo;s as
confusing as finding the shutdown function in the start menu on Windows.&lt;/p&gt;
&lt;p&gt;Apparently the name was borrowed from Johnathan Swift&amp;rsquo;s Gulliver&amp;rsquo;s Travels in
which rebels would break their eggs from the big end in a political opposition
to the Lilliputian king who&amp;rsquo;s tyrannic rule imposed breaking them from the
little end. So in computing we find architectures relying on either ordering
(and in some cases even both I&amp;rsquo;m told). It can get even more messy with “word”
order.&lt;/p&gt;
&lt;p&gt;Network protocols tend to favor big endian representation over the wire so
it&amp;rsquo;s often referred to network byte order too. And for no apparent reason C
was left with nothing to deal with architectural differences besides the usual
undefined behavior. Instead we have cryptic function names from another time
like &lt;code&gt;ntohs&lt;/code&gt; and &lt;code&gt;ntohl&lt;/code&gt; to convert numbers back and forth between network and
host (CPU architecture) byte order. Nothing part of the C standard to go back
and forth between both byte orders. Either those functions are no-op on a big
endian host, or they swap the ordering. But I digress.&lt;/p&gt;
&lt;p&gt;The header looks mostly straightforward: a magic number, audio information,
some padding to align to a power of 2 byte size (32) and the number of bytes
(&lt;code&gt;nDataLen&lt;/code&gt;) after the header. Then there are less obvious fields like
&lt;code&gt;nSamples&lt;/code&gt; that can probably be computed from (and sanity-checked against) the
other values and the &lt;code&gt;befL&lt;/code&gt; and &lt;code&gt;befR&lt;/code&gt; arrays. They will turn out to be very
important clues that I only understood in retrospect. I&amp;rsquo;m not sure whether I
could have figured out their purpose beforehand though, but they definitely
confirmed my interpretation of the codec.&lt;/p&gt;
&lt;p&gt;However, this is a topic for later. In the next post I will describe the
&lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-5/&#34;&gt;decompilation&lt;/a&gt; of &lt;code&gt;xaDecodeOpen&lt;/code&gt; and
how encouraging it was.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>My first function decompilation</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-3/</link>
      <pubDate>Sun, 24 Jun 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-3/</guid>
        <description>&lt;h2 id=&#34;first-x86-contact&#34;&gt;First x86 contact&lt;/h2&gt;
&lt;p&gt;My &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-2/&#34;&gt;hopes&lt;/a&gt; to offload as much work as
possible were shattered as time was running out and I wasn&amp;rsquo;t finding the right
tool for the job that would be both easy, efficient and not require too much
investment from me. If decompilation is not a silver bullet, then there&amp;rsquo;s no
getting around learning some assembly to understand the target code and figure
what the original source code may have looked like. Once you have working
code, you may be happy and move on to using it but I&amp;rsquo;m way too curious to not
try to also understand how things work beyond mechanically turning a byte
stream into a different byte stream.&lt;/p&gt;
&lt;p&gt;They say curiosity killed the cat, so I&amp;rsquo;m probably a serial pet killer at this
point and have always been. Of course it&amp;rsquo;s not my fault, it never is. I can
easily shift the blame to public school that gave me the taste to learn and
the lack of responsible adults when I was a kid to tell me how I would
endanger an entire feline species. But I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;So soon after I discovered programming, I tried to learn more about computers
in general and eventually I got my virtual hands onto a file called &lt;code&gt;nasm.chm&lt;/code&gt;
that would keep me occupied for a while. I would mainly write small useless
programs using a handful of x86 and x87 instructions to compute well known
functions using their Taylor series approximation.&lt;/p&gt;
&lt;h2 id=&#34;learning-x86&#34;&gt;Learning x86&lt;/h2&gt;
&lt;p&gt;To be honest, I don&amp;rsquo;t remember whether I was using nasm or fasm, but either
way it came with a CHM file: a web based self-contained file with an index and
the possibility to jump between sections via hyper links. You&amp;rsquo;d even find
trivia like how many CPU cycles each instruction would take.&lt;/p&gt;
&lt;p&gt;These days I&amp;rsquo;m way more comfortable with the &lt;code&gt;man&lt;/code&gt; utility, but in a sense CHM
can be viewed as a GUI alternative to GNU &lt;code&gt;info&lt;/code&gt;. While I understand the
rationale and terminal appeal behind &lt;code&gt;info&lt;/code&gt;, I&amp;rsquo;m always confused whenever I
need to look up something not mentioned in the standard manual. In that CHM
file I would easily find everything and that probably played a part in the
learning process, but I digress.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s look at a very small and simple function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001110:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#bb60d5&#34;&gt;%esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001111:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x8&lt;/span&gt;(&lt;span style=&#34;color:#bb60d5&#34;&gt;%esp&lt;/span&gt;),&lt;span style=&#34;color:#bb60d5&#34;&gt;%esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001115:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test&lt;/span&gt;   &lt;span style=&#34;color:#bb60d5&#34;&gt;%esi&lt;/span&gt;,&lt;span style=&#34;color:#bb60d5&#34;&gt;%esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001117:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jne&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x1000111d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001119:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#bb60d5&#34;&gt;%eax&lt;/span&gt;,&lt;span style=&#34;color:#bb60d5&#34;&gt;%eax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000111&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#bb60d5&#34;&gt;%esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000111&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000111&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;d:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#bb60d5&#34;&gt;%edi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000113&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks nothing like what I learned about x86 assembly. Well it does look
familiar but I don&amp;rsquo;t understand the notation. It turns out this is the AT&amp;amp;T
notation and even though I&amp;rsquo;ve been living on the UNIX-like side of the fence
for years now I&amp;rsquo;ll stick to the Intel notation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;objdump --disassemble-all --disassembler-options=intel xadec.dll
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Much better, I can now start my mental decompilation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;10001110:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is now 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001111:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;mov&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;DWORD&lt;/span&gt; &lt;span style=&#34;color:#60add5&#34;&gt;PTR&lt;/span&gt; [&lt;span style=&#34;color:#60add5&#34;&gt;esp&lt;/span&gt;&lt;span style=&#34;&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0x8&lt;/span&gt;]  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esi = arg0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001115:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;                  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; if (arg0 == NULL) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001117:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;jne&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0x1000111d&lt;/span&gt;               &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;     /* else jump */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;10001119:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xor&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;,&lt;span style=&#34;color:#60add5&#34;&gt;eax&lt;/span&gt;                  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;     eax = 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000111&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;b:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;pop&lt;/span&gt;    &lt;span style=&#34;color:#60add5&#34;&gt;esi&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;     esp offset to eip is now 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000111&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;c:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;                             &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;;     return (0);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;                                          &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;1000111&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;d:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;push&lt;/span&gt;   &lt;span style=&#34;color:#60add5&#34;&gt;edi&lt;/span&gt;                      &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;; esp offset to eip is now 8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;1000113&lt;/span&gt;&lt;span style=&#34;color:#002070;font-weight:bold&#34;&gt;f:&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;ret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Isn&amp;rsquo;t it funny that physicists accidentally called atoms as such because they
were thought to be indivisible? It turns out they are made of electrons,
protons and neutrons. And we can even break some further down to what we now
think are elementary particles although at this point, I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;I was lucky that &lt;code&gt;xadec.dll&lt;/code&gt; contained only one instruction I had never
encountered before, so the learning curve was almost flat. Instructions are
like atoms, the smallest decomposition of work we can give an x86-compatible
processor although depending on the operands they will yield different
opcodes. The opcodes and their argument bytes don&amp;rsquo;t bring any value to the
&lt;code&gt;objdump&lt;/code&gt; output so I cut them out.&lt;/p&gt;
&lt;p&gt;Prior exposure to x86 code helped a lot. This way I knew immediately that &lt;code&gt;xor eax, eax&lt;/code&gt; is a common alternative to &lt;code&gt;mov eax, 0&lt;/code&gt; and wasn&amp;rsquo;t bewildered that
&lt;code&gt;esi&lt;/code&gt; would be &lt;code&gt;test&lt;/code&gt;ed against itself. Why though, I don&amp;rsquo;t know, but I
suspect this may simply be more efficient or result in smaller machine code. I
may be curious, but I can also enjoy a bit of mystery.&lt;/p&gt;
&lt;p&gt;However, how can I tell that &lt;code&gt;arg0&lt;/code&gt; is a pointer and not simply a scalar? How
can I assume that this is a null check?&lt;/p&gt;
&lt;h2 id=&#34;the-first-clues&#34;&gt;The first clues&lt;/h2&gt;
&lt;p&gt;The snippets above are from the &lt;code&gt;xaDecodeClose&lt;/code&gt; function, one of the 4 public
symbols I can find in the disassembly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Export Address Table -- Ordinal Base 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   0] +base[   1] 1110 Export RVA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   1] +base[   2] 1170 Export RVA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   2] +base[   3] 1000 Export RVA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   3] +base[   4] 1140 Export RVA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Ordinal/Name Pointer] Table
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   0] xaDecodeClose
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   1] xaDecodeConvert
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   2] xaDecodeOpen
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [   3] xaDecodeSize
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at other properties of the file I can make sense of the address &lt;code&gt;1110&lt;/code&gt;
of the first table, and deduce that &lt;code&gt;xaDecodeClose&lt;/code&gt; is located at &lt;code&gt;10001110&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BaseOfCode              00001000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BaseOfData              00006000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ImageBase               10000000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All public symbols seem to land in the code section of the library. The C code
generated by retdec also confirms my amazing deduction of the location of
&lt;code&gt;xaDecodeClose&lt;/code&gt; with my mighty arithmetic powers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// Address range: 0x10001110 - 0x1000113f
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeClose&lt;/span&gt;(&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; pMem, &lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt; a2) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// 0x10001110
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; (pMem &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;NULL&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// 0x10001119
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;// 0x1000111d
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#06287e&#34;&gt;GlobalUnlock&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;GlobalHandle&lt;/span&gt;(pMem));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#06287e&#34;&gt;GlobalFree&lt;/span&gt;(&lt;span style=&#34;color:#06287e&#34;&gt;GlobalHandle&lt;/span&gt;((&lt;span style=&#34;color:#902000&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;)(&lt;span style=&#34;color:#902000&#34;&gt;int32_t&lt;/span&gt;)pMem));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I said earlier that retdec produces horrible C code, this is quite readable.
Don&amp;rsquo;t be fooled though, because retdec was confused and got the signature
wrong. It failed to figure the calling convention of the library but that
didn&amp;rsquo;t bother me too much, I knew.&lt;/p&gt;
&lt;p&gt;How did I know that? And how did I know that &lt;code&gt;arg0&lt;/code&gt; is a pointer prior to
peeping at the decompiled C?&lt;/p&gt;
&lt;h2 id=&#34;open-source-to-the-rescue-again&#34;&gt;Open source to the rescue, again!&lt;/h2&gt;
&lt;p&gt;Even though there&amp;rsquo;s no source code for &lt;code&gt;xadec.dll&lt;/code&gt;, it has been used by more
than one project so they need to know how to use it. Thanks to DTXMania being
open source, I not only found the bundled DLL in the source tree but also a
&lt;code&gt;xadec.h&lt;/code&gt; file and even better: a &lt;code&gt;sample.c&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;After wasting a fair amount of time failing to cross-compile &lt;code&gt;sample.c&lt;/code&gt; to run
it in Wine, hoping to get a sample output to compare to what my code would
provide, I gave up. I had everything: &lt;code&gt;xadec.dll&lt;/code&gt;, &lt;code&gt;xadec.lib&lt;/code&gt;, &lt;code&gt;xadec.h&lt;/code&gt;, a
tool chain to build Windows binaries and Wine to run &lt;code&gt;sample.exe&lt;/code&gt; but it would
always fail to link and at some point I ran out of the 2-hour budget I had
allocated for that. I realized later that it wouldn&amp;rsquo;t be a problem.&lt;/p&gt;
&lt;p&gt;Not too long ago, we discovered that one of our fellow Varnish developers is a
beekeeper on his spare time. That reminded me of an old joke of mine that for
some reason never caught on: API culture. That was supposed to be a pun: “I&amp;rsquo;m
doing apiculture” was suppose to mean “I&amp;rsquo;m designing the API”. In French
“apiculture” means beekeeping. It&amp;rsquo;s a mystery why this joke never caught on.&lt;/p&gt;
&lt;p&gt;Anyway, thanks again to DTXMania I could sum up the API to this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; _XASTREAMHEADER { ... } XASTREAMHEADER;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; _XAHEADER { ... } XAHEADER;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;typedef&lt;/span&gt; HANDLE HXASTREAM;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HXASTREAM &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;__cdecl&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeOpen&lt;/span&gt;(XAHEADER &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;, WAVEFORMATEX &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BOOL &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;__cdecl&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeClose&lt;/span&gt;(HXASTREAM);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BOOL &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;__cdecl&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeSize&lt;/span&gt;(HXASTREAM, ULONG, ULONG &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BOOL &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;__cdecl&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;xaDecodeConvert&lt;/span&gt;(HXASTREAM, XASTREAMHEADER &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a gold mine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 structure definitions&lt;/li&gt;
&lt;li&gt;1 opaque structure&lt;/li&gt;
&lt;li&gt;4 function signatures&lt;/li&gt;
&lt;li&gt;1 calling convention&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After a quick MSDN search and a quick look at other Win32 functions used in
&lt;code&gt;xaDecodeOpen&lt;/code&gt; I was able to decompile the function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#902000&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;xadec_close&lt;/span&gt;(&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;struct&lt;/span&gt; xahandle &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;hdl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#06287e&#34;&gt;free&lt;/span&gt;(hdl);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My actual code doesn&amp;rsquo;t look like that, but in essence I don&amp;rsquo;t care about the
return value and &lt;code&gt;free(3)&lt;/code&gt; already does a null check for me. I can now move to
the next low-hanging fruit because thanks to my past self I didn&amp;rsquo;t need more
research before proceeding. In the &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-4/&#34;&gt;next post&lt;/a&gt; I will discuss audio file formats and the WAVE file
format in particular.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Prep work for xadec.dll</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-2/</link>
      <pubDate>Wed, 20 Jun 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-2/</guid>
        <description>&lt;h2 id=&#34;enter-the-craft&#34;&gt;Enter the craft&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t know where I got this piece of advice, but one should consider that a
super hero might be someone&amp;rsquo;s first super hero. In other words, before
talking about something in depth one should make sure the audience has enough
context to follow. Speaking of context, this is my second post on a series
about reverse engineering of &lt;code&gt;xadec.dll&lt;/code&gt;, a library used in an open source
game I happen to like but missing one crucial thing: its source code.&lt;/p&gt;
&lt;p&gt;So after a lengthy &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-1/&#34;&gt;origin story&lt;/a&gt; that
could be summed up to &amp;ldquo;I used to play fake drums on a home console and then on
a Windows desktop but these days I only use a laptop running Fedora&amp;rdquo; it is now
time to briefly introduce reverse engineering with the assumption that maybe
the reader knows nothing or little about the topic.&lt;/p&gt;
&lt;p&gt;Reverse engineers may not be super heroes, but after spending overall 30 hours
on a small and simple library I can confirm this is no easy task. Much like
Batman and all his bat tools, it would take forever to figure anything out
without standing on the shoulder of giants.&lt;/p&gt;
&lt;p&gt;Speaking of Batman, I love the irony behind the name. While it&amp;rsquo;s obviously the
combination of &amp;ldquo;bat&amp;rdquo; and &amp;ldquo;man&amp;rdquo; it also results in an actual word. This turns
Alfred into Batman&amp;rsquo;s batman, considering Bruce&amp;rsquo;s war on crime and Alfred&amp;rsquo;s
Britishness and military background. But I digress&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;compilation-is-a-lossy-process&#34;&gt;Compilation is a lossy process&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s easier to go from source code to target code. The other way around it
requires additional efforts to guess anything that was lost during compilation
since your processor cares little about type systems or variables and has to
fit whatever high level instructions one may write into a limited set of
instructions and registers. Turn optimizations on and you end up with even
more obfuscation of the original code.&lt;/p&gt;
&lt;p&gt;Disassembly is very easy, it&amp;rsquo;s only a matter of finding where the code is in a
container. On Linux that would usually be somewhere in an ELF (Executable and
Linkable Format) file, while on Windows it&amp;rsquo;s more likely to be found in a PE
(Portable Executable) file. It may not only apply to native code though, a JVM
will look for byte code in class files, and in essence any target code can
easily be disassembled.&lt;/p&gt;
&lt;p&gt;Decompilation on the other hand is very hard. The more we lose during the
compilation process, the harder it becomes to perform the inverse operation.
Debug information can probably greatly help, but &lt;code&gt;xadec.dll&lt;/code&gt; doesn&amp;rsquo;t include
any so going from native code to C code requires a fair amount of guessing. As
an x86 library, it will map 1-1 with x86 assembly. Much like Java byte code
almost maps 1-1 with Java source code, it&amp;rsquo;s usually easy to disassemble. Now
try decompiling Scala code for example, and you will probably get some Java
pidgin you&amp;rsquo;ll need to mentally map to proper Scala (unless tools made progress
in this area).&lt;/p&gt;
&lt;h2 id=&#34;hammer-time&#34;&gt;Hammer time&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been involved in the Varnish Cache project for a fair amount of years now
and it has become my solution to most problems. Granted, most problems my day
job bring to the table tend to be directly related but at some point any
problem looks like it could be solved with a cache. Amusingly, one of my
customers reached the support with interesting questions involving a
disassembly of code generated by Varnish while I was knee-deep in this topic
so that sure was fortunate for me to have spent some time reading assembly
listings and be able to not only follow but contribute to the support case.
But I digress&amp;hellip;&lt;/p&gt;
&lt;p&gt;When all you have is a hammer, all problems look like nails eh? One reason for
the reverse engineering was also the prospect of doing something new and
safely leave the comfort zone. Failing would bear no consequences other than
losing hobby time and succeeding would be quite the payoff (although in
retrospect it wasn&amp;rsquo;t that much).&lt;/p&gt;
&lt;p&gt;It took me around two weeks to evaluate different tools, but evaluate may be
an overstatement. The first one I tried is an online tool called
&lt;a href=&#34;https://onlinedisassembler.com/&#34;&gt;ODA&lt;/a&gt; that scared and misled me into thinking
I needed to know things like the endianness and word size of the library in
addition to its calling convention. Maybe because I replied incorrectly to
those questions the interface would show me many functions and symbols but
nothing very useful. At this point I was already thinking that I was heading
straight to failure.&lt;/p&gt;
&lt;p&gt;I then searched for disassemblers in my package manager and found a couple of
them available on Fedora. I tried &lt;code&gt;examiner&lt;/code&gt;, a tool that adds value on top of
&lt;code&gt;objdump&lt;/code&gt;, but it would only give me this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Binary file is not a known executable type.&lt;br/&gt;
xadec.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I gave up on both of them and went back online to look for more tools.&lt;/p&gt;
&lt;p&gt;Next I moved to Github for a search because most of the results on Fedora were
either libraries or frameworks for disassembly. So maybe I would find actual
programs making use of them that nobody maintains in Fedora. And I found half
a dozen projects, some looking more alive than others. The only one I managed
to build and run is called
&lt;a href=&#34;https://github.com/plasma-disassembler/plasma&#34;&gt;Plasma&lt;/a&gt;. Hobby time is scarce,
and after spending so much time looking for tools and trying to learn this one
I turned to the dark side again and looked for more online tools.&lt;/p&gt;
&lt;h2 id=&#34;giving-up-on-tools&#34;&gt;Giving up on tools&lt;/h2&gt;
&lt;p&gt;The first thing I found was that a recent-enough version of &lt;code&gt;objdump&lt;/code&gt; could
indeed disassemble PE32 executables but looking at the blog post&amp;rsquo;s date,
published years ago, I decided to give it a try:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ objdump --disassemble-all xadec.dll | wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9435
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Good&amp;hellip; I guess? That sure looks like a lot of work. At least I don&amp;rsquo;t need to
install a custom build of GNU binutils.&lt;/p&gt;
&lt;p&gt;Then I shifted to decompilers and found one available online: the
&lt;a href=&#34;https://retdec.com/decompilation/&#34;&gt;Retargetable Decompiler&lt;/a&gt; aka retdec. Not
only was it able to produce C code, it also came with SVG graphs to follow
the code flow and it was smart enough to give their proper names to 3 out of 4
of the public functions. And even better, I could download the entire archive
with all the goodies available from my web browser. At the moment I&amp;rsquo;m writing
this, retdec is no longer available online, I was very lucky!&lt;/p&gt;
&lt;p&gt;However the largest graphs (incidentally most of them) were not built on
purpose, probably for resource savings (and I won&amp;rsquo;t blame a free service for
that) so as soon as I noticed the Github link I went ahead and cloned the
repository to build a copy locally.&lt;/p&gt;
&lt;p&gt;During the lengthy build process I read some of the documentation and watched
a video presenting the project. It is very interesting, I recommend at least
looking at the architecture. Once the build was done, I was able to run it
locally and produce the C code. Bonus point: the master branch was able to map
the function names of the 4 public functions. I was also able to figure that
much with &lt;code&gt;objdump&lt;/code&gt; but it&amp;rsquo;s nice to get a confirmation from retdec. On the
other hand I didn&amp;rsquo;t get any fancy graphs. I gave up and kept the C code around
just in case. The code is understandably horrible because of the loss of
information, but it would sometimes help to compare my observations with
retdec&amp;rsquo;s deductions. I barely used the decompiled C, and in the end never made
use of those nifty SVG graphs&amp;hellip;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s how after spending a good 10 hours over the course of two weeks I
decided to &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-3/&#34;&gt;proceed&lt;/a&gt; because I could
otherwise spend many more hours trying to find a tool I&amp;rsquo;d ultimately need to
spend more time learning. Leaving the comfort zone sucks sometimes, but in the
next post I will show that I had a couple tricks up my sleeves that kept the
whole endeavor not that uncomfortable.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Reverse Engineering xadec.dll</title>
      <link>https://dridi.fedorapeople.org/post/xadec-reveng-part-1/</link>
      <pubDate>Sun, 17 Jun 2018</pubDate>
      
      <guid>https://dridi.fedorapeople.org/post/xadec-reveng-part-1/</guid>
        <description>&lt;h2 id=&#34;playing-music&#34;&gt;Playing music&lt;/h2&gt;
&lt;p&gt;The year is 2005, a game called Guitar Hero comes out and makes 2006 the year
when music games become mainstream worldwide. Surfing on the wave then came
Rock Band in 2007 and you could play more than just the guitar, but also have
other instruments including a drum kit!&lt;/p&gt;
&lt;p&gt;Rewind to 1997, Konami started releasing series of musical games of various
kinds under the &lt;a href=&#34;https://en.wikipedia.org/wiki/Bemani&#34;&gt;Bemani&lt;/a&gt; umbrella. Those
were a huge hit in Japan and in 1999 came the first releases of the
GuitarFreaks and DrumMania games that could be played together and became
mainstream in Japan many years before the rest of the world would enjoy music
video games.&lt;/p&gt;
&lt;p&gt;I remember back when Guitar Hero came out, some people would smugly remark
how pointless those games were and how you&amp;rsquo;d be better off learning the real
instruments in the first place. Living in France, I could always reply that
they should stop playing football (soccer) on their home console and just
play on the field. That would usually make my point, but I digress.&lt;/p&gt;
&lt;p&gt;Thanks to a friend I discovered the Bemani games but unfortunately it was
quite expensive to import any of it so the best I could afford was one game,
one guitar controller and one drum kit controller. I couldn&amp;rsquo;t afford a
Japanese PlayStation so instead I modded the one I already had and all was
fine.&lt;/p&gt;
&lt;h2 id=&#34;playing-actual-music&#34;&gt;Playing actual music&lt;/h2&gt;
&lt;p&gt;Soon after that same friend enrolled me in an actual band and I learned the
hard way the difference between arcade and simulation. It turns out playing
drums involves more than hitting the right drum or cymbal at the right time.
But that&amp;rsquo;s why those games are successful. You don&amp;rsquo;t need to learn an actual
instrument to play or cover songs, you&amp;rsquo;re supposed to have fun!&lt;/p&gt;
&lt;p&gt;So I kept having fun with a GuitarFreaks and DrumMania clone available for
Windows. The final piece of hardware I needed was a PS1 to USB adapter and
suddenly I had access to more songs than just the ones present on the one
game I purchased.&lt;/p&gt;
&lt;p&gt;I eventually moved to a place where there was not enough space to keep the
game controllers or an electronic drum kit around and moreover ditched Windows
in favor of Fedora, because free software. So all I was left with was an
actual band enabling me to compose and play actual drum scores, poor me.&lt;/p&gt;
&lt;h2 id=&#34;enter-xadecdll&#34;&gt;Enter xadec.dll&lt;/h2&gt;
&lt;p&gt;Years have passed and soon I should have enough space to take my electronic
drum kit out of its box every now and then and the very thought made me
research this topic lost in time.&lt;/p&gt;
&lt;p&gt;It turns out the game I was playing at the time is open source! I wouldn&amp;rsquo;t
have guessed that I could actually get the source code for DTXMania but yes,
it is &lt;a href=&#34;https://osdn.net/projects/dtxmania/&#34;&gt;available&lt;/a&gt;. But no luck, it builds
only for Windows and doesn&amp;rsquo;t run in Wine.&lt;/p&gt;
&lt;p&gt;After a quick search, I came across &lt;a href=&#34;http://www.digiband.net/&#34;&gt;DigiBand&lt;/a&gt;,
another GuitarFreaks and DrumMania clone that can even play DTXMania songs.
Sadly the project looks dead and I haven&amp;rsquo;t tried to build it yet because at
first glance it looked like a painful process (at least on Fedora).&lt;/p&gt;
&lt;p&gt;Then my butterfly senses triggered when I read a disturbing note in the
&lt;a href=&#34;http://www.digiband.net/Documentation/windows-cookbook.html&#34;&gt;cook book&lt;/a&gt; for
Windows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To play alot of the already existing songs for DigiBand, you will need XA
decode. XA decode is a decoder written by a Japanese programmer for an
application called bandjam. It has long gone extinct, however DTXMania,
Session stream, and DigiBand all require the use of XA Decode so the developer
released the XA decoder as a binary only library. This is why XA will not work
for DigiBand under linux. We are however, moving to deprecate this library
with the use of OpenAL. The XA format was originally used because MP3 and wav
had inconsistant overhead and latency when playing back on demand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I checked in the DTXMania code repository and there is indeed a &lt;code&gt;xadec.dll&lt;/code&gt;
library bundled with the rest of the code. So apparently a 32bit DLL became
crucial but its source code was lost because bandjam (another GuitarFreaks and
DrumMania clone) was not open source when it disappeared.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s how I decided to take a stab at it. I would try to undo a wrong and
at least give the opportunity to DTXMania to ditch &lt;code&gt;xadec.dll&lt;/code&gt; and enter the
64bit world. Who knows, maybe then I will be able to run it in Wine?&lt;/p&gt;
&lt;p&gt;This is a good example of why free software and open standards matter. By
reverse engineering &lt;code&gt;xadec.dll&lt;/code&gt; I was able to confirm its focus on latency,
but I think another goal was compression and because the PlayStation already
had its own XA format I&amp;rsquo;m guessing that having a different audio codec may
have been a requirement to prevent piracy (with the usual effectiveness)
because of licenses involved in a music game with lots of titles. Considering
the hardware capabilities of the first PlayStation I wouldn&amp;rsquo;t be surprised if
this was actually the format found in the games rather than a thing the
bandjam developer came up with.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&#34;https://dridi.fedorapeople.org/post/xadec-reveng-part-2/&#34;&gt;next&lt;/a&gt; posts of this series on
&lt;code&gt;xadec.dll&lt;/code&gt; I will share the results of my very first reverse engineering
journey.&lt;/p&gt;
</description>
    </item>
  </channel>
</rss>
