The smallest Hello World program
41–50 of 53 posts
Re: The smallest Hello World program
#42Would it be fair to name the program 'Hello World!' and than use argv[0], which is on the stack, to print out 'Hello World!'?
Re: The smallest Hello World program
#43here'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.
> It should be a ‘proper‘ executable binary according to the spec
Re: The smallest Hello World program
#44Re: The smallest Hello World program
#45These 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
Quick'n'dirty:
.model small
.code
org 100h
start:
int 19h ; Bootstrap loader
end start
More "correct": .model small
.code
org 100h
start:
db 0EAh ; Jump to Power On Self Test - Cold Boot
dw 0,0FFFFh
end start
Even more "correct": .model small
.code
org 100h
start:
mov ah,0Dh
int 21h ; DOS Services ah=function 0Dh
; flush disk buffers to disk
sti ; Enable interrupts
hlt ; Halt processor
mov al,0FEh
out 64h,al ; port 64h, kybd cntrlr functn
; al = 0FEh, pulse CPU reset
end startRe: The smallest Hello World program
#46here'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.
Yeah I thought sth like this is possible, but (correct me if I'm wrong) this (ab)uses the ELF header and punts data in there, which goes against my requirement > It should be a ‘proper‘ executable binary according to the spec
Re: The smallest Hello World program
#47This 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…
I was able to shave off one additional byte with this: ... xor rax, rax ; = 0 inc rax ; = 1 - syscall: sys_write mov rdi, rax ; copy 1 - file descriptor: stdout lea rsi, [rel msg] ; pointer to message mov rdx, 14 ; message length syscall ... $ nasm -f bin -o elf elf.asm; wc -c elf; ./elf 166 elf Hello, World! So I guess NASM already optimizes this quite well However, using the stack-based instructions as xpasky hinte…
push 1
pop rax
pop rdi
You can't push a value once and pop it twice, that's not how a stack works! You're popping something else off the stack. So why does this even work?Linux passes your program arguments on the stack, with argc on top. So when you don't pass any arguments, argc just HAPPENS to be 1. Which you then pop into rdi. Gross!
Re: The smallest Hello World program
#48Earlier quoted context omitted.
I was able to shave off one additional byte with this: ... xor rax, rax ; = 0 inc rax ; = 1 - syscall: sys_write mov rdi, rax ; copy 1 - file descriptor: stdout lea rsi, [rel msg] ; pointer to message mov rdx, 14 ; message length syscall ... $ nasm -f bin -o elf elf.asm; wc -c elf; ./elf 166 elf Hello, World! So I guess NASM already optimizes this quite well However, using the stack-based instructions as xpasky hinte…
That second snippet is pretty funny: push 1 pop rax pop rdi You can't push a value once and pop it twice, that's not how a stack works! You're popping something else off the stack. So why does this even work? Linux passes your program arguments on the stack, with argc on top. So when you don't pass any arguments, argc just HAPPENS to be 1. Which you then pop into rdi. Gross!
With that fixed, is there any reason not to use push here?
Re: The smallest Hello World program
#49This 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…
I was able to shave off one additional byte with this: ... xor rax, rax ; = 0 inc rax ; = 1 - syscall: sys_write mov rdi, rax ; copy 1 - file descriptor: stdout lea rsi, [rel msg] ; pointer to message mov rdx, 14 ; message length syscall ... $ nasm -f bin -o elf elf.asm; wc -c elf; ./elf 166 elf Hello, World! So I guess NASM already optimizes this quite well However, using the stack-based instructions as xpasky hinte…
of course
Re: The smallest Hello World program
#50Earlier quoted context omitted.
That second snippet is pretty funny: push 1 pop rax pop rdi You can't push a value once and pop it twice, that's not how a stack works! You're popping something else off the stack. So why does this even work? Linux passes your program arguments on the stack, with argc on top. So when you don't pass any arguments, argc just HAPPENS to be 1. Which you then pop into rdi. Gross!
Of course - you are completely right, an oversight in wanting to correct my mistake as quickly as possible. With that fixed, is there any reason not to use push here?
push 1 ; 6A 01 (2 bytes)
pop rdi ; 5F (1 byte)
is longer than a simple: mov edi, eax ; 89 C7 (2 bytes)