2016-11-13 5 views
0

Мне нужна помощь со строками в emu8086. Я инициализируюсь строка:Как использовать строки в emu8086

str1 db "0neWord" 

И у меня есть пустая строка:

str2 db ? 

Теперь мне нужно проверить все буквы в str1 и скопировать в str2, но если письмо в str1 является 0, Мне нужно заменить его на О. Если нет, мне нужно просто скопировать письмо.

Как я могу это сделать?

ответ

2

str2 db ? не является пустой линией. db означает "define byte", и что ? означает одиночный неинициализированный байт.

Удобство ассемблера db "0neWord", оно будет скомпилировано в байты, определенные как '0', 'n', 'e', ..., 'd'. В ассемблере нет типа «строка», все скомпилировано в машинный код, который можно рассматривать как ряд байтов. То, что «тип» данных хранится в памяти, зависит от инструкций, используемых для их доступа, но в памяти все это всего лишь серия байтов и может рассматриваться как таковая.

Возможно, это подходящее время для проверки документации отладчика emu8086 и просмотра памяти по адресу str1 после загрузки кода в отладчик, чтобы увидеть, как он скомпилировался.

Итак, как только вы скопируете второй байт от str1 до str2, вы начнете перезаписывать некоторую память, которую вы не ожидали перезаписать.

Чтобы выделить некоторый фиксированный размер буфера памяти можно использовать, например str2 db 100 DUP(?) делать 100 раз ? определение db, тем самым резервируя 100 байт памяти там, следующий байт машинного кода в том же разделе будут собраны за str2+100 адрес.


Чтобы сделать что-нибудь с str1 «строка» Вы должны знать:

1) его адрес в памяти, x86 ассемблере есть много способов, как получить это, но два наиболее простой являются:

  • mov <r16>,OFFSET str1 (r16 любое 16b регистр)
  • lea <r16>,[str1] (делает то же самое в данном случае)

2) его размер ИЛИ структура. Вы не помещали никакой структуры там, как строки с нулевым завершением имеют байты со значением 0 с их конца, или DOS int 21h, ah=9 сервис для отображения строки ожидает, что строка завершена знаком доллара '$' и т. Д. Поэтому вам нужен хотя бы размер.И EQU директива ассемблера, и «текущая позиция» может быть использована для расчета размера str1, как это:

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

Hm, я попытался проверить это первое, прочитав некоторые документы, но это очень сложно для меня найти любую хорошую полную документацию emu8086 (найти что-то вроде «ссылки», и это полностью отсутствует описание ассемблерных директив).

Интересно, почему так много людей все еще приземляются на это, а не linux + nasm/подобные, которые полностью бесплатны, с открытым исходным кодом и документированы.

Итак, будем надеяться, что emu8086 работает как MASM/TASM, и что я до сих пор помню этот синтаксис правильно, тогда указанное определение размера должно работать. В противном случае обратитесь к своим примерам/документам.


Наконец, когда у вас есть адрес, размер и достаточно большой целевой буфер (опять же, чтобы загрузить это адрес, который вы можете использовать OFFSET или lea в 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 (значения регистра, флаги) и содержимое памяти после каждой инструкции, чтобы получить представление о том, как это работает.

1

Существует несколько способов сделать это. Вот некоторые примеры:

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 Instruction вы можете узнать больше о инструкции строки из here

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 
+0

Вы можете использовать 'stosb' сделать это гораздо более компактным, а также упростить ветвления, так и для других, чем' 'входов 0'' нет никакой взятой отрасли , (т. е. перейти к блоку, который устанавливает 'al' и возвращается обратно в цикл, вместо того, чтобы вынуждать не принятую сторону также прыгать.) –

+0

Кроме того,' lea dx, str2' - один байт, длиннее, чем 'mov dx, OFFSET str2', и не имеет никаких преимуществ. –

+0

Я сделал редактирование, чтобы добавить более эффективную версию с изменениями, которые я предложил в комментариях. (Непроверенные). Вместо того, чтобы использовать инструкцию 'loop', я разветвлялся на завершающем' $ '. [Это происходит быстрее на современных процессорах] (https: // stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-cannt-intel-have-реализован-он-эффективно), но, возможно, медленнее на реальном 8086, потому что 'loop' более компактен (меньше кода внутри петля, даже если ей требуется больше настроек снаружи). Моя версия, вероятно, еще быстрее на реальном 8086, хотя, особенно если большинство символов не '' 0''. –

Смежные вопросы