WedX - журнал о программировании и компьютерных науках

Как скопировать массив в сборке nasm x86 для Linux, портируя 16-битный код DOS?

Мне нужно написать программу, которая копирует массив в другой массив, используя ассемблер x86.

Исходный код написан в TASM MSDOS для процессора 8086, но я хочу перенести его на Linux NASM с использованием процессора i386.

Код в TASM такой:

.MODEL SMALL

.DATA

    TABLE_A DB 10, 5, 1
    TABLE_B DB 0, 0, 0

.CODE

    MOV AX, SEG TABLE_B
    MOV DS, AX

    MOV SI, 0

    LOOP:
        MOV AL, TABLE_A[SI]
        MOV TABLE_B[SI], AL

        INC SI
        CMP SI, 2
    JBE LOOP


    MOV AH, 4Ch
    INT 21h

END

Я пытаюсь переписать это в nasm, но я не могу сесть в правильную позицию массива, как в инструкции TABLE_A[SI]

Как мне это сделать?


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

Ответы:


1

Окончательный код в nasm такой

section .text
global _start
cpu 386

_Начало:

MOV ESI, TABLE_A
MOV EDI, TABLE_B
MOV CX, 3

COPY_LOOP:      
    MOV AL, [ESI]
    MOV [EDI], AL

    INC SI
    INC DI
LOOP COPY_LOOP

MOV AX,1
INT 80h

section .data
TABLE_A DB 10, 5, 1
TABLE_B DB 0, 0, 0
26.10.2016
  • и если вы убедитесь, что ds и es указывают на сегмент .data (а DF=DirectionFlag равен нулю), то вы можете заменить весь COPY_LOOP одной инструкцией с префиксом повторения rep movsb. 27.10.2016
  • Как я мог это сделать? 29.10.2016
  • mov ax,1 потенциально сломан; используйте mov eax,1, чтобы установить номер вызова, не оставляя никакого старшего мусора в старших 2 байтах. То же самое для CX; ваш цикл использует ECX, но вы устанавливаете только младшие 2 байта; вы можете зациклить несколько кратных 2 ^ 16 раз больше, чем вы имели в виду. 24.04.2021
  • re: rep movsb: DS и ES уже настроены корректно под линуксом, можно буквально просто запустить rep movsb 24.04.2021

  • 2

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

    (вопрос из комментариев к самостоятельному ответу)

    Ну, сначала вы читаете Справочник по инструкции, чтобы понять, что делает инструкция, а затем вы можете использовать ее, если она соответствует вашей цели. Это важный шаг, продолжайте время от времени перечитывать детали инструкции, чтобы убедиться, что она изменяет регистры и флаги так, как вы ожидаете. Особенно, если в отладчике вы видите изменение состояния процессора, которого не ожидали.

    Поскольку вы работаете в Linux, регистры сегментов ds/es, скорее всего, уже имеют разумные значения (охватывающие раздел .data), поэтому после установки eSi на Sисходный адрес, eDi на Dадрес назначения и eCx до Cколичества, вы пишете вместо COPY_LOOP: просто rep movsb ... и затем выходите через int 80h (eax=1). (обратите внимание на подчеркнутые буквы в именах регистров, Intel выбрала их намеренно, чтобы их было легко вспомнить)

    Кстати, только сейчас я заметил, что вы написали в своем коде ошибки:

    1. inc si/di должно быть inc esi/edi, потому что вы используете esi/edi для адресации. Если бы вы копировали массив с границей памяти 64 КБ, inc si зациклился бы на нем.

    2. установите ecx на 3, в режиме 32b инструкция loop использует всю 32b ecx, а не только часть 16b cx. Если код перед копированием будет использовать какое-то большое число в ecx, устанавливая некоторые из старших 16 бит, ваш цикл скопирует гораздо больше байтов, чем только 3.

    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

    3

    В ответ на марк

    Я пробовал эту форму без успешного результата:

    MOV SI, 0
    MOV AX, 0
    
    LOOP:       
        MOV AX, [TABLE_A + SI]
        MOV [TABLE_B + SI], AX
    
        INC SI
        CMP SI, 2
    JBE LOOP
    
    26.10.2016
  • Если результат не успешен, то каков результат? 27.10.2016
  • сначала ld показывает эту ошибку: relocation truncated to fit: R_386_16 против `.data' Когда я меняю SI на ESI, он собирается, но со странным результатом в отладке. В первой итерации значение EAX равно 0000050a Во второй итерации значение равно 00000105 В третьей итерации это значение равно 00000a01 27.10.2016
  • Вы не можете использовать 16-битный регистр в 32-битном режиме адресации. Если ваш массив имеет постоянный размер, почему бы просто не скопировать 4 байта с загрузкой/сохранением двойного слова вместо того, чтобы зацикливать байт за раз? Если вы собираетесь использовать это для чего-либо, копирование отдельных байтов будет медленным. 27.10.2016
  • Я только что решил свою проблему с помощью решения @JoseManuelAbarcaRodríguez. 27.10.2016
  • Итак, почему вы изменили al на ax? Вы загружаете сразу два байта, в то время как исходный код TASM загружает только один байт. Затем вы делаете inc si, перемещая смещение только на 1 байт, в то время как вы уже читаете/сохраняете два байта (с ax). Узнайте, чем отличаются rax/eax/ax/ah:al и каков их размер в битах (и как они частично разделяют биты, поскольку это один и тот же регистр в ЦП). См. stackoverflow.com/documentation/x86/2122/. 27.10.2016

  • 4

    Используйте указатели (SI, DI) на массивы и CX в качестве счетчика:

    MOV SI, Table_A     ;POINTER TO TABLE_A.
    MOV DI, Table_B     ;POINTER TO TABLE_B.
    MOV CX, 3           ;ARRAY LENGTH.
    REPEAT:       
        MOV AL, [SI]
        MOV [DI], AL
        INC SI
        INC DI
        LOOP REPEAT     ;CX-1. IF CX>0 JUMP TO REPEAT.
    
    26.10.2016
  • Спасибо, я попробую 27.10.2016
  • Спасибо, теперь чувствует, что работает хорошо 27.10.2016
  • Это 16-битный код NASM, но не то, что вам нужно для 32-битного режима под Linux. 24.04.2021
  • Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    © 2024 wedx.ru, WedX - журнал о программировании и компьютерных науках
    Для любых предложений по сайту: [email protected]