SCOPO DIDATTICO

Per inquadrare l'argomento, dico per prima cosa perchè lo ho scritto:

  1. insegno sistemi in un ITIS (tradizionale! uno degli ultimi dinosauri)
  2. Alla mia scuola i programmi risalgono all' 82, anche se il D.S. si sforza di dire che è la scuola dell’Autonomia che decide... beato lui.
  3. Nella scuola precedente il progetto ABACUS aveva svecchiato (!! 1990!) i programmi: qui sono precipitato nella preistoria: mi fa sentire giovane, ma non è serio...
  4. In Sistemi andrebbero spiegati i microprocessori e relativo Assembler
  5. Con Windows 2000 e XP NON sono più disponibili tutta una serie di tecniche programmative (ne potremmo fare un articolo "didattico" a parte...) che usavano DOS/BIOS/ASM e accesso diretto alla macchina.
  6. NON è più possibile fare gli esercizi/esperienze di Laboratorio dei libri tradizionali (anche gli ultimi!), nemmeno se si fa riferimento ai testi di Abacus.
  7. Mi pare ridicolo dire ai ragazzi che il loro PC ha al max 1 MB di Ram....

quindi.. ??

    • O si butta a mare l'Assembler (come fanno alcuni qui nel circondario che transitano su Java...! ma cosa c'entra coi microprocessori?)
    • O si tenta i utilizzare lo logiche NUOVE (per modo di dire.. è fin da NT 4.0 che la logica dell’accesso all’Hardware è mutata) per utilizzare i microprocessori.

Poichè ritengo valido l’Assembler da punto di vista didattico, in un mondo informatico ormai invaso da form, Visual basic, Java e HTML (God save us!) ho quindi tentato di produrre una serie di strumenti per poterlo utilizzare nuovamente ma in maniera "moderna" utilizzando l’approccio a 32 bit.

Questo breve articolo (ed il seguente) è un documento prodotto per i miei studenti.

ABSTRACT

Vediamo passo passo come configurare in buon MSVC 6.0 in tamdem con il beloved MASM 611 per produrre un progetto ibrido C/MASM con tutte le caratteristiche di un progetto Visual studio, dimenticando le brutture dell’interfaccia a caratteri del PWB. Verrà creato un piccolo esempio di programma C, modalità console, che chiama una routine esterna in ASM a 32 bit.

INTRO

Ora il mondo va verso lidi sempre più astratti dal puro silicio... Ma sotto c’è pur sempre il buon vecchio ASM.

Vediamo quindi come fare scrivere ASM, ma almeno dentro un ambiente uniforme, a finestre, in un ambiente moderno a 32 bit, mollando il vecchio e caro PWB con interfaccia carattere e finestre a caratteri 80x25, senza cut&paste!!

Prerequisiti:

  • MSVC installato correttamente
  • MASM 6.11 installato nella sua dir. Per default: C:\MASM611 ( in effetti basta ML.exe e solo i file per NT)
  • Ed ovvio, che sappiate ASM e "C"

PASSI DA SEGUIRE

Vediamo cosa fare per creare un progetto misto.

a) Creare un normale progetto MSVC p.es. console.

b) nel sorgente C dichiarare le funzioni scritte in ASM come external, quindi se p.es. ho una funzione esterna che fa la somma di due long, invece di:

long sum(long a, long b);

Deve essere:

extern C void sum(long a, long b);

ossia funzione esterna a questo file.

Ovviamente il proto va dato. Se manca Extern il compliatore trova "C" e non sa che fare ( i.e. error).

"C" è lo stile di chiamata: con la convenzione di passaggio parametri stile C (da destra a sinistra). Quindi il il compliatore caricherà lo stack (diremmo pusha sullo stack ) i parametri dall’ultimo al primo.

ESEMPIO DI MAIN

extern "C" long sum(long a, long b);

int main(int argc, char* argv[])

{

long x=1;

long y =2;

long z = sum(x,y);

printf("Hello World!\n");

return 0;

}

a compile time tutto OK, ma a link time:

Linking...

MIXED1.obj : error LNK2001: unresolved external symbol _sum

Appunto perché manca l’OBJ. Quindi va creato il file ASM, e va invocato il compilatore ASM ML.EXE

CREAZIONE DEL FILE ASM

Creiamo quindi un nuovo TEXT file, non un source file:

 

e salviamolo con estensione *ASM; p.es. "sum.ASM" in una directory qualsiasi (per comodità insieme agli altri file del progetto).

Assolutamente specificare l’estensione!

Poi il file va aggiunto al progetto con :

 e ora lo editiamo:

 ; SUM.ASM

Sum PROC

Sum ENDP; fine proc

END ;fine codice

OSS:

la funzione ASM per ora vuota. NON compilerà né funzionerà per vari motivi:

  1. manca specificazione del MODEL
  2. non estraimo dallo stack parametri né passiamo indietro il risultato.

Vogliamo per ora solo compliare e LINKARE.

Quindi dobbiamo creare un "Custom Build" per il file ASM.

CUSTOM BUILD

Click col tasto DX del mouse ed appare:

Custom Build:

ell’edit box Commands vanno messi tutti quei comandi da command line che producono l’OBJ invocando l’Assemblatore:

c:\masm611\bin\ml /c /Cx /coff $(inputpath)

dove appunto c:\masm611\bin\ml è il masm ml.exe

/c e /coff sono opzioni:

/c = Assembla SENZA linker (usiamo il linker di Visual Studio)

/coff = Common Object file Format: che tipo di OBJ generare

$(inputpath) è una variabile dell’ambiente: ha lo stesso nome del file, quindi sarà: D:\lavori\MIXED\SUM.ASM

Nell’edit box va specificato il nome del file di uscita, e la cosa più comoda è: $(InputName).obj

in modo che abbia lo stesso nome del file sorgente ma estensione OBJ.

OSS:

se non ci sono particolari esigenze di PATH e/o NOMI, usare $(inputpath) e $(InputName).obj

Si dovrebbe avere:

Ora solito F5. ( oppure F7)

Se avete digitato male, nella finestra di stato vi dice la RIGA, perché ML.EXE, invocato dal Visual Studio, redirige l’output alla finestra di stato:

Performing Custom Build Step on .\SUM.ASM

Microsoft (R) Macro Assembler Version 6.11

Copyright (C) Microsoft Corp 1981-1993. All rights reserved.

Assembling: .\SUM.ASM

.\SUM.ASM(4): error A2008: syntax error : integer

.\SUM.ASM(5): error A2085: instruction or register not accepted in current CPU mode

il doppio click (o F4) funziona come un normale file C.

CREAZIONE DEL FILE ASM

Ora la procedura per bene:

; SUM.ASM

.386 ;set di istruzioni da utilizzare;

; anche .586

.MODEL FLAT, C ; SOLO FLAT per win32;

; C specifica il modello della chiamata,

;ossia ordine dei param. sullo stack

; anche se qui li estraiamo "a mano"

.CODE ; inizio codice

.STACK

Sum PROC

MOV EDX, ESP

MOV EAX, [EDX+4]

MOV EBX, [EDX+8]

ADD EAX,EBX ; risultato per convenzione in EAX ; il chiamante ripristina lo stack

RET

Sum ENDP ; fine proc

END ;fine codice

Notare:

  • Modello Flat (4 GB ..), no more Segments..
  • Abilitate istruz. Del 386, ma ilMASM 6.11 supporta anche .586
  • .STACK , ma si può omettere non è un exe separato o una DLL
  • Se un exe separato o DLL esiste anche .DATA
  • aritmetica dei registri per prelevare param. dallo stack:
  • Sulla cima c’è l’indirizzo di ritorno (a 32 bit quindi 4 byte), poco sopra il PRIMO PARAMETRO (dicasi a, se parliamo del param. Formale, x per quello attuale)

    Ed altri 4 bit sopra il 2’ param, infatti b è stato pushato per PRIMO quindi più in alto.

    Top of STACK

     

     

     

    ...

     

     

    2

     

    2’ param

    1

     

    1’ param

    Ret. Address

     

    Indirizzo di ritorno

    < 32 bit >

     

     

    LA "CHICCA"

    Debuggate: tutto funziona, ma dovete prima aprire la finestra del disassembly; scomodo!

    Certo, MOLTO meglio che il debugger del PWB a caratteri..

    Se però si leggo l’help delML.EXE si trova l’opzione /Zd che aggiunge le linee di codice per il debug all’OBJ.

    Quindi cambiamo il cmd in:

    c:\masm611\bin\ml /c /Cx /coff /Zd $(inputpath)

    ed ora si traccia dentro l’asm!!

    ONE STEP BEYOND STACK ARITMETICS

    Per procedure così piccole, la stupida aritmetica con gli spiazzamenti sullo stack è immediata. Ma se i parametri aumentano e sono di tipo diverso, diventa scomodo. E non dimentichiamo che qui siamo sulla nuda macchina: un errore di calcolo e siamo su un altro parametro o su garbage.. O in BSoD!

    Ma già da molti anni gli asm decenti hanno il concetto di procedura con parametri. dal punto di vista pratico significa che fanno loro i calcoli e si usano nomi simbolici ("parametri formali") per poppare dallo stack (nda: poppare è l’infinito di "to pop").

    Un esempio:

    .386

    .MODEL FLAT, C

    .CODE ; inizio codice

    Subtract PROTO C arg1:DWORD, arg2:DWORD; prototipo.CODE

    Subtract PROC C arg1:DWORD, arg2:DWORD

    mov eax, arg1 ; Arg1 in AX

    mov ecx, arg2 ; Arg2 in CX

    sub eax, ecx

    ret

    Subtract ENDP

    END

    Caveat

    Notiamo due cose:

    1. se da C passiamo più parametri o scriviamo male il proto nel c, ancora avremo errori nel calcolo delgi offset sullo stack da parte dell’ASM
    2. Se in C dichiariamo argomenti char o short, COMUNQUE l’occupazione è sempre di 4 byte: lo stack è effciente a colpi di 32 bit.

    Quindi in C il prototipo può essere:

    extern "C" long Subtract(short c, short d);

    oppure:

    extern "C" long Subtract(long c, long d);

    Ma in asm lo stesso codice che prenda 4 BYTE; quindi DWORD.

    NON E’ FINITA: E CON VISUAL C++ 2005?

    Ok, ma ora MVSC ha cambiato nome, sono uscite nuove release, come Studio .Net. Allora? Abbiamo scaricato addirittura la beta per programmatori di Visual Studio C++ Express 2005. (per inciso, anche se stabile pare più una alpha.. mancano un sacco di cose..). Abbiamo semplicemente importato il vecchio file *.DSW: C++2005 ha creato al volo il nuovo progetto *vcproj ed ha tenuto tutto:

    e vediamo se compila e debugga:

    Sì, anche se pare non fare il "Trace Into" al codice ASM. Però funziona.

    Esplorando dentro i Settings dei file ASM:

    vediamo le stesse impostazioni (più o meno..) del VC 6.0.

    CONCLUSIONI

    Anche se nel 2004 impazza JAVA, PHP ed altre tecniche di programmazione "alte", che astraggono in modo estremo dalla macchina fisica, è ancora possibile, utile, necessario utilizzare l’assembler. Questo può servire a chi scrive device driver, a chi deve ottimizzare il codice in modo estremo o anche solo per l’aspetto didattico: conoscere il processore a livello fisico, a livello ASM permette di scrivere codice più robusto, efficiente, funzionante.. Se no.. scrivete in VB!

    Note sull’Autore

    Da anni si occupa di programmazione in un po' tutti gli ambiti.

    Il motto "Il vero programmatore o è un programmatore Assembler o no lo è."

    Attualmente preferisce Obj C, ama il C++ ed il vecchio e caro C K&R.

    Uno dei pochi che legge "There are only 10 type of people, who understand binary and who don’t." come: ci sono solo DUE tipi di persone.. e non 10!

    Parte seconda