Макросы Ассемблера являются чисто текстовыми подстановками.Если вы не используете макрос, его содержимое не обязательно должно быть действительным.И если он используется, он собирается только там, где он используется.(Это не встроенная функция, а макрос препроцессора 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!