Представление инструкций в GAS


  
 К оглавлению
 
 
 
Конечной целью программирования является не написание красивого кода, радующего глаз программиста, а передача последовательности команд центральному процессору (далее по тексту — процессор). Поэтому чем оптимален их набор в коде программы, тем выше её производительность.
В процессе выполнения программы, по мере надобности, процессор вычитывает инструкции из памяти или вернее из КЭШа, который в свою очередь может их иметь один, два или три уровня в зависимости от архитектуры процессора и модели его реализации.
Каждая инструкция имеет размерность в байтах, которая не имеет различий с размерностью данных с которыми она оперирует. Поэтому для различая между данными и инструкциями используются специальные указатели (special pointers), чтобы помочь процессору следить за тем, где в оперативной памяти хранятся инструкции и данные.
В свою очередь любые данные и инструкции являются частью адресного пространства. Соответственно, программа должна знать куда и по какому адресу обращаться, чтобы выполнить инструкцию и/или передать ей данные. Поэтому регистры специальных указателей процессора содержат адрес памяти сегмента данных или кода, где хранятся инструкции или, соответственно, данные.
Листинг 1. Использование указателя инструкции
Адрес в памятиСмещение EIP
0x0804872a0
pushl   %ebp
0x0804872b1
movl	   %esp, %ebp
0x0804872d3
movb    $1,%dl
0x0804872f5
movzbl  %dl,%edx
0x080487328
movw    $65535,%ax
0x0804873612
movzwl  %ax,%eax
0x0804873915
addl    %edx,%eax
0x0804873b17
leave
0x0804873c18
ret
Регистр указателя инструкций EIP (Instruction pointer) используется, чтобы помочь отслеживать процессору какие инструкции уже были обработаны и какие нужно обработать ещё. При этом к регистру EIP нельзя обратиться на прямую, а лишь косвенно через вызов таких инструкций как JMP, Jcc, CALL и RET, а так же прерываний и исключений.
Как видно из листинга 1, адрес памяти в регистре EIP приращивается не в соответствие с префиксом, указанным в мнемоническом объявлении инструкции, а по непонятному на первый взгляд случайному распределению байтов в памяти, который на самом деле следует из формата кодирования инструкции в машинный код.
Листинг 2. Фрагмент дампа результата дизассемблирования объектного файла
Смещение EIPМашинный код
0: 55
       push   %ebp
1: 89 e5
       mov    %esp,%ebp
3: b2 01
       mov    $0x1,%dl
5: 0f b6 d2
       movzbl %dl,%edx
8: 66 b8 ff ff
       mov    $0xffff,%ax
12:0f b7 c0
       movzwl %ax,%eax
15:01 d0
       add    %edx,%eax
17:c9
       leave
18:c3
       ret
Из листинга 2 видно, что счетчик в лице указателя инструкций приращивается ровно на то количество байт сколько фактически инструкции отведено в машинных кодах. Поэтому настала пора рассмотреть ее формат представления к оным.

Формат машинного кода инструкции

На рис.1 представлен формат машинного кода инструкций архитектуры x86-32.
Рис. 1. Формат представления инструкции GAS

Мандатный префикс инструкции

Дополнительно инструкция может иметь один из четырех групп префиксов, имеющие размерность в один байт и обеспечивающие переназначение её поведения от устанавливаемого по-умолчанию (таблица 1). При этом одновременное использование подряд нескольких префиксов может привести к непредсказуемым результатам.
Таблица 1. Мандатные префиксы инструкции
Группа Код Назначение Метка GAS
Блокировки и повторения 0xF0 Префикс LOCK используется в инструкциях для блокировки во время выполнения инструкции. Используется только в следующих инструкциях: BT, BTS, BTR, BTC, XCHG, ADD, OR, ADC, SBB, AND, SUB, XOR, NOT,NEG,INC,DEC. Обычно в мультизадачных системах используется в целях блокировки доступа к разделяемым ресурсам памяти. lock
0xF3 Префикс повторения, позволяющий повторять неограниченное число раз выполнение операции в соответствие с кодом операции инструкции. Префиксы REP, REPE (повторять до тех пор пока равно) и REPNE (повторять до тех пор пока не равно) применяются в операциях со строками.
rep,
repe,
repne
набор инструкций расширения потоковых SIMD (в AMD 3dNow), позволяющих осуществлять вычислительные операции одновременно над разными данными.  
0xF2 Синонимами REPE и REPNE являются REPZ и REPNZ соответственно.
repz,
repnz
Переназначения сегмента 0x2E Сегмента СS Используется в архитектуре x86-32 при трансляции адреса в Flat и страничной моделях распределения памяти. В архитектуре x86-64 не задейтвуются  
0x36 Сегмента SS  
0x3E Сегмента DS  
0x26 Сегмента ES  
0x64 Сегмента FS  
0x65 Сегмента GS  
Переназначения размерности данных 0x66 Используется с кодом операции инструкций, которые оперируют данными с 32-х разрядной размерностью.  
Переназначения размерности адресации 0x67 Используется с кодом операции инструкций, которые оперируют адресами с 32-х разрядной размерностью.  
В листинге 2, префикс инструкции ( выделен жирным) встречается по смещению 8, как показано в листинге 3, при помещения константы 0xffff в 16-ти разрядный регистр аккумулятора AX.
Листинг 3. Пример использования префикса инструкции
                 . . .
8:	66 b8 ff ff          	mov    $0xffff,%ax
                 . . .
В таблице 2 приводится использование префиксов переназначения размера данных (операндов) и адресации согласно режиму работы процессора.
Таблица 2. Использование префиксов переназначения размера операндов и адреса
Режим Префикс переназнач. регистра СS Префикс переназнач. размера операнда, 0х66 Префикс переназнач. адресации, 0х67 Размер операнда в разрядах Размер адреса в разрядах
Реальный режим 16 16
Да 16 32
Да 32 16
Да Да 32 32
Защищенный режим 0 16 16
0 Да 16 32
0 Да 32 16
0 Да Да 32 32
1 32 32
1 Да 32 16
1 Да 16 32
1 Да Да 16 16

Префикс 0x0F

Признак наличия двух-байтового кода операции, который начинается именно с данного значения в первом байте.
В листинге 2, данный префикс присутствует по смещению 5 и 12. В первом случае он используется в инструкции movzbl, а во втором в movzwl, которые производят операции с 8-ми и 16-ти разрядными данными соответственно.
Листинг 4. Пример использования префикса 0f
                    . . .
  5:	0f b6 d2             	movzbl %dl,%edx
                    . . .
 12:	0f b7 c0             	movzwl %ax,%eax
                    . . .

Код операции

Код операции Opcode (Operation code) может состоять из 1 или 2-х байтов. При этом, если операция производится только между регистром и непосредственного значения (способ адресации – непосредственная), код инструкции может состоять из opcode и непосредственного операнда, как показано в таблице 3, а первые три младших разряда её будут содержать идентификатор регистра, соответствующий полю reg байта modR/M.
Таблица 3. Представление в машинных кодах записи непосредственного операнда 0xffffffff, 0xfffff и 0xff в регистры общего назначения.
Идентификатор регистра Мандатный префикс Opcode Операнд Инструкция
0002 B016 ff16 movb $0xff, %al
1011 00002 1111 11112
6616 B816 ff ff16 movw $0xffff, %ax
0110 01102 1011 10002 1111 1111 1111 11112
B816 ff ff ff ff16 movl $0xffffffff, %eax
0110 0110 1011 10002 1111 1111 1111 1111 11112
0012 B116 ff16 movb $0xff, %cl
1011 00012 1111 11112
6616 B916 ff ff16 movw $0xffff, %cx
0110 01102 1011 10012 1111 1111 1111 11112
B916 ff ff ff ff16 movl $0xffffffff, %ecx
0110 0110 1011 10012 1111 1111 1111 1111 11112
0102 B216 ff16 movb $0xff, %dl
1011 00102 1111 11112
6616 BA16 ff ff16 movw $0xffff, %dx
0110 01102 1011 10102 1111 1111 1111 11112
BA16 ff ff ff ff16 movl $0xffffffff, %edx
0110 0110 1011 10102 1111 1111 1111 1111 11112
0112 B316 ff16 movb $0xff, %dl
1011 00112 1111 11112
6616 BB16 ff ff16 movw $0xffff, %dx
0110 01102 1011 10112 1111 1111 1111 11112
BB16 ff ff ff ff16 movl $0xffffffff, %edx
0110 0110 1011 10112 1111 1111 1111 1111 11112
1012 BD16 ff ff ff ff16 movl $0xffffffff, %ebp
0110 0110 1011 11012 1111 1111 1111 1111 11112
1102 BE16 ff ff ff ff16 movl $0xffffffff, %esi
0110 0110 1011 11102 1111 1111 1111 1111 11112
1112 BF16 ff ff ff ff16 movl $0xffffffff, %edi
0110 0110 1011 11112 1111 1111 1111 1111 11112
Таким образом, для регистров общего назначения при использовании непосредственной адресации, можно вывести следующее выражение формально-логического описания, в данном случае для инструкции перемещения данных – MOV.
 

Мнемон. обознач.Форма записи в формально  
инструкции GASлогическом описание 
 
MOVB   imm8, r8
MOVW   imm16, r16[MOV + /r] [imm]
MOVL   imm32, r32

Где
MOV – мнемоническое обозначение opcode, равного значению BA16;
/r – один из регистров общего назначения:
r8 – размерностью 1 байт (8 разрядов) : AL, CL, DL, BL, AH, CH, DH, BH, BPL, SPL, DIL и SIL;
r16 – размерностью 2 байта (16 разрядов): AX, CX, DX, BX, SP, BP, SI, DI;
r32 – размерностью 4 байта (16 разрядов): EAX, ECX, EDX, EBX,ESP, EBP, ESI, EDI;
imm – непосредственное значение операнда, который обозначается с использованием символьного префикса '$'. Иначе, операнд может быть воспринят как адрес памяти.
imm8 – одно-байтовое знаковое значение в диапазоне значений от –128 до +127 включительно или без знаковое, записанное в форме шестнадцатеричной системы представления чисел в диапазоне допустимых значений от 0 до 255 включительно. Для инструкций, которые комбинирует такое одно-байтовое знаковое значение с операндом размерностью слово или двойного слова, непосредственное значение будет расширено с учетом знака до требуемого размера. При этом старшие байты расширяемого значения будут заполнены согласно старшему разряду непосредственного значения.
imm16 – двух-байтовое знаковое значение в диапазоне значений от –32,768 до +32,767 включительно или без знаковое, определенное в форме шестнадцатеричной системы представления чисел от 0 до 65535 включительно.
imm32 – четырех-байтовое с учетом знака значение в диапазоне значений между +2,147,483,647 и –2,147,483,648 включительно или без знаковое, определенное в форме шестнадцатеричной системы представления чисел от 0 до 4294 967 295 включительно.
Общей формой записи инструкции для непосредственной адресации будет являться формула (1), используемой в формально логическом описании
    (1)[OPCODE + /r] [imm]

 
Где
OPCODE – является мнемоническим наименованием инструкции.

  
 
 К оглавлению
Сайт создан в системе uCoz