A few things have changed since 2001 that require extra flags to be able to follow along:
1. Most systems today are 64-bit, where gcc needs "-m32" to build the 32-bit assembly code that this article uses.
2. Modern versions of GCC's ld enable "-z separate-code" by default, which adds several kilobytes of padding that completely dwarfs everything this article does until you start hand-crafting ELF files. Passing "-Wl,-z,noseparate-code" to gcc undoes this.
3. Most Linux distros now configure GCC with "--enable-default-pie", which similarly inflates all of the binaries by several kilobytes. Passing "-no-pie" to gcc undoes this.
I actually did this myself last year for Linux (https://tmpout.sh/3/22.html): it comes out to 73 bytes minimum for a useful program that executes its own code. I should really finish up my writeup establishing that mimimum. (The linked article walks through golfing a 77-byte Hello World program within the headers.)
It's not so easy to find it by naively testing for ignored header fields, since it depends on the precise details of which sizes and addresses must have the same alignment within a page. I instead proceeded from first principles, by studying the ELF loader and determining which programs are definitely ruled out.
1. Most systems today are 64-bit, where gcc needs "-m32" to build the 32-bit assembly code that this article uses.
2. Modern versions of GCC's ld enable "-z separate-code" by default, which adds several kilobytes of padding that completely dwarfs everything this article does until you start hand-crafting ELF files. Passing "-Wl,-z,noseparate-code" to gcc undoes this.
3. Most Linux distros now configure GCC with "--enable-default-pie", which similarly inflates all of the binaries by several kilobytes. Passing "-no-pie" to gcc undoes this.