Visualizza il feed RSS

Titolo provvisorio...

C=64: Ready_

Valuta questo inserimento
di pubblicato il 10-03-2012 alle 04:29 (4381 Visite)
Un recente post del nostro ottimo Antonio sollecita una adeguata risposta: un tuffo in un oceano ben noto e molto amato, quello dei nostri esordi informatici con i PET, sempre modernissimi nonostante gli ormai sei lustri trascorsi dalla loro introduzione sul mercato italiano.

Uno dei primi elementi che attiravano l'attenzione degli allora programmatori in erba erano i primi software semiprofessionali in circolazione, allegati alle modernissime riviste con cassetta o, più di rado, scaricati nottetempo dalle primissime BBS (con costi da sultanato del Brunei per i primi collegamenti internazionali).

Naturalmente il primo istinto dopo un LOAD e prima del RUN era quello di dare un bel comando LIST per dare un'occhiata reverenziale a come i veri programmatori, pagati fior di quattrini, scrivevano il loro codice per ottenere quelli che, all'epoca, parevano risultati mirabolanti (e in molti casi lo erano realmente, tutto sommato). Altrettanto naturalmente, spesso tutto ciò che appariva a video era uno scarno "10 SYS 2198" nei casi migliori, ossia una istruzione che passava immantinente il controllo al codice assembly caricato appunto a partire da tale indirizzo hardcoded: oppure, ancora più curiosamente, una stringa che tutto pareva, tranne una riga di istruzioni basic. Qualcosa come "1985 (Copyright) Vattelapesca Software", che ovviamente - se digitata normalmente nell'editor del C64 e poi inviata in esecuzione non provocava che errori, con conseguenti improperi degli allora imberbi studentelli...

Il tempo e lo studio, dietro la spinta iniziale della curiosità e dello stupore, hanno presto dipanato questi dubbi, rendendoli perfino risibili.

Procuriamoci un C64 virtuale (o meglio una vera macchina) e analizziamo più da vicino una linea di codice CBM BASIC, ad esempio il seguente listato:
codice:
10 A=19
20 PRINT A
Le locazioni di memoria 43 e 44 contengono l'indirizzo di avvio del programma basic (normalmente 2049). Analizzando il contenuto della memoria a partire da tale locazione, otteniamo facilmente il seguente dump decimale:
codice:
10 8 10 0 65 178 49 57 0
18 8 20 0 153 32 65 0
0 0
Per comodità di lettura, il dump è suddiviso in corrispondenza del terminatore di linea. Si notano alcuni campi fondamentali, ovviamente in formato little-endian per quelli a 16 bit: in rosso i due byte dell'indirizzo di memoria della prossima linea, perché tali entità formano di fatto una lista linkata semplice; in blu il numero di linea, memorizzato anch'esso su 16 bit, che compare durante il listing e come tale viene utilizzato per il riordino apparente delle linee di codice, ma ha valore puramente rappresentativo (e moltissimi sporchi trucchi possono esservi applicati, ma non lasciamoci prendere la mano...). Il resto della linea contiene i token, le costanti, le variabili e gli altri elementi fondamentali per l'interprete, nei cui dettagli però non scenderemo adesso.
La linea basic è poi terminata con uno zero, e l'intero programma è chiuso da una coppia di zeri in corrispondenza dell'ultimo indirizzo referenziato.

Ora, è piuttosto chiaro che con questa basilare conoscenza possiamo già far iniziare il nostro listato assembly all'indirizzo desiderato (per default 2048 +1), ponendovi quindi una serie di byte abilmente artefatti per ingannare il comando LIST come a noi fa più comodo.

Ecco un possibile modo per generare quel mirabolante effetto di far elegantemente sparire anche il comando SYS, pur necessario all'avvio canonico del nostro codice Assembly, sostituendolo con una stringa arbitraria e irriverente:
codice:
;**************************************
; Codice "universale" per startup BASIC
;**************************************
        *=$0801

;--------------------------------------
        .WORD BASEND                    ; Indirizzo della prossima linea
        .WORD 1996                      ; Numero di linea -> anno di stesura...
        .BYTE $9E                       ; Token per "SYS"
        .ASC "2105:"                    ; Indirizzo di avvio
        .BYTE $8F,$22                   ; Token per "REM" + '"'
; Rendo illeggibile il listing con una serie di DEL ($14)
        .BYTE 20,20,20,20,20,20,20,20,20,20,20,20
; Solo la stringa seguente apparira' nel listato:
        .ASC "(C) CASA MIA SOFTWAREHOUSE***"
        .BYTE 0                         ; Terminatore di linea
BASEND  .WORD 0                         ; Terminatore di programma
;--------------------------------------
;**************************************
;** Qui inizia il nostro sorgente    **
;**************************************

        .END
Il banale trucco consiste, ovviamente, nel fatto che il povero comando LIST tenta di interpretare letteralmente il contenuto della REM, poiché esso è nequiziosamente posto tra virgolette (ad onor del vero, sono sufficienti quelle di apertura), dunque "eseguirà" una serie di backspace, cancellando la parte di riga già stampata e riportando il cursore ad inizio riga. Semplice, astuto ed efficace...

La maggior parte degli assembler e cross assembler per 6502/C64 accetterà senza lamentarsi la sintassi proposta. Piccole modifiche potrebbero essere necessarie in caso di conclamate idiosincrasie dell'assemblatore... e buon divertimento!

Per amor di generalità, l'indirizzo della SYS nell'esempio soprastante è hardcoded e calcolato manualmente, in modo da non mettere in difficoltà neppure gli assembler più semplici. Si noti tuttavia che, tra le innumerevoli versioni del Turbo Assembler, quasi tutte supportano una sintassi delle varie direttive .text, .null, .shift eccetera che converte una costante numerica di tipo simbolico o label (calcolata a tempo di assemblaggio) direttamente nella sua rappresentazione ASCII, come nell'esempio seguente, che compare anche nella documentazione:
codice:
	*=$0801
	.word ss, 2005
	.null $9e, ^start ;will be sys 4096
ss	.word 0

	*=$1000
start	rts
Quindi in tale contesto l'operatore ^ ha, di fatto, un duplice uso: XOR se usato normalmente con due operandi, e l'equivalente di itoa() se applicato ad un singolo operando entro una direttiva testuale (es. .text o .null).


C64 Turbo Assembler homepage.

64TAss (porting del Turbo Assembler per PC) su sourceforge.

aggiornamento da 28-05-2016 a 15:02 di M.A.W. 1968

Categorie
Programmazione , Tecnologia

Commenti

  1. L'avatar di AntonioG
    Questo il codice preparato in un file

    Blog.s65

    come sorgente per il mio Assembler ...

    codice:
    ;**************************************
    ; Codice "universale" per startup BASIC
    ;**************************************
            
    		.ORG $0801
    
    ;--------------------------------------
            .DW BASEND                    ; Indirizzo della prossima linea
            .DW 1996                      ; Numero di linea -> anno di stesura...
            .DB $9E                       ; Token per "SYS"
            .ASCII "2105:"                ; Indirizzo di avvio
            .DB $8F,$22                   ; Token per "REM" + '"'
    ; Rendo illeggibile il listing con una serie di DEL ($14)
            .DB 20,20,20,20,20,20,20,20,20,20,20,20
    ; Solo la stringa seguente apparira' nel listato:
            .ASCIZ "(C) CASA MIA SOFTWAREHOUSE***"
    BASEND  .DW 0                         ; Terminatore di programma
    ;--------------------------------------
    ;**************************************
    ;** Qui inizia il nostro sorgente    **
    ;**************************************
    
            .END
    e questo il risultato nel file

    Blog.l65

    (naturalmente oltre al file binario Blog.b65)

    codice:
    D64ASM - Development Assembler for C64
    Version 1 revision 47
    (C) Antonio G, 2011
    
     Line #  Addr   Value       Label         Line
    00000001 0000                                                                           ;**************************************
    00000002 0000                                                                           ; Codice "universale" per startup BASIC
    00000003 0000                                                                           ;**************************************
    00000004 0000                                                                           
    00000005 0000 *=0801                             .ORG     $0801                         
    00000006 0801                                                                           
    00000007 0801                                                                           ;--------------------------------------
    00000008 0801 37 08                              .DW      BASEND                        ; Indirizzo della prossima linea
    00000009 0803 CC 07                              .DW      1996                          ; Numero di linea -> anno di stesura...
    00000010 0805 9E                                 .DB      $9E                           ; Token per "SYS"
    00000011 0806 32 31 30 35                        .ASCII   "2105:"                       ; Indirizzo di avvio
                  3A 
    00000012 080B 8F 22                              .DB      $8F,$22                       ; Token per "REM" + '"'
    00000013 080D                                                                           ; Rendo illeggibile il listing con una serie di DEL ($14)
    00000014 080D 14 14 14 14                        .DB      20,20,20,20,20,20,20,20,20,20,20,20
                  14 14 14 14 
                  14 14 14 14 
    00000015 0819                                                                           ; Solo la stringa seguente apparira' nel listato:
    00000016 0819 28 43 29 20                        .ASCIZ   "(C) CASA MIA SOFTWAREHOUSE***"
                  43 41 53 41 
                  20 4D 49 41 
                  20 53 4F 46 
                  54 57 41 52 
                  45 48 4F 55 
                  53 45 2A 2A 
                  2A 00 
    00000017 0837 00 00          BASEND              .DW      0                             ; Terminatore di programma
    00000018 0839                                                                           ;--------------------------------------
    00000019 0839                                                                           ;**************************************
    00000020 0839                                                                           ;** Qui inizia il nostro sorgente    **
    00000021 0839                                                                           ;**************************************
    00000022 0839                                                                           
    00000023 0839                                    .END                                   
    00000024 0839 >End of current source<
    
    Errors    : 00000
    Bei tempi ...
    aggiornamento da 10-03-2012 a 16:28 di M.A.W. 1968 (Privacy)
  2. L'avatar di M.A.W. 1968
    Quote Originariamente inviato da AntonioG
    Bei tempi ...
    Ottimo lavoro, Antonio... e sì, quelli erano davvero bei tempi!