Domanda Assemblatore non "traduce" il codice corettamente

mattstack

Utente Bronze
1 Aprile 2021
62
19
12
41
Stavo scrivendo un paio di programmi, andava tutto bene finché l'assemblatore ha decise di impazzire, ciò che accade secondo me è che decodifica in modo errato le istruzioni.
Dato il seguente codice:
Codice:
PAGE_SIZE EQU 4096

text_VRAM SEGMENT AT 0B800h

    page0      db      PAGE_SIZE DUP(?)
    page1      db      PAGE_SIZE DUP(?)
    page2      db      PAGE_SIZE DUP(?)
    page3      db      PAGE_SIZE DUP(?)
    page4      db      PAGE_SIZE DUP(?)
    page5      db      PAGE_SIZE DUP(?)
    page6      db      PAGE_SIZE DUP(?)
    page7      db      PAGE_SIZE DUP(?)

text_VRAM ENDS

stack SEGMENT PARA STACK

    db    ?

stack ENDS

data SEGMENT PARA PUBLIC

    msg     db     "hello world"

data ENDS

code SEGMENT PARA STACK

    ASSUME cs: code, ds: data, es: text_VRAM, ss: stack ;anche se non c'è ne bisogno(vabè)

_start:
    mov    ax, data
    mov    ds, ax
    mov    ax, text_VRAM
    mov    es, ax

    mov    bx, OFFSET page0
    mov    si, OFFSET msg

    lp: mov    BYTE PTR es:[bx], 0h
         mov    BYTE PTR es:[bx+1], 00010001b
         add    bx, 2

         cmp    bx, 0FFFh
         jbe    lp

    mov    bx, OFFSET page0
    mov    cx, 0Bh

    lp1: mov    al, BYTE PTR [si]
           mov    BYTE PTR es:[bx], al
           mov    BYTE PTR es:[bx+1], 00010111b
           inc    si
           add    bx, 2

           loop   lp1

    hlt

code ENDS
    END _start
Questo è ciò che genera l'assemblatore:
Schermata del 2021-05-23 20-40-53.png

Come si può vedere già dalla seconda istruzione in poi è tutto sfasato.
Inoltre la coppia CS:IP indirizza la giusta istruzione in quanto gli offset delle locazioni nella quale sono memorizzate le istruzioni rispetto alla prima sono giusti.
Ciò accade solo con quel codice, con gli altri va tutto bene, ciò mi fa pensare che sia un problema del programma, ma non capisco come possa intaccare l'Assemblatore.
Qualcuno ha qualche spiegazione? (sto utilizzando l'assemblatore MASM 6.11 e linker 16bit)
 
Su quale emulatore lo stai eseguendo?
Su DOSBox mi dà problemi: viene colorato correttamente tutto in blu, ma quando stampa a video i caratteri si ferma su "h". Con un altro emulatore invece funziona tutto, e termina correttamente.

Sicuramente c'è qualche tipo di errore, non ho modo di verificare ora però.

Ad ogni modo il primo loop puoi riscriverlo così:
Codice:
    mov    ax, 1120h ; colore, spazio
    mov    cx, 7D0h  ; 80x25 = 2000
    xor    di, di
    rep    stosw

Ho modificato un pò il codice "alla buona", così mi funziona anche su DOSBox.

Codice:
PAGE_SIZE EQU 4096

text_VRAM SEGMENT AT 0B800h

    page0      db      PAGE_SIZE DUP(?)
    page1      db      PAGE_SIZE DUP(?)
    page2      db      PAGE_SIZE DUP(?)
    page3      db      PAGE_SIZE DUP(?)
    page4      db      PAGE_SIZE DUP(?)
    page5      db      PAGE_SIZE DUP(?)
    page6      db      PAGE_SIZE DUP(?)
    page7      db      PAGE_SIZE DUP(?)

text_VRAM ENDS

stack SEGMENT PARA STACK

    db    ?

stack ENDS

data SEGMENT PARA PUBLIC

    msg     db     "hello world"

data ENDS

code SEGMENT PARA STACK

    ASSUME cs: code, ds: data, es: text_VRAM, ss: stack ;anche se non c'è ne bisogno(vabè)

_start:
    mov    ax, data
    mov    ds, ax
    mov    ax, text_VRAM
    mov    es, ax

    mov    ax, 1120h
    mov    cx, 7D0h
    xor    di, di
    rep    stosw

    mov    bx, OFFSET page0
    mov    cx, 0Bh

    mov    si, OFFSET msg
    
    lp1:
        mov    al, BYTE PTR [si]
        mov    ah, 17h
        mov    word PTR es:[bx], ax
        inc    si
        add    bx,2
        sub    cx,1
        jnz    lp1
    
    mov    ax, 4c00h
    int    21h

code ENDS
    END _start

Lasciando LOOP, ottengo un errore di DOSBox: Exit to error: Illegal GRP4 Call 5. Intel indica con GRP i "gruppi" (gruppo 4 in questo caso), rappresenta INC/DEC se la componente reg di ModRm è uguale a 0/1 (sono quegli opcode che da soli non identificano un'istruzione serve appunto la componente "reg" di ModRm).

Ho dato anche un occhio al codice di dosbox per capire l'errore e in effetti è dettato dal fatto che l'istruzione non esiste (CALL 5 è reg = 5, non esiste).
Non ho capito perchè si arrivi a quel punto comunque, visto che 0xFE non è un opcode presente nel binario. Tramite debugger dovresti vedere cosa succede.
 
Su quale emulatore lo stai eseguendo?
Su DOSBox mi dà problemi: viene colorato correttamente tutto in blu, ma quando stampa a video i caratteri si ferma su "h". Con un altro emulatore invece funziona tutto, e termina correttamente.

Sicuramente c'è qualche tipo di errore, non ho modo di verificare ora però.

Ad ogni modo il primo loop puoi riscriverlo così:
Codice:
    mov    ax, 1120h ; colore, spazio
    mov    cx, 7D0h  ; 80x25 = 2000
    xor    di, di
    rep    stosw

Ho modificato un pò il codice "alla buona", così mi funziona anche su DOSBox.

Codice:
PAGE_SIZE EQU 4096

text_VRAM SEGMENT AT 0B800h

    page0      db      PAGE_SIZE DUP(?)
    page1      db      PAGE_SIZE DUP(?)
    page2      db      PAGE_SIZE DUP(?)
    page3      db      PAGE_SIZE DUP(?)
    page4      db      PAGE_SIZE DUP(?)
    page5      db      PAGE_SIZE DUP(?)
    page6      db      PAGE_SIZE DUP(?)
    page7      db      PAGE_SIZE DUP(?)

text_VRAM ENDS

stack SEGMENT PARA STACK

    db    ?

stack ENDS

data SEGMENT PARA PUBLIC

    msg     db     "hello world"

data ENDS

code SEGMENT PARA STACK

    ASSUME cs: code, ds: data, es: text_VRAM, ss: stack ;anche se non c'è ne bisogno(vabè)

_start:
    mov    ax, data
    mov    ds, ax
    mov    ax, text_VRAM
    mov    es, ax

    mov    ax, 1120h
    mov    cx, 7D0h
    xor    di, di
    rep    stosw

    mov    bx, OFFSET page0
    mov    cx, 0Bh

    mov    si, OFFSET msg
 
    lp1:
        mov    al, BYTE PTR [si]
        mov    ah, 17h
        mov    word PTR es:[bx], ax
        inc    si
        add    bx,2
        sub    cx,1
        jnz    lp1
 
    mov    ax, 4c00h
    int    21h

code ENDS
    END _start

Lasciando LOOP, ottengo un errore di DOSBox: Exit to error: Illegal GRP4 Call 5. Intel indica con GRP i "gruppi" (gruppo 4 in questo caso), rappresenta INC/DEC se la componente reg di ModRm è uguale a 0/1 (sono quegli opcode che da soli non identificano un'istruzione serve appunto la componente "reg" di ModRm).

Ho dato anche un occhio al codice di dosbox per capire l'errore e in effetti è dettato dal fatto che l'istruzione non esiste (CALL 5 è reg = 5, non esiste).
Non ho capito perchè si arrivi a quel punto comunque, visto che 0xFE non è un opcode presente nel binario. Tramite debugger dovresti vedere cosa succede.
Mmm, se l'istruzione non esiste per quale motivo l'assemblatore decodifica l'istruzione?
Inoltre molte volte il debugger(anche in altri programmi) mi dava una certa istruzione 0xFE, che in effetti non è un opcode, bensì era presente nel binario senza problemi, il programma veniva eseguito e l'istruzione non generava nessuna eccezione.
 
Non so cosa si verifichi al termine del programma, a seguito del LOOP (non ho potuto verificare). Fai qualche altra prova con codici ancora più piccoli, per replicare la situazione. Il programma che ho riportato sopra è corretto, non crea problemi su DOSBox, provalo anche tu. Nell'altro caso mi sono trovato un pò spiazzato... non mi sembra di aver visto errori (dove usi LOOP).
Per altro già il primo codice funziona correttamente su Emu8086. Provalo su un altro emulatore.

0xFE comunque è un opcode valido: ma solo se la componente "reg" del byte ModRm vale 0 o 1. Identifica rispettivamente INC e DEC.

Poi magari mi sto sbagliando io, ma cercando l'errore restituito da DOSBox l'unica istruzione che ho trovato all'interno del codice è l'opcode 0xFE.
 
Mmm, se l'istruzione non esiste per quale motivo l'assemblatore decodifica l'istruzione?
Inoltre molte volte il debugger(anche in altri programmi) mi dava una certa istruzione 0xFE, che in effetti non è un opcode, bensì era presente nel binario senza problemi.

Non so cosa si verifichi al termine del programma, a seguito del LOOP (non ho potuto verificare). Fai qualche altra prova con codici ancora più piccoli, per replicare la situazione. Il programma che ho riportato sopra è corretto, non crea problemi su DOSBox, provalo anche tu. Nell'altro caso mi sono trovato un pò spiazzato... non mi sembra di aver visto errori (dove usi LOOP).
Per altro già il primo codice funziona correttamente su Emu8086. Provalo su un altro emulatore.

0xFE comunque è un opcode valido: ma solo se la componente "reg" del byte ModRm vale 0 o 1. Identifica rispettivamente INC e DEC.

Poi magari mi sto sbagliando io, ma cercando l'errore restituito da DOSBox l'unica istruzione che ho trovato all'interno del codice è l'opcode 0xFE.
Ho trovato questo a riguardo: https://stackoverflow.com/questions...ng-in-debug-after-a-manually-encoded-far-call