Come utilizzare le stringhe in emu8086

Ho bisogno di aiuto con le stringhe in emu8086. Ho inizializzato una stringa:

str1 db "0neWord" 

E ho una stringa vuota:

 str2 db ? 

Ora ho bisogno di controllare tutte le lettere in str1 e copiare in str2 , ma se la lettera in str1 è 0, ho bisogno di sostituirlo con O. In caso contrario, ho solo bisogno di copiare la lettera.

Come posso fare questo?

    str2 db ? non è una stringa vuota. db sta per “define byte” , e quello ? significa singolo byte non inizializzato.

    Il db "0neWord" è comodo per l’assemblatore, verrà compilato in serie di byte definiti come '0', 'n', 'e', ..., 'd' . Non esiste un tipo “stringa” nell’assemblatore, tutto viene compilato in codice macchina, che può essere visualizzato come una serie di byte. Quale “tipo” di dati viene memorizzato in memoria dipende dalle istruzioni utilizzate per accedervi, ma nella memoria tutto è solo una serie di byte e può essere visualizzato come tale.

    Questo è probabilmente un buon momento per controllare la documentazione del debugger emu8086 e guardare la memoria all’indirizzo str1 dopo aver caricato il codice nel debugger, per vedere come è stato compilato.

    Quindi, non appena copi il secondo byte da str1 a str2 , inizierai a sovrascrivere la memoria che non ti aspetti di sovrascrivere.

    Per allocare un buffer di memoria di dimensioni fisse puoi usare ad esempio str2 db 100 DUP(?) Facendo 100 volte ? definizione di db , riservando così 100 byte di memoria, i successivi byte di codice macchina nella stessa sezione saranno compilati oltre l’indirizzo str2+100 .


    Per fare qualsiasi cosa con str1 “string” devi sapere:

    1) il suo indirizzo in memoria, l’assemblatore x86 ha molti modi per ottenerlo, ma due sono i più semplici:

    • mov ,OFFSET str1 (r16 è un qualsiasi registro 16b)
    • lea ,[str1] (fa la stessa cosa in questo caso)

    2) la sua dimensione o struttura. Non hai inserito alcuna struttura, come le stringhe nul-terminate hanno byte con valore 0 alla fine, o DOS int 21h, ah=9 servizio per visualizzare la stringa si aspetta stringa terminata con il simbolo del dollaro '$' , ecc. Quindi è necessario almeno dimensioni E la direttiva EQU dell’assemblatore e la “posizione corrente” possono essere utilizzate per calcolare la dimensione dello str1 come questo:

     str1 db "0neWord" str1size EQU $-str1 ; "$" is assemblers "current_address" counter 

    Hm, ho provato a verificarlo prima, leggendo alcuni documenti, ma per me è molto difficile trovare una buona documentazione completa di emu8086 (ho trovato qualcosa come “reference”, e manca completamente la descrizione delle direttive assembler).

    Mi chiedo perché così tante persone continuino a farlo, invece di linux + nasm / similar, che sono completamente gratuite, open source e documentate.

    Quindi speriamo che emu8086 funzioni come MASM / TASM e che ricordo ancora correttamente la syntax, quindi la definizione di dimensioni sopra menzionata dovrebbe funzionare. Altrimenti consulta i tuoi esempi / documenti.


    Infine, quando si dispone di indirizzo, dimensione e buffer di destinazione sufficientemente grande (di nuovo per caricare il suo indirizzo è ansible utilizzare OFFSET o lea in emu8086), è ansible codificare il proprio compito ad esempio in questo modo:

      ; pseudo code follows, replace it by actual x86 instructions ; and registers as you wish ; ("r16_something" means one of 16b register, r8 is 8b register) lea r16_str1,[str1] ; load CPU with address of str1 mov r16_counter,str1size ; load CPU with str1 size value lea r16_str2,[str2] ; load address of target buffer loop_per_character: mov r8_char,[r16_str1] ; read single character cmp r8_char,'0' jne skip_non_ascii_zero_char ; the character is equal to ASCII '0' character (value 48) mov r8_char,'O' ; replace it with 'O' skip_non_ascii_zero_char: ; here the character was modified as needed, write it to str2 buffer mov [r16_str2],r8_char ; make both str1/2 pointers to point to next character inc r16_str1 inc r16_str2 ; count down the counter, and loop until zero is reached dec r16_counter jnz loop_per_character ; the memory starting at "str2" should now contain ; modified copy of "str1" ; ... add exit instructions ... 

    Hmm … si scopre che lo “pseudo codice” è un codice x86 completo, devi solo assegnare i veri registri agli pseudo e sostituirli ovunque nella fonte.

    Ho provato a inserire commenti molto estesi (secondo il mio punto di vista), quindi posso capire tutte le istruzioni utilizzate. Dovresti consultare ognuno di essi con la guida di riferimento alle istruzioni di Intel, rileggerlo con qualsiasi tutorial / lezione che hai a disposizione per l’Assemblea, fino a quando non sentirai di capire cosa è registro, memoria, ecc.

    Esegui il debug dell’istruzione di codice con istruzioni, controllando lo stato della CPU (valori di registro, flag) e il contenuto della memoria dopo ogni istruzione, per avere l’idea di come funziona.

    Ci sono molti modi per farlo. Ecco alcuni esempi:

    1) Con istruzioni stringa:

     .model small .data str1 db "0neWord$" size equ $-str1 str2 db size dup ('') .code main: mov ax, @data mov ds, ax mov cx, size cld ; DF might have been set, but we want lodsb to go forwards lea si, str1 mov ax, 0 mov bx, 0 copyStr: lodsb ;str1 to al cmp al, '0' je alterChar mov str2[bx], al jmp continue alterChar: mov str2[bx], 'o' continue: inc bx loop copyStr mov str2[bx], '$' mov ah, 09h lea dx, str2 int 21h mov ah, 04ch int 21h end main 

    2) Senza istruzione stringa:

     .model small .data str1 db "0neWord$" str2 db ? .code main: mov ax, @data mov ds, ax mov si, 0 call copyStr mov ah, 09h lea dx, str2 int 21h mov ah, 04ch int 21h copyStr proc mov bx, 0 compute: mov bl, str1 [si] cmp bl, '0' je alterChar mov str2[si], bl jmp continue alterChar: mov str2 [si], 'o' continue: inc si cmp str1[si], '$' je return jmp compute return: mov str2[si], '$' ret copyStr endp end main 

    Istruzioni LODSB puoi saperne di più sulle istruzioni per le stringhe da qui

    3) Con lodsb / stosb e semplificato / ottimizzato:

     .model small .data str1 db "0neWord$" size equ $-str1 str2 db size dup ('') .code main: mov ax, @data mov ds, ax mov es, ax ; stosb stores to [es:di] mov si, OFFSET str1 mov di, OFFSET str2 cld ; make sure stosb/lodsb go forwards ; copy SI to DI, including the terminating '$' copyStr: ; do { lodsb ; str1 to al cmp al, '0' je alterChar doneAlteration: stosb ; al to str2 cmp al, '$' jne copyStr ; } while(c != '$') mov ah, 09h ; print implicit-length string mov dx, OFFSET str2 int 21h mov ah, 04ch ; exit int 21h alterChar: mov al, 'o' ;jmp doneAlteration stosb jmp copyStr end main