[HN Gopher] The smallest Hello World program
       ___________________________________________________________________
        
       The smallest Hello World program
        
       Author : michidk
       Score  : 50 points
       Date   : 2024-12-30 16:23 UTC (3 days ago)
        
 (HTM) web link (blog.lohr.dev)
 (TXT) w3m dump (blog.lohr.dev)
        
       | mrfinn wrote:
       | These challenges are funny - they remind me of the old days. Back
       | in the DOS/Windows days, we used to have the .com format, which
       | was perfect for tiny programs. One could even write a program of
       | less than 10 bytes that could actually do something!
       | 
       | We've come a long way since then, and is like, at some point,
       | nobody cared about optimizing executable size anymore
        
         | xpasky wrote:
         | JMP FFFF:0000
        
           | mrfinn wrote:
           | INT 13h... uff chills
        
         | secondcoming wrote:
         | People in the embedded space care. Symbian OS was compiled for
         | small size, only certain parts were allowed use O3, such as the
         | jpeg decoder.
        
         | hinkley wrote:
         | I learned to write COM programs at some point but quickly
         | unlearned it. There were some spots where you can use them and
         | not .bat files, but outside of that it's a lot.
        
         | theandrewbailey wrote:
         | Some people care about executable size, (mostly) everyone else
         | ships Electron apps.
        
         | smokel wrote:
         | debug       -a 100       178A:0100 int 19       178A:0102
         | -r cx       CX 0000       :2       -n reboot.com       -w
         | Writing 00002 bytes       -q
        
       | gr33kdude wrote:
       | Linking a similar, very popular past example of this: Teensy:
       | https://www.muppetlabs.com/~breadbox/software/tiny/teensy.ht...
        
       | xpasky wrote:
       | Now, can we make it even smaller applying
       | https://nathanotterness.com/2021/10/tiny_elf_modernized.html ? We
       | shouldn't need the full ELF header...
        
         | xpasky wrote:
         | Oh it has been done:
         | https://nathanotterness.com/2021/10/hello_105.asm
        
       | bd01 wrote:
       | This is pretty bad. Let's start with the very first instruction:
       | mov rax, 1
       | 
       | An actual "mov rax, 1" would assemble to 48 B8 01 00 00 00 00 00
       | 00 00, a whopping TEN bytes.
       | 
       | nasm will optimize this to the equivalent "mov eax, 1", that's 6
       | bytes, but still:                 xor eax, eax ; 2 bytes
       | inc eax      ; 2 bytes
       | 
       | would be much smaller. Second line:                 mov rdi, 1
       | 
       | You already have the value 1 in eax, so a "mov edi, eax" (two
       | bytes) would suffice. Etc. etc.
        
         | xpasky wrote:
         | push 1       pop rax
         | 
         | is even shorter (credit: https://old.reddit.com/r/programming/c
         | omments/q6mnz1/what_is...)
        
         | rep_lodsb wrote:
         | Linux initializes all general purpose registers to zero. It's
         | not documented AFAIK, but should be reliable - it has to init
         | them to _some_ value anyway to avoid leaking kernel state. So
         | you can get away with:                   mov     al,1
         | ;write         mov     edi,eax    ;handle=stdout         mov
         | esi,msg    ;assumes load address below 4G         mov
         | dl,msg.len         syscall         mov     al,60      ;assuming
         | syscall succeeded, EAX was bytes written         xor
         | edi,edi         syscall
         | 
         | The load address stays constant unless there's some magic GNU
         | extension header to enable ASLR. If we could get the code
         | loaded below 64K, we could save another byte by using SI
         | instead of ESI; however this doesn't work by default, you'd
         | have to run 'echo 0 > /proc/sys/vm/mmap_min_addr' as root
         | first.
        
           | bd01 wrote:
           | Initial register state is documented to be undefined except
           | for rbp, rsp and rdx [1].
           | 
           | Can you say for certain that no other Linux version _ever_
           | used GPRs to pass something else?
           | 
           | [1] System V ABI, page 29 (last line) and 30,
           | https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
        
             | rep_lodsb wrote:
             | For certain? No, but I wouldn't expect it. Not sure what
             | that function pointer in rdx is intended for, but Linux
             | doesn't use it.
             | 
             | (Note for pedants: rsp is _technically_ a  "general purpose
             | register", but of course it is initialized to point to the
             | userspace stack instead of zero.)
        
           | retrac wrote:
           | Assuming it is initial zero                  inc eax
           | 
           | is a byte shorter than mov al, 1
        
             | rep_lodsb wrote:
             | Yes, but only in 32 bit mode. Not that it matters, except
             | for the hypothetical future processor or Linux kernel that
             | is no longer compatible with that :)
        
       | smokel wrote:
       | My favorite language for implementing short Hello World programs
       | in is HQ9+ [1].
       | 
       | Joking aside, this page [2] used to be a great tutorial on
       | writing small ELF binaries, but I'm not sure whether it will
       | still work in 64-bit land. It proved very helpful for writing a
       | 4K intro back in 1999.
       | 
       | [1] https://esolangs.org/wiki/HQ9%2B
       | 
       | [2]
       | https://www.muppetlabs.com/~breadbox/software/tiny/teensy.ht...
        
       | whynotmaybe wrote:
       | Could a script be a program?
       | 
       | Because it would be much smaller in a bat file than contains :
       | 
       | echo Hello World!
        
         | hinkley wrote:
         | Include the shebang but it's still crazy how big minimal
         | programs are.
        
         | theandrewbailey wrote:
         | For the purposes of this challenge, no.
         | 
         | > Let's first establish some rules for our 'Hello World'
         | program:
         | 
         | > It should be able to execute directly without passing to any
         | other programs first (so no decompression)
         | 
         | > It should be a 'proper' executable binary according to the
         | spec
        
       | oneshtein wrote:
       | The smallest "hello, world" programs in Rust I did for Arduino
       | are 294 bytes for blink and 388 bytes for hw.
        
       | Tepix wrote:
       | Here's a tiny DOS COM file that does it in 18 bytes:
       | ;; 18 bytes         DB 'HELLO_WOIY<$'  ; executes as machine
       | code, returning SP to original position without overwriting
       | return address                  mov  dx, si    ; mov dx,0100h MS-
       | DOS (all versions), FreeDOS 1.0, many other DOSes         xchg
       | ax, bp    ; mov ah,9     MS-DOS 4.0 and later, and FreeDOS 1.0
       | int  21h         ret
       | 
       | (credits: https://stackoverflow.com/questions/72635031/assembly-
       | hello-...)
        
         | rep_lodsb wrote:
         | Well, it prints something that is the same length as the
         | correct message at least.
        
       | 5- wrote:
       | here's an 80 byte x86_64 linux 'hello world' (okay, not 'Hello
       | world!'). convert to binary with xxd -r -p:
       | 7f454c46488d3537000000ffc7b20eeb03003e00
       | b001eb1a01000000050000001800000000000000
       | 1800000005000000b03c0f05ebfa380001006865
       | 6c6c0000010068656c6c00006f20776f726c640a
       | 
       | i'm sure this can be improved -- but i could never get any x86_64
       | linux elf to under 80 bytes. see if you can fit the exclamation
       | point still.
        
       ___________________________________________________________________
       (page generated 2025-01-02 23:00 UTC)