Newsgroup: it.comp.lang.c++
Titolo: OT: Problema con l'assembler

Perdonatemi, ma non ho trovato un NG italiano più adatto per questo
post.
Il problema è: dov'è il problema in questo codice?
Ho provato di tutto, ma ogni volta il computer si pianta!
_data       segment para public 'data'
oldaddr     dd      ?
_data       ends
_stack      segment para stack 'stack'
                 db      64 dup ('STACK  ')
_stack      ends
assume cs:_code,ds:_data,es:_data,ss:_stack
_code       segment para public 'code'
;------------------------------------------------------------------------
;main:
;------------------------------------------------------------------------
main        proc  far
            push  ds              
            xor   ax,ax
            push  ax
            mov   ax,_data
            mov   ds,ax           
            mov   es,ax           
            mov   ah,35h	;GET_INT_VECT
            mov   al,08h
            int   21h
            mov   word ptr oldaddr+2,es
            mov   word ptr oldaddr,bx
            mov   al,08h	;SET_INT_VECT
            mov   ah,25h
            mov   dx,offset newint
            mov   bx,cs
            push  ds
            mov   ds,bx
            int   21h
            pop   ds
            mov   ah,08h	;aspetta che venga premuto un tasto
            int   21h
            mov   al,08h	;SET_INT_VECT
            mov   ah,25h
            mov   dx,word ptr oldaddr
            mov   bx,word ptr oldaddr+2
            push  ds
            mov   ds,bx
            int   21h
            pop   ds
            ret                   ;ritorna al DOS
main        endp
newint      proc  far
	pushf
	call      dword ptr oldaddr	
            	iret
newint      endp
_code    ends                  ;fine del segmento di codice
	 end  main

[big snip]
Il problema sta nel fatto che tu non termini il programma nel modo adeguato.
Le possibilità sono due:
1) Programma .exe
Per terminare correttamente il programma devi passare il controllo al dos
tramite il servizio 4Ch dell'int 21h. Al posto dell'istruzione ret devi
mettere:
mov ah, 4Ch
int  21h
2) Questo, come sai, è un programma che deve essere contenuto tutto in un
segmento e deve iniziare all'indirizzo 100h (usa la direttiva .ORG 100h). In
questo caso puoi tornare al dos emplicemente con l'istruzione RETN.
Ciao, Giuseppe

Le possibilità sono due:
[snip]
In realtà quello che ho usato è un modo un po' obsoleto di terminare
un programma. Purtroppo il problema non è quello. Ho provato anche
come dici tu:
_data       segment para public 'data'
oldaddr     dd      ?
_data       ends
_stack      segment para stack 'stack'
            db      64 dup ('STACK  ')
_stack      ends
            assume cs:_code,ds:_data,es:_data,ss:_stack
_code       segment para public 'code'
;------------------------------------------------------------------------
;corpo principale del programma:
;------------------------------------------------------------------------
main        proc  far
            mov   ax,_data
            mov   ds,ax           ;inizializza DS
            mov   es,ax           ;e ES
            mov   ah,35h
            mov   al,08h
            int   21h
            mov   word ptr oldaddr+2,es
            mov   word ptr oldaddr,bx
            mov   al,08h
            mov   ah,25h
            mov   dx,offset newint
            mov   bx,cs
            push  ds
            mov   ds,bx
            int   21h
            pop   ds
            mov   ah,08h
            int   21h
            mov   al,08h
            mov   ah,25h
            mov   dx,word ptr oldaddr
            mov   bx,word ptr oldaddr+2
            push  ds
            mov   ds,bx
            int   21h
            pop   ds
            mov   ah,4ch
            int   21h
main        endp
newint      proc  far
            pushf
            call  dword ptr oldaddr
            iret
newint      endp
_code       ends                  ;fine segmento di codice
            end  main
...ma non è cambiato nulla.
Questo, come avrai capito, è parte del mio codice. Il programma è
molto più grande, perciò non posso creare un file .com
Comunque se provi ad assemblare il codice che ho postato vedrai che
non funziona!
GRAZIE
Daniele.


Qui ho scordato l'intestazione del secondo caso. Sarebbe
2) Programma .com
scusa


...

                 ^^ Si blocca qui

Ho capito come funziona il programma e lo ho debuggato con il debug del DOS.
Il programma si blocca quando cerchi di sostituire il tuo vettore di
interrupt con l'int 21h e mostra il messaggio:
"L'applicazione ha causato un errore di overflow di divisione
 Se il problema persiste contattare il fornitore dell'applicazione
 Errore di allocazione di memoria
 Impossibile avviare COMMAND".
Potebbe essere il tuo programma o il debug.exe a generare questo errore
(comunque propendo per la seconda ipotesi).
Voglio farti notare quattro cose che potrebbero essere la soluzione al tuo
problema:
1) Quando salvi il vecchio vettore dell'int 8h, l'int 21 ti ritorna
l'indirizzo far in ES:BX. Ho notato (sempre che non mi sbagli) che il
puntatore non veniva memorizzato correttamente.
Esempio:  ES:BX da me era uguale a  C800:0000 e all'indirizzo di memoria
DS:0000 (oldaddr) dopo la memorizzazione vi erano erano i byte 00 00 00 C8
ecc. Sarà giusto? Secondo me ci dovrebbero essere  iyte 00 00 C8 00. O no?
2) Premettendo che non sono un profondo conoscitore dell'asm, nel tuo
vettore di interrupt utilizzi l'istruzione pushf che salva il registro di
flag nello stack. Ma non chiami nessuna funzione di pop quindi prima o dopo
lo stack si saturerà per poi andare in overflow.
3) Invece di attaccarti all'interrupt 8h prova l'1Ch che è equivalente al
primo ed è stato progettato apposta per essere utilizzato dalle
applicazioni. A meno che tu non abbia installato dei TSR dovrebbe essere
libero e tu non avresti necessità di salvare il vecchio vettore.
4) Prova a disabilitare gli interrupt hardware (con CLI e STI) durante
l'installazione del nuovo vettore.
Non saprei cos'altro dirti, perchè in fin dei conti il listato è corretto.
Ciao, Giuseppe



l'installazione del nuovo vettore.
In effetti pensandoci bene e dal poco che so di assembler, bisognerebbe
fare cosi` per evitare inconsistenze... il dos non e` esattamente un sistema
monoprogrammato, con i tsr fu introdotto un certo grado di multiprogrammazione...
Paolo
-----------------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
-----------------------------------------------------------------

Ciao, Giuseppe

 Ho provato di tutto, ma ogni volta il computer si pianta!
Molto semplice, il riferimento a "oldaddr" e' sbagliato in "newint"
  call      dword ptr oldaddr
quando l'assemblatore calcola dove leggere oldaddr lo fa riferito a DS,
pensando che DS punti a _data, ma quando scatta l'interrupt non e' cosi',
perche DS dipende da cosa stava elaborando in quel momento, che potrebbe non
essere il tuo programma.
In questi casi puoi seguire 2 strade:
---------------- metodo 1
 newint      proc  far
     push    ds
     push    ax
     mov     ax,_data
     mov     ds,ax
     pushf
     call    dword ptr oldaddr
     pop    ax
     pop    ds
     iret
 newint      endp
---------------- metodo 2
 _code       segment para public 'code'
 oldaddr     dd      ?                        ;lo devi dichiarare in _code
 newint      proc  far
     assume  ds:nothing, es:nothing, cs:nothing  ;l'assemblatore non deve
prendere riferimenti da solo
     pushf
     call    dword ptr CS:oldaddr
     iret
 newint      endp
a te la scelta.
ciao
donCiccio