Un resoconto della sfida “Super Small Hello World” di hacker.org: le soluzioni che hanno funzionato, quelle che ci sono andate vicino e il trucco che ha finalmente permesso di raggiungere quota 29.
hacker.org ospita un piccolo linguaggio esoterico chiamato
SuperHack. Il compito sembra banale: scrivere un programma in SuperHack che stampi
Hello, World!.
La difficoltà sta nel punteggio. Vieni valutato in base all’area del rettangolo di delimitazione (bounding box)
del tuo codice, e più è piccola, meglio è. Inoltre, il programma deve terminare correttamente:
eseguendo l’istruzione ! (halt). Andare in crash con un’eccezione della VM una volta stampato il
testo non è valido, così come non è valido stampare byte spuri.
Il numero da battere era 29.
SuperHack è una macchina a stack bidimensionale, simile nello spirito a Befunge:
%) e si muove verso destra.| Istruzione | Effetto |
|---|---|
0-9 | inserisce (push) una cifra nello stack |
+ - d | somma, sottrae, divide per difetto (d per zero restituisce 0) |
x | duplica l’elemento in cima allo stack |
n ^ | inserisce una copia dell’elemento che si trova n posizioni sotto la cima (1^ copia il secondo) |
, | legge l’input. Quando non c’è input, inserisce 0 |
g | estrae (pop) x, estrae y, inserisce il codice del carattere in (x, y). Fuori dalla griglia inserisce 0 |
P | estrae e stampa come carattere (solo i 7 bit meno significativi) |
s | salta la cella successiva |
? | estrae; salta la cella successiva se il valore era 0 |
@ | inserisce la posizione corrente (e la direzione) nel call stack |
$ | estrae una posizione, salta lì e prosegue due celle più avanti |
\ | specchio: trasforma il movimento “verso destra” in movimento “verso il basso” |
! | termina l’esecuzione (halt) |
| tutto il resto | nessuna operazione (no-op) |
Due conseguenze plasmano tutto ciò che segue.
g legge il codice stesso del programma, quindi la stringa
Hello, World! può semplicemente risiedere nella griglia ed essere letta un carattere alla
volta. La maggior parte delle sue lettere (H e l o W r) sono no-op quando vengono eseguite. Tre
non lo sono: , inserisce 0, d divide e ! arresta il programma.@ / $ creano cicli, e il numero di iterazioni dipende da dove si trovano le @.
$ riprende due celle dopo la @ a cui ritorna. Questo la fa atterrare sulla @
successiva, che inserisce nuovamente se stessa nello stack, permettendo a poche @ di ripetere il corpo del ciclo molte
volte:@@@@@ adiacenti producono conteggi di Fibonacci. Cinque di esse eseguono il corpo
esattamente 13 volte.@ distanziate di due celle producono potenze di due. Quattro di esse consentono 16
passaggi.Tredici caratteri, tredici passaggi. Tienilo a mente.
L’area è larghezza per altezza, e 29 è un numero primo. Pertanto, un programma di 29 celle deve essere una singola riga o una singola colonna.
Hello, World!%0@s!@@@@@ 01^gP1+$
La prima vera soluzione posiziona il payload all’inizio e avvia l’esecuzione subito dopo:
| parte | ruolo |
|---|---|
Hello, World! | dati, mai eseguiti, perché il PC parte dal carattere % |
% | punto di ingresso (entry point) |
0 | indice i = 0 |
@ s ! | gadget di arresto (halt gadget): vedi sotto |
@@@@@ | cinque trampolini adiacenti, così il corpo viene eseguito 13 volte |
| spaziatura (padding, spiegata sotto) |
0 1^ g | inserisce la riga 0, copia i, quindi legge il carattere alla colonna i |
P | lo stampa |
1+ | i += 1 |
$ | ripete il ciclo |
Il gadget di arresto. La prima @ mette la propria posizione in fondo al
call stack, e s salta oltre il !. La catena di Fibonacci esegue quindi i suoi 13
passaggi. Quando il call stack finalmente si srotola fino a quella prima @, $ riprende
due celle dopo di essa, ovvero esattamente sul !. Il programma si arresta in modo pulito e
non c’è alcun test di fine stringa da nessuna parte.
Il padding. Con le @ adiacenti, il ritorno dall’ultima @ riprende due
celle più avanti, il che salta la prima cella dopo la catena. Quella cella deve
quindi contenere qualcosa di innocuo, motivo per cui è uno spazio.
Risultato: Hello, World!, arresto pulito, area 32. È corretto ma spazioso: il
payload è peso morto, e il %, il padding e lo 0 costano complessivamente tre
celle.
1H@e@l@l@o ,1 ^WgoPr2lsds!+$
L’idea successiva è smettere di sprecare celle per un payload separato e intrecciare la
stringa direttamente nel codice. I caratteri di Hello, World! occupano le colonne
dispari (1, 3, …, 25), mentre il codice riempie le colonne pari intermedie:
1 fa partire l’indice dalla colonna 1 (la H).@ distanziate di due celle (colonne 2, 4, 6, 8) consentono fino a 16 passaggi., stessa del payload (colonna 11) inserisce lo 0 che serve a g come riga.2+ fa avanzare l’indice alla colonna dispari successiva.s saltano oltre la d e il ! del payload, evitando che vengano eseguiti come codice.Il problema è che 16 passaggi sono più di 13. Dopo aver stampato la stringa, il
ciclo continua a leggere oltre la fine e stampa $ e due byte NUL. Poi $
trova il call stack vuoto e la VM muore:
output: "Hello, World!$\0\0"
message: call stack underflow
È piccolo, ma non è una soluzione. Introduce però l’idea chiave:
i caratteri del payload che sono anche istruzioni utili (,) svolgono un doppio lavoro come
dati e come codice.
\
2
H
@
e
@
l
@
l
@
o
x
,
g
P
W
2
o
+
r
$
l
d
!
(Un carattere per riga. Le righe vuote sono singoli spazi, che fanno parte dei dati.)
Ruotare il programma in verticale offre un vantaggio inaspettato. In una singola colonna,
g ha bisogno che la coordinata x sia 0 e la riga sia i. La , del payload
fornisce quello 0 gratuitamente, quindi la lettura si riduce a x , g: duplica i, inserisci
0, leggi. Il costo è un singolo \ in cima per deviare il PC verso il basso.
Ha però lo stesso difetto della soluzione 2. Il ciclo va oltre il limite, stampa byte
NUL e termina con call stack underflow. Con un’area di 27 è il programma più piccolo
di questo articolo, ma non è valido.
La lezione delle soluzioni 2 e 3 è che fermarsi in modo pulito costa celle. L’intreccio rende economico il ciclo, ma ti dà 16 passaggi quando te ne servono esattamente 13.
\
2
H
@
e
@
l
@
l
@
o
x
,
g
P
W
x
o
5
r
d
l
5
d
?
!
2
+
$
La soluzione 4 mantiene l’intreccio verticale della soluzione 3 e aggiunge un vero test di fine stringa:
| riga/righe | celle | ruolo |
|---|---|---|
| 0 | \ | svolta verso il basso |
| 1 | 2 | i = 2 |
| 3, 5, 7, 9 | @ | quattro trampolini, fino a 16 passaggi |
| 11-13 | x , g | legge la riga i (la , fa parte del payload) |
| 15 | P | stampa |
| 17-24 | x 5 d 5 d | valore di test floor(floor(i/5)/5) = floor(i/25) (l’ultima d è payload) |
| 25 | ? | se il test vale 0, salta la cella successiva… |
| 26 | ! | …che è proprio il ! del payload |
| 27-28 | 2 + | i += 2 |
| 29 | $ | ripete il ciclo |
L’indice assume i valori 2, 4, …, 26. floor(i/25) rimane 0 fino all’ultimissimo
carattere (i = 26), quindi il ? salta l’arresto a ogni passaggio tranne l’ultimo.
All’ultimo passaggio, l’esecuzione cade sul ! del payload, che è contemporaneamente
l’ultimo carattere stampato e l’istruzione che ferma il programma.
È un bellissimo esempio di riutilizzo: i caratteri ,, d e ! del payload fungono tutti da codice.
Ma il test costa cinque celle, e il totale è 30.
A questo punto il mio assistente IA ha provato a dimostrare che 30 fosse il minimo assoluto. Ogni approccio sembrava scontrarsi con lo stesso muro:
@ adiacenti, e in un layout intrecciato non ci sono celle di codice adiacenti. Quindi sei
costretto a usare 16 passaggi e un test a pagamento.? non può mai trovarsi
direttamente davanti a $. La cella tra di loro è sempre una cella del payload.% o un indice iniziale grande), perché
eseguire ...d! come codice provoca un crash o un arresto immediato.Le ricerche esaustive al computer su aree più piccole non hanno trovato nulla, e anche le ricerche attorno allo schema della soluzione 4 ad area 29 non hanno dato frutti. “30 è il limite inferiore” iniziava a sembrare un teorema.
Non lo era.
9@s!@@@@@Hello, Worlä¡1^gP1+$
La svolta è arrivata rileggendo il codice sorgente del giudice di gara. Due righe fanno la differenza:
case 'P':
$output .= chr($this->Pop() & 0x7F); break;
...
default:
break; // every unknown character is a no-op
P stampa solo i 7 bit meno significativi. Un byte con il bit più alto impostato a 1, c + 128,
viene stampato esattamente come c.Ogni carattere del payload ha quindi due possibili codifiche. Quella standard può fare
qualcosa quando viene eseguita. Quella con c | 0x80 è garantita inerte. Ecco la
“formula per i dati”: memorizza i caratteri pericolosi come c + 128, e lascia che P
rimuova il bit alto gratuitamente.
Solo due caratteri del payload sono pericolosi: d diventa ä (0xE4) e !
diventa ¡ (0xA1). Modificando questi due, l’intero payload può essere
eseguito. Questo rimuove l’ostacolo descritto nel terzo punto elenco qui sopra.
Ora prendi la soluzione 1 e sposta il payload all’interno del ciclo:
| colonne | celle | ruolo |
|---|---|---|
| 0 | 9 | i = 9 (la colonna della H) |
| 1-3 | @ s ! | gadget di arresto, come nella soluzione 1 |
| 4-8 | @@@@@ | cinque trampolini adiacenti, così il corpo gira esattamente 13 volte |
| 9-21 | Hello, Worlä¡ | il payload, eseguito a ogni passaggio |
| 22-27 | 1 ^ g P 1 + | copia i, legge, stampa, incrementa |
| 28 | $ | ripete il ciclo |
Seguiamo un passaggio passo dopo passo:
@ e attraversa tutto il payload. H e l l o, lo spazio e W o r l non fanno nulla. La , del payload inserisce lo 0
che serve a g come riga. ä e ¡ non fanno nulla.1^ copia i sopra quello 0, e g legge la colonna i.P la stampa. Per gli ultimi due caratteri stampa 0xE4 & 0x7F = 'd' e
0xA1 & 0x7F = '!'.1+ fa avanzare i, e $ ritorna nella catena.Rispetto alla soluzione 1, spariscono tre celle:
%: il payload non ha più bisogno di essere protetto dall’esecuzione.H del payload, che è una no-op.0 prima di 1^g: la , del payload lo fornisce a ogni passaggio.32 − 3 = 29. Dopo il tredicesimo passaggio, il call stack si srotola fino al gadget e
il programma si ferma sul ! alla colonna 3.
Output Hello, World!, nessun messaggio dalla VM, 271 cicli, area 29.
Il primo invio è tornato indietro con got: 'Hello, WorlC$' e un punteggio di 31.
Il modulo web aveva inviato i dati in UTF-8, trasformando ciascun carattere speciale in due
byte (ä → C3 A4, ¡ → C2 A1). Mascherati a 7 bit, 0xC3 viene stampato come C e
0xA4 come $.
La soluzione consiste nel far inviare al browser la codifica Latin-1, in cui ciascuno di quei caratteri occupa un solo byte. Sulla pagina della sfida, ho dovuto aprire la console dei DevTools ed eseguire:
document.querySelectorAll('form').forEach(
f => f.acceptCharset = 'ISO-8859-1');
document.querySelector('textarea').value =
"9@s!@@@@@Hello, Worl\u00e4\u00a11^gP1+$";
Poi basta premere il normale pulsante di invio. Il giudice stampa Hello, World!, e il
punteggio da battere (King of the Hill) diventa 29.
| # | programma | area | termina in modo pulito? |
|---|---|---|---|
| 1 | Hello, World!%0@s!@@@@@ 01^gP1+$ | 32 | ✅ |
| 2 | 1H@e@l@l@o ,1 ^WgoPr2lsds!+$ | 28 | ❌ byte extra e call stack underflow |
| 3 | \2H@e@l@l@ox,g PW2o+r$ld! | 27 | ❌ byte extra e call stack underflow |
| 4 | \2H@e@l@l@ox,g PWxo5rdl5d?!2+$ | 30 | ✅ |
| 5 | 9@s!@@@@@Hello, Worlä¡1^gP1+$ | 29 | ✅ |
, del payload come push 0 gratuito, il suo ! come istruzione di arresto,
e infine l’intero payload come corpo del ciclo.& 0x7F e default: break) hanno ottenuto ciò che ore di ricerca automatica non avevano potuto fare.Scarica l'edizione offline di Lo Stile di Vita di Kaue—una guida pratica per ottimizzare 🍏 Salute, 💰 Ricchezza, ❤️ Amore e 🧘 Significato.
Ricevi una notifica quando pubblico nuovi saggi, riassunti di libri e guide pratiche per vivere bene. Niente spam—annulla l'iscrizione in qualsiasi momento.
Hai una domanda, una prospettiva o un suggerimento? Condividi i tuoi pensieri qui sotto. I commenti utilizzano GitHub Discussions (senza pubblicità e senza spam)—clicca su Accedi con GitHub qui sotto per commentare o reagire (creare un account GitHub gratuito richiede meno di un minuto).
Aggiornato il 2 ott 2026.
AVVERTENZA LEGALE: Il contenuto di questo sito ha scopo esclusivamente informativo ed educativo e non costituisce consulenza medica, psicologica, finanziaria, di investimento, fiscale o legale. Le idee, la selezione e le opinioni qui presentate sono esclusivamente mie e non rappresentano quelle del mio datore di lavoro. I riassunti di libri, conferenze e articoli sono commenti educativi indipendenti e rimangono proprietà intellettuale dei rispettivi autori. Strumenti di IA possono essere utilizzati per assistere nella revisione, formattazione e sintesi; sebbene venga compiuto ogni sforzo per garantire l'accuratezza, possono verificarsi errori. PRIVACY: Questo sito utilizza servizi di terze parti per l'iscrizione facoltativa alla newsletter (follow.it), i commenti (giscus / GitHub Discussions) e i contenuti multimediali incorporati (YouTube), che possono trattare gli indirizzi IP e i cookie dei visitatori in conformità con le rispettive informative sulla privacy.