Кодування команд, osdev wiki, fandom powered by wikia

Загальний формат коду команди Правити

Повний код команди процесорів архітектури IA-32 складається з набору префіксів (prefixes), коду операції (opcode), байта ModR / M. байта SIB. полів відхилення (displacement) і безпосереднього операнда (immediate). Всі ці частини коду команди, за винятком коду операції, є необов'язковими. Загальна довжина коду команди обмежена 15 байтами, а її формат приведений на малюнку.

Загальний формат коду команди процесорів архітектури IA-32

Кодування регістрів Правити

У командах процесорів архітектури IA-32 одночасно може кодуватися до трьох регістрів. Їхні номери можуть перебувати в полях Reg / Opcode і R / M байта ModR / M, полях Base і Index байта SIB, а також в поле номера регістра, що займає молодші розряди коду операції в деяких командах. В 16- і 32-розрядному режимах всі ці поля мають довжину 3 біта, що дозволяє кодувати кожним з них один з восьми регістрів. У 64-розрядному режимі число доступних регістрів подвоєно; доступ до додаткових регістрів можливий за допомогою префікса REX, що містить по одному старшому біту для номерів кожного з трьох використовуваних в команді регістрів (молодші біти і раніше кодуються в коді операції і байтах ModR / M і SIB; якщо в команді використовується менше число регістрів, відповідні біти в префікс REX ігноруються). Додаткові регістри недоступні в 16- і 32-розрядному режимах, оскільки в них префікс REX використаний бути не може.

Наступна таблиця показує кодування регістрів при відсутності префікса REX.

Як видно з таблиці, для сегментних регістрів і регістрів MMX старший біт, який кодується в префіксом REX, ігнорується. Крім того, байтові регістри AH, BH, CH і DH недоступні, якщо в команді є префікс REX.

префікси Правити

IA-32-розпізнають чотири групи так званих успадкованих (legacy) префіксів. які можуть використовуватися в 16-, 32- і 64-розрядному коді. У кожній інструкції може бути присутнім лише один префікс з кожної групи, однак реакція процесора на наявність декількох префіксів однієї групи не обмовляється. Кожен префікс має сенс лише для певних команд; наслідки використання префікса з командою, для якої він не призначений, не визначені. Існуючі процесори зазвичай ігнорують префікси, які не мають сенсу з даною командою, а при наявності декількох префіксів однієї групи використовують тільки останній з них, однак зловживати цим не варто: в майбутньому поведінку процесорів може змінитися.

Крім успадкованих префіксів, в 64-розрядному коді може використовуватися новий префікс REX. В 16- і 32-розрядному коді він недоступний.

Зазвичай порядок проходження префіксів з різних груп не грає ролі, однак з цього правила є два винятки:

  • префікс REX завжди безпосередньо передує коду операції; таким чином, успадковані префікси повинні поміщатися перед ним;
  • в деяких командах певний префікс повинен бути присутнім в обов'язковому порядку (де-факто він стає частиною коду операції, хоча де-юре продовжує залишатися префіксом). Такий префікс повинен бути останнім з числа успадкованих префіксів, між ним і власне кодом операції може розміщуватися тільки префікс REX. Наприклад, інструкція CVTDQ2PD кодується префіксом F3, за яким відразу слідують два байта коду операції: 0F E6.

Успадковані префікси Правити

Група 1 - префікси блокування і повторення:

  • F0h - префікс блокування шини LOCK;
  • F2h - префікс повторення REPNE / REPNZ;
  • F3h - префікс повторення REP або REPE / REPZ.

Префікси повторення використовуються тільки із строковими операціями CMPS. INS. LODS. MOVS. OUTS. SCAS. STOS. Крім того, в деяких інших командах вони є обов'язковими, фактично перетворившись на частину коду операції і втративши свій вихідний сенс.

Зауважимо, що в документації фірми AMD префікси повторення і блокування віднесені до різних груп, тому там вважається, що груп префіксів п'ять. Однак ці префікси не можуть використовуватися разом, тому об'єднання їх в одну групу цілком доречно.

Група 2 - префікси заміни сегмента і оптимізації переходів:

  • 2Eh - префікс заміни сегмента CS: або сумнівного переходу;
  • 36h - префікс SS:;
  • 3Eh - префікс DS: або ймовірного переходу;
  • 26h - префікс ES:;
  • 64h - префікс FS:;
  • 65h - префікс GS :.

У 64-розрядному режимі префікси заміни сегмента DS :. ES :. CS: і SS: ігноруються, а два залишилися діють спеціальним чином: сегментні регістри FS і GS з їх допомогою використовуються в якості додаткових базових регістрів.

В інструкціях переходу наявність префікса заміни сегмента призводить, взагалі кажучи, до непередбачуваних результатів. Однак на практиці ці префікси ігноруються, а в останніх версіях процесорів два з них (DS: і SS:) стали використовуватися в якості «підказок» процесору щодо ймовірності переходу з тієї чи іншої гілки. Тепер ці два префікса офіційно підтримуються у всіх інструкціях умовного переходу.

Група 3 - префікс зміни розміру операнда 66h.

Якщо для поточного сегмента коду розмір даних за замовчуванням дорівнює 16 бітам, то наявність цього префікса змушує команду виконати не 16, а 32-розрядну операцію; якщо ж розмір даних за замовчуванням дорівнює 32 бітам, то при наявності цього префікса команда виконає НЕ 32-, а 16-розрядну операцію. У командах обробки байтів цей префікс ігнорується.

У 64-розрядному режимі розмір даних за замовчуванням дорівнює 32 бітам, а використання префікса 66h дає можливість обробляти 16-розрядні дані. 64-розрядні операнди, за винятком декількох команд, використовуються тільки при наявності префікса REX з встановленим бітом W; в такій ситуації префікс 66h ігнорується.

Префікс зміни розміру операнда програмістом явно не вказується, транслятор самостійно визначає його необхідність.

Цей префікс програмістом явно не задається: транслятор при необхідності вставляє його сам.

Префікс REX Правити

Префікс REX може використовуватися тільки в 64-розрядному коді і розташовується безпосередньо перед кодом операції, після всіх успадкованих префіксів. Він необхідний у таких випадках:

  • коли команда використовує нові регістри, введені разом з 64-розрядних розширенням архітектури IA-32 (див. розташований вище розділ «Кодування регістрів»);
  • коли команда використовує 64-розрядні операнди.

Якщо префікс REX використовується в команді, для якої він марний, він ігнорується.

Старший напівбайт префікса REX завжди містить біти 0100; таким чином, префікс REX може мати коди 40h-4Fh. В 16- і 32-розрядних режимах цими кодами відповідають однобайтові інструкції INC і DEC. тому в 64-розрядному режимі вони недоступні. Замість цього для реалізації тих же функцій застосовуються форми інструкцій INC і DEC. використовують байт ModR / M (код операції FF / 0 і FF / 1).

Молодший напівбайт префікса REX складається з чотирьох бітів, кожен з яких має свою функцію:

  • біт W (3) бере участь у визначенні розміру операндів. Коли він дорівнює 0, а префікс зміни розміру операндів 66h відсутня, розмір операндів буде дорівнює 32 бітам; при нульовому бите W і наявності префікса 66h використовуються 16-розрядні операнди; при W = 1 розмір операндів дорівнює 64 бітам незалежно від наявності префікса 66h. Для обробки 8-розрядних операндів передбачені окремі коди операцій; в цьому випадку біт W і префікс 66h ігноруються.
  • біт R (2) - розряд, який розширює поле Reg / Opcode байта ModR / M для звернення до нових регістрів загального призначення, SSE, керуючим і налагоджувальний;
  • біт X (1) - розряд, який розширює поле Index байта SIB для звернення до нових регістрів загального призначення;
  • біт B (0) - розряд, який розширює поле R / M байта ModR / M, поле Base байта SIB або поле номера регістра, що знаходиться в байті коду операції, для доступу до нових регістрів.

Код операції Правити

Код операції є єдиним обов'язковим полем будь-якої команди. Він має довжину від 1 до 3 байт. У дво- і трёхбайтових командах першим байтом коду операції є 0Fh. Крім того, деякі команди вимагають обов'язкової наявності префікса F2h, F3h або 66h, який повинен розміщуватися безпосередньо перед кодом операції (між таким обов'язковим префіксом, фактично втратив свої початкові функції і перетворився в частину коду операції, і власне перед кодом операції може перебувати тільки префікс REX ).

У деяких командах, які використовують тільки один явно заданий операнд, частина коду операції міститься в трёхбітовом поле Reg / Opcode байта ModR / M (в двохоперандних командах це поле містить номер регістра, використовуваного в якості другого операнда). Документація Intel в таких випадках вказує значення цих розрядів однією цифрою після знака косою риси, наступного за значенням байтів коду операції. Наприклад, команді INC відповідають коди операції FE / 0 і FF / 0, тобто власне байт коду операції має дорівнювати FEh або FFh, а поле Reg / Opcode наступного за кодом операції байта ModR / M - 000.

У ряді команд деякі розряди коду операції використовуються для визначення номера використовуваного регістру. Наприклад, в 16- і 32-розрядному коді для інкремента регістра загального призначення довжиною слово або подвійне слово може використовуватися однобайтовий варіант команди INC. має код операції від 40h до 47h включно, де молодші три біта визначають регістр; в байті ModR / M цей варіант не потребує. У 64-розрядному режимі такий варіант команди INC використовуватися не може, оскільки цей діапазон кодів відведений для префікса REX.

Байт ModR / M Правити

Більшість інструкцій обробки даних і ряд інших команд використовують явно задані операнди, які кодуються цим байтом. Крім нього, для визначення місця розташування операндів можуть використовуватися байт SIB і поле відхилення, а в 64-розрядному коді - ще й префікс REX. У деяких командах операнди задані неявним чином або кодуються кількома битами з байта коду операції; є також інструкції, одним з операндів яких є константа, що розташовується в поле безпосереднього операнда. У деяких випадках існують «паралельні» версії однієї і тієї ж інструкції: наприклад, інкремент вмісту регістра в 16- і 32-розрядних режимах можливий або за допомогою однобайтового команди (код операції від 40h до 47h, причому його молодші три біта позначають регістр), або за допомогою двобайтового (байт коду операції, рівний FFh, і байт ModR / M зі значенням від C0h до C7h; його молодші три біта - поле R / M - вказують використовуваний регістр).

Коли поле Mod дорівнює 11, операнд знаходиться в будь-якому регістрі. Кодування регістрів завжди стандартне і описано в однойменному розділі вище.

Як і в 16-розрядному режимі, при Mod = 11 операнд знаходиться в регістрі; правила кодування регістрів наведені вище у відповідному розділі.

Якщо Mod = 01 або 00, а R / M = 101, тобто при зверненні до пам'яті щодо регістра EBP, доступ за замовчуванням виконується до сегменту стека, а при інших комбінаціях Mod і R / M (крім Mod = 11 або R / M = 100) - до сегменту даних. Можливо звернення до будь-якого іншого сегменту, для чого слід використовувати префікс заміни сегмента.

У 64-розрядному режимі є такі особливості:

Байт SIB Правити

Байт SIB ділиться на три поля: двухбітовий Scale і трёхбітовие Index і Base. розташовані в байті в цьому порядку.

Поле Scale вказує масштаб індексу:

Тут Disp - відхилення, наявність і розрядність якого визначається байтом ModR / M, а значення розташовується в коді команди після байта SIB; Base - вміст базового регістра, номер якого заданий однойменною полем байта SIB; Index - вміст індексного регістра, номер якого заданий однойменною полем байта SIB; Scale - множник для масштабування індексу, який закодований в однойменному полі байта SIB.

Колонка зі значенням «*» відповідає другому з описаних вище винятків для регістра EBP, можливість використання якого в якості базового залежить від значення поля Mod байта ModR / M.

  • за допомогою префікса REX розрядність полів бази і індексу збільшується, що дозволяє ісопльзовать в якості базових та індексних додаткові вісім регістрів R8 / R8D-R15 / R15D. Коли в поле Index байта SIB міститься 100, а біт X префікса REX дорівнює нулю, індексний регістр відсутній (тобто як і в 32-розрядному режимі, регістр RSP / ESP не може виступати в ролі індексу). Коли Index = 100, а REX.X = 1, в якості індексу використовується регістр R12 / R12D;
  • регістр RBP / EBP як і раніше не може використовуватися в якості базового без явної вказівки відхилення. Крім того, байт SIB не дозволяє закодувати використання регістра R13 / R13D як базового без явно заданого відхилення, оскільки при Mod = 00 і Base = 101 вважається, що базового регістра немає, незалежно від стану біта B префікса REX.

відхилення Правити

Безпосередній операнд Правити

  • якщо операнд має розмір 8, 16 або 32 біта, то розмір поля безпосереднього операнда дорівнюватиме розміру операнда;
  • якщо операнд має розмір 64 біта (присутній префікс REX з встановленим бітом W), то у всіх інструкціях, крім MOV reg64, const (коди операції B8h-BFh), використовується 32-розрядне поле безпосереднього операнда, причому сам безпосередній операнд розглядається як число зі знаком і перед виконанням операції розширюється до 64 біт;
  • в інструкціях MOV reg64, const (коди операції B8h-BFh c префіксом REX, які мають одиничний біт W) використовується 64-розрядне поле безпосереднього операнда.
  • Виявлено використання розширення AdBlock.