{"id":2967,"date":"2025-04-04T13:15:48","date_gmt":"2025-04-04T05:15:48","guid":{"rendered":"https:\/\/gergely.imreh.net\/blog\/?p=2967"},"modified":"2025-07-19T23:16:35","modified_gmt":"2025-07-19T15:16:35","slug":"the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker","status":"publish","type":"post","link":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/","title":{"rendered":"The curious case of binfmt for x86 emulation for ARM Docker"},"content":{"rendered":"\n<p>Seemingly identical configurations, different results. When two methods for setting up x86 emulation on ARM showed the exact same system configuration but behaved completely differently in Docker, I began questioning my system administration knowledge and my sanity &#8211; and briefly contemplated a new career as a blacksmith.<\/p>\n\n\n\n<p>This is a debugging tale for those working with containers, and a reminder that things aren&#8217;t always what they seem in Linux, all with a big pinch reminder to Read the Fine Manual, Always!<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">ARM with Achiveteam v2<\/h2>\n\n\n\n<p>Recently I&#8217;ve got an email from a reader of the <a href=\"https:\/\/gergely.imreh.net\/blog\/2021\/04\/arm-images-to-help-the-archive-team\/\">ARM images to help the Archive Team<\/a> blogpost from years ago, asking me about refreshing that project to use again. There I was recompiling the ArchiveTeam&#8217;s Docker images to support ARM, and thus I was looking how things changed in the intervening time. I also got more <s>lazy<\/s> pragmatic since then, I was was wondering if the <a href=\"https:\/\/wiki.archiveteam.org\/\">Archiveteam<\/a> just made some ARM or multi-arch images as I believe(d) they should. That lead me to <a href=\"https:\/\/wiki.archiveteam.org\/index.php\/ArchiveTeam_Warrior#Can_I_run_the_Warrior_on_ARM_or_some_other_unusual_architecture?\">their FAQ entry about ARM images<\/a>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Can I run the Warrior on ARM or some other unusual architecture?<\/strong><\/p>\n\n\n\n<p>Not directly. We currently do not allow ARM (used on Raspberry Pi and M1 Macs) or other non-x86 architectures. This is because we have previously discovered questionable practices in the Wget archive-creating components and are not confident that they run correctly under (among other things) different endiannesses. [&#8230;]<\/p>\n\n\n\n<p>Set up <a href=\"https:\/\/docs.docker.com\/build\/building\/multi-platform\/#qemu\">QEMU with your Docker install<\/a> and add &#8211;platform linux\/amd64 to your docker run command.<\/p>\n<\/blockquote>\n\n\n\n<p>This actually seems like a sensible thing &#8211; if they dug that deep that they&#8217;ve seen issues in <a href=\"https:\/\/www.gnu.org\/software\/wget\/\">wget<\/a>, I&#8217;ve definitely been doing things naively before.<\/p>\n\n\n\n<p>The guidance of installing QEMU seems sensible as well (we were doing a lot of those at <a href=\"https:\/\/www.balena.io\/\">balena<\/a>), and it goes roughly like.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>install <code>binfmt<\/code><\/li>\n\n\n\n<li>install QEMU with statically compiled binaries<\/li>\n\n\n\n<li>load those binaries to emulate the platforms you want with the <code>F<\/code> \/ <code>fix_binary<\/code> flag<\/li>\n<\/ol>\n\n\n\n<p>For those unfamiliar, <code>binfmt_misc<\/code> is a <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/binfmt-misc.html\">Linux kernel feature<\/a> that allows non-native binary formats to be recognized and passed to user space applications. It&#8217;s what makes it possible to run ARM binaries on x86 systems and vice versa through emulation. The various flags are how the actual behaviour of <code>binfmt<\/code> is adjusted (F, P, C, O)<\/p>\n\n\n\n<p>Docker advised to use a image to set things up, that is, for example for the <code>x86_64<\/code>\/<code>amd64<\/code> platform like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">docker run --privileged --rm tonistiigi\/binfmt --install amd4<\/code><\/pre>\n\n\n\n<p>My Raspberry Pi is running <a href=\"https:\/\/archlinuxarm.org\/\">ArchLinuxARM<\/a> which installs <a href=\"https:\/\/www.freedesktop.org\/software\/systemd\/man\/latest\/systemd-binfmt.service.html\">systemd-binfmt<\/a> to load the relevant emulation settings at boot time, which seemed handy: with the docker method I had to run that every time before I could run an emulated container, with systemd I would have thing ready by every time the time Docker is ready to run (ie. keeping the Archiveteam containers always on and restarting after reboot.) So I have a strong incentive to use the systemd-based approach instead of the <code>docker run<\/code> based one.<\/p>\n\n\n\n<p>Now comes the kicker \ud83e\udd2f:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the <code>docker<\/code> installed <code>binfmt<\/code> setup worked and allowed to run <code>linux\/amd64<\/code> containers<\/li>\n\n\n\n<li><code>systemd-binfmt<\/code> initiated <code>binfmt<\/code> setup worked for the <code>x86_64<\/code> binaries in the file system, but not in Docker where the binaries just failed to run<\/li>\n\n\n\n<li>both setups had identical output when looking at the config in <code>\/proc\/sys\/fs\/binfmt_misc<\/code><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">When Same&#8217;s Not the Same<\/h2>\n\n\n\n<p>To see whether emulation works, the <code>tonistiigi\/binfmt<\/code> container can be invoked without any arguments and it shows the status. For example setting things up with <code>docker<\/code> would show:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ docker run --privileged --rm tonistiigi\/binfmt\n{\n  \"supported\": [\n    \"linux\/arm64\",\n    \"linux\/amd64\",\n    \"linux\/amd64\/v2\",\n    \"linux\/arm\/v7\",\n    \"linux\/arm\/v6\"\n  ],\n  \"emulators\": [\n    \"qemu-x86_64\"\n  ]\n}<\/code><\/pre>\n\n\n\n<p>Here the <code>supported<\/code> section shows <code>amd64<\/code> as it should, and their test of running an amd64 image to check if the binaries are run has the expected output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ docker run --rm --platform linux\/amd64 -t alpine uname -m\nx86_64<\/code><\/pre>\n\n\n\n<p>Going back to the alternative, after uninstalling that emulatior I start up <code>systemd-binfmt<\/code>I can test the status again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ docker run --privileged --rm tonistiigi\/binfmt\n{\n  \"supported\": [\n    \"linux\/arm64\",\n    \"linux\/arm\/v7\",\n    \"linux\/arm\/v6\"\n  ],\n  \"emulators\": [\n[...snip...]\n    \"qemu-x86_64\",\n[...snip...]\n  ]\n}<\/code><\/pre>\n\n\n\n<p>This shows that while the emulator is installed, Docker doesn&#8217;t find that the <code>linux\/amd64<\/code> platform is supported, and this checks out with running the <code>alpine<\/code> image again as above:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ docker run --rm --platform linux\/amd64 -t alpine uname -m\nexec \/bin\/uname: exec format error<\/code><\/pre>\n\n\n\n<p>Well, this doesn&#8217;t work.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/docs.kernel.org\/admin-guide\/binfmt-misc.html\">binfmt_misc docs in the Linux Kernel wiki<\/a> do have plenty of info on the setup and use of the that emulation function. For example to check the configuration of the emulation setup, we can look at the contents of a file in <code>\/proc<\/code> filesystem:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ cat \/proc\/sys\/fs\/binfmt_misc\/qemu-x86_64\nenabled\ninterpreter \/usr\/bin\/qemu-x86_64\nflags: POCF\noffset 0\nmagic 7f454c4602010100000000000000000002003e00\nmask fffffffffffefe00fffffffffffffffffeffffff<\/code><\/pre>\n\n\n\n<p>This was the almost the same whether I the <code>docker<\/code> based setup or used <code>systemd-binfmt<\/code> with a slight difference: the <code>flags<\/code> bit is only <code>PF<\/code> when run with <code>systemd-binfmt<\/code>, and <code>POCF<\/code> when set things up with <code>docker run<\/code>. Even if the Docker docs are asking for the <code>F<\/code> flag, I wanted to make sure we are on equal footing, so I&#8217;ve tried to modify  the QEMU setup to be the same. This means overriding the <code>qemu-x86_64.conf<\/code> that is shipped by default:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Copy the config from <code>\/usr\/lib\/binfmt.d\/qemu-x86_64.conf<\/code> to <code>\/etc\/binfmt.d\/qemu-x86_64.conf<\/code> (make sure the file has the same name to ensure this new file overrides the one from the lib folder)<\/li>\n\n\n\n<li>Edit the end of the line from <code>:FP<\/code> to <code>:FPOC<\/code> <\/li>\n\n\n\n<li>restart <code>systemd-binfmt<\/code><\/li>\n<\/ul>\n\n\n\n<p>After this the output of the the runtime info in <code>\/proc\/sys\/fs\/binfmt_misc\/qemu-x86_64<\/code> was completely the same. Why&#8217;s the difference?<\/p>\n\n\n\n<p>More debugging steps ensued:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">More Debugging Ensued<\/h3>\n\n\n\n<p>I&#8217;ve <strong>read through the source code<\/strong> of <code>tonistiigi\/binfmt<\/code> on <a href=\"https:\/\/github.com\/tonistiigi\/binfmt\/tree\/master\/cmd\/binfmt\">GitHub<\/a> and seen that it doesn&#8217;t do anything fancy, it&#8217;s quite clear implementation of the `binfmt_misc` usage docs and the same magic values as QEMU shipped on my system. Good that no surprise, but no hints of any difference<\/p>\n\n\n\n<p>I&#8217;ve tried to <strong>replicate that process<\/strong> of setting up QEMU through translating it into Python and running, still the same<\/p>\n\n\n\n<p>I&#8217;ve <strong>recompiled the binary<\/strong> on my system, and run it outside of docker: it worked the same way as the <code>systemd-binfmt<\/code> setup: <code>x86_64<\/code> static binaries<sup data-fn=\"edde2512-e0d8-4c40-8fc7-32ce3232f660\" class=\"fn\"><a id=\"edde2512-e0d8-4c40-8fc7-32ce3232f660-link\" href=\"#edde2512-e0d8-4c40-8fc7-32ce3232f660\">1<\/a><\/sup> worked outside of Docker but not inside of it<\/p>\n\n\n\n<p>A sort-of <strong>breakthrough<\/strong> came when I&#8217;ve tried out <a href=\"https:\/\/github.com\/dbhi\/qus\">dbhi\/qus<\/a> Docker images, that promises &#8220;qemu-user-static (qus) and containers, non-invasive minimal working setups&#8221;, and can do the similar emulator &amp; platform support setup with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">docker run --rm --privileged aptman\/qus -s -- -p x86_64<\/code><\/pre>\n\n\n\n<p>It was a lot slower to run (coming back to this later), but worked like the charm, just like Docker&#8217;s own recommendation. However there was a difference in the outcome when I checked the runtime config info:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ cat \/proc\/sys\/fs\/binfmt_misc\/qemu-x86_64\nenabled\ninterpreter \/qus\/bin\/qemu-x86_64-static\nflags: F\noffset 0\nmagic 7f454c4602010100000000000000000002003e00\nmask fffffffffffefe00fffffffffffffffffeffffff<\/code><\/pre>\n\n\n\n<p>It has just the apparently required <code>F<\/code> flag, but the interpreter points to <code>\/qus\/bin\/qemu-x86_64-static<\/code> &#8230; which is not in the regular file system. Nevertheless <code>alpine<\/code> happily runs, just as my local static binaries.<\/p>\n\n\n\n<p>How does this actually work, then?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Everything&#8217;s Illuminated<\/h2>\n\n\n\n<p>With this above, and with a better understanding what the docs say, we have everything in place to understand the all the behaviours above, things we had pointers throughout, but not enough experience to put them together:<\/p>\n\n\n\n<p>So, the <code>F<\/code> flag was required by the Docker docs, what does that <em>actually<\/em> do?<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><code>F<\/code> &#8211; fix binary<\/p>\n\n\n\n<p>The usual behaviour of binfmt_misc is to spawn the binary lazily when the misc format file is invoked. However, this doesn\u2019t work very well in the face of mount namespaces and changeroots, so the <code>F<\/code> mode opens the binary as soon as the emulation is installed and uses the opened image to spawn the emulator, meaning it is always available once installed, regardless of how the environment changes.<\/p>\n<\/blockquote>\n\n\n\n<p>Because of this, if <code>F<\/code> is set, the <code>interpreter<\/code> entry in the runtime settings doesn&#8217;t mean the path of the interpreter it <em>will<\/em> be called, but where it <em>was<\/em> called at the time &#8211; ie. it&#8217;s irrelevant for the actual runtime.<\/p>\n\n\n\n<p>The <code>tonistiigi\/binfmt<\/code> image ships its own static-compiled <code>qemu-*<\/code> binarlies, as well as  <code>aptman\/qus<\/code> container gets the right ones at runtime (hence the slowness), and the <code>interpreter<\/code> path is the binary <em>inside the container when the command is run<\/em>. The binary is then kept in memory, and the container can go away, the <code>interpreter<\/code> path&#8217;s not refering anything that exists any longer.<\/p>\n\n\n\n<p>Why does <code>systemd-binfmt<\/code> fail then? Well of course because it&#8217;s a <code>dynamically<\/code> linked binary:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ file \/usr\/bin\/qemu-x86_64\n\/usr\/bin\/qemu-x86_64: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter \/lib\/ld-linux-aarch64.so.1, BuildID[sha1]=a4b8a93a4361be61dfa34a0eab40083325853839, for GNU\/Linux 3.7.0, stripped<\/code><\/pre>\n\n\n\n<p>&#8230; and because it&#8217;s dynamically linked, even if the <code>F<\/code> flag makes it stay in memory, its lib dependencies aren&#8217;t, so when in run in Docker (which uses namespaces) it doesn&#8217;t have everything to run&#8230;<\/p>\n\n\n\n<p>And of course, ArchLinux <a href=\"https:\/\/wiki.archlinux.org\/title\/QEMU\">spells<\/a> this out:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong> At present, Arch does not offer a full-system mode and statically linked variant (neither officially nor via AUR), as this is usually not needed.<\/p>\n<\/blockquote>\n\n\n\n<p>Yes, &#8220;as this is usually not needed&#8221;. :)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Updated Setup and Looking Forward<\/h2>\n\n\n\n<p>Sort of lobbying ArchLinux to have static QEMU<sup data-fn=\"f5c8a1a6-6844-4956-adf5-488644168f92\" class=\"fn\"><a id=\"f5c8a1a6-6844-4956-adf5-488644168f92-link\" href=\"#f5c8a1a6-6844-4956-adf5-488644168f92\">2<\/a><\/sup> what options do I have?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>set up a <code>systemd<\/code> service to run the <code>tonistiigi\/binfmt<\/code> container on startup (which is <a href=\"https:\/\/blog.container-solutions.com\/running-docker-containers-with-systemd\">possible<\/a>)<\/li>\n\n\n\n<li>get some static QEMU binaries and override the settings that <code>systemd-binfmt<\/code> uses<\/li>\n\n\n\n<li>switch to anothe Linux Distro that supports the Pi, the software I run, but also ships static QEMU builds<\/li>\n<\/ul>\n\n\n\n<p>All three are suboptimal, potentially fragile, and the third is way too much work. Still the second one was kinda fine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">cd $(mktemp -d)\ndocker create --name=\"tmp_$$\"  tonistiigi\/binfmt\ndocker export tmp_$$ -o tonistiigi.tar.gz\ndocker rm tmp_$$\ntar -xf tonistiigi.tar.gz --wildcards \"*\/qemu-x86_64\"\n# Copy along the binaries folder:\nsudo cp usr\/bin\/qemu-x86_64 \/usr\/bin\/qemu-x86_64-static<\/code><\/pre>\n\n\n\n<p>Then just like we&#8217;ve overridden the upstream <code>qemu-x86_64.conf<\/code> we do it again:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Copy the config from <code>\/usr\/lib\/binfmt.d\/qemu-x86_64.conf<\/code> to <code>\/etc\/binfmt.d\/qemu-x86_64.conf<\/code> (make sure the file has the same name to ensure this new file overrides the one from the lib folder)<\/li>\n\n\n\n<li>Edit the end of the line from <code>:\/usr\/bin\/qemu-x86_64:FP<\/code> to <code>:\/usr\/bin\/qemu-x86_64-static:FPOC<\/code> (that is updating the binary it points at and the flags for good measure too<\/li>\n\n\n\n<li>As a bonus, can update the <code>:qemu-x86_64:<\/code> in the front too, say to <code>:qemu-x86_64-static:<\/code>, to change the display name of the emulator without affecting any of the functionality, it will just rename the entrin in <code>\/proc\/sys\/fs\/binfmt_misc<\/code> <\/li>\n\n\n\n<li>restart <code>systemd-binfmt<\/code><\/li>\n<\/ul>\n\n\n\n<p>Then the check again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ cat \/proc\/sys\/fs\/binfmt_misc\/qemu-x86_64-static\nenabled\ninterpreter \/usr\/bin\/qemu-x86_64-static\nflags: POCF\noffset 0\nmagic 7f454c4602010100000000000000000002003e00\nmask fffffffffffefe00fffffffffffffffffeffffff<\/code><\/pre>\n\n\n\n<p>And the <code>alpine<\/code>-based checks work once more.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Lessons Learned<\/h2>\n\n\n\n<p>The details were all in plain sight, but not enough experience to piece these things together. The Docker-recommended image ships its own QEMU? What does that <code>F<\/code> flag actually do? Can you run binaries while you don&#8217;t have them anymore? Dynamic and static linking and the signs of their misbehaviours to provide hints&#8230; However this is coupled with confusion when expectations are broken (say the <code>interpreter<\/code> doesn&#8217;t have to refer to an actual file path that exists <em>now<\/em>), until I started to question my expectations. Also, just being a heavy user of Docker doesn&#8217;t mean I&#8217;m knowledgeable of the relevant kernel functionality, and probably I should be more\u2026<\/p>\n\n\n\n<p>This whole process underlined my previous thoughts on <a href=\"https:\/\/gergely.imreh.net\/blog\/2025\/03\/software-engineering-when-ai-seems-everywhere\/\">Software Engineering when AI seems Everywhere<\/a>, as I did try to debug things by rubber ducking with <a href=\"https:\/\/claude.ai\">Claude<\/a>: this time the hallucinations were through the roof (a metric tonne of non-existent systemd funcionality, non-existent command line flags), definitely got me on a wild goose chase in a few cases. So even more care&#8217;s needed, maybe a version of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hofstadter%27s_law\">Hofstadter&#8217;s Law<\/a>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Imreh&#8217;s Law<sup data-fn=\"f632dbc3-dd26-4b73-b6cc-0b53e878e3dc\" class=\"fn\"><a id=\"f632dbc3-dd26-4b73-b6cc-0b53e878e3dc-link\" href=\"#f632dbc3-dd26-4b73-b6cc-0b53e878e3dc\">3<\/a><\/sup>: LLMs are always more wrong than you expect, even when you take into account Imreh&#8217;s Law.<\/p>\n<\/blockquote>\n\n\n\n<p>In the end, Don&#8217;t Panic, make theories and try to prove them, and talk with anyone who listens, even when they are wrong, and you are more likely to get there<sup data-fn=\"692118e9-bc19-43d4-8ac0-1603d91facdf\" class=\"fn\"><a id=\"692118e9-bc19-43d4-8ac0-1603d91facdf-link\" href=\"#692118e9-bc19-43d4-8ac0-1603d91facdf\">4<\/a><\/sup>.<\/p>\n\n\n<ol class=\"wp-block-footnotes\"><li id=\"edde2512-e0d8-4c40-8fc7-32ce3232f660\">I&#8217;ve download static binaries from <a href=\"https:\/\/github.com\/andrew-d\/static-binaries\">andrew-d\/static-binaries<\/a>, recommend <code>strings<\/code> as something that&#8217;s quick and simple to use <code>.\/strings \/bin\/sh | head<\/code> for example, allowing fast iteration. <a href=\"#edde2512-e0d8-4c40-8fc7-32ce3232f660-link\" aria-label=\"Jump to footnote reference 1\">\u21a9\ufe0e<\/a><\/li><li id=\"f5c8a1a6-6844-4956-adf5-488644168f92\">ArchLinux is x86 by default, for them it would be to emulate <code>linux\/arm64<\/code>, <code>linux\/arm\/v7<\/code>, <code>linux\/arm\/v6<\/code> images. For ArchLinux ARM it would be a different work the other direction. If only the main Arch would support ARM, it would be a happier world (even if even more complex). <a href=\"#f5c8a1a6-6844-4956-adf5-488644168f92-link\" aria-label=\"Jump to footnote reference 2\">\u21a9\ufe0e<\/a><\/li><li id=\"f632dbc3-dd26-4b73-b6cc-0b53e878e3dc\">Tongue-in-cheek, of course. <a href=\"#f632dbc3-dd26-4b73-b6cc-0b53e878e3dc-link\" aria-label=\"Jump to footnote reference 3\">\u21a9\ufe0e<\/a><\/li><li id=\"692118e9-bc19-43d4-8ac0-1603d91facdf\">And with this we just rediscovered the <a href=\"https:\/\/wiki.c2.com\/?FeynmanAlgorithm\">Feynman Algorithm<\/a>, I guess. <a href=\"#692118e9-bc19-43d4-8ac0-1603d91facdf-link\" aria-label=\"Jump to footnote reference 4\">\u21a9\ufe0e<\/a><\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>Seemingly identical configurations, different results. When two methods for setting up x86 emulation on ARM showed the exact same system configuration but behaved completely differently in Docker, I began questioning my system administration knowledge and my sanity &#8211; and briefly contemplated a new career as a blacksmith. This is a debugging tale for those working [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2969,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"[{\"content\":\"I've download static binaries from <a href=\\\"https:\/\/github.com\/andrew-d\/static-binaries\\\">andrew-d\/static-binaries<\/a>, recommend <code>strings<\/code> as something that's quick and simple to use <code>.\/strings \/bin\/sh | head<\/code> for example, allowing fast iteration.\",\"id\":\"edde2512-e0d8-4c40-8fc7-32ce3232f660\"},{\"content\":\"ArchLinux is x86 by default, for them it would be to emulate <code>linux\/arm64<\/code>, <code>linux\/arm\/v7<\/code>, <code>linux\/arm\/v6<\/code> images. For ArchLinux ARM it would be a different work the other direction. If only the main Arch would support ARM, it would be a happier world (even if even more complex).\",\"id\":\"f5c8a1a6-6844-4956-adf5-488644168f92\"},{\"content\":\"Tongue-in-cheek, of course.\",\"id\":\"f632dbc3-dd26-4b73-b6cc-0b53e878e3dc\"},{\"content\":\"And with this we just rediscovered the <a href=\\\"https:\/\/wiki.c2.com\/?FeynmanAlgorithm\\\">Feynman Algorithm<\/a>, I guess.\",\"id\":\"692118e9-bc19-43d4-8ac0-1603d91facdf\"}]"},"categories":[7],"tags":[183,217,205,17,256],"class_list":["post-2967","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-comp","tag-arch-linux","tag-archiveteam","tag-docker","tag-linux","tag-qemu"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>The curious case of binfmt for x86 emulation for ARM Docker - ClickedyClick<\/title>\n<meta name=\"description\" content=\"My brain briefly broke, when two methods for setting up x86 emulation on ARM showed the exact same system state but behaved different.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"The curious case of binfmt for x86 emulation for ARM Docker - ClickedyClick\" \/>\n<meta property=\"og:description\" content=\"My brain briefly broke, when two methods for setting up x86 emulation on ARM showed the exact same system state but behaved different.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/\" \/>\n<meta property=\"og:site_name\" content=\"ClickedyClick\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/gergely.imreh\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/gergely.imreh\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-04T05:15:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-07-19T15:16:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gergely.imreh.net\/blog\/wp-content\/uploads\/2025\/04\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"436\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Gergely Imreh\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@imrehg\" \/>\n<meta name=\"twitter:site\" content=\"@imrehg\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Gergely Imreh\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/\"},\"author\":{\"name\":\"Gergely Imreh\",\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/#\\\/schema\\\/person\\\/42391e2ae52c8ed76b37be509a5707b0\"},\"headline\":\"The curious case of binfmt for x86 emulation for ARM Docker\",\"datePublished\":\"2025-04-04T05:15:48+00:00\",\"dateModified\":\"2025-07-19T15:16:35+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/\"},\"wordCount\":1768,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/#\\\/schema\\\/person\\\/42391e2ae52c8ed76b37be509a5707b0\"},\"image\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg\",\"keywords\":[\"Arch Linux\",\"ArchiveTeam\",\"Docker\",\"linux\",\"QEMU\"],\"articleSection\":[\"Computers\"],\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/\",\"url\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/\",\"name\":\"The curious case of binfmt for x86 emulation for ARM Docker - ClickedyClick\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg\",\"datePublished\":\"2025-04-04T05:15:48+00:00\",\"dateModified\":\"2025-07-19T15:16:35+00:00\",\"description\":\"My brain briefly broke, when two methods for setting up x86 emulation on ARM showed the exact same system state but behaved different.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg\",\"contentUrl\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg\",\"width\":1024,\"height\":436,\"caption\":\"Photo by Bernd \ud83d\udcf7 Dittrich on Unsplash\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/2025\\\/04\\\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"The curious case of binfmt for x86 emulation for ARM Docker\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/\",\"name\":\"ClickedyClick\",\"description\":\"Life in real, complex and digital.\",\"publisher\":{\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/#\\\/schema\\\/person\\\/42391e2ae52c8ed76b37be509a5707b0\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/#\\\/schema\\\/person\\\/42391e2ae52c8ed76b37be509a5707b0\",\"name\":\"Gergely Imreh\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g\",\"caption\":\"Gergely Imreh\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g\"},\"description\":\"Physicist, hacker. Enjoys avant-guarde literature probably a bit too much. Open source advocate and contributor, both for software and hardware. Follow these posts on the Fediverse by @gergely@gergely.imreh.net\",\"sameAs\":[\"https:\\\/\\\/gergely.imreh.net\\\/\",\"https:\\\/\\\/www.facebook.com\\\/gergely.imreh\",\"https:\\\/\\\/www.instagram.com\\\/imrehg\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/gergelyimreh\\\/\",\"https:\\\/\\\/www.youtube.com\\\/@GergelyImreh\"],\"url\":\"https:\\\/\\\/gergely.imreh.net\\\/blog\\\/author\\\/gergely\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"The curious case of binfmt for x86 emulation for ARM Docker - ClickedyClick","description":"My brain briefly broke, when two methods for setting up x86 emulation on ARM showed the exact same system state but behaved different.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/","og_locale":"en_GB","og_type":"article","og_title":"The curious case of binfmt for x86 emulation for ARM Docker - ClickedyClick","og_description":"My brain briefly broke, when two methods for setting up x86 emulation on ARM showed the exact same system state but behaved different.","og_url":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/","og_site_name":"ClickedyClick","article_publisher":"https:\/\/www.facebook.com\/gergely.imreh","article_author":"https:\/\/www.facebook.com\/gergely.imreh","article_published_time":"2025-04-04T05:15:48+00:00","article_modified_time":"2025-07-19T15:16:35+00:00","og_image":[{"width":1024,"height":436,"url":"https:\/\/gergely.imreh.net\/blog\/wp-content\/uploads\/2025\/04\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg","type":"image\/jpeg"}],"author":"Gergely Imreh","twitter_card":"summary_large_image","twitter_creator":"@imrehg","twitter_site":"@imrehg","twitter_misc":{"Written by":"Gergely Imreh","Estimated reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#article","isPartOf":{"@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/"},"author":{"name":"Gergely Imreh","@id":"https:\/\/gergely.imreh.net\/blog\/#\/schema\/person\/42391e2ae52c8ed76b37be509a5707b0"},"headline":"The curious case of binfmt for x86 emulation for ARM Docker","datePublished":"2025-04-04T05:15:48+00:00","dateModified":"2025-07-19T15:16:35+00:00","mainEntityOfPage":{"@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/"},"wordCount":1768,"commentCount":0,"publisher":{"@id":"https:\/\/gergely.imreh.net\/blog\/#\/schema\/person\/42391e2ae52c8ed76b37be509a5707b0"},"image":{"@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#primaryimage"},"thumbnailUrl":"https:\/\/gergely.imreh.net\/blog\/wp-content\/uploads\/2025\/04\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg","keywords":["Arch Linux","ArchiveTeam","Docker","linux","QEMU"],"articleSection":["Computers"],"inLanguage":"en-GB","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/","url":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/","name":"The curious case of binfmt for x86 emulation for ARM Docker - ClickedyClick","isPartOf":{"@id":"https:\/\/gergely.imreh.net\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#primaryimage"},"image":{"@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#primaryimage"},"thumbnailUrl":"https:\/\/gergely.imreh.net\/blog\/wp-content\/uploads\/2025\/04\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg","datePublished":"2025-04-04T05:15:48+00:00","dateModified":"2025-07-19T15:16:35+00:00","description":"My brain briefly broke, when two methods for setting up x86 emulation on ARM showed the exact same system state but behaved different.","breadcrumb":{"@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/"]}]},{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#primaryimage","url":"https:\/\/gergely.imreh.net\/blog\/wp-content\/uploads\/2025\/04\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg","contentUrl":"https:\/\/gergely.imreh.net\/blog\/wp-content\/uploads\/2025\/04\/bernd-dittrich-l70397AVgCI-unsplash_v2.jpg","width":1024,"height":436,"caption":"Photo by Bernd \ud83d\udcf7 Dittrich on Unsplash"},{"@type":"BreadcrumbList","@id":"https:\/\/gergely.imreh.net\/blog\/2025\/04\/the-curious-case-of-binfmt-for-x86-emulation-for-arm-docker\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gergely.imreh.net\/blog\/"},{"@type":"ListItem","position":2,"name":"The curious case of binfmt for x86 emulation for ARM Docker"}]},{"@type":"WebSite","@id":"https:\/\/gergely.imreh.net\/blog\/#website","url":"https:\/\/gergely.imreh.net\/blog\/","name":"ClickedyClick","description":"Life in real, complex and digital.","publisher":{"@id":"https:\/\/gergely.imreh.net\/blog\/#\/schema\/person\/42391e2ae52c8ed76b37be509a5707b0"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gergely.imreh.net\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":["Person","Organization"],"@id":"https:\/\/gergely.imreh.net\/blog\/#\/schema\/person\/42391e2ae52c8ed76b37be509a5707b0","name":"Gergely Imreh","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/secure.gravatar.com\/avatar\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g","caption":"Gergely Imreh"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/1d5be311c5d616a3f4c7dfbc6b736ec817d2508b8c420ec29edb950d33fb4946?s=96&d=retro&r=g"},"description":"Physicist, hacker. Enjoys avant-guarde literature probably a bit too much. Open source advocate and contributor, both for software and hardware. Follow these posts on the Fediverse by @gergely@gergely.imreh.net","sameAs":["https:\/\/gergely.imreh.net\/","https:\/\/www.facebook.com\/gergely.imreh","https:\/\/www.instagram.com\/imrehg\/","https:\/\/www.linkedin.com\/in\/gergelyimreh\/","https:\/\/www.youtube.com\/@GergelyImreh"],"url":"https:\/\/gergely.imreh.net\/blog\/author\/gergely\/"}]}},"_links":{"self":[{"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/posts\/2967","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/comments?post=2967"}],"version-history":[{"count":8,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/posts\/2967\/revisions"}],"predecessor-version":[{"id":2979,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/posts\/2967\/revisions\/2979"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/media\/2969"}],"wp:attachment":[{"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/media?parent=2967"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/categories?post=2967"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gergely.imreh.net\/blog\/wp-json\/wp\/v2\/tags?post=2967"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}