Копирование строк в сборке - PullRequest
0 голосов
/ 22 мая 2018

Я изучаю сборку и пытаюсь создать метод, который бы создавал строки в сборке.Я начал пытаться скопировать одну строку в другую и сохранить копию в переменной для возможного использования в будущем.

Я использую emu8086 и получаю следующую ошибку:

неизвестный код операциипропущено: 64

не инструкция 8086 - пока не поддерживается.

org 100h

jmp start

msg:    db      "Hello, World!", 0 
a:      db       0 
start: 


        mov     si,msg
        mov     di, a
        call    _make_str
        mov     a, di
        mov     dx, a
        mov     ah, 09h 
        int     21h 

        mov     ah, 0   
        int     16h 

        ret
_make_str:      
    pusha
_next:
        mov     al, [si]                  
        mov     [di], al                  
        inc     si
        inc     di
        cmp      al, 0                      
        jne    _next
        popa
        ret 

Что означает эта ошибка и что я делаю неправильно?

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Вы немного наивно ожидаете, что это за строка.

msg:    db      "Hello, World!", 0 

Она собирается в машинный код как 14 байтов (каждый символ в кодировке ASCII равен одному байту (существуют разные кодировки с разными характеристиками, ноemu8086 основан на ASCII) и еще один для конечного нуля.

a:      db       0 

Он собран как один байт нулевого значения.

Затем ваш код запускается и внутри _make_str он будетскопируйте 14 байтов с адреса msg по адресу a. Но адрес a+1 равен start, поэтому 13 символов перезаписывают ваш машинный код для самого кода, переходя через call _make_str и следуя mov a,di. Затем в ret код возвращается по адресу, где должен был быть mov a,di, но в строке уже есть байт 64, поэтому сообщается неизвестный код операции.

Встроенный emu8086-в отладчике, так что используйте пошаговые инструкции и представление памяти, чтобы увидеть, как скомпилированы строки и что делает ваш код.

И в задницеВ embler переменных нет, эти имена перед db/dw/dd/... являются «символами», и они похожи на закладки в памяти компьютера, содержащие адрес первого байта этого значения.

Если вам нужно 20 байтовпамять для строк длиной не более 19 символов, затем вам нужно выделить / зарезервировать 20 байт памяти, память не будет автоматически увеличиваться или перенаправить содержимое, чтобы освободить место для неожиданных данных.


Что, если я не знаю, какой длины может быть строка, как мне инициализировать переменную переменной длины?

Вы не используете данные неизвестной длины.Либо вы знаете, какой длины могут быть данные, либо вы должны указать максимум (у языков высокого уровня тоже есть ограничения, если вы будете достаточно настойчивы, вы легко нарушите понятие «неограниченности»).

В зависимости от того, какого типа этот максимум, подход может отличаться.

Например, если вы читаете имя пользователя, вы можете сказать, что максимум составляет 80 байтов, и резервируйте 80 байтов в области данных, и этонапример, пользователь с более длинным именем либо вылетит из вашего приложения, либо, если вы правильно его кодировали, он сможет ввести только 79 или 80 символов (в зависимости от того, нужен ли вам нулевой терминатор или нет, внутри массива из 80 байтов).

Если вы читаете небольшой текст, такой как описание предмета магазина, вы точно не знаете максимум, но вы уверены, что он либо в пределах тысяч, либо что-то ужасно неправильно, тогда вы можете динамически резервировать место в стеке, напримерsub sp,<length_of_text> и сохраните текст в области стека.

Если вы читаете длинные данные, как двоичный редактор 2 + GВ файлах B у вас должен быть какой-то массив, описывающий, какие куски файла у вас в данный момент находятся в памяти, и динамически меняются и выгружаются, используя всю доступную память, которую ОС предлагает в качестве кеша («выделение памяти»), но еслиЕсли у вас закончилась куча, современная ОС увеличит ее за счет использования виртуальной памяти, хранящейся на диске (swap).Но все же лучше избегать таких ситуаций за счет лучшего алгоритма и дизайна приложения.

Также в emu8086 применяются все другие ограничения 16-битного реального режима x86, т.е. в вашем примере, подобном COM, весь ваш код + данные + стекдолжен вписываться в один сегмент размером 64 КБ (начиная со смещения 0x100, даже не полностью 64 КБ), если только ваш код не проверит DOS на наличие дополнительных доступных сегментов и не использует их больше (после загрузки файла COM в обычном DOS в качестве первого приложения, которое вы обычно500–580 КБ свободной памяти после вашего текущего сегмента).

Жить в 16-битном мире и спрашивать о «не знаю размера» - это дополнительная боль, в 16-битном мире вы должны были знать размеры впереди,и планируйте их, иначе вы очень быстро столкнетесь с проблемами.


РЕДАКТИРОВАТЬ: на самом деле ... вы, вероятно, сталкиваетесь с другой ошибкой, или трудно сказать, какая из них.

    mov     si,msg
    mov     di, a

Эти наборы si и di регистрируются с двухбайтовыми (16-битными) значениями из памяти по адресам msg и a.Это синтаксис MASM, где для доступа к памяти не требуется [].

Чтобы получить адрес первого байта, вам нужно mov si, OFFSET msg или lea si,[msg] ... так что теперь я даже не уверен, какую память и где вы перезаписываете, так как вы используете данные символов в качестве указателя памяти, но, очевидно, вы перезаписываетечто-то жизненно важное.

Используйте отладчик emu8086, чтобы увидеть, что именно происходит.

(после того, как вы исправите свой код для правильной загрузки адресов, вы нажмете на перезапись кода, как я его описал)в ответ)

0 голосов
/ 22 мая 2018

Вам нужно, чтобы ваша переменная имела достаточно места для хранения всех символов из исходной строки, теперь она имеет только один байт.Также ознакомьтесь с инструкцией rep movsb.

...