<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://godsped.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://godsped.com/" rel="alternate" type="text/html" /><updated>2026-03-03T08:11:46+00:00</updated><id>https://godsped.com/feed.xml</id><title type="html">Samir Rashid</title><subtitle>Samir Rashid personal website and blog.</subtitle><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><entry><title type="html">Physics of Satellite Internet From First Principles</title><link href="https://godsped.com/satellite/" rel="alternate" type="text/html" title="Physics of Satellite Internet From First Principles" /><published>2025-06-26T00:00:00+00:00</published><updated>2025-06-26T00:00:00+00:00</updated><id>https://godsped.com/satellite</id><content type="html" xml:base="https://godsped.com/satellite/"><![CDATA[<p>Streaming live video by shooting bits through the atmosphere to a hunk of metal racing across the sky at 27,000km/h sounds impossible. Modern satellite internet does this while offering gigabit speeds and latencies competitive with wired connections. How do the laws of physics allow us to engineer systems that deliver this unbelievable service?</p>

<p><a href="https://viasat-webgl.e-showroom.net/"><img src="/images/satellite/viasat_constellation.png" alt="Viasat satellite constellation" /></a></p>

<p>This post explains the fundamental principles enabling high-speed satellite internet possible. We will build an intuition for the constraints without hand-waving the physics.</p>

<p><em>Disclaimer: I am no expert and have no formal electrical engineering background. This post is backed by my readings of nonauthoritative online public resources. I will not be updating this post, so please leave corrections in the comments section.</em></p>

<hr />

<p>Satellite internet crosses multiple different links to provide connectivity. Users connect devices to a satellite terminal, usually a small dish, that talks directly to a satellite. The satellite may relay data across other satellites before reaching a ground station and the internet. This post focuses on satellite-ground link, though these calculations apply all to wireless connections.</p>

<iframe src="/files/satellite/trace.html" width="100%" height="300px" frameborder="0"></iframe>
<figcaption>The path packets take via satellite internet. <a href="https://i0.wp.com/techneconomyblog.com/wp-content/uploads/2024/01/LEO-Satellite-NTN-Architecture.png?ssl=1">See this diagram</a> for a more detailed trace.</figcaption>

<p>There are two orbits we will look at: low Earth orbit (LEO) and geostationary orbit (GEO). In summary, satellites closer to Earth have stronger signal, lower latency, and require smaller antennas. However, further satellites get more coverage, so a handful of GEO satellites can mostly achieve global coverage, while a LEO constellation requires many more satellites.</p>

<figure>
    <video width="100%" controls="" autoplay="">
        <source src="/images/satellite/geo_vs_leo.mp4" type="video/mp4" />
        Your browser does not support the video tag.
    </video>
    <figcaption>Comparison of GEO vs LEO coverages and satellite orbit altitudes. Source: <a href="https://viasat-webgl.e-showroom.net/">Viasat</a>
</figcaption>
</figure>

<h2 id="the-fundamental-challenge">The Fundamental Challenge</h2>

<p>Imagine shouting across a room–you can only shout so loud and it gets quieter with distance. Satellites have the same issue but from hundreds of kilometers away.</p>

<p>When transmitting a signal, you can think of the energy spreading uniformly in all directions. The power density (watts per square meter) follows the <a href="https://en.wikipedia.org/wiki/Inverse-square_law"><strong>inverse square law</strong></a>:</p>

\[\text{Power Density} = \frac{\text{Total Power}}{4\pi R^2}\]

<p>This represents <em>the primary</em> constraint in satellite communications: doubling distance quarters signal strength.</p>

<iframe src="/files/satellite/inverse_square.html" width="100%" height="300px" frameborder="0"></iframe>

<p>At 1,000km away, the signal spreads over 12.6 million \(\mathrm{km}^2\). At <a href="https://en.wikipedia.org/wiki/Geostationary_orbit">geostationary orbit (GEO)</a> altitude of 36,000km, that same energy covers 16.3 <u>billion</u> \(\mathrm{km}^2\). The antenna in your device receives a tiny fraction of that radiated power.</p>

<p>The inverse square law explains low Earth orbit (LEO) advantages: moving satellites closer from 36,000km (GEO) to 550km (LEO) above the Earth’s surface improves received signal strength by over 4,000 times. The satellite needs to “shout” across 35,450 fewer kilometers. Check out <a href="https://commons.wikimedia.org/w/index.php?title=File:Orbitalaltitudes.svg&amp;oldid=704829433">this Wikipedia diagram</a> for a true sense of scale and <a href="https://www.teledyne.com/digital-imaging-space-science-monthly/satellite-orbits">this post</a> if you need a refresher on orbital mechanics.</p>

<h2 id="link-budget"><a href="https://en.wikipedia.org/wiki/Link_budget">Link Budget</a></h2>

<p>Measuring connection performance requires accounting for all signal gains and losses with the <strong>Friis Transmission Formula</strong><sup id="fnref:friis" role="doc-noteref"><a href="#fn:friis" class="footnote" rel="footnote">1</a></sup>:</p>

\[P_r = P_t \cdot G_t \cdot G_r \cdot \left(\frac{\lambda}{4\pi R}\right)^2\]

<p>Where:</p>
<ul>
  <li>\(P_r\) = Power received at your antenna (watts)</li>
  <li>\(P_t\) = Power transmitted by satellite (watts)</li>
  <li>\(G_t\) = Gain of satellite’s transmitting antenna (dimensionless)</li>
  <li>\(G_r\) = Gain of your receiving antenna (dimensionless)</li>
  <li>\(\lambda\) = Wavelength of the radio signal (meters)</li>
  <li>\(R\) = Distance between satellite and your antenna (meters)</li>
</ul>

<p>Decibels (dB) are logarithmic, so they turn multiplication into addition:</p>

\[P_r\text{(dBW)} = P_t\text{(dBW)} + G_t\text{(dBi)} + G_r\text{(dBi)} - \text{FSPL(dB)}\]

<p>The <a href="https://en.wikipedia.org/wiki/Free-space_path_loss"><strong>Free Space Path Loss (FSPL)</strong></a> term captures the inverse square law:</p>

\[\text{FSPL(dB)} = 20\log_{10}\left(\frac{4\pi R}{\lambda}\right) = 20\log_{10}(R) + 20\log_{10}(f) - 147.55\]

<p>Let’s go through each component and its bottlenecks.</p>

<p><strong>Transmit Power (Pt)</strong> faces different bottlenecks at each scale. Large GEO satellites can generate 100+ watts per beam but hit thermal limits as it is hard to <a href="https://en.wikipedia.org/wiki/Spacecraft_thermal_control">dissipate waste heat</a> in <a href="https://www.nasa.gov/wp-content/uploads/2021/02/473486main_iss_atcs_overview.pdf">vacuum</a>. Smaller LEO satellites are constrained by their total power budget from solar panels, limiting power to about 10 watts per beam. Phones trasmit 0.2 watts, limited by battery life and <a href="https://www.fcc.gov/general/radio-frequency-safety-0">SAR regulations</a> that prevent excessive radio frequency exposure to human tissue.</p>

<p><strong>Antenna Gain (Gt, Gr)</strong> measures how well the antenna focuses the signal’s energy. Larger apertures provide higher gain. Satellite phased arrays achieve approximately 35dBi (3,000× amplification) within size and weight constraints. A dish reaches ~38dBi (6,000× amplification) but is bigger and require precise pointing. Phones get ~2dBi (1.6× amplification).</p>

<p><strong>Distance (R)</strong>: As we know from the inverse square law, this quadratic term becomes the dominant factor in link performance. LEO satellites at 550km altitude experience 173dB of free space path loss, while GEO satellites at 35,786km suffer 209dB loss. This 36dB difference means GEO signals arrive 4,000 times weaker than LEO signals. We will go into the tradeoffs of different orbits near the end of this post.</p>

<h2 id="shannon-limit">Shannon Limit</h2>

<p>Once you receive a signal, you need to decipher the encoded data. Maximum data rate follows the <a href="https://en.wikipedia.org/wiki/Shannon%E2%80%93Hartley_theorem"><strong>Shannon–Hartley theorem</strong></a>:</p>

\[C = B \cdot \log_2(1 + S/N)\]

<p>Where:</p>
<ul>
  <li>\(C\) = Channel capacity (bits per second)</li>
  <li>\(B\) = Bandwidth (Hz)</li>
  <li>\(S/N\) = Signal-to-Noise Ratio (dimensionless)</li>
</ul>

<p><a href="https://dsp.stackexchange.com/questions/82831/what-is-the-intuition-explaining-the-shannon-hartley-theorem">This equation</a> reveals you either need more bandwidth or better signal-to-noise ratio.</p>

<p>More <strong>bandwidth (B)</strong> linearly increases the data rate, which explains why access to frequency spectrum can go for <a href="https://www.fcc.gov/auctions-summary">billions of dollars</a>. Higher frequencies are more susceptible to the weather. LTE is a relatively low frequency (~2GHz), which allows the signal to go through buildings.</p>

<p>Improving <strong>signal (S)</strong> quality offers diminishing returns due to the logarithmic relationship, but the effect remains significant.</p>

<p><a href="https://en.wikipedia.org/wiki/Noise_(electronics)"><strong>Noise (N)</strong></a> originates from thermal agitation of electrons and is unavoidable above absolute zero:</p>

\[N = k \cdot T \cdot B\]

<p>Where:</p>
<ul>
  <li>\(k\) = Boltzmann constant \((1.38 \times 10^{-23} \ \mathrm{J/K})\)</li>
  <li>\(T\) = System noise temperature (~150K for good receivers)</li>
  <li>\(B\) = Bandwidth (Hz)</li>
</ul>

<p>Since noise is fixed by physics, improving the Signal-to-Noise Ratio requires increasing signal power–which brings us back to the link budget.</p>

<h2 id="geo-vs-leo-path-loss-calculation">GEO vs LEO Path Loss Calculation</h2>
<p>Now we can quantify why lower orbit satellites are transforming satellite communications.</p>

<p>Given a 20 GHz signal (λ = 0.015m):</p>

<p><strong>GEO Path Loss (35,786km):</strong></p>

\[\begin{align}
\text{FSPL} &amp;= 20\log_{10}(35{,}786{,}000) + 20\log_{10}(20 \times 10^9) - 147.55 \\
&amp;= 209.54 \text{ dB}
\end{align}\]

<p><strong>LEO Path Loss (550km):</strong></p>

\[\begin{align}
\text{FSPL} &amp;= 20\log_{10}(550{,}000) + 20\log_{10}(20 \times 10^9) - 147.55 \\
&amp;= 173.28 \text{ dB}
\end{align}\]

<p><strong>Difference: 36.27dB</strong>
The LEO signal is \(10^{(36.27/10)} =\) <strong>4,233 times stronger</strong> than the GEO signal.</p>

<p>This 36dB difference drastically changes system design. LEO’s stronger signal enables higher-order modulation schemes. While GEO systems might use 16-QAM (4 bits per symbol), LEO can use 1024-QAM (10 bits per symbol) at the same error rate. Also, a 19-inch flat panel can achieve what previously required a 4-foot parabolic dish.</p>

<p><strong>Worlds Away</strong></p>

<p>The proximity advantage comes with complexity costs. GEO satellites match the Earth’s rotation, so they appear stationary in the sky and require no tracking. LEO satellites complete an orbit every 90 minutes, demanding rapid beam steering, satellite handoffs, and constellation management.</p>

<iframe src="/files/satellite/latency.html" width="100%" height="400px" frameborder="0"></iframe>

<p>LEO signals round trip in ~4ms while GEO signals require ~240ms, impacting real-time applications over GEO networks.</p>

<h2 id="dish-vs-phone">Dish vs Phone</h2>

<p>How much bandwidth can you actually get from a LEO satellite based on your antenna?</p>

<p><strong>Assumptions:</strong></p>
<ul>
  <li>LEO satellite at 550km altitude</li>
  <li>20GHz downlink frequency</li>
  <li>250MHz channel bandwidth</li>
  <li>10W satellite transmit power</li>
  <li>35dBi satellite antenna gain</li>
  <li>150K system noise temperature</li>
</ul>

<p><strong>Dish Link Budget:</strong></p>

\[\begin{align}
\text{FSPL} &amp;= 153.3 \text{ dB} \\
P_r &amp;= 10 \text{ dBW} + 35 \text{ dBi} + 38 \text{ dBi} - 153.3 \text{ dB} = -70.3 \text{ dBW} \\
N &amp;= 10\log_{10}(1.38 \times 10^{-23} \times 150 \times 250 \times 10^6) = -122.86 \text{ dBW} \\
\text{SNR} &amp;= -70.3 - (-122.86) = 52.56 \text{ dB} \\
C &amp;= 250 \times 10^6 \times \log_2(1 + 22{,}908) = 4.37 \text{ Gbps}
\end{align}\]

<p><strong>Smartphone Antenna Link Budget:</strong></p>

\[\begin{align}
\text{FSPL} &amp;= 153.3 \text{ dB (same)} \\
P_r &amp;= 10 \text{ dBW} + 35 \text{ dBi} + 2 \text{ dBi} - 153.3 \text{ dB} = -106.3 \text{ dBW} \\
N &amp;= -122.86 \text{ dBW (same)} \\
\text{SNR} &amp;= -106.3 - (-122.86) = 16.56 \text{ dB} \\
C &amp;= 250 \times 10^6 \times \log_2(1 + 57.5) = 1.38 \text{ Gbps}
\end{align}\]

<p>A gigabit to my phone from space!? These calculations assume perfect conditions. In reality, you need at least 10-15dB margin to account for atmospheric losses from rain and clouds, pointing errors as satellites move across the sky, receiver implementation losses from non-ideal components, and Doppler effects from the satellite’s 27,000km/h orbital velocity.</p>

<p>The dish has plenty of margin (52.56dB), but the phone is borderline. This is why a cellular service needs to use much narrower bandwidths.</p>

<p><strong>Real Smartphone Antenna:</strong></p>

<p>Keeping the same frequency with a 5MHz channel instead of 250MHz:</p>

\[\begin{align}
N &amp;= 10\log_{10}(1.38 \times 10^{-23} \times 150 \times 5 \times 10^6) = -139.85 \text{ dBW} \\
\text{SNR} &amp;= -106.3 - (-139.85) = 33.55 \text{ dB} \\
C &amp;= 5 \times 10^6 \times \log_2(1 + 2{,}884) = 55.73 \text{ Mbps}
\end{align}\]

<p>A phone-scale antenna could expect closer to 60Mbps.</p>

<h2 id="engineering-constraints">Engineering Constraints</h2>

<p>Engineers need to navigate the physics to balance trade-offs to make a <a href="https://spacenews.com/op-ed-satellite-bankruptcies-circa-2000-vs-2020-weve-come-a-long-way/">viable system</a>.</p>

<h3 id="power-budget">Power Budget</h3>

<p>A satellite’s power budget determines beam transmit power.</p>

\[P_{\text{available}} = A_{\text{panel}} \cdot \eta_{\text{solar}} \cdot \cos(\theta_{\text{sun}}) \cdot f_{\text{eclipse}}\]

<p>The solar panels need to generate enough energy to power the onboard electronics and are mainly used to power the beams. LEO satellites orbit many times per day, so they need to use battery power for the <a href="https://physics.stackexchange.com/questions/108196/duration-of-satellite-orbit-in-the-shadow-of-the-earth">third of time</a> that the Earth blocks sunlight. Ultimately, it’s the power that determines the size of the satellite and the number of beams and their strength.</p>

<h3 id="frequency-licensing">Frequency Licensing</h3>

<p><a href="https://www.esa.int/Applications/Connectivity_and_Secure_Communications/Satellite_frequency_bands">Radio spectrum</a> is a finite resource managed by country governments. Spectrum allocation creates fundamental trade-offs between bandwidth and propagation characteristics. Higher frequencies offer more bandwidth but suffer worse propagation losses and weather effects.</p>

<table>
  <thead>
    <tr>
      <th>Band</th>
      <th>Frequency Range</th>
      <th>Applications</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>L-band</strong></td>
      <td>1-2 GHz</td>
      <td>Mobile services, GPS</td>
    </tr>
    <tr>
      <td><strong>S-band</strong></td>
      <td>2-4 GHz</td>
      <td>Mobile satellite applications</td>
    </tr>
    <tr>
      <td><strong>Ku-band</strong></td>
      <td>12-18 GHz</td>
      <td>Satellite TV, Satellite internet</td>
    </tr>
    <tr>
      <td><strong>Ka-band</strong></td>
      <td>26-40 GHz</td>
      <td>Broadband services</td>
    </tr>
    <tr>
      <td><strong>V-band</strong></td>
      <td>40-75 GHz</td>
      <td>Future high-capacity links</td>
    </tr>
    <tr>
      <td><strong>5G n53</strong></td>
      <td>2.4 GHz</td>
      <td>Direct-to-device services</td>
    </tr>
    <tr>
      <td><strong>5G n256</strong></td>
      <td>26 GHz</td>
      <td>Shared satellite-terrestrial spectrum</td>
    </tr>
  </tbody>
</table>

<p>L-band (1-2GHz) offers excellent propagation through atmosphere and modest power requirements, but provides limited bandwidth. Ka-band (26-40GHz) enables high-bandwidth broadband services but suffers significant rain attenuation that can shut down links during storms. V-band (40-75GHz) promises future high-capacity links but faces extreme weather sensitivity.</p>

<h3 id="orbital-mechanics">Orbital Mechanics</h3>

<p>LEO satellites orbit Earth every 90 minutes, creating dynamic coverage patterns. Lower altitudes have less path loss but need magnitudes more satellites to maintain coverage.</p>

<p>Orbital inclination determines coverage zones: polar orbits provide global reach including Arctic regions, while equatorial orbits focus capacity on populated areas but leave polar regions uncovered. 
Plane spacing controls satellite visibility. Too few planes create coverage gaps, while too many increase constellation complexity and inter-satellite interference.</p>

<figure>
    <video width="100%" controls="" autoplay="">
        <source src="/images/satellite/starlink_orbits.mp4" type="video/mp4" />
        Your browser does not support the video tag.
    </video>
    <figcaption>The scale of the Starlink constellation is truly astounding. Source: <a href="https://www.starlinkmap.org/">starlinkmap</a></figcaption>
</figure>

<h3 id="antenna-pointing">Antenna Pointing</h3>

<iframe src="/files/satellite/beamforming.html" width="100%" height="400px" frameborder="0"></iframe>
<figcaption>The dish does not move and uses thousands of antennas to focus the energy towards the satellite. <a href="https://www.youtube.com/watch?v=qs2QcycggWU">Watch this video</a> for a beautiful explanation of the concept.</figcaption>

<p>User terminals must track satellites moving at 7.5km/s. Mechanical tracking systems using motors and gears are expensive, slow to respond, and prone to mechanical failure. Phased arrays enable fast electronic steering without moving parts but require complex beamforming algorithms and hundreds of antenna elements, increasing cost and power consumption. Multi-satellite handoffs demand seamless switching between satellites as they pass overhead, requiring precise timing coordination and careful interference management.</p>

<h3 id="cost">Cost</h3>

<p>The cost to deliver one <a href="https://en.wikipedia.org/wiki/ViaSat-3">Viasat-3</a> satellite (6,400kg) to geostationary orbit was $150M aboard an expendable <a href="https://en.wikipedia.org/wiki/Falcon_Heavy">Falcon Heavy</a>. The <a href="https://en.wikipedia.org/wiki/List_of_Falcon_9_and_Falcon_Heavy_launches">same rocket</a> type launched to LEO with 56 Starlink satellites (<a href="https://lilibots.blogspot.com/2020/04/starlink-satellite-dimension-estimates.html">310kg</a>) and can be reused, so the launch costs a reduced $97M. Furthermore, the Viasat-3 satellite <a href="https://arstechnica.com/space/2023/07/viasats-new-broadband-satellite-could-be-a-total-loss/">costs $420M</a>, whereas each Starlink satellite is <a href="https://www.teslarati.com/spacex-starlink-satellite-launch-second-announcement/">below $1M</a>.</p>

<p>Viasat-3 satellites get global coverage with three satellites, while a LEO constellation needs tens of thousands.</p>

<h2 id="why-now">Why Now?</h2>

<p>LEO constellations are not new–<a href="https://en.wikipedia.org/wiki/Iridium_satellite_constellation">Iridium</a> had a network in 1998. If the physics have not changed in the past quarter century, what has?</p>

<h3 id="launch-economics">Launch Economics</h3>

<p>Historically, launch costs have limited access to space. Since the 1990s, the <a href="https://ourworldindata.org/grapher/cost-space-launches-low-earth-orbit">cost to launch</a> payload to LEO has dropped from $20,000/kg to below $2,000/kg. Rapidly reusable Starships promise to reduce costs another order of magnitude. This trend has enabled large LEO constellations to be economically viable.</p>

<h3 id="satellite-miniaturization">Satellite Miniaturization</h3>

<p>Traditional satellites were custom-built, multi-ton systems designed for &gt;15 year lifespans in a harsh radiation environment. LEO satellites operate within the Van Allen radiation belts where Earth’s magnetic field provides partial radiation shielding. Relaxing radiation tolerance allows satellites to use modern electronics that are decades ahead of radiation-hardened components. This modernization means smaller satellites can deliver more bandwidth and use standard components, enabling satellite mass production.</p>

<h3 id="phased-array">Phased Array</h3>

<p>Originally developed for military radar, <a href="https://en.wikipedia.org/wiki/Phased_array">phased arrays</a> electronically steer beams and can track and hop between fast-moving LEO satellites. Semiconductor advances have reduced phased array costs such that they are now ubiquitous in new wireless standards.</p>

<h3 id="configurable-hardware">Configurable Hardware</h3>

<p><a href="https://en.wikipedia.org/wiki/Software-defined_radio">Software-defined radios</a> can adapt modulation, coding, and protocols through software updates. Digital signal processing no longer requires specialized hardware. Field-programmable gate arrays (FPGAs) and digital signal processors enable efficient implementation of advanced techniques like 1024-QAM modulation and adaptive coding.</p>

<h3 id="global-impact">Global Impact</h3>

<p>Satellites already provide essential internet to ships and planes and can be used in emergencies after disasters wipe out terrestrial infrastructure. However, there remain over <a href="https://ourworldindata.org/grapher/share-of-individuals-using-the-internet?tab=chart&amp;time=2000..latest">two</a> <a href="https://ourworldindata.org/internet-history-just-begun">billion</a> <a href="https://www.itu.int/en/ITU-D/Statistics/pages/stat/default.aspx">people</a> without internet access. Widespread, low cost, and high bandwidth satellite connectivity offers gigabit <a href="https://techneconomyblog.com/2025/04/30/can-leo-satellites-close-the-gigabit-gap-of-europes-unconnectables/">internet for the first time</a> to many rural communities, remote islands, and places with undeveloped terrestrial infrastructure.</p>

<p>This post does not begin to get into designing a satellite constellation. There is a tradeoff between wanting global satellite coverage, but demand is not evenly distributed.
Viasat has a cool visualization of flight paths and satellite data usage.</p>

<p><a href="https://viasat-webgl.e-showroom.net/"><img src="/images/satellite/usage_switch.gif" alt="flight paths and data usage" /></a></p>

<p>The application of electromagnetic theory, information theory, and orbital mechanics bring the world’s knowledge to you no matter where you hike, fly, or sail. This post explored a first principles dive into the terabit cosmic beams that are closing the digital divide.</p>

<h2 id="further-reading">Further Reading</h2>
<ul>
  <li>Three great satellite constellation visualizers: <a href="https://viasat-webgl.e-showroom.net/">Viasat</a>, <a href="https://www.starlinkmap.org/">Starlink</a>, and <a href="https://satellitemap.space/?constellation=starlink">general</a></li>
  <li>Great intuitive <a href="https://www.youtube.com/watch?v=qs2QcycggWU">RF Electromagnetics Visualization</a></li>
  <li><a href="https://drive.google.com/file/d/11zzv3xCOeHrzjOUAyT3_RiP_dbQd-2Oz/view">Good slides overview of satcomm</a></li>
  <li>Taste for how complicated <a href="https://mikepuchol.com/modeling-starlink-capacity-843b2387f501">satellite capacity modeling</a> is</li>
  <li>Alright, though outdated series on <a href="https://blog.apnic.net/2021/05/20/everything-you-wanted-to-know-about-leo-satellites-part-1-the-basics/">LEO basics</a></li>
  <li>Overview of <a href="https://www.youtube.com/watch?v=1tw4SmS4Pc4">design space of a LEO constellation</a></li>
  <li><a href="https://www.antenna-theory.com/">Antenna Theory</a></li>
  <li>Some background on why LEO internet is succeeding now: <a href="https://en.wikipedia.org/wiki/Timeline_of_spaceflight">Timeline of Spaceflight</a>, <a href="https://en.wikipedia.org/wiki/Space_launch_market_competition">Space Launch Market Competition</a></li>
  <li>MATLAB has some <a href="https://www.mathworks.com/help/satcom/gs/satellite-link-budget.html">great</a> <a href="https://www.mathworks.com/help/satcom/ug/optical_satellite_communication_link_budget_analysis.html">resources</a> for doing calculations much better than this post</li>
</ul>

<!-- Fun fact: there's some unlicensed LTE spectrum https://en.wikipedia.org/wiki/LTE_in_unlicensed_spectrum -->

<h2 id="fun-quiz">Fun Quiz</h2>

<div style="background: var(--global-footer-bg-color); padding: 20px; margin: 20px 0; border-radius: 10px; border: 1px solid;">
  <p><strong>What is the least population dense continent?</strong></p>
  <input type="text" id="q1" style="width: 300px; padding: 5px; border: 2px solid #ccc;" />
  <span id="q1-result"></span>
  
  <p><strong>Estimate the magnitude difference in cost of deploying satellite internet versus fiber optic internet to the above continent. Answer in log base 10 (satellite cost / fiber cost)</strong><br />
  <em>For example, if the satellite cost is $1M and fiber cost is $1. \(\log_{10}(1,000,000 / 1) = 6\).</em></p>
  <input type="text" id="q2" style="width: 300px; padding: 5px; border: 2px solid #ccc;" />
  <span id="q2-result"></span>
  
  <p><button onclick="checkAnswers()">Submit</button></p>
</div>

<script>
function checkAnswers() {
  const q1Input = document.getElementById('q1');
  const q2Input = document.getElementById('q2');
  const q1 = q1Input.value.trim();
  const q2Original = q2Input.value;
  const q2 = Math.round(parseFloat(q2Original));
  
  // Update the number box to show the rounded value
  if (!isNaN(q2)) {
    q2Input.value = q2;
  }
  
  if (q1.toLowerCase().includes('antar')) { // People can't spell...
    document.getElementById('q1-result').innerHTML = ' <span style="color: green; font-size: 20px;">✓</span>';
    q1Input.style.border = '2px solid green';
  } else {
    document.getElementById('q1-result').innerHTML = ' <span style="color: red; font-size: 20px;">✗</span>';
    q1Input.style.border = '2px solid red';
  }
  
  if (q2 === 0) {
    document.getElementById('q2-result').innerHTML = ' <span style="color: green; font-size: 20px;">✓</span>';
    q2Input.style.border = '2px solid green';
  } else {
    document.getElementById('q2-result').innerHTML = ' <span style="color: red; font-size: 20px;">✗</span>';
    q2Input.style.border = '2px solid red';
  }
}
</script>

<details>
  <summary><b>Reveal Answer</b></summary>

  <p><strong><a href="https://en.wiktionary.org/wiki/Antarctician">Antarctician</a> Internet Cost Estimation​</strong></p>

  <ul>
    <li>Population 1,300 (Winter) to 5,100 (Summer) [<a href="https://en.wikipedia.org/wiki/Antarctica">Wikipedia</a>]​</li>
    <li>181 Polar Starlink satellites [<a href="https://www.teslarati.com/spacex-starlink-internet-antacrtica-coldex-nsf-testing/">article</a>]​</li>
    <li>Overestimate $1M per satellite [<a href="https://www.reddit.com/r/Starlink/comments/1c0nand/first_order_estimate_of_starlink_satellites/">Reddit</a>]​</li>
    <li>On the order of $181M to serve Antartica Starlink​</li>
    <li>Under-sea fiber optic connectivity would cost “upwards of $200M” according to <a href="https://www.technologyreview.com/2024/02/26/1088144/antarctica-starlink-elon-musk-satellite-internet/">NSF​</a></li>
  </ul>

\[\log(181,000,000 ÷ 200,000,000) = 0​\]

  <p>So the order of magnitude difference is \(\log(\sim 1) = 0\).​</p>

  <p>Cost of internet is $200k per person! Satellite cost must be paid every ~5 years!​ (Of course, these satellites do serve other users.)</p>

  <p>Sources:​</p>
  <ul>
    <li><a href="https://www.technologyreview.com/2024/02/26/1088144/antarctica-starlink-elon-musk-satellite-internet/​">Amazing article on internet’s effect in Antarctica</a></li>
    <li><a href="https://satellitemap.space/​">Check out what’s over Antarctica right now</a>
<br /><br /></li>
  </ul>
</details>

<!-- 
Inspirations:
https://ciechanow.ski/exposing-floating-point/
https://planetscale.com/blog/io-devices-and-latency
https://explained-from-first-principles.com/email/
-->
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:friis" role="doc-endnote">
      <p>You can read the <a href="https://capmimo.ece.wisc.edu/capmimo_papers/friis_original_1946.pdf">original paper</a>! Check out <a href="https://en.wikipedia.org/wiki/Friis_transmission_equation">Wikipedia</a> and <a href="https://www.antenna-theory.com/basics/friis.php">antenna-theory’s derivation</a>. <a href="#fnref:friis" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="networking" /><summary type="html"><![CDATA[Beaming bits to space and back sounds like sci-fi, but it's real. Let's learn why it's possible.]]></summary></entry><entry><title type="html">*Binary Room*: Implementation of a RISC-V to ARM Translator</title><link href="https://godsped.com/binary-room/" rel="alternate" type="text/html" title="*Binary Room*: Implementation of a RISC-V to ARM Translator" /><published>2025-04-15T00:00:00+00:00</published><updated>2025-04-15T00:00:00+00:00</updated><id>https://godsped.com/binary-room</id><content type="html" xml:base="https://godsped.com/binary-room/"><![CDATA[<p>by <a href="https://godsped.com/">Samir Rashid</a>, <a href="https://atarbinian.com/">Anthony Tarbinian</a>, <a href="http://trdavid.com/">David Tran</a> (equal contribution)</p>

<div class="notice notice--announcement">
  <h4 id="this-paper-is-best-read-as-a-pdf-in-its-original-typesetting-in-this-paper-we-describe-our-experience-going-from-idea-to-implementation-of-a-binary-translator">This paper is best read as a <a href="https://github.com/Samir-Rashid/binary-room/blob/main/report/Binary Room Report.pdf?raw=true">pdf in its original typesetting</a>. In this paper, we describe our experience going from idea to implementation of a <a href="https://en.wikipedia.org/wiki/Binary_translation">binary translator</a>.</h4>
</div>
<p><a class="btn btn--danger" style="background: #008abf;" href="https://github.com/Samir-Rashid/binary-room/blob/main/report/Binary Room Report.pdf?raw=true">Read the Report PDF</a></p>

<p><strong>Abstract</strong></p>
<p>Binary Room is a static binary translator from
RISC-V to ARM binaries. It targets userspace
applications and supports a subset of the RISC-
V instruction set. We can translate applications
that perform memory operations, control flow
and system calls. This report outlines the details
of the implementation along with challenges we
ran into.</p>
<p>1. <strong>Introduction</strong></p>
<p>Binary Room statically translates binaries from a subset of the riscv64 to aarch64 instruction set architectures (ISA). We support arbitrary 64-bit userspace binaries, which can include function calls and syscalls. We support a subset of RISC-V instructions which perform arithmetic, memory operations, control flow, and system calls. First, Section 3 provides an overground of our design decisions. Next, Section 4 provides an overview of the aspects of our implementation. We outline the high-level flow of binary translation, along with the difficulties in writing each module of the code (Section 5). Lastly, we evaluate Binary Room's input and output binaries (Section 6).</p>
<p>2. <strong>Background</strong></p>
<p>RISC-V is the future of open computing. Binary translation is a form of emulation which enables running binaries from other architectures. To smooth the transition to the RISC-V ISA, we present Binary Room, a tool to run unmodified RISC-V binaries on ARM. Binary Room statically translates binaries without the need for any hardware virtualization extensions.</p>
<p>Our translator is inspired by Apple’s x86 to ARM binary translator, Rosetta 2. Similarly, our tool transparently converts userspace binaries from riscv64 to aarch64 instructions. Binary translation has proved to be a flexible and efficient approach for ensuring binary compatibility (A Comparison of Software and Hardware Techniques for X86 Virtualization, 2006).</p>
<p>3. <strong>Design</strong></p>
<figure>

  <p><img src="/images/binary-room/overview.png" alt="" /></p>
  <figcaption>Figure 1. High level overview of RISC-V to ARM translation and
testing.</figcaption>
</figure>
<p>At a high level, Binary Room operates by consuming a list of RISC-V instructions, iteratively translating each instruction from RISC-V to ARM, converting the ARM instructions to an ARM assembly file, and forming an ARM executable.</p>
<p>Binary room operates at the assembly level, so there are a few steps before producing an executable binary. We assemble the assembly code into an object. Then, we take the object code and link it into the final binary file. On Linux, where we performed the bulk of our testing, this was an ELF file (Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification Version 1.2, 1995).</p>
<p>4. <strong>Implementation</strong></p>
<p>4.1. <strong>Representing Instructions</strong></p>
<p>We exploited the Rust type system to encode information about the RISC-V and ARM instructions (RISC-V Instruction Set Specifications, 2019). Specifically, we extensively used Rust's algebraic data types, enums, throughout our codebase.</p>
<p>Parsing the assembly into the Rust type system provides guarantees of the arguments to instructions at compile time. There are many steps that can go wrong, which makes debugging challenging. Parsing, translation, and runtime errors are examples of issues during development. One difficulty is that to support general binaries, you must implement the entire source and destination instruction set and must also encode all the alignment, calling convention, and syscall constraints. To deal with this complexity, we introduce <em>Panic Driven Development (PDD)</em>. PDD ensures that binaries we cannot translate fail at the parsing stage. The code will be unable to encode instructions it cannot translate by the design of the enum. This strategy prevents debugging malformed assembly output.</p>
<p>Each enum variant encodes the exact instruction and the types of its arguments.</p>
<figure>

  <div class="language-rs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">enum</span> <span class="n">RiscVInstruction</span> <span class="p">{</span>
  <span class="cd">/// add register</span>
  <span class="cd">/// either add or addw</span>
  <span class="cd">/// (addw is 32 bits on 64 bit riscv)</span>
  <span class="cd">///</span>
  <span class="cd">/// `x[rd] = sext((x[rs1] + x[rs2])[31:0])`</span>
  <span class="nd">#[strum(serialize</span> <span class="nd">=</span> <span class="s">"add"</span><span class="nd">)]</span>
    <span class="nb">Add</span> <span class="p">{</span>
    <span class="c1">// dest = arg1 + arg2</span>
    <span class="n">width</span><span class="p">:</span> <span class="n">RiscVWidth</span><span class="p">,</span>
    <span class="n">dest</span><span class="p">:</span> <span class="n">RiscVRegister</span><span class="p">,</span>
    <span class="n">arg1</span><span class="p">:</span> <span class="n">RiscVRegister</span><span class="p">,</span>
    <span class="n">arg2</span><span class="p">:</span> <span class="n">RiscVRegister</span><span class="p">,</span>
  <span class="p">},</span>
  <span class="c1">// Copy register</span>
  <span class="c1">// `mv rd, rs1` expands to `addi rd, rs, 0`</span>
  <span class="nd">#[strum(serialize</span> <span class="nd">=</span> <span class="s">"mv"</span><span class="nd">)]</span>
  <span class="n">Mv</span> <span class="p">{</span>
    <span class="n">dest</span><span class="p">:</span> <span class="n">RiscVRegister</span><span class="p">,</span>
    <span class="n">src</span><span class="p">:</span> <span class="n">RiscVRegister</span><span class="p">,</span>
  <span class="p">},</span>
  <span class="err">…</span>
<span class="p">}</span>
</code></pre></div>  </div>

  <figcaption>Listing 1.Encoding of the ADD and MV<br />RISC-V instructions</figcaption>
</figure>

<p>For the ADD instruction case, the <code>width</code> field specifies whether the instruction is invoked with double or word register width. The arguments to the instruction are defined in another enum which represents CPU registers.</p>

<div class="language-rs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">enum</span> <span class="n">RiscVRegister</span> <span class="p">{</span>
  <span class="nd">#[default]</span>
  <span class="nd">#[strum(serialize</span> <span class="nd">=</span> <span class="s">"x0"</span><span class="nd">)]</span>
  <span class="cd">/// Hard-wired zero</span>
  <span class="n">X0</span><span class="p">,</span>
  <span class="nd">#[strum(serialize</span> <span class="nd">=</span> <span class="s">"ra"</span><span class="nd">)]</span>
  <span class="cd">/// Return address</span>
  <span class="n">RA</span><span class="p">,</span>
  <span class="err">…</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Our instruction type supports ARM instructions that are not present in the RISC-V ISA. Notably, conditional branching in ARM requires a CMP instruction to set condition flags based on registers operands. For example, to branch to the label <code>foo</code> if <code>x1 != x2</code>, we must first <code>cmp x1, x2</code> and then conditionally branch <code>bne foo</code>. RISC-V handles conditional branches by taking additional operands in the branch instruction, e.g. <code>bne x1, x2 foo</code>. During translation, Binary Room may output multiple ARM instructions for a given RISC-V instruction.</p>
<p>One limitation of our enum is that we must manually parse from the disassembled binary into the Rust enum. We prioritized implementing the binary translation and did not finish writing a complete parser. Encoding the enum into assembly is straightforward as we use Rust's formatter to convert the list of instructions into validly formatted assembly.</p>
<p>4.2. <strong>Variable Width ARM Registers</strong></p>
<p>One feature we encode in the type system is register width. Both ARM And RISC-V have 32 general-purpose registers. However, ARM registers can be used as either 32-bit or 64-bit registers. ARM registers are indicated by the first letter of the register name in the assembly. An “x” indicates 64 bits of a register and a “w” indicates the least significant 32 bits of a register (Registers in Aarch64 State, 2024). This variation means that translation must account for the register width that RISC-V instructions specify and output an ARM instruction with the correct register widths.</p>
<p>We ensured correctness of the binary translation by unit testing simple cross-compiled RISC-V programs. Our tests automatically run in GitHub actions on every commit, and can be run locally using <code>cargo</code>, the Rust build system.</p>
<p>4.3. <strong>Register Mapping</strong></p>
<figure>

  <p><img src="/images/binary-room/translation.png" alt="" /></p>
  <figcaption>Figure 2. Flow of types through the translator.</figcaption>
</figure>
<p>During instruction translation, we had to be cautious in how we translate the registers in use. Some registers are not general purpose and have semantic meanings, such as the stack pointer (ARM Register Names, 2024). Other registers are expected to have some meaning after function calls, such as the return register. We needed to be mindful of these invariants and avoid overwriting any important state.</p>
<p>To keep our mapping of registers consistent, we created a look-up table to convert each RISC-V register into its corresponding ARM register.</p>
<figure>

  <div class="language-rs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">map_register</span><span class="p">(</span><span class="n">riscv_reg</span><span class="p">:</span> <span class="n">RiscVRegister</span><span class="p">,</span> <span class="n">riscv_width</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">RiscVWidth</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">ArmRegister</span> <span class="p">{</span>
  
    <span class="n">ArmRegister</span> <span class="p">{</span>
        <span class="n">width</span><span class="p">:</span> <span class="nf">map_width</span><span class="p">(</span><span class="n">riscv_width</span><span class="p">),</span>
        <span class="n">name</span><span class="p">:</span> <span class="nf">map_register_name</span><span class="p">(</span><span class="n">riscv_reg</span><span class="p">),</span>
    <span class="p">}</span>
    
<span class="p">}</span>
</code></pre></div>  </div>

  <figcaption>Listing 2. Mapping registers splits logic into <code>map_width</code> and <code>map_register_name</code></figcaption>
</figure>
<p>Critically, ARM registers can vary in width and RISC-V cannot. For this reason, we added a width argument to this function and decompose the conversion of width and register name into separate functions, <code>map_width</code> and <code>map_register_name</code>. We define widths to be the size of a register and define register names to be the width-agnostic name of the register in assembly (i.e. <code>sp</code> or general purpose register 1).</p>
<p>4.4. <strong>Calling Convention</strong></p>
<p>The calling convention of an ISA ensures compatibility with binaries from other compilers (Volume I: RISC-V User-Level ISA V2.1draft, Chapter 18, Calling Convention, 2014). If a program does not interact with foreign functions, then it is not required to abide by the calling convention. This flexibility makes the register translation easier due to less constraints on how Binary Room handles register mappings. To ensure that local register values are preserved between function calls, Binary Room efficiently saves registers onto the stack before a <code>call</code> instruction and restores them from the stack when returning from a function call.</p>
<p>The calling convention constraint still applies to syscalls and dynamic libraries.</p>
<p>4.4.1. Syscalls</p>
<p>We chose to directly translate syscall instructions. Alternatively, we could have taken advantage of the syscall wrappers built into <code>libc</code> (Syscalls(2) - Linux Manual Page, n.d.). However, we chose not to deal with complexities of dynamic libraries, instead directly modifying the instructions which set up syscall arguments and invoke the syscall.</p>
<p>Originally, we thought syscall translation would be equivalent to normal instruction translation. However, there were some nuances that made this more challenging. One such nuance was that syscall numbers change across architectures.</p>
<figure>
  <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># write(stdout, buf, len)</span>

<span class="c"># syscall number</span>
li a7,64

<span class="c"># arg 2: len</span>
li a2,13

<span class="c"># arg 1: buf</span>
lui a0,%hi<span class="o">(</span>buf<span class="o">)</span>
addi a1,a0,%lo<span class="o">(</span>buf<span class="o">)</span>

<span class="c"># arg 0: stdout fd number</span>
li a0,1

<span class="c"># trigger syscall</span>
ecall
</code></pre></div>  </div>

  <figcaption>Listing 3. Example program which makes syscall in riscv64 assembly. This sample uses the <code>write</code> Linux syscall to write a buffer to standard out.</figcaption>
</figure>
<p>When you want to perform a syscall, you need to indicate which syscall you want to execute by loading the syscall number into a register. In Listing 3, the syscall number, <code>64</code>, is loaded into register <code>a7</code>. However, this syscall number is defined by the operating system. Linux's syscall numbers vary across architectures and ISA variants (i.e. 32-bit and 64-bit) (Arm.syscall.sh, 2024).</p>
<p>Our initial approach inserted instructions to use a lookup table to convert the syscall numbers. At runtime, this code would look at the requested syscall and rewrite the correct value for aarch64 (Linux Kernel System Calls for All Architectures, 2025). Luckily, Linux shares identical syscall numbers between ARM 64-bit and RISC-V 64-bit. It was sufficient for our architecture pair to directly translate the same syscall numbers without modification.</p>
<p>4.4.2. Branching</p>
<p>Binary Room supports relative branching to labels. We extract labels from the disassembled input binary and map them verbatim to the output ARM binary. This insertion guarantees that the label ends up at the same point in the execution of the translated binary. The assembler handles the complexity of turning labels into addresses. Binary Room does not support absolute branches to arbitrary addresses.</p>
<p>5. <strong>Challenges</strong></p>
<p>5.1. <strong>ISA Quirks</strong></p>
<p>Instruction sets handle the same primitives differently. For example, RISC-V uses a zero register to produce zero arguments to instructions. In ARM, you must use a normal register or dummy instruction such as <code>xor</code>ing a register with itself to get a zero (RISC-V Instruction Set Specifications, 2019).</p>
<p>The instruction behaviors also differ between the ISAs. We needed to handle the cases where arguments can change which instruction we need to translate to. For instance, RISC-V's add immediate (<code>addi</code>) opcode can take positive or negative constants, whereas ARM's immediate argument to <code>add</code> can only be positive. Translating this requires handling the different cases of argument values. Sometimes, these translations cannot be determined statically, as seen with syscall numbers.</p>

<figure>

  <p><img src="/images/binary-room/addi.png" alt="" /></p>
  <figcaption>Figure 3. RISC-V Reference for addi instruction</figcaption>
</figure>

<p>Figure 3 shows the information provided by the ISA reference. Instructions have high level implementations which authoritatively define their behavior (RISC-V Reference Card, n.d.). This pseudocode enables us to ensure instruction maps have the same behavior.</p>
<p>5.1.1. Pseudo-instructions</p>
<p>Binary disassemblies contain the list of instructions of the program. However, there are also RISC-V pseudo-instructions that can get generated (RISC-V Assembler: Arithmetic, 2024). These are higher level operations that correspond to multiple individual operations. These abstractions are not documented in the architecture manual, so we had to use unofficial online posts to decipher the meaning of these pseudo-instructions.</p>
<p>5.2. <strong>ISA Documentation</strong></p>
<p>The largest obstacle we encountered during this project was tracking down relevant documentation and discovering what we needed to know. The general ISAs for RISC-V and ARM are open, but exact implementations of the specifications can differ greatly. For example, when looking for documentation, we would often find incorrect or misleading information. Initially we faced confusion with conflicting information online. This mismatch is because the 32-bit and 64-bit versions of the ISAs change the behavior of registers and syscalls. Instructions work differently on different ISA versions, for instance the many versions and parts of ARM (armv7, aarch64, etc.).</p>
<p>Another difficulty was fully understanding how each ISA works. We needed to understand the semantics of each ISA in order to create a mapping. We found unofficial documentation, such as Figure 3, to be more complete and intelligible than official documentation. Mapping instructions and registers required carefully <code>diff</code>ing the register specifications and calling conventions for each ISA. The issues with syscalls led us to decide not to support 32-bit binaries.</p>
<p>As we produced the output binaries, we ended up having to debug invalid assembly. Assembly is itself high level, so we had to deal with linking errors with illegal arguments, unexplainable segfaults, and dealing with OS specific assembly problems such as alignment constraints and extern symbols.</p>
<p>Testing our implementation proved difficult as you need to get everything working in order to test. Each part of the pipeline is dependent on previous parts. Unit testing did not help find bugs as much as running test translations on real programs. Every program you compile with <code>gcc</code> requires dynamic libraries, as there is an implicit <code>libc</code> call to <code>exit</code> the program. We were unable to get static nolibc binaries to work as it has dependencies on the <code>libc</code> provided by the host OS, which needs to be built for RISC-V or ARM.</p>
<p>Another complication is that even simple binaries do not follow the conventions you would expect. For a "hello world" program, we implemented conversion of the text section. Even at minimum optimizations, <code>gcc</code> puts the literal string behind a call to the <code>IO_stdin_used</code> symbol. We decided to not handle all the complications with process and library loading, so a "hello world" program only works with a direct offset to the constant.</p>
<p>5.3. <strong>Development environment</strong></p>
<p>Developing Binary Room requires running a Linux machine with QEMU and cross-compile toolchains for riscv64 and aarch64. Binary Room is built with Rust's cargo toolchain and tests run with cargo and some platform-specific build scripting.</p>
<p>To handle the complexity of the build environment, we use the Nix package manager. Nix shells allow us to create a fully reproducible build environment and easily manage parallel compiler toolchains for each architecture we need. (Cross Compiling - Nixos Wiki, 2025)</p>
<p>5.4. <strong>Debugging</strong></p>
<p>Debugging the output assembly proved difficult. There are no layers of abstraction below the binary, so there is no debug information when a program goes wrong. Additionally, the issues are typically related to hardware or illegal instructions, so debuggers such as <code>gdb</code> cannot provide any help. We ran into such issues when supporting macOS on our output binaries. macOS has different alignment and linking policies than Linux hosts. Debugging crashes can be difficult as there is not much documentation online explaining these failures. When Binary Room introduced unexpected segmentation faults, we debugged the ARM binary using <code>gdb</code> on an AWS EC2 instance with an ARM-based Graviton CPU.</p>
<p>6. <strong>Evaluation</strong></p>
<p>Binary Room provides several programs which it is able to translate. We run translation against all of them by using <code>cargo test</code>. We currently support programs that compute Fibonacci, run arithmetic in a loop, print hello world, and echo stdin. You can view them <a href="https://github.com/Samir-Rashid/binary-room/tree/main/tests">on GitHub</a>.</p>
<p>6.1. <strong>Benchmarking</strong></p>
<figure>

  <p><img src="/images/binary-room/benchmark.png" alt="" /></p>
  <figcaption>Figure 4. Tests against a “Hello World” program which makes
1,000 write syscalls. We graph the mean execution time and
standard deviation.</figcaption>
</figure>
<figure>

  <p><img src="/images/binary-room/add.png" alt="" /></p>
  <figcaption>Figure 5. Evaluates against a program makes 10,000 function calls
to a simple arithmetic function.</figcaption>
</figure>
<p>We evaluate Binary Room in comparison with QEMU. We run the original RISC-V and translated ARM assembly via QEMU on a x86 machine. We use 100 warmup trials and then repeatedly run the test program 1,000 times to get the average and standard deviation of runtime.</p>
<p>We find that the RISC-V binaries run about twice as fast, as compared to our translation. We predict most of the runtime is due to overhead from loading the process and QEMU. We do not have access to a riscv64 machine, so we are unable to do a fair comparison of bare-metal results. We find both ARM translated binaries run 88-103% slower in QEMU. We are unsure of the cause of this slowdown as the instruction mappings are near one-to-one, so each program should run a similar number of instructions.</p>
<p>7. <strong>Discussion</strong></p>
<p>Binary Room introduces a static binary translator from riscv64 to aarch64. Unlike other emulation options, Binary Room produces a fully compatible binary with no dependencies. QEMU and Rosetta2 require just-in-time runtime support to support their translations. Statically translated binaries are more portable, though we forego optimizations that could happen based on runtime values. Furthermore, Binary Room is written in Rust and natively supports both macOS and Linux targets.</p>
<p>8. <strong>Conclusion</strong></p>
<p>Binary Room is open source and freely licensed. You may access the source code on GitHub:</p>
<p><a href="https://github.com/Samir-Rashid/binary-room"><pre>https://github.com/samir-rashid/binary-room</pre></a></p>
<p><strong>References</strong></p>
<div>A Comparison of Software and Hardware Techniques for x86 Virtualization, 2006. <a href="https://web.stanford.edu/class/cs240/readings/hwsw.pdf">https://web.stanford.edu/class/cs240/readings/hwsw.pdf</a></div>
<div>ARM Register names, 2024. <a href="https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names">https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names</a></div>
<div>arm.syscall.sh, 2024. <a href="https://arm.syscall.sh/">https://arm.syscall.sh/</a></div>
<div>Cross Compiling - NixOS Wiki, 2025. <a href="https://nixos.wiki/wiki/Cross_Compiling">https://nixos.wiki/wiki/Cross_Compiling</a></div>
<div>Linux kernel system calls for all architectures, 2025. <a href="https://gpages.juszkiewicz.com.pl/syscalls-table/syscalls.html">https://gpages.juszkiewicz.com.pl/syscalls-table/syscalls.html</a></div>
<div>Registers in AArch64 state, 2024. <a href="https://developer.arm.com/documentation/100076/0100/Instruction-Set-Overview/Overview-of-AArch64-state/Registers-in-AArch64-state">https://developer.arm.com/documentation/100076/0100/Instruction-Set-Overview/Overview-of-AArch64-state/Registers-in-AArch64-state</a></div>
<div>RISC-V Assembler: Arithmetic, 2024. <a href="https://projectf.io/posts/riscv-arithmetic/#pseudoinstructions">https://projectf.io/posts/riscv-arithmetic/#pseudoinstructions</a></div>
<div>RISC-V Instruction Set Specifications, 2019. <a href="https://msyksphinz-self.github.io/riscv-isadoc/html/index.html">https://msyksphinz-self.github.io/riscv-isadoc/html/index.html</a></div>
<div>RISC-V Reference Card, <a href="https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf">https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf</a></div>
<div>syscalls(2) - Linux manual page, <a href="https://www.man7.org/linux/man-pages/man2/syscalls.2.html">https://www.man7.org/linux/man-pages/man2/syscalls.2.html</a></div>
<div>Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification Version 1.2, 1995. <a href="https://refspecs.linuxfoundation.org/elf/elf.pdf">https://refspecs.linuxfoundation.org/elf/elf.pdf</a></div>
<div>Volume I: RISC-V User-Level ISA V2.1draft, Chapter 18, Calling Convention, 2014. <a href="https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf">https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf</a></div>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="research" /><summary type="html"><![CDATA[This report outlines how we implemented static binary translation from RISC-V to ARM binaries.]]></summary></entry><entry><title type="html">Linux Spelunking: How are processes loaded?</title><link href="https://godsped.com/process-loading/" rel="alternate" type="text/html" title="Linux Spelunking: How are processes loaded?" /><published>2025-04-13T00:00:00+00:00</published><updated>2025-04-13T00:00:00+00:00</updated><id>https://godsped.com/linux-spelunking</id><content type="html" xml:base="https://godsped.com/process-loading/"><![CDATA[<h1 id="linux-spelunking-how-are-processes-loaded-how-would-i-figure-it-out">Linux Spelunking: How are processes loaded? How would I figure it out?</h1>

<p>Today we journey into Linux to discover how programs are loaded.
Building new systems requires understanding how the current system actually works—not how the documentation claims it works.
I wrote this post for people who want to learn more about kernel internals but have been hesitating to dive in for themselves;
it’s the post I wish I had when starting out.
This article aims to convince you that kernel development is not intimidating.
We will explore how to deal with ambiguity when researching something new. You will come out with an understanding of the exact actions Linux takes to load a realistic program. Moreover, you will learn the tools to deconstruct any large program.</p>

<blockquote>
  <p><strong>Goal</strong>: How does Linux load a program?</p>
</blockquote>

<p>The first thing you may note is that this question is a bit odd. There are several interpretations for what it means to “load a program”.
This is a good point. However, a priori, I cannot know what the correct question to ask is.
Our expedition begins assuming basic C knowledge and becomes more complex. We will learn about the Linux kernel and its internal mechanisms from scratch.</p>

<div class="quote-author">Roadmap</div>
<div class="quote-body">

  <ol>
    <li>Trace Simple Program
      <ul>
        <li>Try decoding thousands of system calls with <code class="language-plaintext highlighter-rouge">strace</code> and discover <code class="language-plaintext highlighter-rouge">printf</code> is not in the program</li>
      </ul>
    </li>
    <li>Binary Archaeology
      <ul>
        <li>Crack compiled programs with <code class="language-plaintext highlighter-rouge">objdump</code> and <code class="language-plaintext highlighter-rouge">readelf</code></li>
        <li>Find a PLT and GOT that are calling nonexistent functions</li>
      </ul>
    </li>
    <li>Shared Libraries
      <ul>
        <li>Explore the loading of <code class="language-plaintext highlighter-rouge">libc</code> and the dynamic linker <code class="language-plaintext highlighter-rouge">ld-linux.so</code></li>
      </ul>
    </li>
    <li>Kernel Mechanisms
      <ul>
        <li>Follow how <code class="language-plaintext highlighter-rouge">mmap</code>, page faults, and copy-on-write support efficient library sharing</li>
      </ul>
    </li>
    <li>Piecing the Puzzle
      <ul>
        <li>Connect the path from <code class="language-plaintext highlighter-rouge">execve</code> to <code class="language-plaintext highlighter-rouge">main</code> with general purpose kernel mechanisms</li>
        <li>Entirely understand how Linux brings bytes on disk to life as processes :zombie:</li>
      </ul>
    </li>
  </ol>
</div>

<aside class="sidebar__left">
<nav class="toc">
    <header><h4 class="nav__title"><i class="fas fa-file-alt"></i> On This Page</h4></header>
<ul class="toc__menu" id="markdown-toc">
  <li><a href="#linux-spelunking-how-are-processes-loaded-how-would-i-figure-it-out" id="markdown-toc-linux-spelunking-how-are-processes-loaded-how-would-i-figure-it-out">Linux Spelunking: How are processes loaded? How would I figure it out?</a>    <ul>
      <li><a href="#load-a-program" id="markdown-toc-load-a-program">Load a program</a>        <ul>
          <li><a href="#load-hello-world" id="markdown-toc-load-hello-world">Load “Hello World”</a></li>
        </ul>
      </li>
      <li><a href="#its-a-function-call" id="markdown-toc-its-a-function-call">It’s a function call</a></li>
      <li><a href="#binary-spelunking" id="markdown-toc-binary-spelunking">Binary spelunking</a>        <ul>
          <li><a href="#how-to-open-a-binary" id="markdown-toc-how-to-open-a-binary">How to open a binary?</a>            <ul>
              <li><a href="#hello-name" id="markdown-toc-hello-name">“Hello {name}”</a></li>
              <li><a href="#back-to-the-objdump" id="markdown-toc-back-to-the-objdump">Back to the <code class="language-plaintext highlighter-rouge">objdump</code></a></li>
            </ul>
          </li>
          <li><a href="#dumpster-fire" id="markdown-toc-dumpster-fire"><code class="language-plaintext highlighter-rouge">dump</code>ster fire</a>            <ul>
              <li><a href="#where-art-thou-printf" id="markdown-toc-where-art-thou-printf">where art thou, <code class="language-plaintext highlighter-rouge">printf</code>?</a></li>
            </ul>
          </li>
          <li><a href="#pretty-little-thing" id="markdown-toc-pretty-little-thing">Pretty Little Thing</a></li>
          <li><a href="#return-of-the-elves" id="markdown-toc-return-of-the-elves">Return of the Elves</a></li>
        </ul>
      </li>
      <li><a href="#go-deeper-buddy" id="markdown-toc-go-deeper-buddy">Go Deeper, Buddy</a>        <ul>
          <li><a href="#tracing-plt-and-got" id="markdown-toc-tracing-plt-and-got">Tracing PLT and GOT</a></li>
        </ul>
      </li>
      <li><a href="#knowledge-check" id="markdown-toc-knowledge-check">Knowledge Check</a></li>
    </ul>
  </li>
  <li><a href="#now-its-your-turn" id="markdown-toc-now-its-your-turn">Now it’s your turn</a>    <ul>
      <li><a href="#gimme-a-man" id="markdown-toc-gimme-a-man">Gimme a man</a></li>
      <li><a href="#kernel-sourcerers" id="markdown-toc-kernel-sourcerers">Kernel Sourcerers</a>        <ul>
          <li><a href="#summary-of-execution-path" id="markdown-toc-summary-of-execution-path">Summary of Execution Path</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#recap" id="markdown-toc-recap">Recap</a>    <ul>
      <li><a href="#its-for-the-pedagogy-" id="markdown-toc-its-for-the-pedagogy-">It’s for the pedagogy </a></li>
      <li><a href="#what-we-didnt-cover" id="markdown-toc-what-we-didnt-cover">What we didn’t cover</a></li>
      <li><a href="#wrapping-up" id="markdown-toc-wrapping-up">Wrapping up</a>        <ul>
          <li><a href="#further-reading" id="markdown-toc-further-reading">Further Reading:</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

  </nav>
</aside>
<!-- https://github.com/junqing-zhang/junqing-zhang.github.io/blob/master/_includes/toc -->

<p><br /></p>

<p>We must step in any direction to start.
The results of each experiment will allow us to iterate, refine our questions, and learn new concepts.</p>

<p>On first blush, the question seems obvious. Running a program simply means going to the first instruction and running in order until the end. Let’s test this theory.</p>

<h2 id="load-a-program">Load a program</h2>

<p>Let’s try running a simple program and inspect what it is doing.
<a href="https://apps.gnome.org/Nautilus/"><code class="language-plaintext highlighter-rouge">nautilus</code></a> is the file explorer application that ships with GNOME.
We want to know what Linux is doing when nautilus starts.
Luckily, there is a tool called <code class="language-plaintext highlighter-rouge">strace</code> which records every call into Linux.
Before we look at the output, let’s stop to recursively explain what is going on.</p>

<blockquote>
  <p>:information_desk_person:: Why Nautilus?</p>

  <p>No reason. I wanted a simple program that doesn’t do much.</p>
</blockquote>

<blockquote>
  <p>:raising_hand:: How do you know to look at calls into the kernel?</p>

  <p>Think about how the way programs run. Starting any process requires notifying the kernel of the program you are starting.
These interactions are called <strong>syscalls</strong>. User programs use these functions to ask the operating system to do something privileged.
For example, a process cannot open a file without asking for permission first. You can think of system calls as normal function calls for the purposes of this exercise.</p>
</blockquote>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>strace nautilus
execve<span class="o">(</span><span class="s2">"/run/current-system/sw/bin/nautilus"</span>, <span class="o">[</span><span class="s2">"nautilus"</span><span class="o">]</span>, 0x7ffe54d428a0 /<span class="k">*</span> 75 vars <span class="k">*</span>/<span class="o">)</span> <span class="o">=</span> 0
brk<span class="o">(</span>NULL<span class="o">)</span>                               <span class="o">=</span> 0x30e3a000
<span class="nt">---------</span> 23,744 lines snipped <span class="nt">---------</span>
</code></pre></div></div>

<p>What was that output??? My terminal gets flooded with nautilus’ tens of thousands of syscalls. I have made a grave mistake. That’s okay, it’s too early to get demoralized. Evidently, my mental model that a program which does not <em>appear</em> to be doing anything <em>is</em> doing <em>nothing</em> is wrong. How can we adjust course to make better progress?</p>

<blockquote>
  <p><strong>Debugging Process</strong>:</p>

  <p>load “simple” program ⟶ ❌</p>
</blockquote>

<h3 id="load-hello-world">Load “Hello World”</h3>

<p>Instead, we can write a minimal <code class="language-plaintext highlighter-rouge">hello_world.c</code> program to test with<sup id="fnref:assets" role="doc-noteref"><a href="#fn:assets" class="footnote" rel="footnote">1</a></sup>. What happens when the kernel loads this program and prints some text?</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcc hello_world.c
<span class="nv">$ </span>./a.out
hello world!
</code></pre></div></div>

<p>Aha, we have solved the puzzle! The kernel starts running the instructions of <code class="language-plaintext highlighter-rouge">main()</code> and <code class="language-plaintext highlighter-rouge">printf</code> is just a function call. Spoiler alert: this is wrong. We still haven’t explained what this <code class="language-plaintext highlighter-rouge">printf</code> reference is.</p>

<blockquote>
  <p>:angry:: You said I wouldn’t need any prerequisite knowledge to understand this. I don’t understand these keywords. What is this weird <code class="language-plaintext highlighter-rouge">void</code> thing?</p>

  <p>If you haven’t seen this before, you can ignore it for now. It means that the function has no input.</p>
</blockquote>

<blockquote>
  <p>:confounded:: What is that <code class="language-plaintext highlighter-rouge">\n</code> after hello world?</p>

  <p>Wonderful question, though you may not realize it :smile:. Simply, the <code class="language-plaintext highlighter-rouge">\n</code> asks <code class="language-plaintext highlighter-rouge">printf</code> to print a newline. Check out my <a href="/fork">fork</a> post and the resources on <code class="language-plaintext highlighter-rouge">printf</code> at the end of this post to get closer to what <code class="language-plaintext highlighter-rouge">\n</code> <em>actually</em> does.</p>
</blockquote>

<p>In fact, if we remove all unfamiliar syntax, the program behaves the same as before.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">main</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcc hello_world_skeptic.c
<span class="nv">$ </span>./a.out
hello world!
</code></pre></div></div>

<p>This time our compiler, <code class="language-plaintext highlighter-rouge">gcc</code>, complains with a bunch of warnings:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hello_world</span><span class="p">.</span><span class="n">c</span><span class="o">:</span><span class="mi">1</span><span class="o">:</span><span class="mi">2</span><span class="o">:</span> <span class="n">warning</span><span class="o">:</span> <span class="k">return</span> <span class="n">type</span> <span class="n">defaults</span> <span class="n">to</span> <span class="err">‘</span><span class="kt">int</span><span class="err">’</span> <span class="p">[</span><span class="o">-</span><span class="n">Wimplicit</span><span class="o">-</span><span class="kt">int</span><span class="p">]</span>
    <span class="mi">1</span> <span class="o">|</span>  <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
      <span class="o">|</span>  <span class="o">^~~~</span>
<span class="n">hello_world</span><span class="p">.</span><span class="n">c</span><span class="o">:</span> <span class="n">In</span> <span class="n">function</span> <span class="err">‘</span><span class="n">main</span><span class="err">’</span><span class="o">:</span>
<span class="n">hello_world</span><span class="p">.</span><span class="n">c</span><span class="o">:</span><span class="mi">2</span><span class="o">:</span><span class="mi">9</span><span class="o">:</span> <span class="n">warning</span><span class="o">:</span> <span class="n">implicit</span> <span class="n">declaration</span> <span class="n">of</span> <span class="n">function</span> <span class="err">‘</span><span class="n">printf</span><span class="err">’</span> <span class="p">[</span><span class="o">-</span><span class="n">Wimplicit</span><span class="o">-</span><span class="n">function</span><span class="o">-</span><span class="n">declaration</span><span class="p">]</span>
    <span class="mi">2</span> <span class="o">|</span>         <span class="n">printf</span><span class="p">(</span><span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
      <span class="o">|</span>         <span class="o">^~~~~~</span>
<span class="n">hello_world</span><span class="p">.</span><span class="n">c</span><span class="o">:</span><span class="mi">1</span><span class="o">:</span><span class="mi">1</span><span class="o">:</span> <span class="n">note</span><span class="o">:</span> <span class="n">include</span> <span class="err">‘</span><span class="o">&lt;</span><span class="n">stdio</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span><span class="err">’</span> <span class="n">or</span> <span class="n">provide</span> <span class="n">a</span> <span class="n">declaration</span> <span class="n">of</span> <span class="err">‘</span><span class="n">printf</span><span class="err">’</span>
  <span class="o">+++</span> <span class="o">|+</span><span class="err">#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">stdio</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
    <span class="mi">1</span> <span class="o">|</span>  <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">hello_world</span><span class="p">.</span><span class="n">c</span><span class="o">:</span><span class="mi">2</span><span class="o">:</span><span class="mi">9</span><span class="o">:</span> <span class="n">warning</span><span class="o">:</span> <span class="n">incompatible</span> <span class="n">implicit</span> <span class="n">declaration</span> <span class="n">of</span> <span class="n">built</span><span class="o">-</span><span class="n">in</span> <span class="n">function</span> <span class="err">‘</span><span class="n">printf</span><span class="err">’</span> <span class="p">[</span><span class="o">-</span><span class="n">Wbuiltin</span><span class="o">-</span><span class="n">declaration</span><span class="o">-</span><span class="n">mismatch</span><span class="p">]</span>
    <span class="mi">2</span> <span class="o">|</span>         <span class="n">printf</span><span class="p">(</span><span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
      <span class="o">|</span>         <span class="o">^~~~~~</span>
<span class="n">hello_world</span><span class="p">.</span><span class="n">c</span><span class="o">:</span><span class="mi">2</span><span class="o">:</span><span class="mi">9</span><span class="o">:</span> <span class="n">note</span><span class="o">:</span> <span class="n">include</span> <span class="err">‘</span><span class="o">&lt;</span><span class="n">stdio</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span><span class="err">’</span> <span class="n">or</span> <span class="n">provide</span> <span class="n">a</span> <span class="n">declaration</span> <span class="n">of</span> <span class="err">‘</span><span class="n">printf</span><span class="err">’</span>
</code></pre></div></div>

<p>Weird. The program runs the same, so why are we getting all these warnings?
One line jumps out to me. <code class="language-plaintext highlighter-rouge">gcc</code> warns us <strong>four</strong> times about something to do with the “declaration of ‘printf’”.
Before we get ahead of ourselves, allow me to fix these compiler warnings. Fixing these warnings will prevent any weird unrelated issues that interfere with our later debugging results.</p>

<p>Following the error message <code class="language-plaintext highlighter-rouge">include ‘&lt;stdio.h&gt;’ or provide a declaration of ‘printf’</code> tells us precisely how to fix the error.
C becomes aware of functions it can link with by using header files. Including <code class="language-plaintext highlighter-rouge">stdio.h</code> tells <code class="language-plaintext highlighter-rouge">gcc</code> about the definition of <code class="language-plaintext highlighter-rouge">printf</code>.</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gi">&gt; #include &lt;stdio.h&gt;
</span> 
<span class="gi">&gt; int main() {
</span>        printf("hello world!\n");
<span class="gi">&gt;       return 0;
</span>  }

</code></pre></div></div>

<h2 id="its-a-function-call">It’s a function call</h2>

<p>I claim that <code class="language-plaintext highlighter-rouge">printf</code> is not a function call. Let’s either verify or disprove this conclusion. We can run <code class="language-plaintext highlighter-rouge">strace</code> on <code class="language-plaintext highlighter-rouge">hello_world</code> and save the output to a file “hello_world.strace”.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcc hello_world.c
<span class="nv">$ </span>strace <span class="nt">-o</span> hello_world.strace ./a.out
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">strace</code> on this binary returns an overwhelming 45 lines of output, which confirms much more is happening.</p>

<blockquote>
  <p><strong>Abridged output</strong>:</p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">strace</span> <span class="p">.</span><span class="o">/</span><span class="n">a</span><span class="p">.</span><span class="n">out</span>
<span class="n">execve</span><span class="p">(</span><span class="s">"./a.out"</span><span class="p">,</span> <span class="p">[</span><span class="s">"./a.out"</span><span class="p">],</span> <span class="mh">0x7ffc3c8056d0</span> <span class="cm">/* 158 vars */</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">brk</span><span class="p">(</span><span class="nb">NULL</span><span class="p">)</span>                               <span class="o">=</span> <span class="mh">0x33d6f000</span>
<span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">8192</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e57473000</span>
<span class="o">----------</span> <span class="n">snipped</span> <span class="k">for</span> <span class="n">clarity</span> <span class="o">----------</span>
<span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">13</span><span class="p">)</span>          <span class="o">=</span> <span class="mi">13</span>
<span class="n">exit_group</span><span class="p">(</span><span class="mi">13</span><span class="p">)</span>                          <span class="o">=</span> <span class="o">?</span>
<span class="o">+++</span> <span class="n">exited</span> <span class="n">with</span> <span class="mi">13</span> <span class="o">+++</span>
</code></pre></div>  </div>

  <details>
    <summary>

      <p><strong>Full output</strong>
(expand)</p>
    </summary>
    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">strace</span> <span class="p">.</span><span class="o">/</span><span class="n">a</span><span class="p">.</span><span class="n">out</span>
<span class="n">execve</span><span class="p">(</span><span class="s">"./a.out"</span><span class="p">,</span> <span class="p">[</span><span class="s">"./a.out"</span><span class="p">],</span> <span class="mh">0x7ffc3c8056d0</span> <span class="cm">/* 158 vars */</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">brk</span><span class="p">(</span><span class="nb">NULL</span><span class="p">)</span>                               <span class="o">=</span> <span class="mh">0x33d6f000</span>
<span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">8192</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e57473000</span>
<span class="n">access</span><span class="p">(</span><span class="s">"/etc/ld-nix.so.preload"</span><span class="p">,</span> <span class="n">R_OK</span><span class="p">)</span>  <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/glibc-hwcaps/x86-64-v4/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/glibc-hwcaps/x86-64-v4/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/glibc-hwcaps/x86-64-v3/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/glibc-hwcaps/x86-64-v3/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/glibc-hwcaps/x86-64-v2/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/glibc-hwcaps/x86-64-v2/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/sga46w4h0l00adh433634s7kp724czvn-shell/lib/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/glibc-hwcaps/x86-64-v4/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/glibc-hwcaps/x86-64-v4/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/glibc-hwcaps/x86-64-v3/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/glibc-hwcaps/x86-64-v3/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/glibc-hwcaps/x86-64-v2/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">newfstatat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/glibc-hwcaps/x86-64-v2/"</span><span class="p">,</span> <span class="mh">0x7ffc1f6fbf30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s">"</span><span class="se">\177</span><span class="s">ELF</span><span class="se">\2\1\1\3\0\0\0\0\0\0\0\0\3\0</span><span class="s">&gt;</span><span class="se">\0\1\0\0\0</span><span class="s">@</span><span class="se">\244\2\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">832</span><span class="p">)</span> <span class="o">=</span> <span class="mi">832</span>
<span class="n">pread64</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s">"</span><span class="se">\6\0\0\0\4\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">784</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span> <span class="o">=</span> <span class="mi">784</span>
<span class="n">fstat</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="p">{</span><span class="n">st_mode</span><span class="o">=</span><span class="n">S_IFREG</span><span class="o">|</span><span class="mo">0555</span><span class="p">,</span> <span class="n">st_size</span><span class="o">=</span><span class="mi">2335712</span><span class="p">,</span> <span class="p">...})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">pread64</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s">"</span><span class="se">\6\0\0\0\4\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">784</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span> <span class="o">=</span> <span class="mi">784</span>
<span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">2067928</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e5727a000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5e572a2000</span><span class="p">,</span> <span class="mi">1474560</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_EXEC</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mh">0x28000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e572a2000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5e5740a000</span><span class="p">,</span> <span class="mi">352256</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mh">0x190000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e5740a000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5e57460000</span><span class="p">,</span> <span class="mi">24576</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mh">0x1e5000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e57460000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5e57466000</span><span class="p">,</span> <span class="mi">52696</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e57466000</span>
<span class="n">close</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>                                <span class="o">=</span> <span class="mi">0</span>
<span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">12288</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5e57277000</span>
<span class="n">arch_prctl</span><span class="p">(</span><span class="n">ARCH_SET_FS</span><span class="p">,</span> <span class="mh">0x7f5e57277740</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">set_tid_address</span><span class="p">(</span><span class="mh">0x7f5e57277a10</span><span class="p">)</span>         <span class="o">=</span> <span class="mi">467906</span>
<span class="n">set_robust_list</span><span class="p">(</span><span class="mh">0x7f5e57277a20</span><span class="p">,</span> <span class="mi">24</span><span class="p">)</span>     <span class="o">=</span> <span class="mi">0</span>
<span class="n">rseq</span><span class="p">(</span><span class="mh">0x7f5e57278060</span><span class="p">,</span> <span class="mh">0x20</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0x53053053</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">mprotect</span><span class="p">(</span><span class="mh">0x7f5e57460000</span><span class="p">,</span> <span class="mi">16384</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">mprotect</span><span class="p">(</span><span class="mh">0x403000</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span>     <span class="o">=</span> <span class="mi">0</span>
<span class="n">mprotect</span><span class="p">(</span><span class="mh">0x7f5e574aa000</span><span class="p">,</span> <span class="mi">8192</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">prlimit64</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">RLIMIT_STACK</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="p">{</span><span class="n">rlim_cur</span><span class="o">=</span><span class="mi">16384</span><span class="o">*</span><span class="mi">1024</span><span class="p">,</span> <span class="n">rlim_max</span><span class="o">=</span><span class="n">RLIM64_INFINITY</span><span class="p">})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">fstat</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="n">st_mode</span><span class="o">=</span><span class="n">S_IFCHR</span><span class="o">|</span><span class="mo">0620</span><span class="p">,</span> <span class="n">st_rdev</span><span class="o">=</span><span class="n">makedev</span><span class="p">(</span><span class="mh">0x88</span><span class="p">,</span> <span class="mh">0x2</span><span class="p">),</span> <span class="p">...})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">getrandom</span><span class="p">(</span><span class="s">"</span><span class="se">\xc3\xaa\x18\x11\xb5\x45\x97\x82</span><span class="s">"</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="n">GRND_NONBLOCK</span><span class="p">)</span> <span class="o">=</span> <span class="mi">8</span>
<span class="n">brk</span><span class="p">(</span><span class="nb">NULL</span><span class="p">)</span>                               <span class="o">=</span> <span class="mh">0x33d6f000</span>
<span class="n">brk</span><span class="p">(</span><span class="mh">0x33d90000</span><span class="p">)</span>                         <span class="o">=</span> <span class="mh">0x33d90000</span>
<span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">13</span><span class="p">)</span>          <span class="o">=</span> <span class="mi">13</span>
<span class="n">exit_group</span><span class="p">(</span><span class="mi">13</span><span class="p">)</span>                          <span class="o">=</span> <span class="o">?</span>
<span class="o">+++</span> <span class="n">exited</span> <span class="n">with</span> <span class="mi">13</span> <span class="o">+++</span>
</code></pre></div>    </div>
  </details>
</blockquote>

<p>Oh my. Have we even gotten closer to the solution?
Of the following output, the only recognizable line is <code class="language-plaintext highlighter-rouge">write(1, "hello world!\n", 13)          = 13</code>, which tells us that printing is using a <code class="language-plaintext highlighter-rouge">write</code> syscall to send the output.
The output has a lot of information we do not understand yet, and I do not know what data we want to look for.
On the positive side, at least the output fits on a screen now. Tracing the output hasn’t gotten us anywhere and these syscalls still look daunting.</p>

<p>We need to break out our debugging hats :tophat:. If we have faith that we will be able to solve this problem, then we will be able to figure out what is going on.
Let us try repeating the strategy of looking at the output of our tools. This time <code class="language-plaintext highlighter-rouge">gcc</code> and the standard output on the command line haven’t suggested anything to us.</p>

<p>This will be quite tedious. Can we offload the busy work an LLM and see what it says?
We live in the 21st century, so although I wouldn’t trust an LLM to give the correct answer, it can helpfully suggest terms to look up.</p>

<p><img src="/images/spelunking/chatgpt_syscall.png" alt="asking chatgpt to explain the syscalls" /></p>

<blockquote>
  <p>Instructor: You are going down the wrong track. Let’s back up.</p>
</blockquote>

<p>We need to take a moment to think about this approach. <code class="language-plaintext highlighter-rouge">strace</code> is too hard to interpret because it requires us to first understand what all these syscalls are.</p>

<blockquote>
  <p><strong>Debugging Process</strong>:</p>

  <p>↛ Load and trace a “simple” program ⟶ ❌</p>

  <p>↛ Load a minimal program</p>

  <blockquote>
    <p>⇝ Idea: <code class="language-plaintext highlighter-rouge">printf</code> is a function call</p>

    <blockquote>
      <p>↛  check compiler output ⟶ ❌</p>

      <p>↛  check <code class="language-plaintext highlighter-rouge">strace</code> output ⟶ use LLM ⟶ ❌</p>
    </blockquote>

    <p>⇝ dead end…?</p>
  </blockquote>
</blockquote>

<p>Maybe we should take a look at a different level of abstraction? There is nothing more we can learn from the source C file.
It seems like we need to go deeper. Is there another file we have?</p>

<h2 id="binary-spelunking">Binary spelunking</h2>

<p>What is inside this <code class="language-plaintext highlighter-rouge">a.out</code> thing? I know it is a compiled binary, so this must contain all the machine code instructions that are running, right?</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>vim a.out
</code></pre></div></div>

<p><img src="/images/spelunking/vim_binary.png" alt="garbled vim buffer" /></p>

<p>Uh, that’s not right. I don’t think there is anything useful here to see. I do see some characters rendering correctly, but they look like nonsense. I see “ELF” and then some file paths at the start and end of this file.</p>

<p>Let’s put a pin in this stuff we have seen in case it comes up later. Writing a log of what you have tried while debugging is essential to be able to keep all the relevant context in your head. What works, as well as what didn’t, helps narrow the scope of debugging.</p>

<p>So far, <code class="language-plaintext highlighter-rouge">strace</code> did not help. We have some hints on how to proceed. We can either look at the filepaths in the binary file, or we can look further into what <code class="language-plaintext highlighter-rouge">gcc</code> was telling us about the implicit definition of <code class="language-plaintext highlighter-rouge">printf</code>.</p>

<h3 id="how-to-open-a-binary">How to open a binary?</h3>

<blockquote>
  <p>:monocle_face:: Dear search engine, how can I open <code class="language-plaintext highlighter-rouge">a.out</code> C binary file?</p>
</blockquote>

<p>The the tool we need is <code class="language-plaintext highlighter-rouge">objdump</code>. <code class="language-plaintext highlighter-rouge">objdump</code> comes installed with the <code class="language-plaintext highlighter-rouge">gcc</code> package. This bundling indicates that <code class="language-plaintext highlighter-rouge">objdump</code> is a default tool important to be familiar with.</p>

<p>But first, I want to slightly modify the program we are looking at. Our <code class="language-plaintext highlighter-rouge">hello_world.c</code> is deterministic*, which means it does the same thing every time. Instead, let’s make something more realistic, such as a program that asks for the user’s name and responds.</p>

<h4 id="hello-name">“Hello {name}”</h4>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gi">&gt; void main(int argc, char** argv) {
&gt;   if (argc &lt; 2) {
&gt;     printf("hello: error with argc\n");
&gt;     return -1;
&gt;   }
</span><span class="gd">&lt;   printf("hello world!\n");
</span><span class="gi">&gt;   printf("hello, %s!\n", argv[1]);
</span>  return 0;
  }
</code></pre></div></div>

<p>Now we print out a name given to us from the command line, as so <code class="language-plaintext highlighter-rouge">./a.out Samir</code>. Take a moment to think about whether you understand the change I made.</p>

<details>
  <summary>Can you explain what argc is and why I check if it is 2? Why not 1? Why do I index 1 into argv if C arrays are zero indexed?</summary>
  <blockquote>
    <p>Practice looking this question up. Stack overflow is a wonderful library of questions. Try searching “what is argc and argv in C”.</p>
  </blockquote>

</details>

<h4 id="back-to-the-objdump">Back to the <code class="language-plaintext highlighter-rouge">objdump</code></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="c"># first look at the help output</span>
&lt;omitted&gt;
<span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out
&lt;abbreviated <span class="k">for </span>readability&gt;
0000000000401050 &lt;main&gt;:
  401050:       48 83 ec 08             sub    <span class="nv">$0x8</span>,%rsp
  401054:       83 ff 01                cmp    <span class="nv">$0x1</span>,%edi
  401057:       7e 1e                   jle    401077 &lt;main+0x27&gt;
  401059:       48 8b 56 08             mov    0x8<span class="o">(</span>%rsi<span class="o">)</span>,%rdx
  40105d:       bf 02 00 00 00          mov    <span class="nv">$0x2</span>,%edi
  401062:       31 c0                   xor    %eax,%eax
  401064:       48 8d 35 b0 0f 00 00    lea    0xfb0<span class="o">(</span>%rip<span class="o">)</span>,%rsi        <span class="c"># 40201b &lt;_IO_stdin_used+0x1b&gt;</span>
  40106b:       e8 d0 ff ff ff          call   401040 &lt;__printf_chk@plt&gt;
  401070:       31 c0                   xor    %eax,%eax
  401072:       48 83 c4 08             add    <span class="nv">$0x8</span>,%rsp
  401076:       c3                      ret
  401077:       48 8d 3d 86 0f 00 00    lea    0xf86<span class="o">(</span>%rip<span class="o">)</span>,%rdi        <span class="c"># 402004 &lt;_IO_stdin_used+0x4&gt;</span>
  40107e:       e8 ad ff ff ff          call   401030 &lt;puts@plt&gt;
  401083:       83 c8 ff                or     <span class="nv">$0xffffffff</span>,%eax
  401086:       eb ea                   jmp    401072 &lt;main+0x22&gt;
  401088:       0f 1f 84 00 00 00 00    nopl   0x0<span class="o">(</span>%rax,%rax,1<span class="o">)</span>
  40108f:       00
</code></pre></div></div>

<p>I see some nonsense in the objdump. I cannot recognize this binary is the same as my original <code class="language-plaintext highlighter-rouge">hello_name.c</code>.</p>

<p>One tip is to try doing the simplest possible test when trying a new strategy. Minimizing the experiment ensures we do not get overloaded with unnecessary context.</p>

<p>First, we must recompile with debug flags to make this easier. I think we have explored our way to the right level of abstraction on what <code class="language-plaintext highlighter-rouge">printf</code> is actually doing.
Binary spelunking is the perfect way to see what the CPU runs to make “hello world” show up.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcc <span class="nt">-g</span> hello_world.c
<span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out
</code></pre></div></div>

<p>We must be persistent. Making new systems wouldn’t be fun if it was easy. By the end, I promise your appreciation for the immense scope of real systems will grow.</p>

<p>There are many flags to <code class="language-plaintext highlighter-rouge">objdump</code>, which you can find on the <code class="language-plaintext highlighter-rouge">man</code> page. We might need to try some random flags before finding something useful. Again, the goal is to both induct new hypotheses on what is happening and deduct possibilities that are definitely not valid explanations for the behavior we are seeing <sup id="fnref:debug" role="doc-noteref"><a href="#fn:debug" class="footnote" rel="footnote">2</a></sup>.</p>

<p><img src="/images/spelunking/debug_space2.png" alt="diagram of cutting search space in half" style="display:block; margin-left:auto; margin-right:auto" width="60%" /></p>

<p>Debugging tools let us slice the problem space into smaller pieces until we’ve dissected every behavior in the system.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="nt">-p</span> ./a.out
&lt;omitted&gt;
<span class="nv">$ </span>objdump <span class="nt">-h</span> ./a.out
&lt;omitted&gt;
</code></pre></div></div>

<p>Ooh, I like the output of <code class="language-plaintext highlighter-rouge">-h</code>. It’s concise and readable. We are  getting somewhere, so I want to be more thoughtful about what step we take next. Trying a few more commands…</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="nt">-t</span> ./a.out
&lt;omitted&gt;
<span class="nv">$ </span>objdump <span class="nt">-d</span> ./a.out
&lt;omitted&gt;
<span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out
a.out:     file format elf64-x86-64

Disassembly of section .interp:
0000000000400318 &lt;.interp&gt;:
<span class="nt">----------</span> snipped <span class="k">for </span>clarity <span class="nt">----------</span>
</code></pre></div></div>

<p>… this also looks helpful. Let’s recap. What can we check out next? There was the thing called “ELF”. I dismissed it before when looking at the binary, but it keeps coming up. 
I also want to look deeper into the disassembly.</p>

<p>A spoiler: we are going to need to understand both of these things, so the order doesn’t matter.</p>

<h3 id="dumpster-fire"><code class="language-plaintext highlighter-rouge">dump</code>ster fire</h3>

<p>There’s a lot of output from this disassembly, 1257 lines. Scrolling through the assembly, it does not seem productive to jump into tracing the entire program; we need to start with something smaller.</p>

<h4 id="where-art-thou-printf">where art thou, <code class="language-plaintext highlighter-rouge">printf</code>?</h4>

<p>Find <code class="language-plaintext highlighter-rouge">printf</code> with <code class="language-plaintext highlighter-rouge">grep</code>.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out | <span class="nb">grep</span> <span class="s2">"printf"</span>
&lt;output is empty...&gt;
</code></pre></div></div>

<p>We turned on debug symbols, what gives?</p>

<blockquote>
  <p>:fearful:: wtf? :skull:</p>

  <p>:cursing_face:: You know, I have a great idea how to finish debugging this. Let’s give up.</p>
</blockquote>

<p>The challenge is what makes debugging fun! Anticipate how much satisfaction you’ll feel when we figure
this out together! 
Is there something simple we missed, similar to how we skipped over the seemingly irrelevant references to “ELF”?</p>

<p>Another low hanging fruit to investigate is the objdump section titles. Analyzing the sections will give us a foothold on the huge assembly output.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out | <span class="nb">grep</span> <span class="s2">"section"</span>
Disassembly of section .interp:
Disassembly of section .note.gnu.property:
Disassembly of section .note.ABI-tag:
Disassembly of section .hash:
Disassembly of section .gnu.hash:
Disassembly of section .dynsym:
Disassembly of section .dynstr:
Disassembly of section .gnu.version:
Disassembly of section .gnu.version_r:
Disassembly of section .rela.dyn:
Disassembly of section .rela.plt:
Disassembly of section .init:
Disassembly of section .plt:
Disassembly of section .text:
&lt;snipped&gt;
</code></pre></div></div>

<p>Nevermind, these sections are more information that we do not know what to do with.
Since we’re stuck, we need to backtrack and try another path forward.
Instead of using my contrived program, let’s go back to a <del>simple</del> real program like nautilus.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>objdump <span class="nt">-D</span> <span class="si">$(</span>which nautilus<span class="si">)</span> | <span class="nb">grep</span> <span class="s2">"printf"</span>
0000000000401080 &lt;__asprintf_chk@plt&gt;:
  401080:       ff 25 4a 3f 00 00       jmp    <span class="k">*</span>0x3f4a<span class="o">(</span>%rip<span class="o">)</span>        <span class="c"># 404fd0 &lt;__asprintf_chk@GLIBC_2.8&gt;</span>
  40132f:       e8 4c fd ff ff          call   401080 &lt;__asprintf_chk@plt&gt;
</code></pre></div></div>

<p>What? I was not expecting this at all. I was staring at this wall we got stuck at and thought I would have to try a bunch of things to get through. But this is something we didn’t expect. Why did changing the binary we use make a difference?</p>

<p>We have found something that doesn’t fit in our mental model. Great! Now we get an opportunity to learn something cool and update our knowledge.</p>

<p>Does this weird thing also happen for <code class="language-plaintext highlighter-rouge">hello_name.c</code>? Indeed, we see <code class="language-plaintext highlighter-rouge">printf</code>.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out | <span class="nb">grep</span> <span class="s2">"printf"</span>
0000000000401040 &lt;__printf_chk@plt&gt;:
  401040:       ff 25 a2 2f 00 00       jmp    <span class="k">*</span>0x2fa2<span class="o">(</span>%rip<span class="o">)</span>        <span class="c"># 403fe8 &lt;__printf_chk@GLIBC_2.3.4&gt;</span>
  401067:       e9 d4 ff ff ff          jmp    401040 &lt;__printf_chk@plt&gt;
</code></pre></div></div>

<p>Comparing the <code class="language-plaintext highlighter-rouge">objdump</code> of <code class="language-plaintext highlighter-rouge">hello_name</code> and <code class="language-plaintext highlighter-rouge">hello_world</code> reveals two different kinds of library calls.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="mi">40106</span><span class="n">b</span><span class="o">:</span>       <span class="n">e8</span> <span class="n">d0</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">call</span>   <span class="mi">401040</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;</span>

  <span class="mi">40107</span><span class="n">e</span><span class="o">:</span>       <span class="n">e8</span> <span class="n">ad</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">call</span>   <span class="mi">401030</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">hello_world</code> binary doesn’t have any <code class="language-plaintext highlighter-rouge">printf</code>, but <code class="language-plaintext highlighter-rouge">hello_name</code> has both.
What is the difference between <code class="language-plaintext highlighter-rouge">puts</code> and <code class="language-plaintext highlighter-rouge">printf</code>? The binary appears to <code class="language-plaintext highlighter-rouge">call</code> one reference to <code class="language-plaintext highlighter-rouge">puts@plt</code> and one to <code class="language-plaintext highlighter-rouge">__printf_chk@plt</code>.
<code class="language-plaintext highlighter-rouge">puts</code> is simpler than <code class="language-plaintext highlighter-rouge">printf</code> because it does not do string formatting (ex: <code class="language-plaintext highlighter-rouge">%d</code>).
If you are printing a fixed literal string, then the compiler will probably make a call to the more efficient <code class="language-plaintext highlighter-rouge">puts</code> function instead.</p>

<p>We can get back to debugging the main issue of what <code class="language-plaintext highlighter-rouge">printf</code> is doing. The code is a few lines, so we can check this manually. Let us go into the <code class="language-plaintext highlighter-rouge">objdump</code> where this is found, no expert tooling needed:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>objdump <span class="nt">-D</span> ./a.out | less
<span class="c"># then type "/printf" &lt;enter&gt;</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Disassembly</span> <span class="n">of</span> <span class="n">section</span> <span class="p">.</span><span class="n">plt</span><span class="o">:</span>

<span class="mo">0000000000401020</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="o">-</span><span class="mh">0x10</span><span class="o">&gt;:</span>
  <span class="mi">401020</span><span class="o">:</span>       <span class="n">ff</span> <span class="mi">35</span> <span class="n">aa</span> <span class="mi">2</span><span class="n">f</span> <span class="mo">00</span> <span class="mo">00</span>       <span class="n">push</span>   <span class="mh">0x2faa</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span>        <span class="err">#</span> <span class="mi">403</span><span class="n">fd0</span> <span class="o">&lt;</span><span class="n">_GLOBAL_OFFSET_TABLE_</span><span class="o">+</span><span class="mh">0x8</span><span class="o">&gt;</span>
  <span class="mi">401026</span><span class="o">:</span>       <span class="n">ff</span> <span class="mi">25</span> <span class="n">ac</span> <span class="mi">2</span><span class="n">f</span> <span class="mo">00</span> <span class="mo">00</span>       <span class="n">jmp</span>    <span class="o">*</span><span class="mh">0x2fac</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span>        <span class="err">#</span> <span class="mi">403</span><span class="n">fd8</span> <span class="o">&lt;</span><span class="n">_GLOBAL_OFFSET_TABLE_</span><span class="o">+</span><span class="mh">0x10</span><span class="o">&gt;</span>
  <span class="mi">40102</span><span class="n">c</span><span class="o">:</span>       <span class="mi">0</span><span class="n">f</span> <span class="mi">1</span><span class="n">f</span> <span class="mi">40</span> <span class="mo">00</span>             <span class="n">nopl</span>   <span class="mh">0x0</span><span class="p">(</span><span class="o">%</span><span class="n">rax</span><span class="p">)</span>

<span class="mo">0000000000401030</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;:</span>
  <span class="mi">401030</span><span class="o">:</span>       <span class="n">ff</span> <span class="mi">25</span> <span class="n">aa</span> <span class="mi">2</span><span class="n">f</span> <span class="mo">00</span> <span class="mo">00</span>       <span class="n">jmp</span>    <span class="o">*</span><span class="mh">0x2faa</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span>        <span class="err">#</span> <span class="mi">403</span><span class="n">fe0</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">GLIBC_2</span><span class="p">.</span><span class="mi">2</span><span class="p">.</span><span class="mi">5</span><span class="o">&gt;</span>
  <span class="mi">401036</span><span class="o">:</span>       <span class="mi">68</span> <span class="mo">00</span> <span class="mo">00</span> <span class="mo">00</span> <span class="mo">00</span>          <span class="n">push</span>   <span class="err">$</span><span class="mh">0x0</span>
  <span class="mi">40103</span><span class="n">b</span><span class="o">:</span>       <span class="n">e9</span> <span class="n">e0</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">jmp</span>    <span class="mi">401020</span> <span class="o">&lt;</span><span class="n">_init</span><span class="o">+</span><span class="mh">0x20</span><span class="o">&gt;</span>

<span class="mo">0000000000401040</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;:</span>
  <span class="mi">401040</span><span class="o">:</span>       <span class="n">ff</span> <span class="mi">25</span> <span class="n">a2</span> <span class="mi">2</span><span class="n">f</span> <span class="mo">00</span> <span class="mo">00</span>       <span class="n">jmp</span>    <span class="o">*</span><span class="mh">0x2fa2</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span>        <span class="err">#</span> <span class="mi">403</span><span class="n">fe8</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">GLIBC_2</span><span class="p">.</span><span class="mi">3</span><span class="p">.</span><span class="mi">4</span><span class="o">&gt;</span>
  <span class="mi">401046</span><span class="o">:</span>       <span class="mi">68</span> <span class="mo">01</span> <span class="mo">00</span> <span class="mo">00</span> <span class="mo">00</span>          <span class="n">push</span>   <span class="err">$</span><span class="mh">0x1</span>
  <span class="mi">40104</span><span class="n">b</span><span class="o">:</span>       <span class="n">e9</span> <span class="n">d0</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">jmp</span>    <span class="mi">401020</span> <span class="o">&lt;</span><span class="n">_init</span><span class="o">+</span><span class="mh">0x20</span><span class="o">&gt;</span>

<span class="n">Disassembly</span> <span class="n">of</span> <span class="n">section</span> <span class="p">.</span><span class="n">text</span><span class="o">:</span>

<span class="mo">0000000000401050</span> <span class="o">&lt;</span><span class="n">main</span><span class="o">&gt;:</span>
  <span class="mi">401050</span><span class="o">:</span>       <span class="mi">83</span> <span class="n">ff</span> <span class="mo">01</span>                <span class="n">cmp</span>    <span class="err">$</span><span class="mh">0x1</span><span class="p">,</span><span class="o">%</span><span class="n">edi</span>
  <span class="mi">401053</span><span class="o">:</span>       <span class="mi">7</span><span class="n">e</span> <span class="mi">17</span>                   <span class="n">jle</span>    <span class="mi">40106</span><span class="n">c</span> <span class="o">&lt;</span><span class="n">main</span><span class="o">+</span><span class="mh">0x1c</span><span class="o">&gt;</span>
  <span class="mi">401055</span><span class="o">:</span>       <span class="mi">48</span> <span class="mi">8</span><span class="n">b</span> <span class="mi">56</span> <span class="mi">08</span>             <span class="n">mov</span>    <span class="mh">0x8</span><span class="p">(</span><span class="o">%</span><span class="n">rsi</span><span class="p">),</span><span class="o">%</span><span class="n">rdx</span>
  <span class="mi">401059</span><span class="o">:</span>       <span class="n">bf</span> <span class="mo">02</span> <span class="mo">00</span> <span class="mo">00</span> <span class="mo">00</span>          <span class="n">mov</span>    <span class="err">$</span><span class="mh">0x2</span><span class="p">,</span><span class="o">%</span><span class="n">edi</span>
  <span class="mi">40105</span><span class="n">e</span><span class="o">:</span>       <span class="mi">31</span> <span class="n">c0</span>                   <span class="n">xor</span>    <span class="o">%</span><span class="n">eax</span><span class="p">,</span><span class="o">%</span><span class="n">eax</span>
  <span class="mi">401060</span><span class="o">:</span>       <span class="mi">48</span> <span class="mi">8</span><span class="n">d</span> <span class="mi">35</span> <span class="n">b4</span> <span class="mi">0</span><span class="n">f</span> <span class="mo">00</span> <span class="mo">00</span>    <span class="n">lea</span>    <span class="mh">0xfb4</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">),</span><span class="o">%</span><span class="n">rsi</span>        <span class="err">#</span> <span class="mi">40201</span><span class="n">b</span> <span class="o">&lt;</span><span class="n">_IO_stdin_used</span><span class="o">+</span><span class="mh">0x1b</span><span class="o">&gt;</span>
  <span class="mi">401067</span><span class="o">:</span>       <span class="n">e9</span> <span class="n">d4</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">jmp</span>    <span class="mi">401040</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Disassembly</span> <span class="n">of</span> <span class="n">section</span> <span class="p">.</span><span class="n">plt</span><span class="o">:</span>
<span class="p">[...]</span>
<span class="mo">0000000000401040</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;:</span>
  <span class="mi">401040</span><span class="o">:</span>       <span class="n">ff</span> <span class="mi">25</span> <span class="n">a2</span> <span class="mi">2</span><span class="n">f</span> <span class="mo">00</span> <span class="mo">00</span>       <span class="n">jmp</span>    <span class="o">*</span><span class="mh">0x2fa2</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span>        <span class="err">#</span> <span class="mi">403</span><span class="n">fe8</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">GLIBC_2</span><span class="p">.</span><span class="mi">3</span><span class="p">.</span><span class="mi">4</span><span class="o">&gt;</span>
  <span class="mi">401046</span><span class="o">:</span>       <span class="mi">68</span> <span class="mo">01</span> <span class="mo">00</span> <span class="mo">00</span> <span class="mo">00</span>          <span class="n">push</span>   <span class="err">$</span><span class="mh">0x1</span>
  <span class="mi">40104</span><span class="n">b</span><span class="o">:</span>       <span class="n">e9</span> <span class="n">d0</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">jmp</span>    <span class="mi">401020</span> <span class="o">&lt;</span><span class="n">_init</span><span class="o">+</span><span class="mh">0x20</span><span class="o">&gt;</span>

<span class="n">Disassembly</span> <span class="n">of</span> <span class="n">section</span> <span class="p">.</span><span class="n">text</span><span class="o">:</span>
<span class="p">[...]</span>
<span class="mo">0000000000401050</span> <span class="o">&lt;</span><span class="n">main</span><span class="o">&gt;:</span>
  <span class="p">[...]</span>
  <span class="mi">401067</span><span class="o">:</span>       <span class="n">e9</span> <span class="n">d4</span> <span class="n">ff</span> <span class="n">ff</span> <span class="n">ff</span>          <span class="n">jmp</span>    <span class="mi">401040</span> <span class="o">&lt;</span><span class="n">__printf_chk</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;</span>
</code></pre></div></div>

<h3 id="pretty-little-thing">Pretty Little Thing</h3>

<p>We see all these references to <code class="language-plaintext highlighter-rouge">plt</code>. The Internet informs us that the PLT is some sort of table with pointers
to the real locations of functions.</p>

<p>Why would we not know where <code class="language-plaintext highlighter-rouge">printf</code> is? We must remember this function is from <code class="language-plaintext highlighter-rouge">libc</code>. In fact, the dump notes <code class="language-plaintext highlighter-rouge">printf</code> is defined from GLIBC version 2.3.4.</p>

<p>We have debunked the theory that <code class="language-plaintext highlighter-rouge">printf</code> is a normal function call. Then what is it? You will be unable to find a definition of <code class="language-plaintext highlighter-rouge">printf</code> in the binary, regardless of how hard you look.</p>

<blockquote>
  <p>:hear_no_evil:: how can I be sure <code class="language-plaintext highlighter-rouge">printf</code> is <em>actually</em> a part of libc? You’re some rando on the internet, not my teacher. :dizzy_face:</p>

  <p>Instructor: Spoken like a true skeptic.</p>

  <p>:hear_no_evil:: When I run a binary, all the OS does is go to <code class="language-plaintext highlighter-rouge">main()</code> and then start executing instructions. My entire binary has been printed, so something is definitely wrong with <code class="language-plaintext highlighter-rouge">objdump</code>.</p>
</blockquote>

<p>Alas, another twist in the road. First one nitpick–<code class="language-plaintext highlighter-rouge">main()</code> is not the first thing that runs. The dump has a <code class="language-plaintext highlighter-rouge">_start</code> symbol which is the entrypoint that <code class="language-plaintext highlighter-rouge">libc</code> uses to call <code class="language-plaintext highlighter-rouge">main</code><sup id="fnref:entrypoint" role="doc-noteref"><a href="#fn:entrypoint" class="footnote" rel="footnote">3</a></sup>. Yes, it is the case that we have the whole binary. Think back to when we opened <code class="language-plaintext highlighter-rouge">a.out</code> in <code class="language-plaintext highlighter-rouge">vim</code>. Did we see something in addition to some uninterpretable binary? Hint: at the start and end of the file.</p>

<h3 id="return-of-the-elves">Return of the Elves</h3>

<p>Yes! There are ELF headers. 
The Internet reveals that ELF is a file format. The <code class="language-plaintext highlighter-rouge">readelf</code> tool is used to inspect ELF headers.
Let’s look at this data for hints about our elusive <code class="language-plaintext highlighter-rouge">printf</code>.</p>

<p>The <code class="language-plaintext highlighter-rouge">man</code> page suggests to use <code class="language-plaintext highlighter-rouge">-a</code> to print all headers. We can use our newfound knowledge of PLTs to <code class="language-plaintext highlighter-rouge">grep</code> for <code class="language-plaintext highlighter-rouge">plt</code>. This leads us to the “Relocation section” of the <code class="language-plaintext highlighter-rouge">readelf</code> output. For readability, we can print this one section and inspect it.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">readelf</span> <span class="o">-</span><span class="n">r</span> <span class="p">.</span><span class="o">/</span><span class="n">a</span><span class="p">.</span><span class="n">out</span>
<span class="n">Relocation</span> <span class="n">section</span> <span class="err">'</span><span class="p">.</span><span class="n">rela</span><span class="p">.</span><span class="n">dyn</span><span class="err">'</span> <span class="n">at</span> <span class="n">offset</span> <span class="mh">0x5f0</span> <span class="n">contains</span> <span class="mi">2</span> <span class="n">entries</span><span class="o">:</span>
  <span class="n">Offset</span>          <span class="n">Info</span>           <span class="n">Type</span>           <span class="n">Sym</span><span class="p">.</span> <span class="n">Value</span>    <span class="n">Sym</span><span class="p">.</span> <span class="n">Name</span> <span class="o">+</span> <span class="n">Addend</span>
<span class="mo">000000403</span><span class="n">ff0</span>  <span class="mo">000100000006</span> <span class="n">R_X86_64_GLOB_DAT</span> <span class="mo">0000000000000000</span> <span class="n">__libc_start_main</span><span class="err">@</span><span class="n">GLIBC_2</span><span class="p">.</span><span class="mi">34</span> <span class="o">+</span> <span class="mi">0</span>
<span class="mo">000000403</span><span class="n">ff8</span>  <span class="mo">000300000006</span> <span class="n">R_X86_64_GLOB_DAT</span> <span class="mo">0000000000000000</span> <span class="n">__gmon_start__</span> <span class="o">+</span> <span class="mi">0</span>

<span class="n">Relocation</span> <span class="n">section</span> <span class="err">'</span><span class="p">.</span><span class="n">rela</span><span class="p">.</span><span class="n">plt</span><span class="err">'</span> <span class="n">at</span> <span class="n">offset</span> <span class="mh">0x620</span> <span class="n">contains</span> <span class="mi">2</span> <span class="n">entries</span><span class="o">:</span>
  <span class="n">Offset</span>          <span class="n">Info</span>           <span class="n">Type</span>           <span class="n">Sym</span><span class="p">.</span> <span class="n">Value</span>    <span class="n">Sym</span><span class="p">.</span> <span class="n">Name</span> <span class="o">+</span> <span class="n">Addend</span>
<span class="mo">000000403</span><span class="n">fe0</span>  <span class="mo">000200000007</span> <span class="n">R_X86_64_JUMP_SLO</span> <span class="mo">0000000000000000</span> <span class="n">puts</span><span class="err">@</span><span class="n">GLIBC_2</span><span class="p">.</span><span class="mi">2</span><span class="p">.</span><span class="mi">5</span> <span class="o">+</span> <span class="mi">0</span>
<span class="mo">000000403</span><span class="n">fe8</span>  <span class="mo">000400000007</span> <span class="n">R_X86_64_JUMP_SLO</span> <span class="mo">0000000000000000</span> <span class="n">__printf_chk</span><span class="err">@</span><span class="n">GLIBC_2</span><span class="p">.</span><span class="mi">3</span><span class="p">.</span><span class="mi">4</span> <span class="o">+</span> <span class="mi">0</span>
</code></pre></div></div>

<p>Lucky! <code class="language-plaintext highlighter-rouge">printf</code> has conveniently appeared here. Indeed, these addresses match up with the offsets we saw in the binary. A call to <code class="language-plaintext highlighter-rouge">printf</code> will dereference the value at the offset and use that implementation <code class="language-plaintext highlighter-rouge"># 403fe8 &lt;__printf_chk@GLIBC_2.3.4&gt;</code>.</p>

<p>We can see that the compiler has told us in the “Sym[bol] Value” column that <code class="language-plaintext highlighter-rouge">printf</code> is located at 0x0. But wait, isn’t that a suspicious address? 0x0 is a NULL pointer.</p>

<p>We have all the information we need. Let’s continue backtracking and synthesizing this new intel we gathered.
Let’s go back to <code class="language-plaintext highlighter-rouge">strace</code>. This will capture everything happening at runtime and the order in which it happens.</p>

<p>Ignoring the noisy failures of looking for <code class="language-plaintext highlighter-rouge">libc</code>, the program takes a few steps.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">openat</span><span class="p">(</span><span class="n">AT_FDCWD</span><span class="p">,</span> <span class="s">"/nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s">"</span><span class="se">\177</span><span class="s">ELF</span><span class="se">\2\1\1\3\0\0\0\0\0\0\0\0\3\0</span><span class="s">&gt;</span><span class="se">\0\1\0\0\0</span><span class="s">@</span><span class="se">\244\2\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">832</span><span class="p">)</span> <span class="o">=</span> <span class="mi">832</span>
<span class="n">pread64</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s">"</span><span class="se">\6\0\0\0\4\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">784</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span> <span class="o">=</span> <span class="mi">784</span>
<span class="n">fstat</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="p">{</span><span class="n">st_mode</span><span class="o">=</span><span class="n">S_IFREG</span><span class="o">|</span><span class="mo">0555</span><span class="p">,</span> <span class="n">st_size</span><span class="o">=</span><span class="mi">2335712</span><span class="p">,</span> <span class="p">...})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">pread64</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s">"</span><span class="se">\6\0\0\0\4\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">784</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span> <span class="o">=</span> <span class="mi">784</span>
<span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">2067928</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5c576cd000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5c576f5000</span><span class="p">,</span> <span class="mi">1474560</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_EXEC</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mh">0x28000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5c576f5000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5c5785d000</span><span class="p">,</span> <span class="mi">352256</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mh">0x190000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5c5785d000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5c578b3000</span><span class="p">,</span> <span class="mi">24576</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mh">0x1e5000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5c578b3000</span>
<span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f5c578b9000</span><span class="p">,</span> <span class="mi">52696</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f5c578b9000</span>
<span class="n">close</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>                                <span class="o">=</span> <span class="mi">0</span>
</code></pre></div></div>

<p>If you roll up your sleeves and do some good, old-fashioned documentation sleuthing, you can understand what this previously overwhelming <code class="language-plaintext highlighter-rouge">strace</code> output means. We also know that our LLM above was speaking confidently about things it doesn’t know. Although it looked believable, it got many facts completely wrong.
Instead of LLMs, let’s apply our willpower to see what these straced lines mean.
<code class="language-plaintext highlighter-rouge">man 2</code> has all the info we need. You can see more detail in <a href="#now-its-your-turn">now it’s your turn</a>.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">openat(libc.so.6)</code>: open the <code class="language-plaintext highlighter-rouge">libc</code> executable file on disk</li>
  <li><code class="language-plaintext highlighter-rouge">read</code>: read <code class="language-plaintext highlighter-rouge">libc.so.6</code> from disk into memory</li>
  <li><code class="language-plaintext highlighter-rouge">pread64</code>: continue reading from where it left off</li>
  <li><code class="language-plaintext highlighter-rouge">mmap</code>: map the library into the process address space as readable and executable, but not writable. Allocates some writable memory.</li>
  <li><code class="language-plaintext highlighter-rouge">close</code>: close the file descriptor of the library</li>
</ol>

<blockquote>
  <p>Student: I’m still not satisfied. We never saw any reference to any logic of looking for <code class="language-plaintext highlighter-rouge">libc</code> in our <code class="language-plaintext highlighter-rouge">objdump</code>.</p>

  <p>Instructor: That’s the spirit. Do you have any ideas?</p>

  <p>Student: The first thing that pops into my mind is let’s open this file <code class="language-plaintext highlighter-rouge">.../libc.so.6</code> in <code class="language-plaintext highlighter-rouge">vim</code></p>

  <p>Instructor: Good idea. I can’t discern anything from this file, but I do see this “ELF” mention again. What do we do when we see this?</p>

  <p>Student: <code class="language-plaintext highlighter-rouge">readelf</code>!</p>
</blockquote>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>readelf <span class="nt">-a</span> ...path/to/libc.so.6
</code></pre></div></div>

<p>There is a lot of output, but we can take a few seconds to skim the output. I piped this multi-thousand line output into <code class="language-plaintext highlighter-rouge">less</code> and held the spacebar to skim if anything catches my eye. I see a huge section 
“Symbol table ‘.dynsym’ contains 3158 entries” which has a lot of “FUNC” entries. This table appears to contain a reference to every function in <code class="language-plaintext highlighter-rouge">libc</code>. But why are these all in the dynamic symbol section?
It appears this file doesn’t know where these functions are located. The rabbit hole goes deeper; let’s not lose hope.</p>

<h2 id="go-deeper-buddy">Go Deeper, Buddy</h2>

<p>We first need to search up some background information to understand what is going on. The Procedure Linkage Table (PLT) contains stub code which looks up the location of a function in the Global Offset Table (GOT) and jumps there.
The GOT is an array of pointers which holds the actual addresses of these functions.</p>

<blockquote>
  <p>Instructor: That’s great you know that. But what is it <em>actually doing</em>?</p>
</blockquote>

<p>We can use <code class="language-plaintext highlighter-rouge">gdb</code> to gain confidence in (or to invalidate) our new theory.
We know the address of our <code class="language-plaintext highlighter-rouge">plt</code>, so let’s print out that memory and confirm it gets loaded even before our code runs.</p>

<h3 id="tracing-plt-and-got">Tracing PLT and GOT</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"hello world!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<!-- nix-shell -p gcc gdb (musl) -->
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcc <span class="nt">-fno-pie</span> <span class="nt">-no-pie</span> <span class="nt">-g</span> explore_plt.c
<span class="nv">$ </span>gdb a.out
<span class="o">(</span>gdb<span class="o">)</span> b explore_plt.c:4
Breakpoint 1 at 0x401040: file explore_plt.c, line 4.
<span class="o">(</span>gdb<span class="o">)</span> b explore_plt.c:5
Breakpoint 2 at 0x40104e: file explore_plt.c, line 5.
<span class="o">(</span>gdb<span class="o">)</span> r
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="n">gdb</span><span class="p">)</span> <span class="n">disass</span> <span class="n">main</span>
<span class="n">Dump</span> <span class="n">of</span> <span class="n">assembler</span> <span class="n">code</span> <span class="k">for</span> <span class="n">function</span> <span class="n">main</span><span class="o">:</span>
   <span class="mh">0x0000000000401050</span> <span class="o">&lt;+</span><span class="mi">0</span><span class="o">&gt;:</span>     <span class="n">sub</span>    <span class="err">$</span><span class="mh">0x8</span><span class="p">,</span><span class="o">%</span><span class="n">rsp</span>
   <span class="mh">0x0000000000401054</span> <span class="o">&lt;+</span><span class="mi">4</span><span class="o">&gt;:</span>     <span class="n">mov</span>    <span class="err">$</span><span class="mh">0x402000</span><span class="p">,</span><span class="o">%</span><span class="n">edi</span>
   <span class="mh">0x0000000000401059</span> <span class="o">&lt;+</span><span class="mi">9</span><span class="o">&gt;:</span>     <span class="n">call</span>   <span class="mh">0x401020</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;</span>
   <span class="mh">0x000000000040105e</span> <span class="o">&lt;+</span><span class="mi">14</span><span class="o">&gt;:</span>    <span class="n">mov</span>    <span class="err">$</span><span class="mh">0x402000</span><span class="p">,</span><span class="o">%</span><span class="n">edi</span>
   <span class="mh">0x0000000000401063</span> <span class="o">&lt;+</span><span class="mi">19</span><span class="o">&gt;:</span>    <span class="n">add</span>    <span class="err">$</span><span class="mh">0x8</span><span class="p">,</span><span class="o">%</span><span class="n">rsp</span>
   <span class="mh">0x0000000000401067</span> <span class="o">&lt;+</span><span class="mi">23</span><span class="o">&gt;:</span>    <span class="n">jmp</span>    <span class="mh">0x401020</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="o">&gt;</span>
<span class="n">End</span> <span class="n">of</span> <span class="n">assembler</span> <span class="n">dump</span><span class="p">.</span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span> <span class="n">disass</span> <span class="err">'</span><span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="err">'</span>
<span class="n">Dump</span> <span class="n">of</span> <span class="n">assembler</span> <span class="n">code</span> <span class="k">for</span> <span class="n">function</span> <span class="n">puts</span><span class="err">@</span><span class="n">plt</span><span class="o">:</span>
   <span class="mh">0x0000000000401030</span> <span class="o">&lt;+</span><span class="mi">0</span><span class="o">&gt;:</span>     <span class="n">jmp</span>    <span class="o">*</span><span class="mh">0x2fb2</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span>        <span class="err">#</span> <span class="mh">0x403fe8</span> <span class="o">&lt;</span><span class="n">puts</span><span class="err">@</span><span class="n">got</span><span class="p">.</span><span class="n">plt</span><span class="o">&gt;</span>
   <span class="mh">0x0000000000401036</span> <span class="o">&lt;+</span><span class="mi">6</span><span class="o">&gt;:</span>     <span class="n">push</span>   <span class="err">$</span><span class="mh">0x0</span>
   <span class="mh">0x000000000040103b</span> <span class="o">&lt;+</span><span class="mi">11</span><span class="o">&gt;:</span>    <span class="n">jmp</span>    <span class="mh">0x401020</span>
<span class="n">End</span> <span class="n">of</span> <span class="n">assembler</span> <span class="n">dump</span><span class="p">.</span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span> <span class="n">p</span><span class="o">/</span><span class="n">x</span> <span class="o">*</span><span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="mh">0x403fe8</span>
<span class="err">$</span><span class="mi">1</span> <span class="o">=</span> <span class="p">...</span>
<span class="cp"># Exercise: What does this line print at different points in the function?
</span></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">jmp</code> instruction in the <code class="language-plaintext highlighter-rouge">plt</code> is a jump which follows a pointer to the jump location.
<code class="language-plaintext highlighter-rouge">gdb</code> left a comment telling us that this value points to the entry for the “puts” symbol in the GOT.
Cool! We can confirm this pointer lives in the area of virtual memory which <code class="language-plaintext highlighter-rouge">strace</code> told us that <code class="language-plaintext highlighter-rouge">libc</code> got read to. This discovery confirms <code class="language-plaintext highlighter-rouge">printf</code> is not a function call inside our code. Your OS’s <code class="language-plaintext highlighter-rouge">libc</code> provides the implementation.</p>

<p>If we look back at the <code class="language-plaintext highlighter-rouge">strace</code> and search for this address <code class="language-plaintext highlighter-rouge">0x403fe8</code>, we will see this line get matched.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mprotect</span><span class="p">(</span><span class="mh">0x403000</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span>     <span class="o">=</span> <span class="mi">0</span>
</code></pre></div></div>
<p>This line makes the table entries read only. The pwning blog post in <a href="#further-reading">further reading</a> explains more.
In context of our program, this means that the entire GOT got resolved and then marked as read only for security<sup id="fnref:RELRO" role="doc-noteref"><a href="#fn:RELRO" class="footnote" rel="footnote">4</a></sup>.</p>

<details>
  <summary>Exercise: What does print statement at the end of the above `gdb` code block print at different breakpoints in the function? Why?</summary>
  <blockquote>
    <p>You should notice that the value stored at the pointer changes before and after the first <code class="language-plaintext highlighter-rouge">printf</code> call.
Most programs do not use every function of every dynamically linked library, so it can be more efficient to only load entries which are used.
Initially, GOT entries initially point to a stub in the PLT that will invoke the dynamic linker for resolution.
The code for this initialization is already in the process’ address space, so the PLT can directly call it to load the needed entry on-demand.</p>
  </blockquote>

</details>

<p>The execution flows from the assembly which points to the PLT that contains a shim to do a GOT lookup. The happy path leads directly to the library code. On the first use of a library function, the execution falls through using the red path, which asks some code to locate the library function.</p>

<p><img src="/images/spelunking/plt_trace.drawio.png" alt="" /></p>

<p>In the process’ memory layout, the GOT entries initially point to loader executable code, then to the location of the instructions inside the library.</p>

<p><img src="/images/spelunking/plt_memory.drawio.png" alt="" style="display:block; margin-left:auto; margin-right:auto" width="60%" /></p>

<h2 id="knowledge-check">Knowledge Check</h2>

<p>Armed with this knowledge, we can both understand the world and bend it to our will. Let’s use <code class="language-plaintext highlighter-rouge">gdb</code> to change where the function points. If I write a second function and recompile, I can modify execution from <code class="language-plaintext highlighter-rouge">printf</code> to my own function! (Left as an exercise for you in <a href="#knowledge-check">this section</a>.) How does it feel to be able to fully understand the system and control its behavior?</p>

<blockquote>
  <p>With what you know, you should be able to complete this fun and difficult exercise using normal control flow.
Can you find an input to this function which causes the <code class="language-plaintext highlighter-rouge">printf</code> line to run?</p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="n">target</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">hello</span><span class="p">()</span>
<span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"code execution redirected! you win</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">_exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">vuln</span><span class="p">()</span>
<span class="p">{</span>
  <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">512</span><span class="p">];</span>

  <span class="n">fgets</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">stdin</span><span class="p">);</span>

  <span class="n">printf</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>

  <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>  
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">vuln</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div>  </div>
  <p>Source: <a href="https://exploit.education/protostar/format-four/">protostar</a>, <a href="https://exploit.education/phoenix/stack-four/">updated version</a></p>

  <p>Background knowledge: <a href="https://www.youtube.com/watch?v=kUk5pw4w0h4">LiveOverflow video</a></p>

  <p>Solution: <a href="https://www.youtube.com/watch?v=t1LH9D5cuK4">LiveOverflow video</a></p>
</blockquote>

<p>Even if you do not go through the exercise, this video is well worth watching.
It is far easier to understand the execution flow through the GOT and PLT in video form.</p>

<p>We learned how Linux loads processes and dynamically loads libraries. We even know how to manipulate a running program.
The “GOT and PLT for pwning” in <a href="#further-reading">further reading</a> explains how to pwn the PLT/GOT.</p>

<h1 id="now-its-your-turn">Now it’s your turn</h1>

<p>We have covered everything now. Can you explain it? Do it, I’m serious. I’m listening from the other side of your screen. Draw out all the steps.</p>

<p>To make sure we haven’t missed anything, we can map these steps to the each syscall <code class="language-plaintext highlighter-rouge">strace</code> lists when running a program.</p>

<ol>
  <li>Pressing enter with <code class="language-plaintext highlighter-rouge">./a.out</code> in bash</li>
  <li><code class="language-plaintext highlighter-rouge">bash</code> will fork and then execve <code class="language-plaintext highlighter-rouge">./a.out</code></li>
  <li>Linux reads the ELF and loads the headers</li>
  <li>ld-loader</li>
  <li>libc start</li>
  <li>run app</li>
  <li>printf</li>
  <li>exit</li>
</ol>

<p>For a detailed explanation of every line, expand this dropdown:</p>
<details>
  <summary>

    <p><strong>Detailed syscall explanation</strong>
(expand)</p>
  </summary>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">syscall</span> <span class="n">tracing</span> <span class="n">a</span> <span class="n">dynamic</span><span class="o">-</span><span class="n">linked</span> <span class="err">'</span><span class="n">Hello</span> <span class="n">World</span><span class="err">'</span> <span class="n">program</span> <span class="n">with</span> <span class="mi">1</span> <span class="n">format</span> <span class="n">argument</span>
<span class="n">maizure</span><span class="p">.</span><span class="n">org</span>

<span class="err">$</span><span class="n">strace</span> <span class="p">.</span><span class="o">/</span><span class="n">printf1</span>
<span class="mi">1</span>  <span class="o">-</span> <span class="n">execve</span><span class="p">(</span><span class="s">"./printf1"</span><span class="p">,</span> <span class="p">[</span><span class="s">"./printf1"</span><span class="p">],</span> <span class="p">[</span><span class="cm">/* 47 vars */</span><span class="p">])</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">2</span>  <span class="o">-</span> <span class="n">brk</span><span class="p">(</span><span class="nb">NULL</span><span class="p">)</span>                               <span class="o">=</span> <span class="mh">0x1dde000</span>
<span class="mi">3</span>  <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bce82000</span>
<span class="mi">4</span>  <span class="o">-</span> <span class="n">access</span><span class="p">(</span><span class="s">"/etc/ld.so.preload"</span><span class="p">,</span> <span class="n">R_OK</span><span class="p">)</span>      <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ENOENT</span> <span class="p">(</span><span class="n">No</span> <span class="n">such</span> <span class="n">file</span> <span class="n">or</span> <span class="n">directory</span><span class="p">)</span>
<span class="mi">5</span>  <span class="o">-</span> <span class="n">open</span><span class="p">(</span><span class="s">"/etc/ld.so.cache"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="mi">3</span>
<span class="mi">6</span>  <span class="o">-</span> <span class="n">fstat</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="p">{</span><span class="n">st_mode</span><span class="o">=</span><span class="n">S_IFREG</span><span class="o">|</span><span class="mo">0644</span><span class="p">,</span> <span class="n">st_size</span><span class="o">=</span><span class="mi">83694</span><span class="p">,</span> <span class="p">...})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">7</span>  <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">83694</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bce6d000</span>
<span class="mi">8</span>  <span class="o">-</span> <span class="n">close</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>                                <span class="o">=</span> <span class="mi">0</span>
<span class="mi">9</span>  <span class="o">-</span> <span class="n">open</span><span class="p">(</span><span class="s">"/lib64/libc.so.6"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="o">|</span><span class="n">O_CLOEXEC</span><span class="p">)</span> <span class="o">=</span> <span class="mi">3</span>
<span class="mi">10</span> <span class="o">-</span> <span class="n">read</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="s">"</span><span class="se">\177</span><span class="s">ELF</span><span class="se">\2\1\1\3\0\0\0\0\0\0\0\0\3\0</span><span class="s">&gt;</span><span class="se">\0\1\0\0\0\20\35\2\0\0\0\0\0</span><span class="s">"</span><span class="p">...,</span> <span class="mi">832</span><span class="p">)</span> <span class="o">=</span> <span class="mi">832</span>
<span class="mi">11</span> <span class="o">-</span> <span class="n">fstat</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="p">{</span><span class="n">st_mode</span><span class="o">=</span><span class="n">S_IFREG</span><span class="o">|</span><span class="mo">0755</span><span class="p">,</span> <span class="n">st_size</span><span class="o">=</span><span class="mi">2127336</span><span class="p">,</span> <span class="p">...})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">12</span> <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">3940800</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_EXEC</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bc89f000</span>
<span class="mi">13</span> <span class="o">-</span> <span class="n">mprotect</span><span class="p">(</span><span class="mh">0x7f59bca57000</span><span class="p">,</span> <span class="mi">2097152</span><span class="p">,</span> <span class="n">PROT_NONE</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">14</span> <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f59bcc57000</span><span class="p">,</span> <span class="mi">24576</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mh">0x1b8000</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bcc57000</span>
<span class="mi">15</span> <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="mh">0x7f59bcc5d000</span><span class="p">,</span> <span class="mi">16832</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_FIXED</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bcc5d000</span>
<span class="mi">16</span> <span class="o">-</span> <span class="n">close</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>                                <span class="o">=</span> <span class="mi">0</span>
<span class="mi">17</span> <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bce6c000</span>
<span class="mi">18</span> <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">8192</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bce6a000</span>
<span class="mi">19</span> <span class="o">-</span> <span class="n">arch_prctl</span><span class="p">(</span><span class="n">ARCH_SET_FS</span><span class="p">,</span> <span class="mh">0x7f59bce6a740</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">20</span> <span class="o">-</span> <span class="n">mprotect</span><span class="p">(</span><span class="mh">0x7f59bcc57000</span><span class="p">,</span> <span class="mi">16384</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">21</span> <span class="o">-</span> <span class="n">mprotect</span><span class="p">(</span><span class="mh">0x600000</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span>     <span class="o">=</span> <span class="mi">0</span>
<span class="mi">22</span> <span class="o">-</span> <span class="n">mprotect</span><span class="p">(</span><span class="mh">0x7f59bce83000</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">23</span> <span class="o">-</span> <span class="n">munmap</span><span class="p">(</span><span class="mh">0x7f59bce6d000</span><span class="p">,</span> <span class="mi">83694</span><span class="p">)</span>           <span class="o">=</span> <span class="mi">0</span>
<span class="mi">24</span> <span class="o">-</span> <span class="n">fstat</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="n">st_mode</span><span class="o">=</span><span class="n">S_IFCHR</span><span class="o">|</span><span class="mo">0620</span><span class="p">,</span> <span class="n">st_rdev</span><span class="o">=</span><span class="n">makedev</span><span class="p">(</span><span class="mi">136</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">...})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">25</span> <span class="o">-</span> <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bce81000</span>
<span class="mi">26</span> <span class="o">-</span> <span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"Hello World 1</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">14</span><span class="n">Hello</span> <span class="n">World</span> <span class="mi">1</span><span class="p">)</span>         <span class="o">=</span> <span class="mi">14</span>
<span class="mi">27</span> <span class="o">-</span> <span class="n">exit_group</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="o">?</span>
<span class="o">+++</span> <span class="n">exited</span> <span class="n">with</span> <span class="mi">0</span> <span class="o">+++</span>

<span class="n">Line</span> <span class="mi">1</span>  <span class="o">-</span> <span class="n">Program</span> <span class="n">is</span> <span class="n">forked</span> <span class="n">from</span> <span class="n">bash</span> <span class="n">and</span> <span class="n">calls</span> <span class="n">execve</span><span class="p">()</span> <span class="n">to</span> <span class="n">load</span> <span class="p">.</span><span class="o">/</span><span class="n">printf1</span> <span class="n">with</span> <span class="n">the</span> <span class="k">default</span> <span class="n">argument</span> <span class="n">of</span> <span class="n">program</span> <span class="n">name</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">2</span>  <span class="o">-</span> <span class="n">Program</span> <span class="n">calls</span> <span class="n">brk</span><span class="p">()</span> <span class="n">to</span> <span class="n">find</span> <span class="n">the</span> <span class="n">current</span> <span class="n">end</span> <span class="n">of</span> <span class="n">the</span> <span class="n">data</span> <span class="n">segment</span><span class="p">,</span> <span class="n">which</span> <span class="n">is</span> <span class="mh">0x1dde000</span><span class="p">.</span> <span class="n">If</span> <span class="n">this</span> <span class="n">program</span> <span class="n">wanted</span>
          <span class="n">space</span> <span class="n">on</span> <span class="n">the</span> <span class="n">heap</span><span class="p">,</span> <span class="n">there</span> <span class="n">would</span> <span class="n">be</span> <span class="n">subsequent</span> <span class="n">calls</span> <span class="n">to</span> <span class="n">brk</span><span class="p">()</span> <span class="n">using</span> <span class="n">higher</span> <span class="n">values</span><span class="p">.</span> <span class="n">That</span><span class="err">'</span><span class="n">s</span> <span class="n">not</span> <span class="n">the</span> <span class="k">case</span> <span class="n">this</span> <span class="n">time</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">3</span>  <span class="o">-</span> <span class="n">Memory</span> <span class="n">maps</span> <span class="n">a</span> <span class="n">page</span> <span class="n">of</span> <span class="n">read</span><span class="o">-</span><span class="n">write</span> <span class="n">memory</span> <span class="n">that</span> <span class="n">is</span> <span class="n">not</span> <span class="n">backed</span> <span class="n">by</span> <span class="n">a</span> <span class="n">file</span> <span class="p">(</span><span class="n">all</span> <span class="mi">0</span><span class="n">s</span><span class="p">)</span> <span class="n">and</span> <span class="n">not</span> <span class="n">sharable</span><span class="p">.</span> <span class="n">At</span> <span class="mh">0x7f59bce82000</span>
<span class="n">Line</span> <span class="mi">4</span>  <span class="o">-</span> <span class="n">Checks</span> <span class="n">permissions</span> <span class="n">of</span> <span class="n">user</span><span class="o">-</span><span class="n">specified</span> <span class="n">shared</span> <span class="n">libraries</span><span class="p">.</span> <span class="n">There</span> <span class="n">are</span> <span class="n">none</span><span class="p">,</span> <span class="n">so</span> <span class="n">this</span> <span class="n">access</span> <span class="n">attempt</span> <span class="n">fails</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">5</span>  <span class="o">-</span> <span class="n">Opens</span> <span class="n">the</span> <span class="n">file</span> <span class="n">containing</span> <span class="n">the</span> <span class="n">list</span> <span class="n">of</span> <span class="n">directors</span> <span class="n">to</span> <span class="n">search</span> <span class="k">for</span> <span class="n">shared</span> <span class="n">libraries</span><span class="p">.</span> <span class="n">Returned</span> <span class="n">as</span> <span class="n">file</span> <span class="n">descriptor</span> <span class="mi">3</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">6</span>  <span class="o">-</span> <span class="n">Checks</span> <span class="n">the</span> <span class="n">status</span> <span class="n">of</span> <span class="n">the</span> <span class="n">new</span> <span class="n">file</span> <span class="n">descriptor</span><span class="p">.</span> <span class="n">File</span> <span class="n">is</span> <span class="mi">21</span> <span class="n">pages</span> <span class="n">of</span> <span class="n">memory</span> <span class="n">size</span> <span class="p">(</span><span class="mi">83694</span> <span class="n">bytes</span><span class="p">,</span> <span class="mi">4096</span> <span class="n">bytes</span> <span class="n">per</span> <span class="n">page</span><span class="p">).</span>
<span class="n">Line</span> <span class="mi">7</span>  <span class="o">-</span> <span class="n">Memory</span> <span class="n">maps</span> <span class="n">the</span> <span class="n">directory</span> <span class="n">list</span> <span class="n">as</span> <span class="n">private</span> <span class="n">and</span> <span class="n">read</span><span class="o">-</span><span class="n">only</span><span class="p">.</span> <span class="n">It</span> <span class="n">now</span> <span class="n">lives</span> <span class="n">between</span> <span class="mh">0x7f59bce6d000</span> <span class="o">-</span> <span class="mh">0x7f59bce81000</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">8</span>  <span class="o">-</span> <span class="n">Closes</span> <span class="n">the</span> <span class="n">shared</span><span class="o">-</span><span class="n">library</span> <span class="n">directory</span> <span class="n">list</span><span class="p">,</span> <span class="n">file</span> <span class="n">descriptor</span> <span class="mi">3</span> <span class="n">is</span> <span class="n">available</span> <span class="n">again</span>
<span class="n">Line</span> <span class="mi">9</span>  <span class="o">-</span> <span class="n">Opens</span> <span class="n">the</span> <span class="n">symbolic</span> <span class="n">link</span> <span class="n">to</span> <span class="n">the</span> <span class="n">shared</span> <span class="n">standard</span> <span class="n">library</span> <span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">so</span><span class="p">.</span><span class="mi">6</span><span class="p">)</span> <span class="n">as</span> <span class="n">file</span> <span class="n">descriptor</span> <span class="mi">3</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">10</span> <span class="o">-</span> <span class="n">Reads</span> <span class="n">the</span> <span class="n">first</span> <span class="mi">832</span> <span class="n">bytes</span> <span class="n">of</span> <span class="n">the</span> <span class="n">library</span><span class="p">,</span> <span class="n">header</span> <span class="o">+</span> <span class="n">extras</span> <span class="k">for</span> <span class="mi">64</span><span class="o">-</span><span class="n">bit</span><span class="p">.</span> <span class="n">Success</span><span class="p">,</span> <span class="n">with</span> <span class="mi">832</span> <span class="n">bytes</span> <span class="n">read</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">11</span> <span class="o">-</span> <span class="n">Gets</span> <span class="n">the</span> <span class="n">file</span> <span class="n">data</span> <span class="k">for</span> <span class="n">the</span> <span class="n">shared</span> <span class="n">library</span><span class="p">.</span> <span class="n">Size</span> <span class="n">is</span> <span class="mi">2127336</span> <span class="p">(</span><span class="mi">520</span> <span class="n">pages</span> <span class="n">of</span> <span class="n">memory</span><span class="p">)</span>
<span class="n">Line</span> <span class="mi">12</span> <span class="o">-</span> <span class="n">Memory</span> <span class="n">map</span> <span class="n">the</span> <span class="n">standard</span> <span class="n">library</span> <span class="n">as</span> <span class="n">read</span><span class="o">-</span><span class="n">able</span> <span class="n">and</span> <span class="n">executable</span><span class="p">,</span> <span class="n">but</span> <span class="n">not</span> <span class="n">writable</span><span class="p">.</span> <span class="n">It</span> <span class="n">will</span> <span class="n">live</span> <span class="n">at</span> <span class="mh">0x7f59bc89f000</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">13</span> <span class="o">-</span> <span class="n">Removes</span> <span class="n">all</span> <span class="n">access</span> <span class="n">to</span> <span class="o">~</span><span class="mi">2</span><span class="n">MB</span> <span class="n">of</span> <span class="n">memory</span> <span class="n">after</span> <span class="n">libc</span> <span class="n">code</span> <span class="p">(</span><span class="n">likely</span> <span class="n">guard</span> <span class="n">pages</span><span class="p">)</span>
<span class="n">Line</span> <span class="mi">14</span> <span class="o">-</span> <span class="n">Memory</span> <span class="n">maps</span> <span class="mi">6</span> <span class="n">more</span> <span class="n">pages</span> <span class="n">from</span> <span class="n">libc</span> <span class="p">(</span><span class="n">pages</span> <span class="mi">440</span><span class="o">-</span><span class="mi">445</span><span class="p">)</span> <span class="n">as</span> <span class="n">read</span><span class="o">-</span><span class="n">write</span><span class="p">.</span> <span class="n">Scratch</span> <span class="n">space</span><span class="o">?</span>
<span class="n">Line</span> <span class="mi">15</span> <span class="o">-</span> <span class="n">Maps</span> <span class="n">four</span> <span class="n">more</span> <span class="n">pages</span> <span class="n">of</span> <span class="n">generic</span> <span class="n">read</span><span class="o">-</span><span class="n">write</span> <span class="n">memory</span> <span class="n">between</span> <span class="mh">0x7f59bcc5d000</span> <span class="n">and</span> <span class="mh">0x7f59bcc62000</span>
<span class="n">Line</span> <span class="mi">16</span> <span class="o">-</span> <span class="n">Closes</span> <span class="n">the</span> <span class="n">shared</span> <span class="n">standard</span> <span class="n">library</span> <span class="n">file</span><span class="p">.</span> <span class="n">File</span> <span class="n">descriptor</span> <span class="mi">3</span> <span class="n">is</span> <span class="n">now</span> <span class="n">available</span> <span class="n">again</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">17</span> <span class="o">-</span> <span class="n">Memory</span> <span class="n">maps</span> <span class="n">a</span> <span class="n">page</span> <span class="n">of</span> <span class="n">read</span><span class="o">-</span><span class="n">write</span> <span class="n">memory</span><span class="p">,</span> <span class="n">probably</span> <span class="n">to</span> <span class="n">suppose</span> <span class="kr">thread</span> <span class="n">usage</span><span class="p">.</span>
<span class="n">Line</span> <span class="mi">18</span> <span class="o">-</span> <span class="n">Memory</span> <span class="n">maps</span> <span class="n">another</span> <span class="mi">2</span> <span class="n">pages</span> <span class="n">of</span> <span class="n">memory</span> <span class="k">for</span> <span class="n">read</span> <span class="n">and</span> <span class="n">write</span><span class="p">.</span> <span class="n">This</span> <span class="n">is</span> <span class="n">probably</span> <span class="n">used</span> <span class="k">for</span> <span class="kr">thread</span> <span class="n">local</span> <span class="n">storage</span>
<span class="n">Line</span> <span class="mi">19</span> <span class="o">-</span> <span class="n">Sets</span> <span class="n">FS</span> <span class="n">to</span> <span class="n">the</span> <span class="n">newly</span> <span class="n">reserved</span> <span class="kr">thread</span> <span class="n">local</span> <span class="n">storage</span> <span class="n">area</span>
<span class="n">Line</span> <span class="mi">20</span> <span class="o">-</span> <span class="n">Sets</span> <span class="mi">4</span> <span class="n">pages</span> <span class="n">of</span> <span class="n">the</span> <span class="n">standard</span> <span class="n">library</span> <span class="n">to</span> <span class="n">read</span> <span class="n">only</span>
<span class="n">Line</span> <span class="mi">21</span> <span class="o">-</span> <span class="n">Sets</span> <span class="n">the</span> <span class="n">read</span><span class="o">-</span><span class="n">only</span> <span class="n">data</span> <span class="n">application</span> <span class="n">segment</span> <span class="p">(</span><span class="n">subsequent</span> <span class="n">page</span> <span class="n">is</span> <span class="p">.</span><span class="n">BSS</span><span class="p">)</span>
<span class="n">Line</span> <span class="mi">22</span> <span class="o">-</span> <span class="n">Sets</span> <span class="n">a</span> <span class="n">page</span> <span class="n">of</span> <span class="n">the</span> <span class="n">dynamic</span> <span class="n">linker</span> <span class="n">library</span> <span class="n">to</span> <span class="n">read</span><span class="o">-</span><span class="n">only</span>
<span class="n">Line</span> <span class="mi">23</span> <span class="o">-</span> <span class="n">Unmaps</span> <span class="n">the</span> <span class="n">shared</span> <span class="n">library</span> <span class="n">directory</span> <span class="n">memory</span> <span class="n">space</span><span class="p">,</span> <span class="n">since</span> <span class="n">the</span> <span class="n">library</span> <span class="n">has</span> <span class="n">been</span> <span class="n">loaded</span>
<span class="n">Line</span> <span class="mi">24</span> <span class="o">-</span> <span class="n">Gets</span> <span class="n">the</span> <span class="n">status</span> <span class="n">of</span> <span class="n">the</span> <span class="n">stdout</span> <span class="n">file</span> <span class="n">descriptor</span> <span class="p">(</span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">pts</span><span class="o">/</span><span class="mi">0</span><span class="p">)</span>
<span class="n">Line</span> <span class="mi">25</span> <span class="o">-</span> <span class="n">Memory</span> <span class="n">maps</span> <span class="n">a</span> <span class="n">page</span> <span class="n">used</span> <span class="n">in</span> <span class="n">printf</span><span class="err">'</span><span class="n">s</span> <span class="n">temporary</span> <span class="n">buffer</span> <span class="k">for</span> <span class="n">format</span> <span class="n">resolution</span>
<span class="n">Line</span> <span class="mi">26</span> <span class="o">-</span> <span class="n">Printf</span><span class="err">'</span><span class="n">s</span> <span class="n">write</span> <span class="n">syscall</span> <span class="k">for</span> <span class="n">Hello</span> <span class="n">World</span> <span class="mi">1</span>
<span class="n">Line</span> <span class="mi">27</span> <span class="o">-</span> <span class="n">Exit</span> <span class="n">with</span> <span class="n">status</span> <span class="mi">0</span>
</code></pre></div>  </div>
  <p>Source: <a href="https://www.maizure.org/projects/printf/dynamic_strace_walkthrough.txt">maizure</a></p>

</details>

<p>We can be confident that these are the steps that get taken. We found a path that definitely explains the chain of events. However, the question remains: <strong><em>who</em> is doing all this work?</strong>
Nothing happens by magic. There is code somewhere that is populating our PLT table, and it sure is not in <code class="language-plaintext highlighter-rouge">a.out</code>. Or is it?</p>

<p>There are two cases. Either this logic is in <code class="language-plaintext highlighter-rouge">a.out</code> or it is done by the kernel during the <code class="language-plaintext highlighter-rouge">execve</code> syscall to set up the process.
It’s easy to blame behavior we don’t understand on things we don’t understand. In either case, we should be able to trace what is going on. What if I told you dynamic loading does not use any special kernel features? We saw every syscall that gets called. If <code class="language-plaintext highlighter-rouge">strace</code> is observing a syscall happening, then it must be getting triggered by something in userspace. All the syscalls we see getting called are completely general. I don’t see syscalls called anything like “dynamic load” to suggest a special mechanism is happening. Unix is all about simplicity. Given this hint, let’s take it from the top and trace to see where the code is coming from.</p>

<p>Look at the bytes of <code class="language-plaintext highlighter-rouge">a.out</code> in <code class="language-plaintext highlighter-rouge">vim</code> again. I can see there is a bunch of text at the start and end of the binary. There is compile-time info at the end. This suggests that the text at the end is debug info and the text at the start is the ELF header.</p>

<p>If we carefully scan the binary and <code class="language-plaintext highlighter-rouge">readelf</code> this time, there is this file path in both places, which we have been skipping.</p>

<div class="language-md highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Requesting program interpreter: /nix/store/nqb2ns2d1lahnd5ncwmn6k84qfd7vx2k-glibc-2.40-36/lib/ld-linux-x86-64.so.2]
</code></pre></div></div>

<p>If you have seen <code class="language-plaintext highlighter-rouge">bash</code> or <code class="language-plaintext highlighter-rouge">python</code> scripts, this is like the <code class="language-plaintext highlighter-rouge">#!</code> shebang placed at the start of a file<sup id="fnref:shebang" role="doc-noteref"><a href="#fn:shebang" class="footnote" rel="footnote">5</a></sup>. 
This file path leads to a loader program which does the work of loading our libraries.</p>

<blockquote>
  <p>:exploding_head:: What is the loader doing to reach the start of the program?</p>

  <p>The loader copies code and data from an executable file on disk into memory. The loader starts execution of the program at the entrypoint specified in the ELF header.
The address of the first instruction is usually the start of <code class="language-plaintext highlighter-rouge">.text</code>, which contains a <code class="language-plaintext highlighter-rouge">_start</code> symbol that runs some CPU specific assembly. This architecture-specific assembly sets up memory and any bookkeeping that need to be done before starting <code class="language-plaintext highlighter-rouge">main()</code> by calling <code class="language-plaintext highlighter-rouge">__libc_start_main</code> <sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">6</a></sup>.</p>
</blockquote>

<p>Isn’t that cool? We loaded libraries with standard kernel mechanisms. The kernel knows how to read ELF headers and called the binary at the provided absolute file path. The kernel does not implement any logic to load libraries.</p>

<p>Now this will blow your mind.</p>

<p>Programs are files. Code is just binary wrapped with some ELF headers sitting on your disk drive. We can see dynamic linking is done using normal file operations. All it takes to dynamically load is to map the library into the memory space at runtime. Using the <code class="language-plaintext highlighter-rouge">mmap</code> syscall does just this! Programs can modify their own address space and load libraries however they wish. No special kernel support required! Linux provides us with these general syscall mechanisms which we can flexibly use.</p>

<p>If we zoom out, what was the point of dynamically loading in the first place? We have observed most programs dynamically load <code class="language-plaintext highlighter-rouge">libc</code>. But it is all code in the end, why not include it in the same file? Indeed, this would have less runtime overhead since you don’t have to do any loading.</p>

<p>Dynamic linking saves a lot of disk space by deduplicating the code for <code class="language-plaintext highlighter-rouge">libc</code> functions like <code class="language-plaintext highlighter-rouge">printf</code>. Libraries save disk space and make updating libraries as easy as swapping a single file. Note the size differences between the source code and static vs. dynamically linked binaries.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">ls</span> <span class="o">-</span><span class="n">lah</span> <span class="n">hello_world</span><span class="o">*</span>
<span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="n">r</span><span class="o">--</span><span class="n">r</span><span class="o">--</span> <span class="mi">1</span> <span class="n">user</span> <span class="n">group</span>   <span class="mi">64</span> <span class="n">Apr</span> <span class="mi">11</span> <span class="mo">00</span><span class="o">:</span><span class="mo">00</span> <span class="n">hello_world</span><span class="p">.</span><span class="n">c</span>
<span class="o">-</span><span class="n">rwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> <span class="mi">1</span> <span class="n">user</span> <span class="n">group</span>  <span class="mi">16</span><span class="n">K</span> <span class="n">Apr</span> <span class="mi">11</span> <span class="mo">00</span><span class="o">:</span><span class="mo">00</span> <span class="n">hello_world</span><span class="p">.</span><span class="n">dynamic</span>
<span class="o">-</span><span class="n">rwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> <span class="mi">1</span> <span class="n">user</span> <span class="n">group</span>  <span class="mi">22</span><span class="n">K</span> <span class="n">Apr</span> <span class="mi">11</span> <span class="mo">00</span><span class="o">:</span><span class="mo">00</span> <span class="n">hello_world</span><span class="p">.</span><span class="k">static</span>
</code></pre></div></div>

<p>But, if we load many programs, then we still have the issue that these <code class="language-plaintext highlighter-rouge">libc</code> functions are now duplicated in the memory of each program.</p>

<blockquote>
  <p>Instructor: How would you do that if you were designing it? How would we need to modify library loading to support sharing the same physical memory for every process?</p>
</blockquote>

<p>Consider that loading libraries simply puts bytes into memory. All applications run in their own virtual memory spaces.
What if we could load <code class="language-plaintext highlighter-rouge">libc</code> once and then share this same physical memory.</p>

<p><img src="/images/spelunking/shared_file_map.gif" alt="shared file map" style="display:block; margin-left:auto; margin-right:auto" /></p>

<p>The diagram<sup id="fnref:diagram_shm" role="doc-noteref"><a href="#fn:diagram_shm" class="footnote" rel="footnote">7</a></sup> shows how we could facilitate this sharing. We can keep exactly one copy of a library in physical memory and each process’ virtual addresses map into it.</p>

<p>Let’s dive into what <code class="language-plaintext highlighter-rouge">mmap</code> is doing to hypothesize how to add support for sharing physical memory.</p>

<blockquote>
  <p>:disguised_face:: Hoooold on. This doesn’t make any sense. The libraries may need to be loaded into a different place in memory
for each process depending on the libraries they specify and the process’ memory layout. It is impossible for a program
to be at different points in memory because the addresses in the instructions will be wrong.</p>

  <p>Very thoughtful! The libraries are instructions, so any pointers you create will be in a different stack for that process. Pointers should be correct within each individual process. And remember, even if the library is loaded in a different place, our program can locate the libraries by looking up the symbol in the PLT/GOT. This solves the relocation problem from the perspective of our user program. However, the libraries have the challenge that they cannot rely on using fixed addresses in their code because they do not know where they will get loaded in memory. For symbols that call into other libraries it is easy as we can reuse the same idea of symbol to address lookup tables.</p>

  <p>Recall in assembly you need to specify a destination address to jump to.
Luckily, compiler engineers invented <a href="https://en.wikipedia.org/wiki/Position-independent_code">Position Independent Code</a> (PIC/PIE) to support the shared library use case. Using <code class="language-plaintext highlighter-rouge">gcc</code> with <a href="https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html"><code class="language-plaintext highlighter-rouge">-pie</code></a> will make the compiler emit instructions that only use relative addressing, allowing it to run from any start address. 
Here is a concrete <a href="https://yurichev.com/news/20211015_PIC/">example exercise</a> that shows the conversion of a normal assembly to position independent.</p>
</blockquote>

<h3 id="gimme-a-man">Gimme a man</h3>

<p>We need to get a better understanding of what the kernel is doing when we load a library to figure out how many processes changes the way libraries get loaded. We can start by reverse engineering the actions the kernel takes in the <code class="language-plaintext highlighter-rouge">strace</code>. Tracing how the library gets loaded by the <code class="language-plaintext highlighter-rouge">mmap</code> call should give us some ideas how to support memory sharing.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">3940800</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_EXEC</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_DENYWRITE</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f59bc89f000</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">mmap</code> <code class="language-plaintext highlighter-rouge">man</code> documentation explains the behavior of <code class="language-plaintext highlighter-rouge">mmap</code> and its flags. <code class="language-plaintext highlighter-rouge">man mmap</code> notes to check the other manual, so I check <code class="language-plaintext highlighter-rouge">man 2 mmap</code>.</p>

<p>Most of the arguments to <code class="language-plaintext highlighter-rouge">mmap</code> are self explanatory from the function prototype: <code class="language-plaintext highlighter-rouge">void *mmap(void addr[.length], size_t length, int prot, int flags, int fd, off_t offset);</code>. However, the flag <code class="language-plaintext highlighter-rouge">MAP_PRIVATE</code> appears to significant change the way <code class="language-plaintext highlighter-rouge">mmap</code> operates.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ man mmap

MMAP(3P)                                      POSIX Programmer's Manual                                      MMAP(3P)

PROLOG
       This  manual  page  is  part of the POSIX Programmer's Manual.  The Linux implementation of this interface may
       differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface  may  not
       be implemented on Linux.

[...]

       The  parameter  flags provides other information about the handling of the mapped data.  The value of flags is
       the bitwise-inclusive OR of these options, defined in &lt;sys/mman.h&gt;:
                                      ┌───────────────────┬─────────────────────────┐
                                      │ Symbolic Constant │       Description       │
                                      ├───────────────────┼─────────────────────────┤
                                      │ MAP_SHARED        │ Changes are shared.     │
                                      │ MAP_PRIVATE       │ Changes are private.    │
                                      │ MAP_FIXED         │ Interpret addr exactly. │
                                      └───────────────────┴─────────────────────────┘

       It is implementation-defined whether MAP_FIXED shall be supported.  MAP_FIXED shall be supported  on  XSI-con‐
       formant systems.

       MAP_SHARED and MAP_PRIVATE describe the disposition of write references to the memory object. If MAP_SHARED is
       specified,  write references shall change the underlying object. If MAP_PRIVATE is specified, modifications to
       the mapped data by the calling process shall be visible only to the calling process and shall not  change  the
       underlying  object.   It is unspecified whether modifications to the underlying object done after the MAP_PRI‐
       VATE mapping is established are visible through the MAP_PRIVATE mapping. Either MAP_SHARED or MAP_PRIVATE  can
       be specified, but not both. The mapping type is retained across fork().

[...]

$ man 2 mmap
mmap(2)                                          System Calls Manual                                          mmap(2)

NAME
       mmap, munmap - map or unmap files or devices into memory

LIBRARY
       Standard C library (libc, -lc)

SYNOPSIS
       #include &lt;sys/mman.h&gt;

       void *mmap(void addr[.length], size_t length, int prot, int flags,
                  int fd, off_t offset);
       int munmap(void addr[.length], size_t length);

       See NOTES for information on feature test macro requirements.

DESCRIPTION
       mmap()  creates  a  new mapping in the virtual address space of the calling process.  The starting address for
       the new mapping is specified in addr.  The length argument specifies the length of the mapping (which must  be
       greater than 0).

[...]

       MAP_PRIVATE
              Create a private copy-on-write mapping.  Updates to the mapping are not visible to other processes map‐
              ping the same file, and are not carried through to the underlying  file.   It  is  unspecified  whether
              changes made to the file after the mmap() call are visible in the mapped region.
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">MAP_PRIVATE</code> flag tells <code class="language-plaintext highlighter-rouge">mmap</code> to “Create a private copy-on-write mapping”. This is a key phrase. Without getting into the weeds of what copy-on-write (COW) entails, this point means that each process’ call to map <code class="language-plaintext highlighter-rouge">libc</code> will share the same physical memory. There is <u>no</u> coordination needed between processes, <u>nor</u> any special kernel mechanism to support shared libraries.</p>

<blockquote>
  <p>:thinking:: Wait, so it is magic?</p>

  <p>Operating systems sure are magic.</p>
</blockquote>

<p>By exercising your curiosity, we have quickly reached the frontier of how libraries get loaded.
The fun part of diving into everyday things is you find out that everything is created by real people.
I find it immensely rewarding to learn about the history behind how these abstractions have developed.
The <code class="language-plaintext highlighter-rouge">mmap</code> docs give us a glimpse into kernel lore.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RATIONALE
       After considering several other alternatives, it was decided to adopt the mmap() definition found in SVR4  for
       mapping  memory objects into process address spaces. The SVR4 definition is minimal, in that it describes only
       what has been built, and what appears to be necessary for a general and portable mapping facility.

       Note that while mmap() was first designed for mapping files, it is actually a general-purpose  mapping  facil‐
       ity. It can be used to map any appropriate object, such as memory, files, devices, and so on, into the address
       space of a process.
</code></pre></div></div>

<blockquote>
  <p>Instructor: Cool. You know what the docs claim about <code class="language-plaintext highlighter-rouge">mmap</code>, but what sequence of instructions <em>actually run</em> to support sharing?</p>
</blockquote>

<h2 id="kernel-sourcerers">Kernel Sourcerers</h2>

<p>Ooh let’s look at source code. We are still in the realm of theory and haven’t proved our ideas are what gets run.</p>

<div class="notice notice--announcement">
  <p><strong>This source code explanation is a bit dry. Feel free to skim to the next section.</strong></p>
</div>

<p>Instead of pulling the latest kernel, I like using a web search such as <a href="https://livegrep.com/search/linux">livegrep</a> or <a href="https://elixir.bootlin.com/linux/v6.13.7/source">Elixir bootlin</a>.
We want to find the entrypoint of calling the <code class="language-plaintext highlighter-rouge">mmap</code> syscall.
Searching “mmap” does not get anywhere. 
Stackoverflow tells us to <a href="https://livegrep.com/search/linux?q=file%3A.c%20sys_mmap%20path%3Aarm64&amp;fold_case=auto&amp;regex=false&amp;context=true">look for <code class="language-plaintext highlighter-rouge">sys_mmap</code></a> or the macro which defines syscalls <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">8</a></sup>.</p>

<blockquote>
  <p><a href="https://github.com/torvalds/linux/blob/v6.13/arch/arm64/kernel/sys.c#L28">arch/arm64/kernel/sys.c</a></p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SYSCALL_DEFINE6</span><span class="p">(</span><span class="n">mmap</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span>
		<span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> <span class="n">prot</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span>
		<span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> <span class="n">off</span><span class="p">)</span>
<span class="p">{</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">offset_in_page</span><span class="p">(</span><span class="n">off</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
		<span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>

	<span class="k">return</span> <span class="n">ksys_mmap_pgoff</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">prot</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="n">off</span> <span class="o">&gt;&gt;</span> <span class="n">PAGE_SHIFT</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>  </div>
</blockquote>

<p>The GitHub symbols panel makes it easy to find definitions and references of symbols. 
GitHub reveals the definition of <code class="language-plaintext highlighter-rouge">ksys_mmap_pgoff</code> is <a href="https://github.com/torvalds/linux/blob/586de92313fcab8ed84ac5f78f4d2aae2db92c59/mm/mmap.c#L569">in <code class="language-plaintext highlighter-rouge">mmap.c</code></a>.</p>

<p>The filename indicates we are in the right place. A manual inspection of this file shows us that the core logic is in <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/mmap.c#L280"><code class="language-plaintext highlighter-rouge">do_mmap</code></a>.
Here we have a source code comment telling us the exact mechanics of what is happening. It fills in some of the implementation details.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * do_mmap() - Perform a userland memory mapping into the current process
 * address space of length @len with protection bits @prot, mmap flags @flags
 * (from which VMA flags will be inferred), and any additional VMA flags to
 * apply @vm_flags. If this is a file-backed mapping then the file is specified
 * in @file and page offset into the file via @pgoff.
 * [...]
 */</span>
<span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">do_mmap</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">addr</span><span class="p">,</span>
			<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">prot</span><span class="p">,</span>
			<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">,</span> <span class="n">vm_flags_t</span> <span class="n">vm_flags</span><span class="p">,</span>
			<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pgoff</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">populate</span><span class="p">,</span>
			<span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">uf</span><span class="p">)</span>
<span class="p">{</span> <span class="p">[...]</span> <span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/mmap.c#L359-L381">do_mmap()</a></p>
  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">((</span><span class="n">prot</span> <span class="o">&amp;</span> <span class="n">PROT_READ</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">current</span><span class="o">-&gt;</span><span class="n">personality</span> <span class="o">&amp;</span> <span class="n">READ_IMPLIES_EXEC</span><span class="p">))</span>
		<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">file</span> <span class="o">&amp;&amp;</span> <span class="n">path_noexec</span><span class="p">(</span><span class="o">&amp;</span><span class="n">file</span><span class="o">-&gt;</span><span class="n">f_path</span><span class="p">)))</span>
			<span class="n">prot</span> <span class="o">|=</span> <span class="n">PROT_EXEC</span><span class="p">;</span>

	<span class="cm">/* force arch specific MAP_FIXED handling in get_unmapped_area */</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MAP_FIXED_NOREPLACE</span><span class="p">)</span>
		<span class="n">flags</span> <span class="o">|=</span> <span class="n">MAP_FIXED</span><span class="p">;</span>

	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MAP_FIXED</span><span class="p">))</span>
		<span class="n">addr</span> <span class="o">=</span> <span class="n">round_hint_to_min</span><span class="p">(</span><span class="n">addr</span><span class="p">);</span>

	<span class="cm">/* Careful about overflows.. */</span>
	<span class="n">len</span> <span class="o">=</span> <span class="n">PAGE_ALIGN</span><span class="p">(</span><span class="n">len</span><span class="p">);</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">len</span><span class="p">)</span>
		<span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span>

	<span class="cm">/* offset overflow? */</span>
	<span class="k">if</span> <span class="p">((</span><span class="n">pgoff</span> <span class="o">+</span> <span class="p">(</span><span class="n">len</span> <span class="o">&gt;&gt;</span> <span class="n">PAGE_SHIFT</span><span class="p">))</span> <span class="o">&lt;</span> <span class="n">pgoff</span><span class="p">)</span>
		<span class="k">return</span> <span class="o">-</span><span class="n">EOVERFLOW</span><span class="p">;</span>

	<span class="cm">/* Too many mappings? */</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">mm</span><span class="o">-&gt;</span><span class="n">map_count</span> <span class="o">&gt;</span> <span class="n">sysctl_max_map_count</span><span class="p">)</span>
		<span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span>
</code></pre></div>  </div>
</blockquote>

<p>You can see all this function does is a lots of permission checking. Here we find the source of truth for the <code class="language-plaintext highlighter-rouge">MAP_PRIVATE</code> flag<sup id="fnref:semantics" role="doc-noteref"><a href="#fn:semantics" class="footnote" rel="footnote">9</a></sup>.</p>

<blockquote>
  <p><a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/mmap.c#L469-L482"><code class="language-plaintext highlighter-rouge">MAP_PRIVATE</code> case</a></p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="k">case</span> <span class="n">MAP_PRIVATE</span><span class="p">:</span>
			<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">file</span><span class="o">-&gt;</span><span class="n">f_mode</span> <span class="o">&amp;</span> <span class="n">FMODE_READ</span><span class="p">))</span>
				<span class="k">return</span> <span class="o">-</span><span class="n">EACCES</span><span class="p">;</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">path_noexec</span><span class="p">(</span><span class="o">&amp;</span><span class="n">file</span><span class="o">-&gt;</span><span class="n">f_path</span><span class="p">))</span> <span class="p">{</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">vm_flags</span> <span class="o">&amp;</span> <span class="n">VM_EXEC</span><span class="p">)</span>
					<span class="k">return</span> <span class="o">-</span><span class="n">EPERM</span><span class="p">;</span>
				<span class="n">vm_flags</span> <span class="o">&amp;=</span> <span class="o">~</span><span class="n">VM_MAYEXEC</span><span class="p">;</span>
			<span class="p">}</span>

			<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">file</span><span class="o">-&gt;</span><span class="n">f_op</span><span class="o">-&gt;</span><span class="n">mmap</span><span class="p">)</span>
				<span class="k">return</span> <span class="o">-</span><span class="n">ENODEV</span><span class="p">;</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">vm_flags</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">VM_GROWSDOWN</span><span class="o">|</span><span class="n">VM_GROWSUP</span><span class="p">))</span>
				<span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>
			<span class="k">break</span><span class="p">;</span>
</code></pre></div>  </div>
</blockquote>

<blockquote>
  <p><a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/mmap.c#L561-L567">code after permissions checking</a></p>
  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="n">addr</span> <span class="o">=</span> <span class="n">mmap_region</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">vm_flags</span><span class="p">,</span> <span class="n">pgoff</span><span class="p">,</span> <span class="n">uf</span><span class="p">);</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">IS_ERR_VALUE</span><span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
	    <span class="p">((</span><span class="n">vm_flags</span> <span class="o">&amp;</span> <span class="n">VM_LOCKED</span><span class="p">)</span> <span class="o">||</span>
	     <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">MAP_POPULATE</span> <span class="o">|</span> <span class="n">MAP_NONBLOCK</span><span class="p">))</span> <span class="o">==</span> <span class="n">MAP_POPULATE</span><span class="p">))</span>
		<span class="o">*</span><span class="n">populate</span> <span class="o">=</span> <span class="n">len</span><span class="p">;</span>
	<span class="k">return</span> <span class="n">addr</span><span class="p">;</span>
<span class="err">}</span>
</code></pre></div>  </div>
</blockquote>

<p>I follow this technique to trace functions. I sequentially find the definition of referenced symbols, recursively searching within as needed.
Once you find a function, tracing backwards from the return code helps to reduce the irrelevant code to sift through.</p>

<p>We repeat tracing the function calls <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/vma.c#L2509"><code class="language-plaintext highlighter-rouge">mmap_region</code></a>
⟶ <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/vma.c#L2434"><code class="language-plaintext highlighter-rouge">__mmap_region</code></a></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">/**</span>
 <span class="o">*</span> <span class="n">mmap_region</span><span class="p">()</span> <span class="o">-</span> <span class="n">Actually</span> <span class="n">perform</span> <span class="n">the</span> <span class="n">userland</span> <span class="n">mapping</span> <span class="n">of</span> <span class="n">a</span> <span class="n">VMA</span> <span class="n">into</span>
 <span class="o">*</span> <span class="n">current</span><span class="o">-&gt;</span><span class="n">mm</span> <span class="n">with</span> <span class="n">known</span><span class="p">,</span> <span class="n">aligned</span> <span class="n">and</span> <span class="n">overflow</span><span class="o">-</span><span class="n">checked</span> <span class="err">@</span><span class="n">addr</span> <span class="n">and</span> <span class="err">@</span><span class="n">len</span><span class="p">,</span> <span class="n">and</span>
 <span class="o">*</span> <span class="n">correctly</span> <span class="n">determined</span> <span class="n">VMA</span> <span class="n">flags</span> <span class="err">@</span><span class="n">vm_flags</span> <span class="n">and</span> <span class="n">page</span> <span class="n">offset</span> <span class="err">@</span><span class="n">pgoff</span><span class="p">.</span>
 <span class="o">*</span>
 <span class="o">*</span> <span class="n">This</span> <span class="n">is</span> <span class="n">an</span> <span class="n">internal</span> <span class="n">memory</span> <span class="n">management</span> <span class="n">function</span><span class="p">,</span> <span class="n">and</span> <span class="n">should</span> <span class="n">not</span> <span class="n">be</span> <span class="n">used</span>
 <span class="o">*</span> <span class="n">directly</span><span class="p">.</span>
 <span class="o">*</span>
 <span class="o">*</span> <span class="n">The</span> <span class="n">caller</span> <span class="n">must</span> <span class="n">write</span><span class="o">-</span><span class="n">lock</span> <span class="n">current</span><span class="o">-&gt;</span><span class="n">mm</span><span class="o">-&gt;</span><span class="n">mmap_lock</span><span class="p">.</span>
 <span class="o">*</span>
 <span class="o">*</span> <span class="err">@</span><span class="n">file</span><span class="o">:</span> <span class="n">If</span> <span class="n">a</span> <span class="n">file</span><span class="o">-</span><span class="n">backed</span> <span class="n">mapping</span><span class="p">,</span> <span class="n">a</span> <span class="n">pointer</span> <span class="n">to</span> <span class="n">the</span> <span class="k">struct</span> <span class="n">file</span> <span class="n">describing</span> <span class="n">the</span>
 <span class="o">*</span> <span class="n">file</span> <span class="n">to</span> <span class="n">be</span> <span class="n">mapped</span><span class="p">,</span> <span class="n">otherwise</span> <span class="nb">NULL</span><span class="p">.</span>
</code></pre></div></div>

<p>We can ignore the details about virtual memory; the full details of Linux <a href="https://www.kernel.org/doc/gorman/html/understand/">Virtual Memory Areas</a> are in this document.
We are focusing on tracing the path to loading the backing library file.
If you continue tracing you will get stuck. How is the file never actually used in any of this code?
This dead end demonstrates why looking at real code gets complicated. We need to first understand what we are looking at.</p>

<p>Linux tries to be as fast as possible. It will not load data from disk unless necessary. Thus, this <code class="language-plaintext highlighter-rouge">mmap</code> call is
a lie. It is not loading any files. The kernel simply sets up page table entries for the virtual memory space.</p>

<blockquote>
  <p>Instructor: Can you think about how the OS would know when it has to load a page in?</p>
</blockquote>

<p>The OS can rely on the hardware generating a page fault when the user tries to access this unloaded memory. 
The OS marks the page table entries as invalid, which causes the hardware to generate a fault. This execution transfer allows the OS to inspect what it should do in response, such as loading the backing memory or killing the process with a segmentation fault.</p>

<p>You might guess that we need to look at the logic on a page fault of one of these addresses. 
Inside of arm64’s <code class="language-plaintext highlighter-rouge">do_page_fault</code> we see where the memory mapping code gets called</p>

<blockquote>
  <p><a href="https://github.com/torvalds/linux/blob/ffd294d346d185b70e28b1a28abe367bbfe53c04/arch/arm64/mm/fault.c#L647">arch/arm64/mm/fault.c</a></p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">int</span> <span class="n">__kprobes</span> <span class="nf">do_page_fault</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">far</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">esr</span><span class="p">,</span>
				   <span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
<span class="p">{</span>
  <span class="p">[...]</span>
	<span class="n">fault</span> <span class="o">=</span> <span class="n">handle_mm_fault</span><span class="p">(</span><span class="n">vma</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">mm_flags</span> <span class="o">|</span> <span class="n">FAULT_FLAG_VMA_LOCK</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</code></pre></div>  </div>
  <p>⟶
<a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L6177"><code class="language-plaintext highlighter-rouge">handle_mm_fault</code></a></p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vm_fault_t</span> <span class="nf">handle_mm_fault</span><span class="p">(</span><span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">,</span>
			   <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
<span class="p">{</span>
  <span class="p">[...]</span>
		<span class="n">ret</span> <span class="o">=</span> <span class="n">__handle_mm_fault</span><span class="p">(</span><span class="n">vma</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div>  </div>
  <p>⟶
<a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L5950"><code class="language-plaintext highlighter-rouge">__handle_mm_fault</code></a></p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">vm_fault_t</span> <span class="nf">__handle_mm_fault</span><span class="p">(</span><span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">,</span>
		<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span>
<span class="p">{</span>
</code></pre></div>  </div>
</blockquote>

<p>Are you getting a hang of it? 
The high quality kernel code makes it easy to explore and pick up their naming conventions.
For example, <code class="language-plaintext highlighter-rouge">do_</code> functions do the work, <code class="language-plaintext highlighter-rouge">sys_</code> and <code class="language-plaintext highlighter-rouge">SYSCALL_DEFINE</code> help you find where syscalls enter, and <code class="language-plaintext highlighter-rouge">__function_name</code> functions are internal functions that implement core logic and get called after all permission checks.
Reading unfamiliar code is difficult, but you can follow the same process we have been using: recursively explore function definitions until you understand what the acronyms are, what functions do, and what the jargon means in context.</p>

<p>Going back to <code class="language-plaintext highlighter-rouge">__handle_mm_fault</code>, you will realize these function calls are not relevant. They have to do with unrelated unhappy paths that can get hit on a page fault. At a high level, this code walks and allocates the multi-level page table.</p>

<blockquote>
  <p>⟶ <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L5856"><code class="language-plaintext highlighter-rouge">handle_pte_fault</code></a></p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">vm_fault_t</span> <span class="nf">handle_pte_fault</span><span class="p">(</span><span class="k">struct</span> <span class="n">vm_fault</span> <span class="o">*</span><span class="n">vmf</span><span class="p">)</span>
<span class="p">{</span>
 <span class="p">[...]</span>

	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">vmf</span><span class="o">-&gt;</span><span class="n">pte</span><span class="p">)</span>
		<span class="k">return</span> <span class="n">do_pte_missing</span><span class="p">(</span><span class="n">vmf</span><span class="p">);</span>

	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pte_present</span><span class="p">(</span><span class="n">vmf</span><span class="o">-&gt;</span><span class="n">orig_pte</span><span class="p">))</span>
		<span class="k">return</span> <span class="n">do_swap_page</span><span class="p">(</span><span class="n">vmf</span><span class="p">);</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">pte_protnone</span><span class="p">(</span><span class="n">vmf</span><span class="o">-&gt;</span><span class="n">orig_pte</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">vma_is_accessible</span><span class="p">(</span><span class="n">vmf</span><span class="o">-&gt;</span><span class="n">vma</span><span class="p">))</span>
		<span class="k">return</span> <span class="n">do_numa_page</span><span class="p">(</span><span class="n">vmf</span><span class="p">);</span>
</code></pre></div>  </div>
</blockquote>

<p>Now the fault must get handled. The backing memory must become valid before the OS can return to the faulted program.
In our case, the address that faulted is inside <code class="language-plaintext highlighter-rouge">libc</code>, which needs to be placed into our process’ address space from disk.</p>

<blockquote>
  <p><strong>Overview of Page Fault Execution Flow</strong></p>

  <ul>
    <li>Check if the Page Middle Directory (PMD) is present.
      <ul>
        <li>If the Page Middle Directory (PMD) entry is missing, it means there is no page table yet.
If the PTE is empty (<code class="language-plaintext highlighter-rouge">pte_none()</code>), then the page is not allocated yet, so we will handle it as a missing page.</li>
      </ul>
    </li>
    <li>Get or allocate a Page Table Entry (PTE).
  Determine the type of fault and handle it accordingly:
      <ul>
        <li>Page is missing → Allocate a new page (<code class="language-plaintext highlighter-rouge">do_pte_missing()</code>).</li>
        <li>Page is swapped out → Swap it back in (<code class="language-plaintext highlighter-rouge">do_swap_page()</code>).</li>
        <li>Page migration/NUMA fault → Handle it (<code class="language-plaintext highlighter-rouge">do_numa_page()</code>).</li>
        <li>Write protection fault → Handle copy-on-write (COW) (<code class="language-plaintext highlighter-rouge">do_wp_page()</code>).</li>
        <li>Otherwise, mark the page as accessed and dirty if needed.</li>
      </ul>
    </li>
  </ul>
</blockquote>

<p>When the faulted page is missing or swapped out, the execution path continues as follows:</p>

<blockquote>
  <ul>
    <li>Page is missing → <code class="language-plaintext highlighter-rouge">do_pte_missing()</code>
      <ul>
        <li>If the mapping is anonymous, a new page is allocated.</li>
        <li>If the mapping is file-backed, the function calls <code class="language-plaintext highlighter-rouge">filemap_fault()</code> to fetch data from disk.</li>
      </ul>
    </li>
    <li>File-backed page → <code class="language-plaintext highlighter-rouge">filemap_fault()</code>
      <ul>
        <li>If the page is not in memory, it requests disk access via the block layer.</li>
      </ul>
    </li>
    <li>Disk access happens via the filesystem &amp; block layer
      <ul>
        <li>The requested page is fetched from disk into the page cache.
Once loaded, the page is mapped and execution continues.</li>
      </ul>
    </li>
  </ul>
</blockquote>

<blockquote>
  <p>⟶ We fall into <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L4053"><code class="language-plaintext highlighter-rouge">do_pte_missing</code></a> because the page for this mmap has not been created nor has the file been loaded.</p>

  <p>This page is not a normal stack or heap page, so we need to do work to load the file.</p>

  <p>⟶ <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L5507"><code class="language-plaintext highlighter-rouge">do_fault</code></a></p>

  <p>The code branches on the types of faults
⟶ This is a <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L5383"><code class="language-plaintext highlighter-rouge">do_read_fault</code></a>
⟶ <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/mm/memory.c#L4961"><code class="language-plaintext highlighter-rouge">__do_fault</code></a></p>
</blockquote>

<p>This leads to a function pointer for the exact fault handler we want to use for this filesystem</p>

<p>This layer of indirection (<a href="https://en.wikipedia.org/wiki/Virtual_file_system">VFS</a>) allows the implementation to be general for the exact filesystem in use.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ret</span> <span class="o">=</span> <span class="n">vma</span><span class="o">-&gt;</span><span class="n">vm_ops</span><span class="o">-&gt;</span><span class="n">fault</span><span class="p">(</span><span class="n">vmf</span><span class="p">);</span>
</code></pre></div></div>

<p>The types help us figure this out <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/include/linux/mm.h#L560"><code class="language-plaintext highlighter-rouge">struct vm_fault</code></a> ⟶ <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/include/linux/mm_types.h#L681"><code class="language-plaintext highlighter-rouge">vm_area_struct</code></a> ⟶ <a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/include/linux/mm.h#L611"><code class="language-plaintext highlighter-rouge">vm_operations_struct</code></a></p>

<p>Bingo. We now know what the type of <code class="language-plaintext highlighter-rouge">fault</code> is: <code class="language-plaintext highlighter-rouge">vm_fault_t (*fault)(struct vm_fault *vmf);</code>.</p>

<p>Although we have hit a dead end, applying the same exploration tricks gets us to <a href="https://github.com/torvalds/linux/blob/ffd294d346d185b70e28b1a28abe367bbfe53c04/fs/ext4/file.c#L796"><code class="language-plaintext highlighter-rouge">filemap_fault</code></a>. <code class="language-plaintext highlighter-rouge">grep</code> finds us many definitions, but we can choose the <code class="language-plaintext highlighter-rouge">ext4</code> filesystem as an example. We can use the types to find this does nothing other than call the generic implementation of <a href="https://github.com/torvalds/linux/blob/ffd294d346d185b70e28b1a28abe367bbfe53c04/mm/filemap.c#L3293"><code class="language-plaintext highlighter-rouge">filemap_fault</code></a>. Yet again, the comments on the function are extremely helpful and let us confirm we are in the right place.</p>

<p>Let’s update our snapshot of our current understanding.</p>

<blockquote>
  <h4 id="summary-of-execution-path">Summary of Execution Path</h4>

  <ol>
    <li>The kernel walks the page table in <code class="language-plaintext highlighter-rouge">__handle_mm_fault()</code>. This generates a page fault.</li>
    <li>A missing file-backed page triggers <code class="language-plaintext highlighter-rouge">handle_pte_fault()</code>.</li>
    <li>It calls <code class="language-plaintext highlighter-rouge">do_pte_missing()</code>, which routes to do_fault().</li>
    <li><code class="language-plaintext highlighter-rouge">do_fault()</code> identifies the fault as a read fault and calls <code class="language-plaintext highlighter-rouge">do_read_fault()</code>.</li>
    <li>This invokes <code class="language-plaintext highlighter-rouge">vma-&gt;vm_ops-&gt;fault()</code>, which for files is <code class="language-plaintext highlighter-rouge">filemap_fault()</code>.</li>
    <li><code class="language-plaintext highlighter-rouge">filemap_fault()</code> checks if the page is in the page cache.
      <ul>
        <li>If present → Map it into the process and return.</li>
        <li>If missing → Request disk I/O via the block layer[^2].</li>
      </ul>
    </li>
    <li>The page is read from disk into the page cache.</li>
    <li>The process blocks while the page is mapped, and execution resumes.</li>
  </ol>
</blockquote>

<p>This looks much more precise than before!
We can continue recursively unfolding function defintions. There is a call to <code class="language-plaintext highlighter-rouge">filemap_get_folio</code> which returns a <code class="language-plaintext highlighter-rouge">folio</code> type. The type’s comment indicates something interesting. 
Both the filesystem function and this function mention a “page cache”</p>

<blockquote>
  <p><a href="https://github.com/torvalds/linux/blob/7eb172143d5508b4da468ed59ee857c6e5e01da6/include/linux/mm_types.h#L324"><code class="language-plaintext highlighter-rouge">folio</code></a></p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> * A folio is a physically, virtually and logically contiguous set
 * of bytes.  It is a power-of-two in size, and it is aligned to that
 * same power-of-two.  It is at least as large as %PAGE_SIZE.  If it is
 * in the page cache, it is at a file offset which is a multiple of that
 * power-of-two.
</code></pre></div>  </div>
</blockquote>

<p>A <code class="language-plaintext highlighter-rouge">folio</code> is a reference counted page cache entry. We are loading a new file for the first time, so this page will not be in the page cache.</p>

<blockquote>
  <p>Instructor: Or will it?</p>
</blockquote>

<p>What file are we loading again? We are loading <code class="language-plaintext highlighter-rouge">libc</code>. Effectively, every program is using <code class="language-plaintext highlighter-rouge">libc</code>. This file will surely be in memory already. Alas, this file is in use by other processes, so we cannot reuse the file.</p>

<blockquote>
  <p>Instructor: Or can we?</p>
</blockquote>

<p>Let’s look back at the syscall we are executing in the first place.
Take a look at the flags. We only want to execute <code class="language-plaintext highlighter-rouge">libc</code>. Thus, every program can share the same read-only copy of this physical memory mapped into their virtual address spaces.</p>

<p>This is magic. There was no coordination between the programs reading this same file. No special mechanisms are used in the kernel. The same ideas that support virtual memory are working in harmony to make dynamic library loading invisibly work.</p>

<p>Now, let’s follow the path when a file-backed page is missing and needs to be read from disk.</p>

<blockquote>
  <p>Hardware tries to access an uninitialized page</p>

  <p>⟶ <code class="language-plaintext highlighter-rouge">handle_pte_fault()</code>: If the page is not present, it calls <code class="language-plaintext highlighter-rouge">do_fault()</code>.</p>

  <p>⟶ <code class="language-plaintext highlighter-rouge">do_fault()</code>: If the mapping is from a file, it calls <code class="language-plaintext highlighter-rouge">filemap_fault()</code>.</p>

  <p>⟶ <code class="language-plaintext highlighter-rouge">filemap_fault()</code>: This function tries to load the missing page from disk. It calls <code class="language-plaintext highlighter-rouge">page_cache_read()</code> if the page is not already cached.</p>

  <p>⟶ <code class="language-plaintext highlighter-rouge">page_cache_read()</code> Reads the page from the filesystem’s page cache.
If the page is not cached, it requests disk access via the block layer.</p>
</blockquote>

<p>There you have it! The library has been mapped into the process from the cache. Our process can continue running with shared libraries, oblivous to all this work the kernel has done in the background. Yet, the kernel did not do anything special to support this one library sharing use case! Every kernel action was on behalf of a user syscall.</p>

<h1 id="recap">Recap</h1>

<p>The solution is elegant: <strong>there is no special “dynamic linking” support in the kernel</strong>.</p>

<p>These general purpose mechanisms are used:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">mmap()</code> with <code class="language-plaintext highlighter-rouge">MAP_PRIVATE</code> creates copy-on-write mappings</li>
  <li><em>Page faults</em> trigger on-demand loading</li>
  <li>The <em>page cache</em> automatically shares identical file content between processes</li>
  <li><em>Virtual memory</em> lets each process see libraries at different addresses while sharing the same physical memory</li>
</ul>

<p><strong>At a high level:</strong>
<img src="/images/spelunking/recap.svg" alt="actions in userspace and kernel space" style="display:block; margin-left:auto; margin-right:auto" width="100%" /></p>

<p><strong>More precisely:</strong>
<img src="/images/spelunking/flow.drawio.png" alt="flowchart of library loading steps" style="display:block; margin-left:auto; margin-right:auto" width="100%" /></p>

<h2 id="its-for-the-pedagogy-">It’s for the pedagogy <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">10</a></sup></h2>

<blockquote>
  <p>:lying_face:: Holupaminnit, how did we get to <code class="language-plaintext highlighter-rouge">printf</code> and page faults? I thought we were talking about loading binaries?</p>
</blockquote>

<p>Alas, I have tricked you into learning something new. One way to ask this question is to ask
what happens when there is a <code class="language-plaintext highlighter-rouge">printf</code> in your code, but I think the framing of our initial
question at the start led us along a more interesting route.</p>

<p>Undoubtedly, there are many other aspects of loading a program I have skipped. The point to
take home is that exploration is nonlinear. All the irrelevant things we tried while
inspecting system behavior turned out to be completely relevant! There is a lot going on, but
I hope you will believe me and believe yourself that you could have figured this out.
The approach we took for figuring this puzzle out is great because it works in general. For kernel code,
the better approach is probably to go directly to kernel documentation and to start reading the
source code. However, documentation is not enough to see what precisely happens beneath the hood and make changes.</p>

<h2 id="what-we-didnt-cover">What we didn’t cover</h2>

<p>Think about these for yourself.</p>

<ul>
  <li>Can you write a C program to test your mental model? Can you spelunk your kernel to find out? Remember, just because LLMs act authoritative, it does not mean they know anything.</li>
  <li>How do we know when a program has finished executing? What does it mean to be the last instruction of the file?</li>
  <li>How does <code class="language-plaintext highlighter-rouge">printf</code> actually work. <a href="https://www.maizure.org/projects/printf/index.html">This post</a> is supremely interesting. I love the presentation of the post and it goes into much more detail than I get into here. If you think you can explain how <code class="language-plaintext highlighter-rouge">printf</code> works, the author will humble you.</li>
  <li>We stopped at the assembly level, but how is each of these instructions actually executing? What hardware is involved? What is the hardware doing?</li>
  <li>Can you have multiple versions of the same library installed?</li>
  <li>If you remove the <code class="language-plaintext highlighter-rouge">return</code> statement in <code class="language-plaintext highlighter-rouge">hello_world.c</code>, can you explain why the program returns <code class="language-plaintext highlighter-rouge">13</code>? Hint: what does the <code class="language-plaintext highlighter-rouge">void</code> keyword mean? Where are return values stored?</li>
  <li>Why does a simple program with no library calls, such as addition, still load <code class="language-plaintext highlighter-rouge">libc</code>? Hint: try looking at the output of <code class="language-plaintext highlighter-rouge">strace</code>. What is the last system call called by the program?</li>
  <li>Can you figure out what dynamic library an address belongs to in the virtual address space of a program on your computer?
<code class="language-plaintext highlighter-rouge">$ cat /proc/$(pidof binary_name)/maps</code>. What is the program being run? You should be able to tell from the sections.</li>
</ul>

<p>You now have all the tools to learn anything you want. To keep this knowledge, you must exercise it. I leave you with a quest: embark on your personal journey of Linux spelunking and discover what happens when you start running a program with the <code class="language-plaintext highlighter-rouge">exec</code> syscall. You can find a sample solution in the <a href="https://www.cs.utexas.edu/~rossbach/cs380p/papers/ulk3.pdf#page=846&amp;zoom=auto,27,416">“The <code class="language-plaintext highlighter-rouge">exec</code> Functions”</a> section of <em>Understanding the Linux Kernel</em>. The “How programs get run” series by LWN also has a great explanation (<a href="https://lwn.net/Articles/630727/">part 1</a>, <a href="https://lwn.net/Articles/631631/">part 2</a>).</p>

<h2 id="wrapping-up">Wrapping up</h2>

<p>In this post, we demystified how Linux loads processes and discovered how Linux works on a journey that reminds me of the joys of computers and discovery.</p>

<p>The great part about learning things this way is that you feel empowered to learn anything. The power of open source allows us to figure absolutely anything out with enough effort. We also do not need to trust anything. We looked at the source ourselves and can be quite confident that we have created a mental model accurate to the real world.</p>

<p>This post was inspired by <a href="https://www.youtube.com/watch?v=d0gS5TXarXc">this video</a> on Linux signals. It is one of the best videos I have ever seen. I rewatch it every few months to remind myself how beautiful it is to be able to understand these precise and complex beasts which are the machines we use.
I hope you can appreciate the beauty of the ridiculous world we live in. All it takes is a sense of wonder and you can build anything.</p>

<p>Thank you for reading! This article took me 49 hours over 8 weeks.
I have surely gotten details wrong in the post. I am sorry. Point them out!
Please email me any feedback at <code class="language-plaintext highlighter-rouge">process-loading &lt;at&gt; this domain</code> or leave it in the comments below.</p>

<p>The objective is curiosity maximization.
Happy exploring.</p>

<h3 id="further-reading">Further Reading:</h3>

<ul>
  <li>Best resource I have found on shared libraries: <a href="https://www.akkadia.org/drepper/dsohowto.pdf">How To Write Shared Libraries by Ulrich Drepper</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Dynamic_linker">Dynamic linker wiki</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Mmap"><code class="language-plaintext highlighter-rouge">mmap</code> wiki</a></li>
  <li><a href="https://eli.thegreenplace.net/2012/08/13/how-statically-linked-programs-run-on-linux">How statically linked programs run on Linux (and how you get from libc to the start symbol)</a></li>
  <li><a href="http://s.eresi-project.org/inc/articles/elf-rtld.txt">Understanding Linux ELF RTLD internals</a></li>
  <li><a href="https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html">GOT and PLT for pwning</a></li>
  <li><code class="language-plaintext highlighter-rouge">man ld.so</code>: Describes in detail all the places dynamic libraries come from and how you indicate what gets loaded.
    <ul>
      <li><code class="language-plaintext highlighter-rouge">ldd</code> trivia: it has <a href="https://catonmat.net/ldd-arbitrary-code-execution">arbitrary code execution</a> as it may <a href="https://man7.org/linux/man-pages/man1/ldd.1.html">run the target binary</a></li>
    </ul>
  </li>
  <li>Try compiling some files and disassmbling them. Here are some flags to make it more readable. <code class="language-plaintext highlighter-rouge">objdump --disassemble=main  --no-show-raw-insn --visualize-jumps --disassembler-color=on a.out | less</code></li>
  <li><a href="https://www.cs.utexas.edu/~rossbach/cs380p/papers/ulk3.pdf#page=834&amp;zoom=auto,27,390">“Libraries” part of <em>Understanding the Linux Kernel, 3rd Edition</em></a></li>
  <li><a href="https://sysadvent.blogspot.com/2010/12/day-15-down-ls-rabbit-hole.html">a similar blog post</a> for tracing <code class="language-plaintext highlighter-rouge">ls</code></li>
  <li><a href="https://lwn.net/Articles/604287/">Anatomy of a system call part 1</a>, <a href="https://lwn.net/Articles/604515/">part 2</a></li>
  <li><a href="https://jvns.ca/wizard-zine.pdf">You can be a wizard</a></li>
</ul>

<p>Resources for filesystem details I glossed over:</p>
<ul>
  <li>For more details on the exact actions to read from disk, <a href="https://www.cs.cornell.edu/courses/cs4410/2021fa/assets/material/lecture24_blk_layer.pdf">blk layer slides</a></li>
  <li><a href="https://chemnitzer.linux-tage.de/2021/media/programm/folien/165.pdf">An Introduction to the Linux Kernel Block I/O Stack</a></li>
  <li><a href="http://blog.vmsplice.net/2020/04/how-linux-vfs-block-layer-and-device.html">How the Linux VFS, block layer, and device drivers fit together</a></li>
  <li><a href="https://devarea.com/wp-content/uploads/2017/10/Linux-VFS-and-Block.pdf">Linux VFS and Block Layers</a></li>
  <li><a href="https://www.oreilly.com/library/view/understanding-the-linux/0596005652/ch14s02.html">The Generic Block Layer</a> from Understanding the Linux Kernel</li>
  <li>
    <p><a href="https://www.kernel.org/doc/Documentation/filesystems/vfs.txt">kernel VFS docs</a></p>
  </li>
  <li>If you want extreme detail on Linux Virtual Memory, there’s an <a href="https://www.kernel.org/doc/gorman/pdf/understand.pdf">entire book</a>. The <a href="https://www.kernel.org/doc/gorman/pdf/understand.pdf#page=94">“Page Faulting” section</a> is a good supplement to this post.</li>
</ul>

<p>I tried to make every logical jump explicit as an educational method. When you are debugging for real, you should reach to the best tool for the job instead of the winding path I took. For example, I used <code class="language-plaintext highlighter-rouge">vim</code> to open files to show that binary is not scary. You would never look at a binary in a normal text editor like <code class="language-plaintext highlighter-rouge">vim</code>–reach directly for <code class="language-plaintext highlighter-rouge">objdump</code> or <code class="language-plaintext highlighter-rouge">readelf</code>. If high level tools don’t work, then you can use a hex viewer.</p>

<p>Another much faster path to figuring out what a program does is to use a disassembler. We were manually going through the process of a small part of what disassemblers can automatically do for us.
This would have shown what <code class="language-plaintext highlighter-rouge">hello_world.c</code> is actually doing as something like this</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">function</span> <span class="n">main</span> <span class="p">{</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Hello world!"</span><span class="p">);</span>
  <span class="n">exit</span><span class="p">(</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Of course, there is a lot more code running. You can use a full-fat disassembler such as Ghidra. This <a href="https://dogbolt.org/?id=8f1e28f5-3bfc-4d41-8be2-82c12f54487f">dogbolt web disassembly</a> of a hello world program is enough to get an idea of what the output looks like.</p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:assets" role="doc-endnote">
      <p>The code I ran is available at godsped.com/files/{explore_plt.c, hello_name.c, hello_name.strace, hello_world.c, hello_world_skeptic.c, hello_world.strace}. <a href="#fnref:assets" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:debug" role="doc-endnote">
      <p>A good POV of the <a href="https://blog.regehr.org/archives/199">debugging mental model</a> <a href="#fnref:debug" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:entrypoint" role="doc-endnote">
      <p>It’s conventionally called <code class="language-plaintext highlighter-rouge">_start</code>, but in reality the initial point of execution is determined by the entrypoint of the (ELF) header. Further reading: <a href="https://stackoverflow.com/a/36165001">one</a>, <a href="https://unix.stackexchange.com/questions/588240/what-mandates-the-start-entrypoint-kernel-ld-linux-so-etc">two</a>. <a href="#fnref:entrypoint" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:RELRO" role="doc-endnote">
      <p>The system you are using probably resolves all symbols at startup so that GOT overwrite attacks cannot happen. This security feature is called Full RELRO and is enabled by the <a href="https://stackoverflow.com/questions/62527697/why-does-gcc-link-with-z-now-by-default-although-lazy-binding-is-the-default"><code class="language-plaintext highlighter-rouge">BIND_NOW</code> flag</a>. <a href="#fnref:RELRO" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:shebang" role="doc-endnote">
      <p>It’s the exact same! Having a file start with the bytes <code class="language-plaintext highlighter-rouge">#!</code> indicates that the file should be <a href="https://elixir.bootlin.com/linux/v6.14-rc6/source/fs/binfmt_script.c">interpeted as a script</a>. I’ll keep hammering the point home. Everything is only bits at the end of the day. An executable is not different than other files stored on your disk. Let’s take this idea to the extreme: you can write an executable directly in a text editor. ISN’T THAT CRAZY? Kay Lack has a <a href="https://youtu.be/cX5tQJhuNeY">beautiful video</a> demonstrating manually writing an ELF file and Steve Chamberlin has a great <a href="https://www.bigmessowires.com/2015/10/08/a-handmade-executable-file/">blog post</a> where he does this on Windows. <a href="#fnref:shebang" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p><a href="https://www.youtube.com/watch?v=Ss2e6JauS0Y">Great lecture explaining PLT and GOT</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:diagram_shm" role="doc-endnote">
      <p>Image from <em>Win32 API Programming with Visual Basic</em> by Steven Roman page 212. <a href="#fnref:diagram_shm" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:1" role="doc-endnote">
      <p>footnote: path to finding this is using this post https://stackoverflow.com/questions/14542348/how-to-find-a-definition-of-a-specific-syscall-in-linux-sources and then use regex “.” syntax to find the definition of mmap <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:semantics" role="doc-endnote">
      <p>If you have used <a href="https://en.wikipedia.org/wiki/Not_Another_Completely_Heuristic_Operating_System">Nachos</a> or are only familiar with using <code class="language-plaintext highlighter-rouge">read</code>/<code class="language-plaintext highlighter-rouge">write</code> with files, you may get confused by <code class="language-plaintext highlighter-rouge">mmap</code> semantics. <code class="language-plaintext highlighter-rouge">mmap</code> does copy data from disk to memory, but if the process does not modify the data, then the physical pages can be shared. Technically, sharing libraries does require this much kernel support. <a href="#fnref:semantics" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://www.youtube.com/watch?v=bYv_Jcd27Gc">The true meaning of teaching</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="research" /><category term="recommended read" /><summary type="html"><![CDATA[In this post, we will demystify how Linux loads processes and discover how Linux works on a journey that reminds me of the joys of computers and discovery.]]></summary></entry><entry><title type="html">*Tabula Rasa*: Starting Safe Stays Safe</title><link href="https://godsped.com/tabula-rasa/" rel="alternate" type="text/html" title="*Tabula Rasa*: Starting Safe Stays Safe" /><published>2025-02-18T00:00:00+00:00</published><updated>2025-02-18T00:00:00+00:00</updated><id>https://godsped.com/tabula-rasa</id><content type="html" xml:base="https://godsped.com/tabula-rasa/"><![CDATA[<p>I’m ecstatic to share that we won best paper at The 3rd Workshop on Security and Privacy in Connected Embedded Systems (SPICES 2024). My collaborators and I studied the security of embedded operating systems and their usage <em>in the wild</em>.</p>

<blockquote>
  <p><a href="https://patpannuto.com/pubs/potyondy2024tabularasa.pdf">You can read the full paper here, or read on for some relevant excerpts.</a></p>
</blockquote>

<p>Embedded and connected devices have become a ubiquitous and
integral part of our world. From medical devices and smart home
products to industrial controllers, these devices perform an increasing set of complex, critical tasks. To abstract these complexities, embedded operating systems (OSes) evolved to provide rich
development environments and high-level abstractions, such as
platform-independent hardware models and separable tasks. Despite the availability of these abstractions and isolation mechanisms
for tasks, we find that in practice many embedded applications lack
strong isolation and do not enable security reinforcements. This
paper explores projects using embedded OSes to quantify how configurable security features are used and how they factor into the
given project’s design.</p>

<p>Historically, embedded devices did not offer connectivity. For
instance, industrial controllers or automotive Electronic Control
Units (ECUs) required a technician physically access and “plug-into”
the device. As embedded devices have evolved into the Internet of
Things (IoT), many now offer internet connectivity to gather data,
offer remote control, and provide firmware updates. Developers
now expect embedded OSes to provide library features such as
over-the-air updates and network stacks. Internet connectivity and
the global scale of many billions of deployed devices implies that
embedded devices now face an attack surface more akin to that of a
traditional operating system. As such, the security embedded OSes
provide is paramount.</p>

<p>With this connectivity, embedded devices now
face a more complex attack surface, underscoring the importance
of device security. Embedded operating systems are able to span
diverse application and hardware domains because they are highly
configurable. This flexibility, however, implies that downstream
embedded applications may be flexible in how they use security
features. This paper investigates how downstream applications use
configurable security features in practice. We find that a majority of
applications do not alter the default configuration provided by their
chosen runtime, and as a result, do not utilize available security
options. Early evidence suggests that this under-utilization is due
to both runtime and development overhead.</p>

<p><strong>Result 1</strong>: Zephyr &amp; FreeRTOS MPU Feature Usage.</p>

<p>Zephyr and
FreeRTOS offer similar MPU-based security configurations,
and both disable process isolation and stack overflow protection by default. Of surveyed Zephyr and FreeRTOS applications, 17% of Zephyr and 8% of FreeRTOS projects enable
both process isolation and hardware stack guards. We subsequently observe that 89% of surveyed FreeRTOS/Zephyr
projects do not enable the full suite of opt-in, configurable
MPU security features. We do not include RIOT in this
result as RIOT does not support MPU process isolation.</p>

<p><strong>Result 2</strong>: SW/HW Stackguard Usage.</p>

<p>Surveyed FreeRTOS repositories exhibit a more than sixfold increase of software-based stackguards usage in comparison to hardware-based
stack guard usage.</p>

<p><strong>Result 3</strong>: Opt-out Configuration Usage.</p>

<p>For RIOT platforms possessing an MPU, RIOT enables <code class="language-plaintext highlighter-rouge">mpu_stack_guard</code> by default.
We find that no surveyed project disables this feature.</p>

<p><strong>Result 4</strong>: Runtime Overhead.</p>

<p>Our preliminary benchmarking of Zephyr in Result 4 finds that
hardware security features impose a mere 224 cycle overhead per
context switch. This result agrees with the documentation
excerpts and shows an overhead that is in fact noticeable, but likely
only problematic for high performance applications. We argue that
<strong>the vast majority of IoT embedded applications do not require “every last drop of performance,” but instead that the primary overhead
impeding the usage of configurable security features is not performance but developer overhead.</strong></p>

<p>This paper shows the disparity between the configurable security
features the studied embedded OSes offer and the features that
are actually used <em>in the wild</em>. Our preliminary results and analysis
suggest the primary overhead limiting the use of these features is
developer overhead. Nonetheless, further investigation is required
to gain a more complete understanding of why these features are
left disabled by developers. So long as downstream applications
see limited use in enabling such optional features, the potential
security benefits embedded OSes can provide is left unrealized. This
is particularly problematic given the increased attack surface of
modern IoT devices.</p>

<p><a class="btn" style="" href="https://patpannuto.com/pubs/potyondy2024tabularasa.pdf">Read the full paper</a></p>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="research" /><summary type="html"><![CDATA[I’m ecstatic to share that we won best paper at The 3rd Workshop on Security and Privacy in Connected Embedded Systems (SPICES 2024). My collaborators and I studied the security of embedded operating systems and their usage in the wild.]]></summary></entry><entry><title type="html">Pronoun usage in the Linux Kernel</title><link href="https://godsped.com/linux-pronouns/" rel="alternate" type="text/html" title="Pronoun usage in the Linux Kernel" /><published>2025-02-17T00:00:00+00:00</published><updated>2025-02-17T00:00:00+00:00</updated><id>https://godsped.com/linux-pronouns</id><content type="html" xml:base="https://godsped.com/linux-pronouns/"><![CDATA[<p>I analyzed the distribution of pronouns in the 6.13 Linux kernel source. Unsurprisingly, I find that male pronouns are common, but this makes female pronouns all the more unusual.</p>

<aside class="sidebar__left">
<nav class="toc">
    <header><h4 class="nav__title"><i class="fas fa-file-alt"></i> On This Page</h4></header>
<ul class="toc__menu" id="markdown-toc">
  <li><a href="#results" id="markdown-toc-results">Results</a>    <ul>
      <li><a href="#counts-by-pronoun" id="markdown-toc-counts-by-pronoun">Counts by pronoun</a></li>
      <li><a href="#pronoun-usage-over-time" id="markdown-toc-pronoun-usage-over-time">Pronoun usage over time</a></li>
    </ul>
  </li>
  <li><a href="#analysis" id="markdown-toc-analysis">Analysis</a>    <ul>
      <li><a href="#her-usage" id="markdown-toc-her-usage">“her” usage</a></li>
      <li><a href="#she-usage" id="markdown-toc-she-usage">“she” usage</a></li>
      <li><a href="#womanwomen" id="markdown-toc-womanwomen">“woman”/”women”</a></li>
      <li><a href="#swearing-in-linux" id="markdown-toc-swearing-in-linux">Swearing in Linux</a></li>
      <li><a href="#age" id="markdown-toc-age">Age</a></li>
    </ul>
  </li>
</ul>

  </nav>
</aside>
<!-- https://github.com/junqing-zhang/junqing-zhang.github.io/blob/master/_includes/toc -->

<h1 id="results">Results</h1>

<h2 id="counts-by-pronoun">Counts by pronoun</h2>

<table>
  <thead>
    <tr>
      <th>Term</th>
      <th>Count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>he/him/his</td>
      <td>2516</td>
    </tr>
    <tr>
      <td>she/her/hers</td>
      <td>33</td>
    </tr>
    <tr>
      <td>man</td>
      <td>many references to <code class="language-plaintext highlighter-rouge">man</code></td>
    </tr>
    <tr>
      <td>men</td>
      <td>3</td>
    </tr>
    <tr>
      <td>wom{a,e}n</td>
      <td>4</td>
    </tr>
    <tr>
      <td>person</td>
      <td>many license usages</td>
    </tr>
    <tr>
      <td>people</td>
      <td>779</td>
    </tr>
  </tbody>
</table>

<p>The count for <a href="https://livegrep.com/search/linux?q=file%3A%5C.c%24%20%5Cb%5CW*person%5CW*%5Cb&amp;fold_case=auto&amp;regex=true&amp;context=true">“person”</a> is tainted by all of its usages in license verbiage. Similarly, <a href="https://livegrep.com/search/linux?q=%5Cb%5CW*man%5CW*%5Cb&amp;fold_case=auto&amp;regex=true&amp;context=true">“man”</a> is polluted with all the references to “man pages”.</p>

<p>I pruned non-pronoun usages. I did not include uses of “they” or “them” because I cannot grep to distinguish between uses of the gender-neutral pronoun “they” or as the plural for neuter terms (such as referring to function calls or variable values).</p>

<h2 id="pronoun-usage-over-time">Pronoun usage over time</h2>

<p><a href="https://www.vidarholen.net/contents/wordcount/#she,her,hers,he,him,his,man,woman,men,women" target="_blank"><img src="/images/pronouns/graph2.png" alt="pronouns over time in Linux source" /></a></p>

<p><a href="https://www.vidarholen.net/contents/wordcount/#man,woman*,men,women*,person*,people*" target="_blank"><img src="/images/pronouns/graph1.png" alt="pronouns over time in Linux source" /></a></p>

<h1 id="analysis">Analysis</h1>

<p>The kernel overwhelmingly uses male pronouns. This result is expected due to the &gt;90% male contributor population. Bitergia looked at the contributions of men and women to the Linux kernel in 2016. <a href="https://bitergia.com/blog/reports/gender-diversity-analysis-of-the-linux-kernel-technical-contributions/">Their study</a> found that women produced 6.8% of git activity as 9.9% of the developer population. This analysis was  based on identifying gender from names.</p>

<p>I expected there to only be uses of male or gender-neutral phrases. This hypothesis led me to inspect every usage of female pronouns.</p>

<p>Excluding some gender-neutral uses of “he/she”, “his/her”, and “[s]he”, the results for grepping <a href="https://livegrep.com/search/linux?q=%5Cb%5CW*her%5CW*%5Cb%20max_matches%3A1000&amp;fold_case=auto&amp;regex=true&amp;context=true">“her”</a> are peculiar.</p>

<h4 id="her-usage">“her” usage</h4>

<table>
  <thead>
    <tr>
      <th>noun which the pronoun refers to</th>
      <th>notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>female student</td>
      <td>A didactic quote with a female student <a href="https://github.com/torvalds/linux/blob/v6.13/Documentation/process/howto.rst?plain=1#L554">[commit]</a></td>
    </tr>
    <tr>
      <td>user of the computer</td>
      <td>unsure of authors as commits are from before the kernel switched to git <a href="https://github.com/torvalds/linux/blob/v6.13/drivers/video/fbdev/aty/mach64_ct.c#L512">[commit 1]</a> and <a href="https://github.com/torvalds/linux/blob/v6.13/net/bridge/netfilter/ebtables.c#L1070">[commit 2]</a></td>
    </tr>
    <tr>
      <td>a disk transaction</td>
      <td><a href="https://github.com/torvalds/linux/blob/v6.13/fs/jfs/jfs_logmgr.c#L881">[commit]</a></td>
    </tr>
    <tr>
      <td>busy waiter on a lock</td>
      <td><a href="https://github.com/torvalds/linux/blob/v6.13/kernel/printk/printk.c#L1935">[commit]</a></td>
    </tr>
  </tbody>
</table>

<h3 id="she-usage">“she” usage</h3>

<table>
  <thead>
    <tr>
      <th>noun which the pronoun refers to</th>
      <th>notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>scientist user</td>
      <td><a href="https://github.com/torvalds/linux/blob/v6.13/Documentation/admin-guide/LSM/Smack.rst?plain=1#L501">[commit]</a></td>
    </tr>
    <tr>
      <td>code author</td>
      <td><a href="https://github.com/torvalds/linux/blob/v6.13/Documentation/watchdog/pcwd-watchdog.rst?plain=1#L68">[commit]</a></td>
    </tr>
    <tr>
      <td>user</td>
      <td><a href="https://github.com/torvalds/linux/blob/v6.13/drivers/usb/gadget/function/u_fs.h#L222">[commit]</a></td>
    </tr>
    <tr>
      <td>parody song quote</td>
      <td><a href="https://www.phrases.org.uk/bulletin_board/47/messages/84.html">David Bowie</a> quote <a href="https://github.com/torvalds/linux/blob/v6.13/arch/sparc/kernel/wuf.S#L204">[commit]</a></td>
    </tr>
    <tr>
      <td>the GPU?</td>
      <td>This commit, by the esteemed <a href="https://rosenzweig.io/">Alyssa Rosenzweig</a>, was the only commit using female pronouns which I could attribute to a <a href="https://rosenzweig.io/blog/growing-up-alyssa.html">woman</a>. <a href="https://github.com/torvalds/linux/blame/v6.13/drivers/gpu/drm/panfrost/panfrost_issues.h#L113">[commit]</a></td>
    </tr>
  </tbody>
</table>

<h3 id="womanwomen">“woman”/”women”</h3>

<p>The only reference to a <a href="https://livegrep.com/search/linux?q=%5Cb%5CW*woman%5CW*%5Cb&amp;fold_case=auto&amp;regex=true&amp;context=true">“woman”</a> in the kernel is in <a href="https://github.com/torvalds/linux/blob/ffd294d346d185b70e28b1a28abe367bbfe53c04/lib/decompress_bunzip2.c#L23-L39">a eulogy</a></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I would ask that anyone benefiting from this work, especially those
using it in commercial products, consider making a donation to my local
non-profit hospice organization in the name of the woman I loved, who
passed away Feb. 12, 2003.
</code></pre></div></div>

<p>And the only usage of <a href="https://livegrep.com/search/linux?q=%5Cb%5CW*women%5CW*%5Cb&amp;fold_case=auto&amp;regex=true&amp;context=true">“women”</a> is in <a href="https://github.com/torvalds/linux/blob/ffd294d346d185b70e28b1a28abe367bbfe53c04/Documentation/process/howto.rst?plain=1#L506">contribution guidelines documentation</a>.</p>

<h2 id="swearing-in-linux">Swearing in Linux</h2>

<p>This paper shows there is a correlation between <a href="https://cme.h-its.org/exelixis/pubs/JanThesis.pdf">swear word usage and code quality</a>. In unrelated news, there is a large, negative trend line for the <a href="https://www.vidarholen.net/contents/wordcount/#fuck*,shit*,damn*,idiot*,retard*">amount of swearing in Linux</a> over the past ten years.</p>

<h2 id="age">Age</h2>

<p>The kernel continues to evolve as new developers come in. The amount of contributors joining and staying on the Linux project <a href="https://bitergia.com/blog/opensource/demographics-of-linux-kernel-developers-how-old-are-they/">keeps</a> <a href="https://www.zdnet.com/article/graying-linux-developers-look-for-new-blood/">dropping</a>.</p>

<p>For example, efforts to push Rust into Linux have been causing controversy. Eventually, Linus himself will have to step down. Being a maintainer is stressful, and even <a href="https://www.redox-os.org/news/open-source-mental-health/">maintainers are human</a>.</p>

<p>Further, contributions are done less than ever by open source hackers. Linux contributions are becoming more commercial, which means that contributors’ incentives may not align with that of the Linux project as a whole. <a href="https://www.linuxfoundation.org/blog/blog/jonathan-corbet-on-linux-kernel-contributions-community-and-core-needs">Over 90%</a> of contributors are being paid by their employer to submit patches. Nobody wants to pay to build the infrastructure to make Linux development better (ex: Coccinelle) or to write high quality documentation. These create barriers to the natural growth of the project among younger developers and other demographics.</p>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><summary type="html"><![CDATA[How are pronouns used in the Linux kernel? I analyzed the distribution of pronouns in the 6.13 Linux kernel source. Unsurprisingly, I find that male pronouns are common, but this makes female pronouns all the more unusual.]]></summary></entry><entry><title type="html">Bug snack: `fork`s upon `fork`s</title><link href="https://godsped.com/fork" rel="alternate" type="text/html" title="Bug snack: `fork`s upon `fork`s" /><published>2024-10-11T00:00:00+00:00</published><updated>2024-10-11T00:00:00+00:00</updated><id>https://godsped.com/fork-question</id><content type="html" xml:base="https://godsped.com/fork"><![CDATA[<p>I wouldn’t eat a cockroach. But this bug snack is quite delectable. This “bug” is a fun little puzzle to solve. I think this is an interesting question to discriminate OS programming experience across a wide range of skill levels.</p>

<aside class="sidebar__left">
<nav class="toc">
    <header><h4 class="nav__title"><i class="fas fa-file-alt"></i> On This Page</h4></header>
<ul class="toc__menu" id="markdown-toc">
  <li><a href="#part-1" id="markdown-toc-part-1">Part 1</a>    <ul>
      <li><a href="#by-inspecting-the-code-how-many-processes-are-created-and-how-many-times-is-ls-run" id="markdown-toc-by-inspecting-the-code-how-many-processes-are-created-and-how-many-times-is-ls-run">By inspecting the code, how many processes are created and how many times is <code class="language-plaintext highlighter-rouge">ls</code> run?</a></li>
    </ul>
  </li>
  <li><a href="#part-2" id="markdown-toc-part-2">Part 2</a>    <ul>
      <li><a href="#what-is-the-output-of-this-program-how-many-times-do-you-think-start-and-else-are-printed" id="markdown-toc-what-is-the-output-of-this-program-how-many-times-do-you-think-start-and-else-are-printed">What is the output of this program? How many times do you think “start” and “else” are printed?</a></li>
    </ul>
  </li>
  <li><a href="#part-3" id="markdown-toc-part-3">Part 3</a>    <ul>
      <li><a href="#with-access-to-edit-and-run-the-code-explain-this-behavior" id="markdown-toc-with-access-to-edit-and-run-the-code-explain-this-behavior">With access to edit and run the code, explain this behavior.</a></li>
    </ul>
  </li>
</ul>

  </nav>
</aside>
<!-- https://github.com/junqing-zhang/junqing-zhang.github.io/blob/master/_includes/toc -->

<p><br /></p>

<h1 id="part-1">Part 1</h1>
<h2 id="by-inspecting-the-code-how-many-processes-are-created-and-how-many-times-is-ls-run">By inspecting the code, how many processes are created and how many times is <code class="language-plaintext highlighter-rouge">ls</code> run?</h2>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">arg</span><span class="p">[])</span>
<span class="p">{</span>
    <span class="n">fork</span> <span class="p">();</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">fork</span> <span class="p">())</span> <span class="p">{</span>
      <span class="n">fork</span> <span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"/bin/ls"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span>
        <span class="n">execv</span> <span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">argv</span><span class="p">);</span>
        <span class="n">fork</span> <span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<details>
  <summary><b>Reveal Answer</b></summary>

  <p>Let’s trace the execution of this code snippet.</p>

  <p>The initial <code class="language-plaintext highlighter-rouge">fork()</code> call creates a child process, resulting in two processes. Now there are two processes which proceed to the <code class="language-plaintext highlighter-rouge">if (fork())</code>. Note that <code class="language-plaintext highlighter-rouge">if (fork())</code> is equivalent to <code class="language-plaintext highlighter-rouge">if (fork() != 0)</code>. <code class="language-plaintext highlighter-rouge">fork</code> works by cloning the entire data of the process. <code class="language-plaintext highlighter-rouge">fork</code> returns to the parent process with the process ID (PID) of the child and returns in the child process with <code class="language-plaintext highlighter-rouge">0</code>.</p>

  <p>Thus, there are now two processes which return inside the <code class="language-plaintext highlighter-rouge">if (fork())</code> with a return code <code class="language-plaintext highlighter-rouge">&gt; 0</code> and two with return code <code class="language-plaintext highlighter-rouge">== 0</code>.
Two processes fall through to the <code class="language-plaintext highlighter-rouge">if</code> block and then <code class="language-plaintext highlighter-rouge">fork()</code>, creating two more processes.</p>

  <p>The other two processes take the <code class="language-plaintext highlighter-rouge">else</code> block. The <code class="language-plaintext highlighter-rouge">execv()</code> call switches the process to <code class="language-plaintext highlighter-rouge">ls</code>. <code class="language-plaintext highlighter-rouge">execv</code> replaces the current process with the <code class="language-plaintext highlighter-rouge">ls</code> command, so no additional processes are created.</p>

  <p>Therefore, a total of six processes are created, and the ls command is run twice.</p>

  <p><img src="/images/bug_snacks/fork-tree.png" alt="tree diagram of the processes created" /></p>

</details>

<h1 id="part-2">Part 2</h1>
<h2 id="what-is-the-output-of-this-program-how-many-times-do-you-think-start-and-else-are-printed">What is the output of this program? How many times do you think “start” and “else” are printed?</h2>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">arg</span><span class="p">[])</span>
<span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"start"</span><span class="p">);</span>
    <span class="n">fork</span> <span class="p">();</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">fork</span> <span class="p">())</span> <span class="p">{</span>
      <span class="n">fork</span> <span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"/bin/ls"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span>
        <span class="n">execv</span> <span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">argv</span><span class="p">);</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"else"</span><span class="p">);</span>
        <span class="n">fork</span> <span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<details>
  <summary><b>Reveal Answer</b></summary>

  <p>Answer: <code class="language-plaintext highlighter-rouge">startstartstartstart</code> is printed and <code class="language-plaintext highlighter-rouge">else</code> is not printed. (<code class="language-plaintext highlighter-rouge">else</code> could be printed in a weird edge case where <code class="language-plaintext highlighter-rouge">execv</code> fails, say due to exhausted process space or <code class="language-plaintext highlighter-rouge">/bin/ls</code> not existing.)</p>

  <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./a.out 
startstartstartstarta.out  main.c
a.out  main.c
</code></pre></div>  </div>

</details>

<h1 id="part-3">Part 3</h1>
<h2 id="with-access-to-edit-and-run-the-code-explain-this-behavior">With access to edit and run the code, explain this behavior.</h2>

<details>
  <summary><b>Reveal Answer</b></summary>

  <p>In short, the <code class="language-plaintext highlighter-rouge">printf</code> does not have a <code class="language-plaintext highlighter-rouge">\n</code>, so the buffer does not get flushed. Each fork clones the entire process (and its unflushed buffer). All of the forked process’ buffers get printed to the console.</p>

  <p>This bug is kind of interesting because the <code class="language-plaintext highlighter-rouge">execv</code> is a red herring. If you change that line to something like <code class="language-plaintext highlighter-rouge">return</code> or <code class="language-plaintext highlighter-rouge">exit</code> you get a different number of prints. Moreover, this is not a bug at all — it’s the defined behavior of <code class="language-plaintext highlighter-rouge">fork</code>. This makes the behavior undebuggable with gdb.</p>

  <div class="commentary-author"><a href="https://cseweb.ucsd.edu/~voelker/" style="color:white;">Geoffrey M. Voelker</a></div>
  <div class="commentary-body">

    <p>in Unix, output is controlled by the line mode (a part of a larger
subsystem called the line discipline). essentially the line mode has
two options, cooked and raw (yes, those are the names). in cooked
mode, for efficiency, output from <code class="language-plaintext highlighter-rouge">printf</code> is buffered in the process
until a newline, at which point the buffer gets printed. so
<code class="language-plaintext highlighter-rouge">printf("hi")</code> gets buffered, but <code class="language-plaintext highlighter-rouge">printf("hi\n")</code> gets immediately
printed. and cooked mode is the default. in raw mode, everything
gets printed immediately (even single characters).</p>

    <p>since <code class="language-plaintext highlighter-rouge">printf("hi")</code> is buffered, when the program calls fork the child
also has <code class="language-plaintext highlighter-rouge">"hi"</code> in its buffer (and also their children). this
eventually results in multiple processes printing hi even though only
the original parent called <code class="language-plaintext highlighter-rouge">printf</code>.</p>

    <p>in short, on Unix the newline matters.</p>

    <p>for your original program, running <code class="language-plaintext highlighter-rouge">stty raw</code> in your shell before you
run the program should make it behave more like you expect it would.</p>

  </div>

  <p>Don’t believe me? How can we test this? Tools like gdb and strace will not be of much use. To test this theory, we need to realize that the unbuffered text does not get magically printed by the shell. The following program does not print “start”.</p>

  <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">arg</span><span class="p">[])</span>
<span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"start"</span><span class="p">);</span>
    <span class="n">raise</span><span class="p">(</span><span class="n">SIGABRT</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>  </div>

  <p>It is <a href="https://superuser.com/a/1288912"><code class="language-plaintext highlighter-rouge">libc</code> semantics</a> to flush the buffer on clean exit. This is not OS semantics, but the implementation of how <code class="language-plaintext highlighter-rouge">libc</code> exits. Of course, if you print with a newline then this problem will never arise.</p>

</details>

<hr />

<p>Thanks to Anon. Calc and Professor Voelker.</p>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="bug snack" /><summary type="html"><![CDATA[I wouldn’t eat a cockroach. But this bug snack is quite delectable. This “bug” is a fun little puzzle to solve. I think this is an interesting question to discriminate OS programming experience across a wide range of skill levels.]]></summary></entry><entry><title type="html">100 Best Movies</title><link href="https://godsped.com/100-movies/" rel="alternate" type="text/html" title="100 Best Movies" /><published>2024-10-06T00:00:00+00:00</published><updated>2024-10-06T00:00:00+00:00</updated><id>https://godsped.com/best-movies</id><content type="html" xml:base="https://godsped.com/100-movies/"><![CDATA[<p>100 movies I recommend. I make no attempt to rank or find the “best”; these are simply what I subjectively found memorable.</p>

<table>
  <thead>
    <tr>
      <th>Movie Name</th>
      <th>Year</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/1056360-american-fiction">American Fiction</a></td>
      <td>2023</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/76600-avatar-the-way-of-water">Avatar: The Way of Water</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/242224-the-babadook">The Babadook</a></td>
      <td>2014</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/115-the-big-lebowski">The Big Lebowski</a></td>
      <td>1998</td>
      <td>incredibly funny</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/823754-bo-burnham-inside">Bo Burnham: Inside</a> :star:</td>
      <td>2021</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/814776-bottoms">Bottoms</a></td>
      <td>2023</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/155-the-dark-knight">The Dark Knight</a></td>
      <td>2008</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/635302">Demon Slayer: Mugen Train</a></td>
      <td>2020</td>
      <td>epic animated fighting</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/619730-don-t-worry-darling">Don’t Worry Darling</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/38-eternal-sunshine-of-the-spotless-mind">Eternal Sunshine of the Spotless Mind</a></td>
      <td>2004</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/545611-everything-everywhere-all-at-once">Everything Everywhere All at Once</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/787752-fresh">Fresh</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/17768-a-funny-thing-happened-on-the-way-to-the-forum">A Funny Thing Happened on the Way to the Forum</a></td>
      <td>1966</td>
      <td>timeless Plautine comedy</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/949-heat">Heat</a> :star:</td>
      <td>1995</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/2640-heathers">Heathers</a></td>
      <td>1989</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/21614-hera-pheri">Hera Pheri</a></td>
      <td>2000</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/840430-the-holdovers">The Holdovers</a></td>
      <td>2023</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/3782">Ikiru</a> :star:</td>
      <td>1952</td>
      <td>a timeless take on life and bureaucracy</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/245891-john-wick">John Wick</a></td>
      <td>2014</td>
      <td>I love the world and the whole series</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/637-la-vita-e-bella">Life is Beautiful</a></td>
      <td>1997</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/560016-monkey-man">Monkey Man</a></td>
      <td>2024</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/242582-nightcrawler">Nightcrawler</a></td>
      <td>2014</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/615457-nobody">Nobody</a></td>
      <td>2021</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/639933-the-northman">The Northman</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/1542-office-space">Office Space</a></td>
      <td>1999</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/4977">Paprika</a></td>
      <td>2007</td>
      <td>what dreams are made of</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/496243">Parasite</a></td>
      <td>2019</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/976893-perfect-days">Perfect Days</a></td>
      <td>2023</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/555604-guillermo-del-toro-s-pinocchio">Pinocchio (Guillermo del Toro)</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/14072">Rab Ne Bana Di Jodi</a></td>
      <td>2008</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/274-the-silence-of-the-lambs">The Silence of the Lambs</a></td>
      <td>1991</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/324857-spider-man-into-the-spider-verse">Spider-Man: Into the Spider-Verse</a></td>
      <td>2018</td>
      <td>mindblowing animation and music</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/1091-the-thing">The Thing</a></td>
      <td>1982</td>
      <td>horror, but the characters behave intelligently</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/605886-to-catch-a-killer">To Catch a Killer</a></td>
      <td>2023</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/10681-wall-e">WALL·E</a></td>
      <td>2008</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/785084-the-whale">The Whale</a> :star:</td>
      <td>2022</td>
      <td>MUST WATCH</td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/1587-what-s-eating-gilbert-grape">What’s Eating Gilbert Grape</a></td>
      <td>1993</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/1184918-the-wild-robot">The Wild Robot</a></td>
      <td>2024</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/724495-the-woman-king">The Woman King</a></td>
      <td>2022</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/29845-a-woman-under-the-influence">A Woman Under the Influence</a></td>
      <td>1974</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="https://www.themoviedb.org/movie/10201-yes-man">Yes Man</a></td>
      <td>2008</td>
      <td> </td>
    </tr>
    <tr>
      <td>To be continued…</td>
      <td> </td>
      <td> </td>
    </tr>
  </tbody>
</table>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><summary type="html"><![CDATA[100 movies I recommend. I make no attempt to rank or find the “best”; these are simply what I subjectively found memorable.]]></summary></entry><entry><title type="html">Compile time techniques for safer firmware</title><link href="https://godsped.com/safe-firmware/" rel="alternate" type="text/html" title="Compile time techniques for safer firmware" /><published>2024-09-03T00:00:00+00:00</published><updated>2024-09-03T00:00:00+00:00</updated><id>https://godsped.com/osfc24</id><content type="html" xml:base="https://godsped.com/safe-firmware/"><![CDATA[<h2 id="provable-security-in-embedded-systems-verification-work-in-tock-os">Provable Security in Embedded Systems: Verification Work in Tock OS</h2>

<blockquote>
  <p><a href="https://tockos.org/">Tock OS</a> secures millions of devices and uses language, architectural, and formal techniques to statically enforce system guarantees. This talk will go over how the Tock operating system eliminates many bugs that plague other OSes at compile time. I will demonstrate how we are mitigating logic bugs in Tock OS by using lightweight formal verification (<a href="https://github.com/flux-rs/flux">Flux</a>).</p>
</blockquote>

<div class="notice notice--announcement">
  <h4 id="update-the-results-of-our-work-were-published-at-sosp-2025">UPDATE: The <a href="https://ranjitjhala.github.io/static/sosp25-ticktock.pdf">results of our work</a> were published at <a href="https://sigops.org/s/conferences/sosp/2025/schedule.html">SOSP 2025</a>.</h4>
</div>
<h2 id="watch-now">Watch now</h2>

<p><a href="https://youtu.be/S7LZKfoEkYM"><img src="/files/osfc24/img/thumbnail.jpeg" alt="" /></a></p>

<p><a class="btn btn--danger" style="background: red;" href="https://youtu.be/S7LZKfoEkYM">Watch on YouTube</a>
<a class="btn btn--danger" style="background: #008abf;" href="https://www.osfc.io/2024/talks/provable-security-in-embedded-systems-verification-work-in-tock-os/">Watch on Vimeo</a></p>

<h2 id="slides">Slides</h2>

<iframe src="/files/osfc24/slides.html" width="100%" height="500px" style="border:none;"></iframe>

<p><a class="btn" href="/files/osfc24/slides.html">View slides in fullscreen</a></p>

<p>Find the <a href="https://github.com/Samir-Rashid/osfc24-tockos-lightweight-verification/blob/master/slides.pdf">pdf of the slides</a> and the source code for the slides and demo <a href="https://github.com/Samir-Rashid/osfc24-tockos-lightweight-verification">in this repo</a>.</p>

<h2 id="connect-with-us">Connect with us!</h2>
<h3 id="tock-safe-embedded-operating-system">Tock: safe embedded operating system</h3>
<ul>
  <li>Tock is open source!</li>
  <li><a href="https://tockos.org/">tockos.org</a></li>
  <li>Join Tock Slack, Matrix, and verification mailing list</li>
</ul>

<h3 id="flux-scalable-rust-verification">Flux: scalable Rust verification</h3>
<blockquote>
  <p>Proving should be as easy as programming</p>
</blockquote>

<ul>
  <li><a href="https://github.com/flux-rs/flux/">github.com/flux-rs/flux/</a></li>
  <li><a href="https://flux.programming.systems/">Live demo</a></li>
</ul>

<h2 id="share-the-presentation-permalink-godspedcomsafe-firmware">Share the presentation permalink: <a href="https://godsped.com/safe-firmware/">godsped.com/safe-firmware</a></h2>

<p>I want to credit the amazing support and work on this project done by Pat Pannuto, Nico Lehmann, Evan Johnson, and Ranjit Jhala.</p>

<p>I must to give an enormous thanks to OSFC for sponsoring me to present. If you found this presentation interesting, you should consider going to the <a href="https://www.osfc.io/">next OSFC</a>!</p>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="talk" /><category term="research" /><category term="recommended read" /><summary type="html"><![CDATA[Provable Security in Embedded Systems: Verification Work in Tock OS]]></summary></entry><entry><title type="html">10 reasons I chose to join Triton UAS</title><link href="https://godsped.com/10-reasons" rel="alternate" type="text/html" title="10 reasons I chose to join Triton UAS" /><published>2024-05-04T00:00:00+00:00</published><updated>2024-05-04T00:00:00+00:00</updated><id>https://godsped.com/10-reasons-tuas</id><content type="html" xml:base="https://godsped.com/10-reasons"><![CDATA[<div class="notice notice--announcement">

  <h4>

This post is a reprint of the <a href="http://tritonuas.com/blog/10-reasons/">original post</a> I wrote on the Triton UAS blog. This post has been edited to add <code class="language-plaintext highlighter-rouge">COMMENTARY</code> blocks with my own commentary.
</h4>

  <h4>

<a href="http://tritonuas.com/">Triton UAS</a> is a club at UC San Diego which makes Unmanned Aerial Systems, aka autonomous planes.
</h4>
</div>

<p>LA JOLLA, CA - <a href="https://ucsd.edu/">UC San Diego</a>’s massive campus offers hundreds of clubs to join and thousands of classes to take. When I came to UCSD, I spent a lot of time shopping around for what I wanted to do with my free time here. I read through the list of all clubs multiple times to find a place to belong. I want to share why Triton UAS members chose to join, and why sticking with Triton UAS for four years turned out to be the best decision I could ever make.</p>

<aside class="sidebar__left">
<nav class="toc">
    <header><h4 class="nav__title"><i class="fas fa-file-alt"></i> On This Page</h4></header>
<ul class="toc__menu" id="markdown-toc">
  <li><a href="#1-the-project-is-exciting" id="markdown-toc-1-the-project-is-exciting">1. The project is exciting</a></li>
  <li><a href="#2-making-something-cool" id="markdown-toc-2-making-something-cool">2. Making something cool</a></li>
  <li><a href="#3-mentorship" id="markdown-toc-3-mentorship">3. Mentorship</a></li>
  <li><a href="#4-collaboration" id="markdown-toc-4-collaboration">4. Collaboration</a></li>
  <li><a href="#5-competition" id="markdown-toc-5-competition">5. Competition</a></li>
  <li><a href="#6-tuas-is-approachable" id="markdown-toc-6-tuas-is-approachable">6. TUAS is approachable</a></li>
  <li><a href="#7-culture" id="markdown-toc-7-culture">7. Culture</a></li>
  <li><a href="#8-career-opportunities" id="markdown-toc-8-career-opportunities">8. Career Opportunities</a></li>
  <li><a href="#9-alumni" id="markdown-toc-9-alumni">9. Alumni</a></li>
  <li><a href="#10-and-takeoff" id="markdown-toc-10-and-takeoff">10. And Takeoff</a></li>
  <li><a href="#11-mentoring" id="markdown-toc-11-mentoring">11. Mentoring</a></li>
</ul>

  </nav>
</aside>
<!-- https://github.com/junqing-zhang/junqing-zhang.github.io/blob/master/_includes/toc -->

<div class="commentary-author">Commentary</div>
<div class="commentary-body">

Clearly I had nothing to do during lockdown before and during college because I made a huge 43 page document where I wrote everything I need to know about UCSD. I went through the entire UCSD club list and course catalog. I made a list of 18 clubs I wanted to check out.
Reading through it 4 years later, almost all of it except for course planning turned out to be completely irrelevant. I guess I had no one to talk to, so I went on the internet to know what the school I go to is like.
</div>

<h2 id="1-the-project-is-exciting">1. The project is exciting</h2>

<p>Triton UAS participates in the <a href="https://suas-competition.org/">Student Unmanned Aerial Systems competition</a>. Each year, we design and manufacture a plane from scratch to compete. Then our plane autonomously flies an obstacle course, searches for lost targets on the ground, and safely delivers aid to their locations.</p>

<p><img src="/images/10-reasons/size.webp" class="post-image" loading="lazy" /></p>

<p>The project is so cool! We build a real, double-than-human sized plane that carries out a mission autonomously. It is inspiring to take part in the process of going from nothing to plane. At the end of the year, I can squint up into the sky and see my work flying.</p>

<p><img src="/images/10-reasons/sky.webp" class="post-image" loading="lazy" /></p>

<blockquote>
  <p>Flying to the moon</p>
</blockquote>

<div class="quote-author">BRANDON VINH</div>
<div class="quote-body">

I first heard about TritonUAS while searching through a large list of student project teams that I was interested in. Immediately reading through their website, I was hooked and scheduled a meeting with the project manager. What he told me solidified my interest. They make their own autonomous aircraft, which at that time I had never done before, and they teach everything we need to know to make it? Of course I'm going to join.

First stepping into the lab later in the year, my mind was absolutely blown. The project manager explained to me that the TritonUAS team has existed for almost 20 years and has competed in the annual SUAS international competition for almost every year of its existence. The ever-changing competition task guidelines inspire innovation and creativity, as each year they design and manufacture a new aircraft from scratch, and all parts are made by the students. Because experience is not required, they will teach you everything you need to know. Through this, I learned manufacturing processes like wet-composite layups to build the wings and the fuselage with carbon fiber and fiber glass. CNC laser cutting and hot wire cutting to create all of the ribs, bulkheads, wing molds and more. Design software like Solidworks, Onshape, and Matlab were also taught. Tolerancing 3D printed parts to make molds for forged carbon fiber, optimization to understand the best sizing recommendations for the aircraft, and computational fluid dynamic simulations are all things I have learned and are all done by the students! Best of all, after your first quarter, you are immediately added to the competition aricraft design team and are able to create your own parts for the aircraft. It was rewarding and amazing.
</div>

<div class="commentary-author">Commentary</div>
<div class="commentary-body">

I first came across TUAS during Zoom University. There was an online event where you could meet all engineering clubs. I was popping into the rooms, listening to the pitches, and asking questions. I came across Garrett, who was the software lead. He was presenting slides about TUAS and told me about what he worked on. In a way that is impossible to describe, I was hooked. He is an amazing nice person and geniunely curious. As a freshman, I knew nothing compared to the leads. If I ever asked any question about what Docker is, or any of the multitude of things they had set up, the leads were ready to answer questions and cared about helping us. I didn't know about CI, Pythonic stuff, or anything other than basic coding logic. It was so funny becoming friends with people I only knew over Zoom.
</div>

<h2 id="2-making-something-cool">2. Making something cool</h2>

<p>I love that we build a real system. It is no comparison that an autonomous flying plane is cooler than any class project. Some of the <a href="https://tritonuas.com/project/">things we do</a> have never been done, by students or professionals. Autonomous vehicles are still a largely unsolved problem — you cannot search for existing solutions to the problems we face. Building planes is tough, and moreso given our time and monetary constraints.</p>

<p>However, we rise to the challenge. Triton UAS is a team effort. It is amazing to create something that I could never do on my own.</p>

<p><img src="/images/10-reasons/team2.webp" class="post-image" loading="lazy" /></p>

<div class="quote-author">SAMIR RASHID</div>
<div class="quote-body">

My only previous experience was with highschool FIRST Robotics Competition. I remember finding working on robots extremely difficult, but we had plenty of mentor help and you could always find reference implementations online. In comparison, Triton UAS is engineering its way through problems that do not have well defined solutions. We have to figure things out ourselves instead of treading paths where others have discovered the dangers for us. I feel satisfaction by watching us step towards conquering these extremely hard problems.
</div>

<h2 id="3-mentorship">3. Mentorship</h2>

<p>Triton UAS taught me that you can learn anything. Each team lead is an expert at what they do. The leads will teach you everything you need to know. We have an onboarding plane project which allows new members to hit the ground running. Rookie members learn our manufacturing processes and the onboarding projects help all the teams work together towards a unified goal. Experienced members use this time to work on the design of the competition plane. New recruits get to deploy something they built within their first quarter.</p>

<p><img src="/images/10-reasons/mentor2.webp" class="post-image" loading="lazy" /></p>

<p>Even outside of TUAS, making friends with upperclasspeople can help you navigate school and choosing your future.</p>

<div class="quote-author"> ANTHONY TARBINIAN</div>
<div class="quote-body">

I think the best reason to join TritonUAS is to get the opportunity to learn by doing. I think there's no better way to pick up new skills then to set out to work on a project. TritonUAS provides members with opportunities to get involved on a long term project where they can be free to make mistakes and learn new skills.
</div>

<p><img src="/images/10-reasons/tour.webp" class="post-image" loading="lazy" /></p>

<h2 id="4-collaboration">4. Collaboration</h2>
<p>There are several subteams which are critical to our mission: <em>airframe, business, embedded, and software</em>. We actively encourage collaboration between teams and make sure that we are foremost learning and having fun. Our airdrop task requires us to design a mechanism to deliver a package to the target. For the dropping mechanism, airframe designed a door in the bottom of the plane and iterated on the internal machinery. Members collaborated with embedded to make the electronics for the guided payload and enlisted software to handle the logic for dropping and making sure that the communications fail safely.</p>

<p><img src="/images/10-reasons/layup.webp" class="post-image" loading="lazy" /></p>

<p>TUAS is in the sweet spot of size. You can get to know everyone in the club. Also, you are not a cog working on a random minor aspect of the plane. Another great part of the community is that you get to interact with the local domain experts. Within TUAS, I have met students who have spent hundreds of hours working with carbon composites, the state of the art of machine learning research, and experts in PCB manufacturing.</p>

<p>Check out why members of our different subteams think:</p>

<details>
  <summary>

    <p><strong>Airframe</strong>: 🛫</p>
  </summary>

  <div class="quote-author">JACK SWANTKO</div>
  <div class="quote-body">

From Day One in TUAS we have been learning all sorts of manufacturing techniques. I learned how to do carbon fiber layups, create airfoils, and laser cut wood all in the first couple weeks. As the year went on we started designing specific parts of the plane, for me it was the tail joints and control surfaces. It was an interesting and educational process trying to design a connection that was strong enough to withstand the many forces acting on the tail while minimizing weight and difficulty of manufacturing. Overall, TUAS has been a fun place to learn about all the different steps in the engineering process from day one.
</div>
</details>

<details>
  <summary>

    <p><strong>Software</strong>: 💻</p>
  </summary>

  <p>I liked that TUAS is uniquely <strong>both</strong> a novel hardware chanllenge and a novel software challenge. Although self driving is not solved, the kinds of things you do with terrestrial robotics are mostly well-defined issues by now. Whereas there is less research in the SOTA of autonomous planes. We face a different set of constraints and have to engineer solutions which I haven’t seen published anywhere online. Also we have great onboarding for people at all levels: people who have never coded can learn from our git workshop, or we will teach Computer Vision to those new to doing vision.</p>

  <div class="quote-author"> ANTHONY TARBINIAN</div>
  <div class="quote-body">

I also think TritonUAS is unique among other organizations and projects for how wide it's scope is. At least for the software team, we touch many aspects of computer science ranging from computer vision and machine learning, systems and networking, and search algorithms. It's a great place to acquire a wide breadth of knowledge and get to explore interests in a supportive environment.</div>

</details>

<details>
  <summary>

    <p><strong>Embedded</strong>: 🔌</p>
  </summary>

  <div class="quote-author">ALEJANDRO MARTINEZ</div>
  <div class="quote-body">

If it has to do with power, general electronics, or microcontrollers and the software that interfaces them, the embedded team does it. I like the variety you can find in the embedded team. On one hand you have people who are purely on the electrical engineering side of things and work with things like powerboard, and on the other people who prefer software in a more hardware context working on things like controls algorithms for the guided payloads.
</div>

  <p><img src="/images/10-reasons/TUAS_PCB.webp" class="post-image" loading="lazy" /></p>

</details>

<details>
  <summary>

    <p><strong>Business</strong>: 🕴</p>
  </summary>

  <p>We run the finances and logistics for the team. Business is charge of corporate sponsorships, running fundraisers, and managing expenses. We also manage external communication through this <a href="https://tritonuas.com/blog/">blog</a>, our <a href="https://www.linkedin.com/company/tritonuas">LinkedIn</a>, and <a href="https://www.instagram.com/tritonuas/">Instagram</a>. We also make awesome merch and bring the team together with our epic socials like the beach day and TUAS Olympics.</p>
</details>

<hr />

<p>And remember that these distinctions are fluid. We have people in multiple subteams, or people who jump over for a single project. For example, a software member could hop into the embedded meetings for a quarter to work on our camera gimbal.</p>

<h2 id="5-competition">5. Competition</h2>
<p>Our work culminates in flying out to the competition in Maryland each year. We fly our plane autonomously all the way from California to Maryland! Unfortunately, it only sits autonomously in the cargo hold of a Boeing airliner.</p>

<p>I find the deadline very motivating. The bonding we experience at deadlines is stronger than I have ever experienced elsewhere. Everyone bands together to meet the integration test deadlines. I know that if I ever need help, I can call out and multiple people will come to help me at any time of day or night.</p>

<p><img src="/images/10-reasons/sticks_and_stones.webp" class="post-image" loading="lazy" /></p>

<p>Competition also means that a lot of work has to be done each year; we design and build a new plane every year to meet the ever-changing competition objectives. We are not creating a project that gets thrown away after demoing 24 hours of work or presenting a quarter of work; our plane is not a one-off launch that then turns into an art exhibit. We must work to create reliable systems which will be maintainable by other people. We work to improve our systems year-over-year. In addition to short term goals, we have multi-year projects to improve the plane, such as turning electronics wiring into a custom PCB, developing new Computer Vision models for dynamic detection, and experimenting with new carbon fiber manufacturing techniques for the plane.</p>

<div class="quote-author"> DAVID NIELSON</div>
<div class="quote-body">

I like our rapid iteration. We output ≥1 plane per year, so there is the opportunity to see your design carrying out the mission and improve it based on the results.
</div>

<p>TUAS is an established club. TUAS has been around for nearly two decades, whereas many of the other robotics and aviation clubs were founded a few years ago. This means that we have to work with some systems that have been made entirely by graduated students. We have the realistic situation of working with hardware and decisions made long ago.</p>

<p><img src="/images/10-reasons/software_meeting2.jpg" class="post-image" loading="lazy" /></p>

<h2 id="6-tuas-is-approachable">6. TUAS is approachable</h2>
<p>There is <strong>no</strong> mandatory attendance policy. There is <strong>no</strong> required previous experience. There are <strong>no</strong> interviews. There is <strong>no</strong> member fee. I love that TUAS is open to everyone from every background, experience, and history. In Fall, our number one goal is to mentor new members. We are not screening new hires for their experience to be able to work on their minor part of the system and learn nothing new.</p>

<p><img src="/images/10-reasons/onboarding.webp" class="post-image" loading="lazy" /></p>

<p>The more you put into the club, the more you get back. We understand people have other obligations, especially with the gruelling quarter system. We just ask that members communicate with us. The great part is that you get to “own” your task and get to make decisions yourself.</p>

<p>We do not just say we are open to everyone, we actually are. You can check out all our <a href="https://tritonuas.com/calendar/">meeting times</a> on our website, you can join our Discord server, or meet our members at campus outreach events (library walk tabling, <a href="https://tesc.ucsd.edu/eotg">EOTG</a>). We want to help the greater engineering community outside of UCSD. We visit San Diego fairs and schools, publish documentation and tutorials publicly on our wiki, publish a <a href="https://tritonuas.com/blog/blog-post-21/">whitepaper</a> of our work, and license our code as Free Software.</p>

<div class="commentary-author">Commentary</div>
<div class="commentary-body">

I like that our projects are not 4 year long rockets that may end up blowing up. Our iteration has allowed me to learn so much more and experiment with many different parts of our systems.

Other schools and other clubs have horrible interview processes. For example, UCB is infamous for clubs having several rounds of interviews. UCSD's main rocketry club, SEDS, asked me brainteasers in the interview.

I joined SEDS and Triton Robotics for about a week each. Both clubs gave me horrible first impressions. The Triton Robotics software lead did not know anything. He was only into computer vision and pawning off tasks without giving any help. SEDS has literally zero software. They jebaited me saying there was something to work on, but they just wanted me to do CRUD work. I would have been making software to view launch logs and support the ground control station. The lead for the project I was assigned to did not know any software himself. Also, they cancelled the project I worked on the next year (cubesat), so I dodged a bullet. The rocket clubs are MATLAB enjoyers and don't want any software engineering.

If I remember correctly, neither Triton Robotics nor SEDS were using git when I joined. Also it's stupid that SEDS has 100k in funding yet still begs community members for money and charges fees to students.
</div>

<p><img src="/images/10-reasons/outreach.webp" class="post-image" loading="lazy" />
<img src="/images/10-reasons/outreach2.webp" class="post-image" loading="lazy" /></p>

<div class="quote-author">TYLER LENTZ</div>
<div class="quote-body">

I joined Triton UAS at the beginning of my freshman year. At first it was incredibly intimidating because I quickly realized that there was a lot of software knowledge that I just didn't have: I had never used a Linux command line, never used Git branches or GitHub Pull requests, and never used any of the programming languages TUAS used. But it never was insurmountable, and I was encouraged every step of the way. It might have taken me an entire quarter to make my first contribution, but it never felt like I wasn't making progress. Every week I was learning new things, getting good feedback, and feeling more and more like a member of the team. The camaraderie really got me through the worst of the pandemic, and made me feel like I had a community at UCSD when I had barely even seen the campus.

Now, as a Software lead, whenever I see a new member that wants to join the club, I always make it a high priority to ensure that I put in as much effort to helping them get started as I can. I feel a strong motivation to give back to the club, and help mentor the next generation of TUAS members.
</div>

<h2 id="7-culture">7. Culture</h2>
<p>The leads are so kind. I have seen that when people see notice someone struggling, they band together to raise the struggling person up. I saw this camaraderie when the software team switched the core flight controller to C++ from Python. To do this, we switched to the CMake build system. We were all unfamiliar with setting up C++ project infrastructure and had to figure out many things. Together, we succeeded against The Great CMake War (c. 2024).</p>

<p><img src="/images/10-reasons/software_meeting.webp" class="post-image" loading="lazy" /></p>

<p>We have open documentation, actively share, and encourage people to attend other subteams’ meetings. I have so much secondhand knowledge about carbon fiber molding from watching and listening to explanations from airframe members. People who have spent thousands of hours on ANSYS modelling entertain my dumb questions. The team is so open minded to new ideas, even from inexperienced members.</p>

<p>This year we were weighing whether to add VTOL (vertical takeoff and landing) to our plane. We needed to make the decision judiciously as has huge implications on both software and hardware. The team came together and openly presented the pro and con considerations at our town halls. We did not devolve into a war between the two sides and did not do this through democracy. All the debate was done in public for anyone to add to, and then the team project manager made the ultimate decision. I like that we trust others’ decisions in TUAS. Instead of silos for each subteam, we have cohesive all hands “townhall” meetings to make sure everyone is on the same page. We have necessary hierarchy because leads need to make choices for cross-subteam projects quickly.</p>

<p><img src="/images/10-reasons/townhall2.webp" class="post-image" loading="lazy" /></p>

<p>I have not seen any other club that solicits member feedback so much. TUAS sends member CAPES, an evaluation form to give feedback on your experience in the club. Feedback is constantly being asked for and being shared at our townhall meetings.</p>

<p><img src="/images/10-reasons/yay.webp" class="post-image" loading="lazy" /></p>

<p>TUAS is not all serious decision making. There is so much fun club lore and our business team does a fantastic job organization social events and fundraisers. These are some schenanigans that we have <em>definitely</em> not done:</p>

<ul>
  <li>shorted the electrical board on carbon fiber, setting the plane on fire</li>
  <li>worked in the lab overnight</li>
  <li>set the world record for any% fastest Tapex order</li>
  <li>made a Tapex time leaderboard</li>
  <li>run regression algorithms to predict Tapex order numbers</li>
  <li>carved the Tapex logo into a pumpkin</li>
  <li>flown bread</li>
  <li>there are NO easter eggs at all in our ground control station software</li>
  <li>gotten a plane prop stuck on the motor</li>
  <li>eaten 1000 oreos</li>
  <li>gone to Tuas</li>
  <li>played Minecraft in a hotel until 4am</li>
  <li>snacked on packing peanuts</li>
  <li>canary in the Jacob’s mine</li>
  <li>1 inch thick exploding laptops</li>
  <li>amogus world record</li>
  <li>yummy orange fumes tier list</li>
</ul>

<div class="image-carousel owl-carousel" style="overflow: initial">
<div>
<img src="/images/10-reasons/tuas1.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/tuas2.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/tuas3.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/carving.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/pumpkin.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/ikea.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/funny_moments.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/games.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/sea.webp" class="post-image" loading="lazy" />
</div>
<div>
<img src="/images/10-reasons/selfie.webp" class="post-image" loading="lazy" />
</div>
</div>

<p>Being around other TUAS people is so fun. Going to a school with 40,000 students, I’m accustomed to encountering people randomly and in classes and never seeing them again. But with TUAS, you are growing with the other people. It’s so awesome to be around other curious people who are interested in hearing about what you are working on and meeting people who are passionate about learning. In a huge campus, the TUAS lab feels more like home than my apartment does.</p>

<div class="quote-author"> BEN GAROFALO</div>
<div class="quote-body">

Things that fly are cool. When I was a freshman, I had to choose if I wanted to spend my time with TritonUAS or Rocket Propulsion Lab (RPL) and I'm very glad I chose TUAS. It's been easy to move between projects and work on things that I'm interested in, starting out in Software, moving to Airframe/Mechanical and eventually leading Business team.

I also love going on test flights and hanging out with team members! At a test flight, there's usually a period of mucking around (sometimes literally, in mud) and downtime as the aircraft gets checked over by different team members. We like to spend this time playing cards on the airplane wings or watching family guy funny moments on our custom ground station. Once the plane is ready for take-off, everyone watches and records with bated breath. No matter how routine the flight, takeoff and landing are always a bit nerve-wracking! After each test flight, we usually go get food as a team and this always feels great, especially if you have class later that day. A morning adventure always makes the day feel longer.

Something else that I really value about TUAS is the amount of experimentation and discovery we do together. Trying new things and pushing the envelope is the everyday experience. Just this year we've discovered and implemented many awesome manufacturing techniques and designs that are highly applicable to industry practice.
</div>

<p><img src="/images/10-reasons/chair.webp" class="post-image" loading="lazy" />
<img src="/images/10-reasons/tent.webp" class="post-image" loading="lazy" /></p>

<h2 id="8-career-opportunities">8. Career Opportunities</h2>

<p>The culture in TUAS has shown me that these people are in this club because of their passion and not for the resume line item. Nevertheless, the experience is a boon for our future careers. Interviewers often ask me about my work in TUAS, and TUAS has led to me scoring an internship. I know many of our members have gotten jobs at aviation and engineering companies because this club experience sets them apart from people who only know theoretical course material. The effect of TUAS on career outcomes is clear if you look at out alumni.</p>

<h2 id="9-alumni">9. Alumni</h2>
<p>You get opportunities to interact with alumni of the club, who have gone onto great graduate programs, <a href="https://evt.ai/">founded</a> <a href="https://techcrunch.com/2022/02/16/following-acquisition-by-bowery-traptics-strawberry-picking-robotics-move-into-vertical-farming/">successful</a> startups, and worked their dream jobs at JPL. While a student, it’s great to have the mentorship of elder students who have gone through the same path as you. Beyond graduation, you can get advice from people who have gone down different paths.</p>

<h2 id="10-and-takeoff">10. And Takeoff</h2>

<p><img src="/images/10-reasons/flight.webp" class="post-image" loading="lazy" /></p>

<p>I’ll mention this again. But launching at the end of the year is so fun. The first successful full-system integration test is pure euphoria.</p>

<video autoplay="" muted="" loop="" loading="lazy">
  <source src="/images/10-reasons/takeoff.mp4" loading="lazy" type="video/mp4" />
  Your browser does not support the video tag.
</video>

<p>I went from knowing nothing about planes to making one of the coolest things I have ever seen.</p>

<div class="quote-author">ANTHONY TARBINIAN</div>
<div class="quote-body">

Getting to go to the SUAS competition was an exhilarating experience. There's so much tension building up to the mission demonstration. A whole year of work all down to 30 minutes. However, amidst all the stress that comes with that, it was amazing to be there with the team and see all our hard work pay off.
</div>

<h2 id="11-mentoring">11. Mentoring</h2>

<p>A last bonus benefit: After making it through your first competition year, you are no longer a rookie. It is an amazing journey slowly becoming the expert that you looked up to as a rookie. We are here to help each other out.</p>

<p><img src="/images/10-reasons/mentor.webp" class="post-image" loading="lazy" /></p>

<p>TUAS can be stressful. Dealing with deadline and scrambling as things break during testing can start to consume all your time. But we have bonded and become better engineers, better teammates, and better people having come through the other side.</p>

<p>For all these reasons, the TUAS lab holds a special place in my heart. All the work we have done together and all the people I have met will always stay with me.</p>

<p><img src="/images/10-reasons/team.webp" class="post-image" loading="lazy" /></p>

<p>You can choose to spend your time anywhere, but you’ll be glad to have spent it with us.</p>

<p><a href="/#join">Join us</a> near the start of any quarter. See you in the skies.</p>

<hr />

<p>This post is inspired by <a href="https://rocketry.mit.edu/10-reasons-i-joined-rocket-team" style="text-decoration: underline">a post</a> from the MIT rocketry team.
Check out <a href="https://godsped.com/10-reasons">this post</a> with my <em>unofficial</em>, personal commentary.</p>

<p><img src="/images/10-reasons/plane.webp" class="post-image" loading="lazy" /></p>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="undergrad" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">The case for Nix on the home server</title><link href="https://godsped.com/nix-homeserver/" rel="alternate" type="text/html" title="The case for Nix on the home server" /><published>2024-03-15T00:00:00+00:00</published><updated>2024-03-15T00:00:00+00:00</updated><id>https://godsped.com/nixcon-na24</id><content type="html" xml:base="https://godsped.com/nix-homeserver/"><![CDATA[<p>I <a href="https://2024-na.nixcon.org/talks/#the-case-for-nix-on-the-home-server">spoke</a> at <a href="https://2024-na.nixcon.org/">NixCon North America</a> this year. The event was co-located with <a href="https://www.socallinuxexpo.org/scale/21x">SCaLE 21x</a> (March 14-17, 2024 in Pasadena, California). This is a talk for <strong>beginners</strong> to Nix. You will learn the highlights of what Nix offers and see how Nix helps to set up a home server.</p>

<blockquote>
  <p>Why is Nix a good choice for a home server? Learn how Nix enables maintenance free, secure, and reproducible home servers. The talk will cover why Nix is a powerful choice compared to other technologies like Docker or Ansible. It will also showcase how Nix makes it easy to get up and running with server applications such as Nginx, Wireguard, Jellyfin, Samba, and more.</p>
</blockquote>

<p><a href="https://www.youtube.com/watch?v=h8oyoDMUM2I"><img src="/files/nixcon/img/youtube.jpg" alt="" /></a>
<a class="btn btn--danger" style="background: red;" href="https://www.youtube.com/watch?v=h8oyoDMUM2I">Watch on YouTube</a></p>

<p>If you want to set up your own home server, <strong>check out <a href="https://github.com/atar13/nixcon24-home-server/">our repo</a></strong> with a config to follow along after the talk.</p>

<h2 id="view-the-slides">View the slides</h2>

<iframe src="/files/nixcon/slides.html" width="100%" height="500px" style="border:none;"></iframe>

<p><a class="btn" href="/files/nixcon/slides.html">View slides in fullscreen</a></p>

<p>You can download the rendered <a href="https://github.com/atar13/nixcon24-home-server/blob/main/slides.pdf">pdf file here</a> or check out the <a href="https://github.com/atar13/nixcon24-home-server/blob/main/slides.md">Markdown source code here</a>.</p>]]></content><author><name>Samir Rashid</name><email>s3rashid@ucsd.edu</email></author><category term="talk" /><category term="recommended read" /><summary type="html"><![CDATA[I spoke at NixCon North America this year. The event was co-located with SCaLE 21x (March 14-17, 2024 in Pasadena, California). This is a talk for beginners to Nix. You will learn the highlights of what Nix offers and see how Nix helps to set up a home server.]]></summary></entry></feed>