Как я мог это сделать?
(вопрос из комментариев к самостоятельному ответу)
Ну, сначала вы читаете Справочник по инструкции, чтобы понять, что делает инструкция, а затем вы можете использовать ее, если она соответствует вашей цели. Это важный шаг, продолжайте время от времени перечитывать детали инструкции, чтобы убедиться, что она изменяет регистры и флаги так, как вы ожидаете. Особенно, если в отладчике вы видите изменение состояния процессора, которого не ожидали.
Поскольку вы работаете в Linux, регистры сегментов ds
/es
, скорее всего, уже имеют разумные значения (охватывающие раздел .data
), поэтому после установки eSi
на Sисходный адрес, eDi
на D strong>адрес назначения и eCx
до Cколичества, вы пишете вместо COPY_LOOP:
просто rep movsb
... и затем выходите через int 80h (eax=1)
. (обратите внимание на подчеркнутые буквы в именах регистров, Intel выбрала их намеренно, чтобы их было легко вспомнить)
Кстати, только сейчас я заметил, что вы написали в своем коде ошибки:
inc si/di
должно быть inc esi/edi
, потому что вы используете esi/edi для адресации. Если бы вы копировали массив с границей памяти 64 КБ, inc si
зациклился бы на нем.
установите ecx
на 3, в режиме 32b инструкция loop
использует всю 32b ecx
, а не только часть 16b cx
. Если код перед копированием будет использовать какое-то большое число в ecx
, устанавливая некоторые из старших 16 бит, ваш цикл скопирует гораздо больше байтов, чем только 3.
перед повторным вызовом int 80h
вы должны установить целое eax
с номером функции, иначе вы рискуете получить мусор в старших 16 битах eax
из предыдущего кода, запрашивая неверную функцию.
Итак, после их применения ваш код может выглядеть так:
section .text
global _start
cpu 386
_start:
MOV ESI, TABLE_A
MOV EDI, TABLE_B
MOV ECX, 3
REP MOVSB ; copy ECX bytes from DS:ESI to ES:EDI
MOV EAX,1 ; call sys_exit, again FIXED to EAX!
INT 80h
section .data
TABLE_A DB 10, 5, 1
TABLE_B DB 0, 0, 0
Если вы читали документацию о регистрах, вы уже должны понимать, в чем разница между eax
и ax
. В Linux вы находитесь в режиме 32b (когда вы связываете двоичный файл как 32b elf, в настоящее время 64b может быть по умолчанию в системе 64b, что немного отличается от режима 32b), поэтому по умолчанию используйте варианты регистров 32b. Если вам действительно не нужен вариант 16b/8b по определенной причине, и вы убедитесь, что код не работает позже с регистром 32b, пока вы устанавливаете только меньшее его значение (например, loop
, rep movsb
и int 80h
).
Кроме того, это обычно делает код быстрее, так как использование 16b ax
в режиме 32b требует дополнительного байта кода операции перед инструкцией, например, mov eax,ebx
— это 2 байта кода операции 89 D8
, mov ax,bx
— это 3 байта кода операции 66 89 D8
.
29.10.2016
ds
иes
указывают на сегмент .data (а DF=DirectionFlag равен нулю), то вы можете заменить весь COPY_LOOP одной инструкцией с префиксом повторенияrep movsb
. 27.10.2016mov ax,1
потенциально сломан; используйтеmov eax,1
, чтобы установить номер вызова, не оставляя никакого старшего мусора в старших 2 байтах. То же самое для CX; ваш цикл использует ECX, но вы устанавливаете только младшие 2 байта; вы можете зациклить несколько кратных 2 ^ 16 раз больше, чем вы имели в виду. 24.04.2021rep movsb
: DS и ES уже настроены корректно под линуксом, можно буквально просто запуститьrep movsb
24.04.2021