assembly emulation emu8086

assembly - Cómo usar cadenas en emu8086



emulation (2)

Hay múltiples formas de hacerlo. Aquí hay unos ejemplos:

1) Con instrucciones de cuerda:

.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) Sin instrucciones de cuerda:

.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

Instrucciones de LODSB puedes aprender más sobre las instrucciones de cuerdas desde here

3) Con lodsb / stosb y simplificado / optimizado:

.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

Necesito ayuda con cadenas en emu8086. He inicializado una cadena:

str1 db "0neWord"

Y tengo una cadena vacía:

str2 db ?

Ahora necesito verificar todas las letras en str1 y copiarlas en str2 , pero si la letra en str1 es 0, necesito reemplazarla con O. Si no, solo necesito copiar la letra.

¿Cómo puedo hacer esto?


str2 db ? No es una cadena vacía. db significa "definir byte" , y eso ? significa un solo byte no inicializado.

El db "0neWord" es la conveniencia del ensamblador, se compilará en series de bytes definidos como ''0'', ''n'', ''e'', ..., ''d'' . No existe el tipo de "cadena" en el ensamblador, todo se compila en código de máquina, que se puede ver como una serie de bytes. El "tipo" de datos almacenados en la memoria depende de las instrucciones utilizadas para acceder a ellos, pero en la memoria todo es solo una serie de bytes y puede verse como tal.

Probablemente sea un buen momento para que compruebe la documentación del depurador emu8086 y mire la memoria en la dirección str1 después de cargar el código en el depurador, para ver cómo se compiló.

Tan pronto como copie el segundo byte de str1 a str2 , comenzará a sobrescribir alguna memoria que no esperaba sobrescribir.

Para asignar un búfer de memoria de tamaño fijo, puede usar, por ejemplo, str2 db 100 DUP(?) Haciendo 100 veces ? definición a db , reservando así 100 bytes de memoria allí, los siguientes bytes de código de máquina en la misma sección se compilarán más allá de la dirección str2+100 .

Para hacer cualquier cosa con str1 "cadena" necesita saber:

1) su dirección en la memoria, el ensamblador x86 tiene muchas formas de obtenerlo, pero las dos más sencillas son:

  • mov <r16>,OFFSET str1 (r16 es cualquier registro 16b)
  • lea <r16>,[str1] (hace lo mismo en este caso)

2) su tamaño o estructura. No colocó ninguna estructura allí, como las cadenas terminadas en nulo tienen un byte con valor 0 al final, o DOS int 21h, ah=9 para mostrar la cadena espera que la cadena termine con el signo de dólar ''$'' , etc. Por lo tanto, necesita Al menos tamaño. Y la directiva EQU del ensamblador, y la "posición actual" se pueden usar para calcular el tamaño de str1 esta manera:

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

Hm, intenté verificar esto primero, leyendo algunos documentos, pero es muy difícil para mí encontrar una buena documentación completa de emu8086 (encontré algo como "referencia", y me falta por completo la descripción de las directivas del ensamblador).

Me pregunto por qué tanta gente todavía aterriza en esto, en lugar de linux + nasm / similar, que son completamente gratuitos, de código abierto y documentados.

Esperemos que emu8086 funcione como MASM / TASM y que todavía recuerde esa sintaxis correctamente, entonces la definición de tamaño mencionada anteriormente debería funcionar. De lo contrario, consulte sus ejemplos / documentos.

Finalmente, cuando tiene dirección, tamaño y un búfer de destino lo suficientemente grande (de nuevo para cargar su dirección, puede usar OFFSET o lea en emu8086), puede codificar su tarea, por ejemplo, de esta manera:

; 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 ... resulta que el "pseudocódigo" es un código x86 completo, solo tiene que asignar registros reales a los pseudocódigos y reemplazarlos en todas partes en la fuente.

Traté de poner comentarios muy extensos (desde mi punto de vista), para que pueda entender cada instrucción utilizada. Debe consultar cada uno con la guía de referencia de instrucciones de Intel, leerlo en forma cruzada con cualquier tutorial / lección que tenga disponible para ensamblar, hasta que sienta que comprende lo que es registro, memoria, etc.

También depure la instrucción de código por instrucción, verificando el estado de la CPU (valores de registro, indicadores) y el contenido de la memoria después de cada instrucción, para tener una idea de cómo funciona.