Live data from Hacker News

The smallest Hello World program

blog.lohr.dev

21–30 of 53 posts

Re: The smallest Hello World program

#21
post #2

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

  debug
  -a 100
  178A:0100 int 19
  178A:0102
  -r cx
  CX 0000
  :2
  -n reboot.com
  -w
  Writing 00002 bytes
  -q

Re: The smallest Hello World program

#22
post #7

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 suff…

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…

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

Re: The smallest Hello World program

#23
post #7

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 suff…

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…

Assuming it is initial zero

   inc eax
is a byte shorter than mov al, 1

Re: The smallest Hello World program

#25
post #23

Earlier quoted context omitted.

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…

Assuming it is initial zero inc eax is a byte shorter than mov al, 1

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 :)

Re: The smallest Hello World program

#26
post #22

Earlier quoted context omitted.

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…

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

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.)

Re: The smallest Hello World program

#27
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.

Re: The smallest Hello World program

#29
post #2

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

Some people care about executable size, (mostly) everyone else ships Electron apps.

Tell it to my boss, he wants his app last week.

Re: The smallest Hello World program

#30
post #7

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 suff…

Thanks, that makes total sense. I was so focused on the ELF part that I didn't even consider optimizing the initial assembly further. Will fix it and edit the article.
Post reply on HN