Почему movw di, [ebp + 4] будет незаконным? - PullRequest
1 голос
/ 29 сентября 2019

Я пытаюсь скомпилировать эмулятор на основе 6502 для системы Intel Atom, но я получаю следующие ошибки для этого файла: https://github.com/littlefluffytoys/Beebdroid/blob/master/app/src/main/jni/6502asm_x86.S

jni/6502asm_x86.S:163:5: error: invalid instruction mnemonic 'movb'
movb ch, [ ebp+9] # ch = r10 = S
^~~~
jni/6502asm_x86.S:181:2: error: invalid instruction mnemonic 'pushw'
pushw 0xfffa
^~~~~

Это 32/64 битвопрос?Я знаком со сборкой, но не с x86 или x86_64, и мне трудно отследить, что происходит.Я понимаю, что movq не будет доступен на 32-битной, но я не могу понять, почему байт вообще не был бы доступен.

Мне пришлось удалить все знаки% из файла - кажется, моя версияиз cc (4.8.4) они не понравились - но затем столкнулись с этой проблемой mov.

Что особенно сбивает с толку, так это то, что более ранние экземпляры movw и movb не выдают ошибок, как

    movw  di,  [ ebp+4]     #  di = r6  = PC
    movb  cl,  [ ebp+6]     #  cl = r7  = A

(хотя я заметил, что они в определениях макросов, так что, возможно, они еще не проанализированы)

Я читал в некоторых документах Intel, что mov иногда выглядит следующим образом, но я не знаю достаточно оэтот формат, чтобы попробовать переписать десятки ошибок:

MOV     ECX, dword ptr table[RBX][RDI]

Любая помощь будет оценена!

1 Ответ

3 голосов
/ 29 сентября 2019

Макросы Ассемблера являются чисто текстовыми подстановками.Если вы не используете макрос, его содержимое не обязательно должно быть действительным.И если он используется, он собирается только там, где он используется.(Это не встроенная функция, а макрос препроцессора C.)


В исходном файле вверху используется .intel_syntax noprefix, но затем он заполнен безумным кодом, например
mov %ebx, [%ebx + %eax*4]и movb %al,[%esi+%edi], который все еще украшает имена регистров %, несмотря на noprefix, и, что более важно, все еще использует суффиксы размера операнда в стиле AT & T.

Это мутантный гибрид синтаксиса Intel и AT & T,неудивительно, что некоторые ассемблеры отвергают его.

См. https://stackoverflow.com/tags/intel-syntax/info против https://stackoverflow.com/tags/att/info

На моем рабочем столе Linux исходный файл прекрасно собирается с GNU Binutils as, который я призываю gcc -m32 -c 6502asm_x86.S.(Я работаю в Linux, так что это настоящий GCC, в частности gcc --version говорит gcc (GCC) 9.1.0 Copyright (C) 2019 Free Software Foundation, Inc. и т. Д. Он использует as. as --version говорит "GNU ассемблер (GNU Binutils) 2.32")

Iподозреваю, что вы на Mac с Apple Clang.Ваш "cc (4.8.4)" больше похож на номер версии gcc, но GCC не содержит ассемблера.Он всегда использует внешний.А на Mac это может быть Clang / LLVM, а не GNU Binutils.

На моем рабочем столе Linux clang 8.0.1 отклоняет этот файл .Намного строже не принимать AT & T-измы в режиме Intel, и вообще не поддерживает .intel_syntax prefix, только intel noprefix или att prefix.После удаления всех % символов в файле clang -m32 -c 6502asm_x86.S выдает те же сообщения об ошибках, которые вы показывали:

6502asm_x86.S:121:5: error: invalid instruction mnemonic 'movw'
    movw di, [ebp+4] # di = r6 = PC
    ^~~~

Исправление этого беспорядка:

Если возможно, используйте as aka gas из GNU binutils.Но IDK, если он поддерживает объектные файлы MachO, так что это может быть не вариант для вас.(Обновление: очевидно, вы работаете в Linux, пытаясь использовать инструментальную цепочку Android. Это также лязг, но, вероятно, создает объекты ELF. Так что вы можете просто использовать as вручную.)

Чтобы на самом деле исправить исходный кодудалите также все суффиксы размера операнда и позвольте операнду (ам) регистра указывать размер.

Этот файл правильно использует переопределения размера операнда GAS .intel_syntax в случаях, подобных mov dword ptr [ebp+20], 0, когда ниоперанд является регистром, поэтому ему требуется dword ptr.

Но вы не можете просто удалить последний символ каждой мнемоники: некоторые инструкции уже опускают его.(Похоже, что этот файл делает это для размера операнда dword, но избыточно указывает его для каждой инструкции, использующей размер операнда в байтах или словах.)

Есть несколько инструкций, которые все еще могут использоваться (ииногда требуется) суффикс размера в синтаксисе Intel , например pushw immediate.Некоторые ассемблеры, такие как NASM, используют push word 123, а GAS .intel_syntax noprefix использует pushw 123.Если есть регистр или операнд памяти, это может означать размер.Например, push di - это слово push, pop word ptr [ecx] - это слово pop.У вас также есть суффиксы в «строковых» инструкциях, таких как movsb/w/d / lodsb/w/d и т. Д.

например,

do_interrupt:
        PUSHWORD di                     # push(cpu->pc)
        movzx eax, byte ptr [ebp+10]
        or  eax, 0x20           # uint8_t temp = cpu->p | 0x20;
        PUSH_BYTE al             # push(temp);
        popw ax
        movw di, [esi+eax]              # cpu->pc=*(uint16_t*)&(cpu->mem[0xfffe]);
        or byte ptr [ebp+10], 4         # cpu->p |= FLAG_I;
        movw [ebp+4],di            # Remove when C-only
        movb [ebp+9],ch             # Remove when C-only
        pop eax
        add eax,7                           # c += 7;
        push eax

становится

do_interrupt:
        PUSHWORD di                     # push(cpu->pc)
        movzx eax, byte ptr [ebp+10]
        or    eax, 0x20           # uint8_t temp = cpu->p | 0x20;
        PUSH_BYTE al             # push(temp);
        pop   ax
        mov   di, [esi+eax]              # cpu->pc=*(uint16_t*)&(cpu->mem[0xfffe]);
        or    byte ptr [ebp+10], 4         # cpu->p |= FLAG_I;
        mov   [ebp+4],di            # Remove when C-only
        mov   [ebp+9],ch             # Remove when C-only

        # pop eax; add eax,7 ; push eax   # optimize into one instruction:
        add   dword ptr [esp], 7     # c += 7;
        # or address it relative to EBP if we know where ESP is relative to EBP

Очевидно, вам также нужно взглянуть на определения макросов.


Это не похоже на самый эффективный код;мог бы сделать больше в регистрах.Но это не относится к делу.Я видел только одну маленькую оптимизацию «глазок» для pop / add / push в добавлении к месту назначения памяти, не пытался оптимизировать остальные.

Есть и другие очевидные вещи, такие как

    movb %dl,  [%ebp+7]     #  dl = r8  = X
    movb %dh,  [%ebp+8]     #  dh = r9  = Y

, которыеможет быть загрузка одного слова в DX = DH: DL (x86 является прямым порядком байтов и имеет очень эффективные не выровненные загрузки, если это происходит не выровненными).

Так что я бы не рекомендовал использовать этот код какпример для изучения x86!

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