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