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.