Почему мой ассемблер не использует код операции 05 (добавить eax, imm32), краткую форму ручных документов для ADD EAX, 1, а для 04 ADD AL, 1? - PullRequest
0 голосов
/ 13 октября 2018

Я пишу ассемблер x86-64.Я просматривал руководство по Intel x86, том 2, пытаясь понять, как генерировать правильные инструкции из сборки.Я в основном понимаю, как это работает, но собирал и разбирал инструкции, чтобы проверить, правильно ли я это понял.

В справочной таблице ADD (Vol 2A, 3.31):

opcode        | Instruction  
04 ib         | ADD AL, imm8  
05 iw         | ADD AX, imm16  
05 id         | ADD EAX, imm32  
REX.W + 05 id | ADD RAX, imm32  

Сборка:

;add.s   
add al, 1
add ax, 1
add eax, 1
add rax, 1

Разборка:

.text:
   0:   04 01           add al, 1
   2:   66 83 c0 01     add ax, 1
   6:   83 c0 01        add eax, 1
   9:   48 83 c0 01     add rax, 1

Итакпервая верна, как написано в руководстве, но ассемблер использует инструкции внизу справочной таблицы ADD, такие как префиксы REX, зачем использовать те, которые я перечислил ранее?

Теперь второй ADD ax, 1;после поиска я обнаружил, что 66 был префиксом переопределения размера операнда, но он не указан в справочной таблице ADD, поэтому, когда я решаю добавить этот префикс, я не могу найти много информации о нем или других устаревших префиксахв руководстве Intel?

Я пытался разобрать 05 01, как показано в руководстве, но он не распознал его как код операции только по номерам.Руководство Intel является хорошим ресурсом, я думаю, что в нем просто отсутствуют какие-то дополнительные пояснения и структура, но я все еще пытаюсь разобраться в материалах ModRM.

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Существует несколько кодов операций для добавления немедленного в 64-битный регистр

REX.W + 05 id     ADD RAX, imm32     Add imm32 sign-extended to 64-bits to RAX.
REX.W + 81 /0 id  ADD r/m64, imm32   Add imm32 sign-extended to 64-bits to r/m64.
REX.W + 83 /0 ib  ADD r/m64, imm8    Add sign-extended imm8 to r/m64.

https://www.felixcloutier.com/x86/ADD.html

, поскольку 01 помещается в байт, ваш ассемблер использует код операции 83 чтобы сохранить длину инструкции.Если вы попробуете add rax, 100000000 или что-то подобное, вы получите код операции 05

Теперь для принудительного другого декодирования вместо более эффективного вам потребуется определить некоторый синтаксис в ассемблере.Например, nasm использует ключевое слово strict

mov    eax, 1                ; 5 bytes to encode (B8 imm32)
mov    rax, strict dword 1   ; 7 bytes: REX mov r/m64, sign-extended-imm32.    NASM optimizes mov rax,1 to the 5B version, but dword or strict dword stops it for some reason
mov    rax, strict qword 1   ; 10 bytes

Почему NASM в Linux изменяет регистры в сборке x86_64

Теперь, если вы посмотрите наВ таблице близко вы можете увидеть что-то странное

05 iw       ADD AX, imm16       Add imm16 to AX.
05 id       ADD EAX, imm32      Add imm32 to EAX.
81 /0 iw    ADD r/m16, imm16    Add imm16 to r/m16.
81 /0 id    ADD r/m32, imm32    Add imm32 to r/m32.
01 /r       ADD r/m16, r16      Add r16 to r/m16.
01 /r       ADD r/m32, r32      Add r32 to r/m32.
03 /r       ADD r16, r/m16      Add r/m16 to r16.
03 /r       ADD r32, r/m32      Add r/m32 to r32.

Почему все 16 и 32-битные версии одной и той же инструкции имеют одинаковые коды операций?

Ответ таков: текущий режим определит тип инструкции.Если вы работаете в 16-битном режиме, то по умолчанию будут использоваться 16-битные регистры, а если вы используете 32- или 64-битный режим, то размер по умолчанию будет 32-битным.Если вы хотите использовать другой размер, вам придется использовать 66h (переопределение размера операнда) префикс .Это означает, что в 16-битном режиме вы получите вывод ниже, чем то, что вы видели выше

83 c0 01           add ax, 1
66 83 c0 01        add eax, 1

Я пытался разобрать 05 01, как показано в руководстве, но он не распознал егов качестве кода операции просто используются номера

Поскольку за 05 должен следовать 4-х байтовый код (id/imm32, как указано в руководстве) или 2-байтовый протокол (iw/imm16) в зависимости отразмер операнда по умолчанию.Только инструкции с imm8/ib могут иметь один байт сразу.Например, онлайн-дизассемблер дает мне следующий вывод

0:  05 01 02 03 04          add    eax,0x4030201
5:  66 05 01 02             add    ax,0x201

По той же причине, что и выше, был выбран код операции 83h, потому что 0x01 помещается в байт, делая одинаковую длину иассемблер может выбирать все, что ему нравится

0:  66 83 c0 01             add    ax,0x1
4:  66 05 01 00             add    ax,0x1

Вы можете прочитать это

0 голосов
/ 13 октября 2018

Обратите внимание на размер немедленного в инструкциях, которые вы перечислили.Немедленный размер совпадает с размером регистра.В инструкциях, используемых протестированным ассемблером, используется однобайтовый запрос независимо от размера регистра.Это делает инструкцию короче.Вы можете использовать инструкции, которые вы перечислили, предоставив немедленный правильный размер, например: 05 01 00 00 00

См. Раздел 2.1.1 для описания префиксов.Префикс переопределения размера операнда позволяет программе переключаться между 16- и 32-разрядными размерами операндов.Любой размер может быть по умолчанию;использование префикса выбирает размер не по умолчанию.В 64-битном режиме 32-битные значения всегда используются по умолчанию, поэтому префикс 66h выбирает размер 16-битного операнда.

...