Developer Assistant

------------------------------------------

Programmare in Assembler con OS/2

In questa sezione vorrei presentare lo sviluppo di una semplicissima utility per OS/2 che ho deciso di realizzare in questi giorni (università permettendo :)).
L'utility in questione serve per sapere il tipo processore installato sul computer fin nei più minimi dettagli cercando di riconoscere il maggior numero possibile di CPU presenti sul mercato. Per svolgere questo 'delicato' compito mi servirò di porzioni di codice rilasciate dall'Intel stessa, di sorgenti trovati a giro e informazioni tecnice ottenute direttamente dai produttori (AMD, Cyrix, IBM, ecc.).
In questo esempio suppongo una buona conoscenza del linguaggio assembler 386, comunque nel caso ci fossero alcuni dubbi sono disponibile a chiarimenti via e-mail.

Prima di tutto bisogna sapere cosa riceve dal sistema operativo il programma appena lanciato, e per far questo ricorrerò al commento di un sorgento trovato sul sito Hobbes "SKELOS2.ZIP".

Condizioni all'ingresso (Author: Bill Magletta (CIS 72411,2473)
Segmento OS Bits Commento
CS DOS
?
OS/2 16-Bit Code segment selector.
32-Bit Code selector for the base of the address space.
SS DOS
Stack segment selector, except in TINY model, where SS=CS
OS/2 16-Bit Automatic data segment selector.
32-Bit Data selector for the base of the address space.
DS DOS
PSP Segment Selector
OS/2 16-Bit Automatic data segment selector.
32-Bit Data selector for the base of the address space.
ES DOS
PSP segment selector
OS/2 16-Bit 0
32-Bit Data selector for the base of the address space.
FS DOS
?
OS/2 16-Bit ?
32-Bit TIB (Thread Information Block) Data Selector.
IP DOS
Program entry point offset.
OS/2 16-Bit Program entry point offset.
32-Bit Program entry point offset.
AX DOS
?
OS/2 16-Bit Environment segment selector. (This selector can also be obtained via DosGetEnv.
32-Bit 0
BX DOS
?
OS/2 16-Bit Offset to program name in environment segment. (this offset can also be obtained via DosGetEnv.)
32-Bit 0
CX DOS
?
OS/2 16-Bit Size of automatic data segment.Zero means 65,536.
32-Bit 0
DX DOS
?
OS/2 16-Bit ?
32-Bit 0
SP DOS

OS/2 16-Bit Top of stack offset.
32-Bit Top of stack offset.
[ESP+00] Return address; EAX should = exit code.
[ESP+04] Program module handle.
[ESP+08] (reserved)
[ESP+12] Environment data object address.
[ESP+16] Address of cmd line in env data object.
BP DOS
?
OS/2 16-Bit 0
32-Bit 0
Other All other register are undefined

Questo breve riassunto ci informa di tutto quello che il sistema ci fornisce sia esso: DOS, OS/2 16-bit o OS/2 32-bit. A questo punto dobbiamo mettere a frutto questa conoscenza creandoci i segmenti base della nostra applicazione che saranno ovviamente in numero minimo per poter sviluppare semplici applicazioni: un segmento di codice, un segmento di dati statici, un segmento di dati non inizzializzati, e ovviamente lo stack. I due segmenti di dati e lo stack fanno tutti parte del gruppo DGROUP. Attenzione che l'ordine di definizione dei segmenti è importante specialmente se non viene specificata al linker l'opzione DOSSEG che stabilisce come ordinare i segmenti in base alla loro classe.
Vi prego di fare attenzione al fatto che questa è la definizione dei segmenti, ma nessuno di questi contiene niente. Ho fatto questa scelta per ragioni di chiarezza ed anche per stabilire subito l'ordine dei segmenti in quanto non volevo usare l'opzione DOSSEG. La cosa più eclatante è che lo stack non può avere dimensione nulla ! :-)

Definiamo quindi lo stack.
Avremo quindi uno stack di 4096 bytes che dovrebbe essere sufficiente anche per l'utilizzo delle DLL di sistema.

Eccoci quindi al programma vero e proprio che sarà composto da una funzione principale, che chiameremo Main, e da tante sottofunzioni. La nostra Main si occupa di salvare l'indirizzo dell'environment, della linea di comando (saltando però il nome del programma), scrivere il titiolo del programma e quindi di chiamare le varie sottofunzioni.
Ho inserito anche tutti i dati costanti che verranno usati anche nelle funzioni successive perché sono quasi esclusivamente messaggi da stampare sul video.
Vi prego di notare la chiamata alla funzione di sistema DosExit. Questa funzione è esattamente la stessa che si usa programmando in C (definita come DosExit(ULONG,ULONG) ) e questo vuol dire che per passarle dei parametri è necessario usare il metodo standard del C, cioè lo stack.
Questa osservazione rimane valida per tutte le funzioni di sistema !
La label CPUType fa riferimento ad una variabile inizzializzata nella funzione check_cpu quindi per il momento vi prego di ignorarla, se non per il fatto che il suo valore viene restituito come valore di ritorno del programma.

A questo punto mi limiterò a presentare il codice corrispondente alla chiamata della funzione DosPutMessage e la dichiarazione delle label esterne tralasciando il resto del codice in quanto non ha niente di specifico per OS/2 e chiunque abbia pratica col linguaggio assembler può studiarselo direttamente.

Definizione delle macro.
La macro PutMessage serve per passare e preparare tutti i parametri per DosPutMessage rispettando il metodo di passaggio dei parametri usato dal C. La funzione strlen calcola la lunghezza in byte di una stringa, terminata con uno zero, che inizia all'indirizzo contenuto nel registro eax.

A questo punto prima di concludere non mi rimane che fornire le istruzioni per la compilazione del file CPUID.ASM. L'unica accortezza che bisogna avere è di ricordarsi di includere la libreria os2386.lib in fase di linking. Per i fortunati possessori dell'assemblatore e il linker della Watcom eccovi i comandi già pronti:

wasm cpuid.asm
wlink system os2v2 file cpuid.obj option map=cpuid.map library os2386.lib

Con questo concludo e rimango a disposizione via e-mail per qualsiasi commento e/o dubbio.

---------------------------------------------------

Torna alla nostra HomePage - Pagina a cura di: Giovanni Pagni
Last modified 24-10-97