Към съдържанието

Глава IV — Програмен модел и система команди на x86 микропроцесорите

1. Програмен модел. Регистри с общо предназначение

Програмният модел дефинира какво е достъпно за програмиста: кои регистри съществуват, колко бита са, и за какво служат. Всичко останало (кеш, TLB, конвейер) е скрито от програмата.

32-битов програмен модел (IA-32)

Програмно достъпните регистри в защитен 32-битов режим:

Регистри с общо предназначение (GPR) — 8 × 32 бита:

Всеки регистър е достъпен като цял (32 бита) или чрез именувани части:

63 32 31 16 15 8 7 0
┌────────────────┬─────────────────┬────────┬───────┐
│ (само x64) │ EAX │ AH │ AL │
└────────────────┴────────┬────────┴────────┴───────┘
│ AX (16 бита)
│ EAX (32 бита)
│ RAX (64 бита, само x64)
64-бита (x86-64)32-бита16-бита8H (15–8)8L (7–0)Предназначение
RAXEAXAXAHALАкумулатор — резултат от операции, I/O
RBXEBXBXBHBLБазов регистър за адресиране
RCXECXCXCHCLБрояч — LOOP, REP, SHL CL
RDXEDXDXDHDLДанни — разширение на EAX при MUL/DIV
RSIESISISILSource Index — изходна позиция при стрингови операции
RDIEDIDIDILDestination Index — целева позиция при стрингови операции
RSPESPSPSPLStack Pointer — върхът на стека (не се ползва свободно!)
RBPEBPBPBPLBase Pointer — база на стековия кадър при процедури

Указател на инструкциите:

  • EIP [31..0] — адресът на следващата инструкция за изпълнение (не се чете/пише директно)

Регистър на флаговете:

  • EFLAGS [31..0] — битов регистър: статусни флагове (CF, ZF, SF, OF), управляващи (DF), системни (IF, TF, IOPL)

Сегментни регистри (6 × 16 бита):

  • CS (Code Segment) — сегментът на кода; DS (Data) — данни; SS (Stack) — стек
  • ES, FS, GS — допълнителни данни (FS/GS се ползват за thread-local/per-CPU данни от ОС)

64-битов програмен модел (Intel 64 / AMD64)

16 × 64-битови GPR — RAX–RBP са разширения на IA-32 регистрите; R8–R15 са нови:

64-бита32-бита16-бита8-битаБележки
RAX–RBPEAX–EBPAX–BPAL/AH–BPLРазширения на IA-32 (8 регистъра)
R8–R15R8D–R15DR8W–R15WR8B–R15BНови в x86-64 (8 регистъра)
RIPEIPУказател на инструкциите
RFLAGSEFLAGSFLAGSФлагов регистър

Достъп към части на 64-битовите регистри: RAX[63..0] → EAX[31..0] → AX[15..0] → AH[15..8]/AL[7..0]; аналогично за R8 → R8D → R8W → R8B.

Важно правило: Запис в 32-битов подрегистър (напр. MOV EAX, 1) автоматично зануля горните 32 бита (RAX[63..32] = 0). Запис в 8/16-битови подрегистри не зануля горните битове — старите стойности остават!

XMM/YMM/ZMM регистри: виж Глава III (SIMD)


2. Система команди. Общ формат на x86 команда

Формат на инструкция (променлива дължина: 1–15 байта)

x86 инструкцията не е с фиксирана дължина — всяко поле е незадължително или с различен размер. Процесорът разчита (декодира) инструкцията последователно, поле по поле.

┌──────────┬─────┬────────┬────────┬─────┬──────────────┬───────────┐
│ Prefixes │ REX │ Opcode │ ModR/M │ SIB │ Displacement │ Immediate │
│ 0–4 B │ 0/1 │ 1–3 B │ 0/1 B │0/1B │ 0/1/2/4 B │ 0/1/2/4B │
└──────────┴─────┴────────┴────────┴─────┴──────────────┴───────────┘
ПолеРазмерЗадължително?Роля
Prefixes0–4 байтаНеМодифицира поведението на инструкцията
REX1 байтСамо в 64-bit режимРазширява регистровите полета до R8–R15
Opcode1–3 байтаДаКодът на операцията
ModR/M1 байтПри операндиОпределя регистър и/или начин на адресиране
SIB1 байтПри сложно адресиранеScale + Index + Base за [reg + reg×n + disp]
Displacement0 / 1 / 2 / 4 байтаПри памет + отместванеЧислово отместване спрямо базовия регистър
Immediate0 / 1 / 2 / 4 байтаПри непосредствена стойностБуквална стойност, вградена в инструкцията

Префикси (Prefixes)

ГрупаПримериФункция
Група 1LOCK, REP, REPE, REPNEЗаключване на шината / повторение на стрингова операция
Група 2CS:, SS:, DS:, ES:, FS:, GS:Замества подразбирания сегментен регистър
Група 30x66Замества размера на операнда (32↔16 бита)
Група 40x67Замества размера на адреса (32↔16 бита)

REX Prefix (само в 64-битов режим)

Байт с формат 0100WRXB:

  • W=1: операцията работи с 64-битови операнди (иначе 32-битови)
  • R: разширява полето REG в ModR/M — дава достъп до R8–R15
  • X: разширява INDEX полето в SIB
  • B: разширява R/M или BASE в SIB

Пример: MOV RAX, R10 изисква REX.W=1 (64-бита) и REX.R=1 (R10 в REG поле) + REX.B=1 (RAX в R/M).

Opcode (1–3 байта)

Кодът на операцията. Може да съдържа вграден код на регистър в долните 3 бита (напр. B8+rd за MOV reg, imm32).

ModR/M байт

Управлява избора на регистър и режима на адресиране:

Bits 7–6: Mod 00=памет без disp | 01=памет+disp8 | 10=памет+disp32 | 11=само регистър
Bits 5–3: Reg регистър (src или dst) или разширение на opcode
Bits 2–0: R/M регистър или адресиращ режим (при Mod≠11 → указва паметта)

Пример: MOV EAX, [EBX+8]

  • Mod=01 (памет + disp8), Reg=EAX (000), R/M=EBX (011)
  • Displacement = 0x08

SIB (Scale-Index-Base) байт

Присъства само когато R/M=100 и Mod≠11. Позволява сложно адресиране:

Bits 7–6: Scale 00=×1 | 01=×2 | 10=×4 | 11=×8
Bits 5–3: Index регистър-индекс (ESP=100 означава "без индекс")
Bits 2–0: Base регистър-база
Ефективен адрес = Base + (Index × Scale) + Displacement

Пример: MOV EAX, [EBX + ESI×4 + 100h] → SIB: Scale=10(×4), Index=ESI, Base=EBX, Disp=0x100

Displacement и Immediate

  • Displacement: отместване (0, 8 или 32 бита) — добавя се към адреса от ModR/M или SIB
  • Immediate: буквална стойност (0, 8, 16 или 32 бита) — директно вградена в машинния код

3. Основни групи x86 команди

3.1 Команди за пренос на данни

ИнструкцияДействие
MOV dst, srcКопиране (регистър↔регистър, регистър↔памет)
MOVZX dst, srcКопиране с нулево разширение (напр. AL → EAX, горните битове = 0)
MOVSX dst, srcКопиране със знаково разширение (знаковият бит се разпространява нагоре)
XCHG op1, op2Атомарна размяна (с LOCK — безопасна при мултипроцесорна среда)
PUSH srcЗаписва в стека: ESP −= 4, след това [ESP] = src
POP dstЧете от стека: dst = [ESP], след това ESP += 4
LEA dst, [mem]Зарежда адреса (не съдържанието!) — полезно за изчисляване на указатели
IN AL, port / OUT port, ALВход/изход от I/O порт

3.2 Аритметични команди

ИнструкцияДействие
ADD dst, srcСъбиране; задава CF, ZF, SF, OF
ADC dst, srcСъбиране + CF (за многоточна аритметика: 64-бита в 32-бит. режим)
SUB dst, srcИзваждане
SBB dst, srcИзваждане − CF (заем при многоточна аритметика)
INC op / DEC op+1 / −1 (не засяга CF — внимание при проверка за пренос!)
NEG opСмяна на знак (двоично допълнение)
MUL opБеззнаково умножение: AX = AL×op (8b) или EDX:EAX = EAX×op (32b)
IMUL opЗнаково умножение (1, 2 или 3 операнда)
DIV opБеззнаково деление: AL=AX/op, AH=AX mod op
IDIV opЗнаково деление
CMP op1, op2Изваждане без запис — само задава флагове за Jcc

3.3 Логически и битови команди

ИнструкцияДействие
AND, OR, XOR, NOTПобитови операции; AND/OR/XOR нулират CF и OF
SHL/SAL, SHR, SARЛогическо отместване наляво/надясно; SAR запазва знака
ROL, ROR, RCL, RCRРотация (с или без CF)
BT, BTS, BTR, BTCТест / задаване / нулиране / инверт на отделен бит; резултатът в CF
BSF, BSRСканиране за първи 1-бит (напред/назад); ZF=1 ако операндът е нула
TEST op1, op2AND без запис — само задава ZF/SF/PF (не записва резултата)

3.4 Команди за управление на потока

ИнструкцияДействие
JMP labelБезусловен преход (near = в сегмента, far = между сегменти)
Jcc labelУсловен преход по флагове: JZ/JE (ZF=1), JNZ/JNE (ZF=0), JG, JL, JGE, JLE…
CALL procИзвикване на процедура: [стек] ← EIP, след това JMP proc
RET / RETFВръщане от процедура (near / far)
LOOP / LOOPE / LOOPNEECX−=1; прескача ако ECX≠0 (+ условие по ZF при LOOPE/LOOPNE)
INT nПрограмно прекъсване (вектор n) — извиква OS или BIOS функция
INTOПрекъсване при OF=1
IRET / IRETDВръщане от обработчик на прекъсване (зарежда EIP, CS, EFLAGS от стека)

3.5 Стрингови команди

MOVS, CMPS, SCAS, LODS, STOS работят с ESI (изход) и EDI (вход):

  • С REP — повтаря ECX пъти
  • С REPE/REPNE — повтаря докато ZF=1 / ZF=0 (и ECX > 0)
  • Посоката зависи от DF: CLD → ESI/EDI нарастват; STD → намаляват

3.6 Системни команди (привилегировани)

Само от ниво 0 (ядрото на ОС):

LGDT, LIDT, LLDT, LTR — зареждат системни дескрипторни таблици
MOV CRx — четене/запис на управляващи регистри
WRMSR, RDMSR — запис/четене на MSR регистри
INVLPG — инвалидира TLB запис за страница
HLT — спира процесора до следващото прекъсване
WBINVD — записва и инвалидира кеша


4. Организация на адресното пространство в 32- и 64-битов режим. Линейни и физически адреси

x86 използва многостепенна адресна трансформация: програмата работи с логически адреси, процесорът ги превежда в линейни (чрез сегментация), а после в физически (чрез странициране).

32-битов режим (Protected Mode)

Трипластова адресна трансформация:

Логически адрес Линеен адрес Физически адрес
[Selector : Offset] → [0 … 4 GB] → [0 … 4 GB (max 64 GB с PAE)]
(Сегментация) (Странициране)

Стъпка 1 — Сегментация:
Линеен адрес = Сегментна база (от GDT/LDT) + Offset
При плоско адресно пространство (flat model) базата е 0 → линеен = offset.

Стъпка 2 — Странициране (ако CR0.PG=1):
Физически адрес = Page Table Entry [линеен адрес / 4096] + (линеен адрес mod 4096)

Адресни пространства:

  • Линейно: 2³² = 4 GB (при 32-битов режим)
  • Физическо: 2³² = 4 GB (без PAE) или 2³⁶ = 64 GB (с PAE, CR4.PAE=1)

64-битов режим (Long Mode / Intel 64)

Двупластова адресна трансформация:

Виртуален адрес (48 бита канонична форма) → Физически адрес (до 52 бита)
(4-нивово странициране: PML4 → PDPT → PD → PT → страница)

Канонична форма на 64-битов адрес:
Само 48 бита [47..0] носят информация. Битовете [63..48] трябва да са знаково разширение на бит 47:

  • Бит 47 = 0 → биткове [63..48] = 0 → потребителско пространство
  • Бит 47 = 1 → биткове [63..48] = 1 → адресно пространство на ядрото
Потребителски: 0x0000_0000_0000_0000 – 0x0000_7FFF_FFFF_FFFF
Ядро: 0xFFFF_8000_0000_0000 – 0xFFFF_FFFF_FFFF_FFFF
(неканоничната "дупка" между тях е невалидна)

Адресни пространства в 64-битов режим:

  • Виртуално: 2⁴⁸ = 256 TB (с PML4 странициране)
  • Физическо: до 2⁵² = 4 PB (при MAXPHYADDR=52)

Изчисляване на ефективния (логически) адрес

Адресиращите режими определят как процесорът изчислява адреса в паметта:

РежимПримерФормула
Непосредствен[1000h]EA = 1000h
Регистров[EBX]EA = EBX
Базов + отместване[EBP + 8]EA = EBP + 8
Индексен[ESI × 4]EA = ESI × 4
Базов + индексен[EBX + ESI]EA = EBX + ESI
Пълен SIB[EBX + ESI×4 + 100h]EA = EBX + ESI×4 + 100h

Пример за пълна трансформация в 32-битов режим:

Инструкция: MOV EAX, [EBX + ESI×4 + 100h]
Ефективен адрес = EBX + ESI×4 + 100h (от SIB + Displacement)
Линеен адрес = DS.Base + ефективен адрес (от Сегментация)
Физически адрес = Page Table[линеен >> 12] × 4096 + (линеен & 0xFFF)

Резюме за изпита

  • 32-битов модел: 8 GPR (EAX–EBP), EIP, EFLAGS, 6 сегментни регистри
  • 64-битов модел: 16 GPR (RAX–R15, 64 бита), RIP, RFLAGS; записът в 32-битов подрегистър нулира горните 32 бита
  • Инструкция: Prefixes + REX (само x86-64) + Opcode + ModR/M + SIB + Disp + Imm (1–15 байта)
  • REX.W=1 → 64-битов операнд; REX.R/X/B → достъп до R8–R15
  • ModR/M: Mod(2b) + Reg(3b) + R/M(3b) — определя режима на адресиране
  • SIB: Scale(2b) + Index(3b) + Base(3b) → EA = Base + Index×Scale + Disp
  • Линеен адрес = Сегментна база + Ефективен адрес; Физически = след странициране
  • В 64-битов режим: виртуален адрес е 48-битов (канонична форма), физически до 52 бита

→ Речник на всички съкращения


Източници: