Gabrielpappalardo.org

Il blog di gabrielpappalardo.org

Da un post di mortebianca ad una follia totale

- Pubblicato in altro di

Da un Post di Mortebianca all'Assembly: Cronaca di una Follia Collettiva

Indice


1. Come tutto è cominciato: un codice "sospetto"

Tutto è partito da un tranquillo giorno sul canale Telegram di Mortebianca (che potete trovare qui). Morte pubblica un post con un piccolo snippet di codice, un'idea tanto semplice quanto... sbagliata.

L'intento era chiaro: ciclare una lista di nazioni e, se il nome conteneva la parola "socialist", cambiare la sua ideologia in "communist". Il problema? L'esecuzione. Questo era il codice "incriminato":

countries = [/* tutti i vari stati*/];
for each country in countries {
  if (country.name = "%socialist%")  
    country.ideology = "communist";
}

Ora, per chi mastica un po' di programmazione, l'occhio cade subito su quel country.name = "%socialist%". Quello non è un confronto, ma un'assegnazione! E l'uso dei caratteri '%' per indicare una "contains" è, diciamo, fantasioso. È stato un attimo: la community si è scatenata.


2. La correzione del precisino: Visual Basic .NET alla riscossa

Sentendomi chiamato in causa dal sacro fuoco del debugging, ho deciso di fare il "precisino della situazione". Ho preso l'idea originale e l'ho trasformata in un codice funzionante, completo di un esempio pratico, usando il buon vecchio Visual Basic .NET. Un linguaggio un po' bistrattato, ma perfetto per mostrare la logica in modo chiaro.

Imports System
Imports System.Collections.Generic

Public Module Module1

    Public Class Stato
        Public Property Nome As String
        Public Property Popolazione As Integer
        Public Property Classificazione As String

        Public Overrides Function ToString() As String
            Return $"{{Nome: '{Me.Nome}', Popolazione: {Me.Popolazione}, Classificazione: '{Me.Classificazione}'}}"
        End Function
    End Class

    Public Sub ClassificaStati(ByVal lista_stati As List(Of Stato))
        For Each stato As Stato In lista_stati
            If stato.Nome = "socialist" Then
                stato.Classificazione = "comunista"
            Else
                stato.Classificazione = "non comunista"
            End If
        Next
    End Sub

    Public Sub Main()
        Dim stati As New List(Of Stato) From {
            New Stato With {.Nome = "socialist", .Popolazione = 1000000},
            New Stato With {.Nome = "capitalist", .Popolazione = 5000000},
            New Stato With {.Nome = "republic", .Popolazione = 3000000},
            New Stato With {.Nome = "socialist", .Popolazione = 2500000}
        }

        ClassificaStati(stati)

        For Each s As Stato In stati
            Console.WriteLine(s)
        Next
    End Sub

End Module

Semplice, pulito e, soprattutto, funzionante. Ma la storia era appena iniziata.


3. Momento "adesso vi faccio vedere io": l'Assembly

Preso dall'entusiasmo della discussione nei commenti, ho pensato: "Perché non alzare il livello?". Così, per puro divertimento e per farmi un po' figo, ho riscritto la stessa logica in Assembly x86-64. Un salto carpiato dal comfort di un linguaggio ad alto livello alla gestione manuale della memoria e delle chiamate di sistema. Un'inutile e meravigliosa fatica.

; File: classifica.asm
; Per compilare ed eseguire su Linux (a 64-bit):
; nasm -f elf64 classifica.asm -o classifica.o
; ld classifica.o -o classifica
; ./classifica

section .data
    ; --- Stringhe costanti ---
    socialist_target_str db "socialist", 0
    comunista_str      db "comunista", 0
    non_comunista_str  db "non comunista", 0

    ; --- Dati di output ---
    separator          db ": ", 2
    newline            db 10, 1

    ; --- Definizione della nostra "lista" di stati ---
    STATO_SIZE equ 24

    stati:
        ; Stato 1
        dq state1_name
        dq 1000000
        dq 0
        ; Stato 2
        dq state2_name
        dq 5000000
        dq 0
        ; Stato 3
        dq state3_name
        dq 3000000
        dq 0
        ; Stato 4
        dq state4_name
        dq 2500000
        dq 0

    NUM_STATI equ ($ - stati) / STATO_SIZE

    ; Nomi degli stati
    state1_name db "socialist", 0
    state2_name db "capitalist", 0
    state3_name db "republic", 0
    state4_name db "socialist", 0


section .text
    global _start

_start:
    call classifica_stati
    call stampa_risultati
    mov rax, 60
    xor rdi, rdi
    syscall

classifica_stati:
    mov rbx, stati
    mov rcx, NUM_STATI
class_loop:
    mov rsi, [rbx]
    mov rdi, socialist_target_str
    call strcmp
    cmp rax, 0
    je  is_socialist
is_not_socialist:
    mov rax, non_comunista_str
    mov [rbx + 16], rax
    jmp next_stato
is_socialist:
    mov rax, comunista_str
    mov [rbx + 16], rax
next_stato:
    add rbx, STATO_SIZE
    loop class_loop
    ret

stampa_risultati:
    mov rbx, stati
    mov rcx, NUM_STATI
print_loop:
    mov rsi, [rbx]
    call strlen
    mov rdx, rax
    mov rsi, [rbx]
    call print
    mov rdx, 2
    mov rsi, separator
    call print
    mov rsi, [rbx + 16]
    call strlen
    mov rdx, rax
    mov rsi, [rbx + 16]
    call print
    mov rdx, 1
    mov rsi, newline
    call print
    add rbx, STATO_SIZE
    loop print_loop
    ret

print:
    mov rax, 1
    mov rdi, 1
    syscall
    ret

strlen:
    xor rax, rax
.loop:
    cmp byte [rsi + rax], 0
    je .done
    inc rax
    jmp .loop
.done:
    ret

strcmp:
.loop:
    mov al, [rsi]
    mov dl, [rdi]
    cmp al, dl
    jne .done
    cmp al, 0
    je .done
    inc rsi
    inc rdi
    jmp .loop
.done:
    sub rax, rdx
    ret

4. L'impeto di imbecillità: il Linguaggio Muccastico

A questo punto, la situazione era già degenerata in una gara di virtuosismi. E cosa c'è di più virtuoso che abbandonare completamente la logica e la sintassi umane? In un impeto di assoluta e totale imbecillità, ho riscritto tutto nel Linguaggio della Mucca. O "codice muccastico", come l'ho battezzato. Non chiedetemi cosa fa. Fa "Muu".

muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu muuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuuuuu muuuuuuuuuuuuuuuuuu

5. Un tocco di classe (e di Italia): il codice per l'ELEA 9003

Per chiudere in bellezza e dare un tocco di orgoglio nazionale, ho deciso di fare un ultimo omaggio: riscrivere il programma per l'ELEA 9003. Per chi non lo sapesse, l'ELEA 9003 è un capolavoro dell'ingegneria italiana, uno dei primi computer a transistor del mondo, creato da Olivetti nel 1958. Un esemplare è ancora funzionante all'Istituto Fermi di Bibbiena. Il linguaggio è un dialetto dell'ALGOL 60, il PALGO. Un tuffo nel passato dell'informatica italiana.

begin
    comment Questo è un programma per l'ELEA 9003 scritto in PALGO/ALGOL 60;

    integer i; comment Dichiaro una variabile intera per il ciclo;

    comment Dichiaro tre array paralleli per contenere 4 elementi ciascuno;
    string array nomi, classificazioni [1:4];
    integer array popolazioni [1:4];

    comment Assegno i valori iniziali ai nostri dati;
    nomi[1] := "socialist";   popolazioni[1] := 1000000;
    nomi[2] := "capitalist";  popolazioni[2] := 5000000;
    nomi[3] := "republic";    popolazioni[3] := 3000000;
    nomi[4] := "socialist";   popolazioni[4] := 2500000;

    comment Inizia il ciclo di classificazione.
        Il ciclo 'for' va da 1 a 4;
    for i := 1 step 1 until 4 do
    begin
        comment Controlla se il nome dello stato all'indice i è 'socialist';
        if nomi[i] = "socialist" then
            classificazioni[i] := "comunista"
        else
            classificazioni[i] := "non comunista";
    end;

    comment Ora, stampiamo i risultati. Le procedure di stampa (come 'stampa_stringa')
        sarebbero state fornite dalla libreria standard della macchina;
    for i := 1 step 1 until 4 do
    begin
        stampa_stringa(nomi[i]);
        stampa_stringa(": ");
        stampa_stringa(classificazioni[i]);
        va_a_capo(); comment Va alla riga successiva sulla stampante;
    end;

end

E così, da un semplice errore in un post su Telegram, è nata una splendida e inutile avventura attraverso decenni di storia della programmazione. Grazie, Morte, per lo spunto!