1

我需要有关 emu8086 中字符串的帮助。我已经初始化了一个字符串:

str1 db "0neWord"

我有一个空字符串:

str2 db ?

现在我需要检查所有的字母str1并复制到str2,但是如果输入的字母str1是0,我需要用O替换它。如果不是,我只需要复制这个字母。

我怎样才能做到这一点?

4

2 回答 2

2

str2 db ?不是空字符串。db代表“定义字节”,这?意味着单个未初始化的字节。

db "0neWord"是汇编程序的便利,它将编译成定义为的一系列字节'0', 'n', 'e', ..., 'd'。汇编中没有“字符串”类型,一切都被编译成机器码,可以看作是一系列字节。存储在内存中的数据“类型”取决于用于访问它们的指令,但在内存中,所有内容都只是一系列字节,可以这样看待。

这可能是您检查 emu8086 调试器文档的好时机,并在str1将代码加载到调试器后查看地址处的内存,看看它是如何编译的。

因此,一旦您将第二个字节从str1to复制str2,您将开始覆盖一些您没想到会覆盖的内存。

要分配一些固定大小的内存缓冲区,您可以使用例如对str2 db 100 DUP(?)进行 100 次?定义db,从而在那里保留 100 字节的内存,同一节中的下一个字节的机器代码将被编译超出str2+100地址。


要使用“字符串”做任何事情,str1您需要知道:

1) 它在内存中的地址,x86 汇编器有很多方法可以得到它,但最简单的两种方法是:

  • mov <r16>,OFFSET str1(r16 是任何 16b 寄存器)
  • lea <r16>,[str1](在这种情况下做同样的事情)

2)它的大小或结构。您没有在那里放置任何结构,例如以 nul 结尾的字符串0在其末尾具有带有值的字节,或者int 21h, ah=9显示字符串的 DOS 服务需要以美元符号结尾的字符串'$'等。所以您至少需要大小。汇编程序的指令和EQU“当前位置”可以用来计算str1这样的大小:

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

嗯,我首先尝试通过阅读一些文档来验证这一点,但是我很难找到任何好的完整的 emu8086 文档(找到类似“参考”的东西,并且完全缺少对汇编程序指令的描述)。

我想知道为什么还有这么多人使用它,而不是完全免费、开源和文档化的 linux + nasm/similar。

所以让我们希望 emu8086 像 MASM/TASM 一样工作,并且我仍然正确地记得那个语法,那么上面提到的大小定义应该可以工作。否则请查阅您的示例/文档。


最后,当您拥有地址、大小和足够大的目标缓冲区(再次加载您可以使用的地址OFFSETlea在 emu8086 中)时,您可以通过以下方式对您的任务进行编码:

    ; 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 ...

嗯..原来“伪代码”是完整的 x86 代码,您只需将真实寄存器分配给伪寄存器,并在源代码中的任何地方替换它们。

我试图在那里发表非常广泛的评论(以我的观点),以便可以理解使用的每条指令。您应该使用 Intel 的指令参考指南来查阅每个指南,将其与您可用于组装的任何教程/课程进行交叉阅读,直到您觉得您了解什么是寄存器、内存等。

还要逐条调试代码指令,在每条指令之后检查 CPU 的状态(寄存器值、标志)和内存内容,以了解它是如何工作的。

于 2016-11-14T01:57:25.030 回答
2

有多种方法可以做到这一点。这里有些例子:

1)带字符串指令:

.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)没有字符串指令:

.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 

LODSB 指令,您可以从此处了解有关字符串指令的更多信息

3) 使用 lodsb / stosb 并简化 / 优化:

.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 
于 2017-11-16T17:39:32.400 回答