КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Структура команд процессора INTEL 80х86
Дизассемблирование основано на знании формата инструкций процессора и правил их интерпретации процессором. Формат инструкций архитектуры Intel приведен на рис.1.
Рис.3. Формат инструкций процессоров архитектуры Intel 80х86 Все поля, кроме поля опкода, являются необязательными, в одних командах они могут присутствовать, а в других - нет. Рассмотрим поля инструкций подробнее. Префиксы занимают один байт и делятся на четыре группы: 1. Префиксы блокировки 0xF0 - LOCK-префикс и повторения только для строковых инструкций 0xF2 REPNZ и 0xF3 REP. 2. Префиксы переопределения сегмента: 0х2Е - CS:, 0х36 - SS:, 0хЗЕ - DS:, 0х26 - ES:, 0х64 - FS:, 0х65 - GS: 3. Префикс переопределения размеров операндов: 0х66. 4. Префикс переопределения размеров адреса: 0х67. Если используется более одного префикса из той же самой группы, то действие команды не определено и по-своему реализовано на разных типах процессоров. Префикс переопределения размера операндов используется в 16-разрядном режиме для манипуляции с 32-битными операндами и наоборот. При этом он может стоять перед любой командой, например 0х66: CLI будет работать. Рассмотрим, как работает конструкция 0х66: RETN. Если функция RETN не имеет операндов, то префикс 0х66 можно просто игнорировать. Но на самом деле RETN работает с неявным операндом — регистром IP/EIP. Именно это определяет префикс. В реальном и 16-разрядном режиме указатель команд всегда обрезается до 16 бит, и поэтому на первый взгляд возврат выполнится корректно. Но стек окажется несбалансированным. Из него вместо одного слова взяли целых два. В результате можно получить и исключение 0хС — исчерпание стека. Префиксы перекрытия сегмента могут встречаться перед любой командой, в том числе и не обращающейся к памяти, — например, CS:NOP вполне успешно выполнится. А вот некоторые дизассемблеры могут сбиться. Комбинация из DS:FS:FG:CS:MOV AX,[100] работает вполне нормально, хотя и не гарантируется фирмой Intel. При этом последний префикс в цепочке перекрывает все остальные. Некоторые отладчики, наоборот, ориентируются на первый префикс в цепочке, что дает неверный результат. Этот пример хорош тем, что великолепно выполняется под Windows и другими операционными системами. Но на декодирование каждого префикса тратится один такт и все это может медленно работать. Поле опкода занимает 8 бит и часто имеет формат, приведенный на рис.2. Если значение поля размера равно нулю, то операнды имеют размер один байт. Единичное значение указывает на слово (двойное слово в 32-режиме или с префиксом 0х66 в 16-разрядном режиме).
Рис.4. Формат поля опкода Направление обозначает операнд-приемник. Нулевое значение присваивает результат правому операнду, а единица - левому. Рассмотримэто на примере инструкции MOV BX,DX, где при изменении одного бита направления меняются местами регистры операнды: 8 B DA = 100010 1 1b 11011010b MOV BX,DX 8 9 DA = 100010 0 1b 11011010b MOV DX,BX Однако в случае, когда один из операндов имеет непосредственное значение, он не может быть приемником и независимо от значения поля направления будет только источником. Но бит направления позволяет в ситуации, когда операнду размером в слово или двойное слово присваивается непосредственное значение, меньшее по модулю 0х100, указать процессору, что значащим является только младший байт, все старшие являются нулем. Рассмотрим команду ADD W,[00123],0066: 8 1 062301 6600 = 81 (100010 0 1b) 062301 6600 Если теперь флаг направления установить в единицу, то произойдет следующее: 8 3 062301 66 = 83( 100010 1 1b) 062301 66 h Таким образом, происходит экономия один байт в 16-разрядном режиме и целых три в 32-разрядном. Это следует учитывать при написании самомодифицирующегося кода. Большинство ассемблеров генерируют второй (оптимизированный) вариант, и длина команды оказывается меньше ожидаемой. Формат команд различается от одной команды к другой. Однако можно выделить и некоторые общие правила. Практически для каждой команды, если регистром-приемником фигурирует AX(AL), существует специальный однобайтовый опкод, который в трех младших битах содержит регистр-источник. Этот факт следует учитывать при оптимизации. Так, среди двух инструкций XCHG АХ,ВХ (0x93) и XCHG BX,DX (0x87 0xDA) следует всегда автоматически выбирать первую, так как она на байт короче. Для многих команд условного перехода (Jx) четыре младшие бита обозначают условие операции. Точнее, условие задается в битах 1-2-3, а младший бит приводит к его инверсии табл.1. Например, по табл. 1 легко определить, что код условия 'JZ' равен 0х74, а условия 'JNZ' - 0х75. Не все опкоды смогли поместиться в первый байт и дополнительно для размещения еще нескольких бит используется байт ModR/M. В этом случае первый байт называется основным, а второй - уточняющим опкодом. Когда в инструкции используется непосредственный операнд, трехбитовое поле Reg, содержащее регистр-источник, не используется и его применяют для задания дополнительных бит опкода. На такую ситуацию процессору указывает префикс 0xF, размещенный в первом байте опкода (MOV CR0,CX = 0x0F 0x22). Заметим, что то же поле используют многие инструкции, оперирующие с одним операндом (JMP, CALL). Это все очень сильно затрудняет написание собственного ассемблера/дизассемблера, но зато дает простор для самомодифицирующегося кода. В восьмибитовом поле ModR/M два трехбитовых поля могут задавать код регистра общего назначения по табл.2. Таблица 1 Кодирование условий команд ветвления
Таблица 2 Кодирование регистров общего назначения
При такой организации кодирования регистров нельзя выборочно обращаться к старшим и младшим байтам регистров SP, BP, SI, DI и, аналогично, старшему слову всех 32-битных регистров, так как нет свободных полей, в которые можно было занести дополнительные регистры. Алфавитный порядок регистров AX-CX-DX-BX-SP-BP-SI-DI. Порядок нарушен, так как BX — это индексный регистр, и он стоит первым среди индексных. Таким образом, теперь можно без дизассемблера, распознавать в шестнадцатиричном дампе регистры-операнды. Или писать самомодифицирующийся код. Например:
Он изменит строку 0х6 на XOR SP,SP. Это не позволит дизассемблерам отслеживать локальные переменные, адресуемые через SP. В приведенном примере это очевидно, но в условиях многопоточной системы изменение кода очень трудно отследить, особенно в листинге дизассемблера. Первоначально сегментные регистры кодировались всего двумя битами, и этого хватало, так как их было всего четыре. Позже, когда их стало больше, перешли на трехбитную кодировку. При этом два регистра 110b и 111b отсутствуют. Если попытаться их использовать, произойдет генерация INT 0х6. Таблица 3 Кодирование сегментных, управляющих и отладочных регистров
Регистр CR1 в настоящее время зарезервирован и не используется, но на самом деле регистр CR1 не существует и любая попытка обращения к нему вызывает генерацию исключения int 0х6. При обращении к регистрам DR4-DR5 исключения не генерируется. Режимы адресации микропроцессоров Intel задаются значением байтового поля ModR/M. Если поле Mod = 11b, то два следующие поля будут представлять собой регистры. Это регистровая адресация. Например:
Здесь значение поля размер управляет значениями регистров. По байту ModR/M нельзя точно установить регистры. В зависимости от кода операции и префиксов размера операндов, результат может варьироваться в ту или иную сторону. Биты 3-5 могут вместо регистра представлять уточняющий опкод (в случае, если один из операндов представлен непосредственным значением). Младшие три бита всегда либо регистр, либо способ адресации. Последнее зависит от значения 'mod'. Отметим, что биты 3-5 никак не зависят от выбранного режима адресации и всегда задают либо регистр, либо непосредственный операнд. Начиная с процессора 80386 (для 32-разрядного режима), концепция адресаций была пересмотрена и поле R/M стало всегда выражать регистр, независимо от способа его использования. Им управляло поле 'mod', задающее (кроме регистровой) три вида адресации: Mod=00b - [Reg], Mod=01b - [Reg+08], Mod=10b - [Reg+32], Mod=11b – Reg. Поле Mod выражает длину следующего поля — смещения, разве что с учетом 32-разрядного режима, где все слова расширяются до 32 бит. Система адресации 32-разрядного режима, кроме приведенных в табл. 5 режимов, использует байт SIB (Scale-Index Base). Процессор будет ждать его вслед за R/M всякий раз, когда последний равен 100b. Эти поля отмечены в табл.5 как '[--]'. Назначения полей SIB показаны на рис.1. 'Base' — это базовый регистр, Index — индексный, а два байта Scale — это степень двойки для масштабирования. Индексный регистр, например, [SI], в качестве него можно выбирать любой регистр в качестве индексного, за исключением SP. Базовый регистр — это тот, который суммировался с индексным, например, [BP+SI]. Точно так же теперь можно выбрать любой регистр в качестве базового. При этом есть возможность выбрать SP. Заметим, что если мы выберем последний в качестве индексного, то получим вместо 'SP' — "никакой". В этом случае адресацией будет управлять только базовый регистр.
Таблица 5 Режимы адресации
Масштабирование — это возможность умножать индексный регистр на 1, 2, 4, 8 (т.е. степень двойки, которая задается в поле Scale). Это очень удобно для доступа к различным структурам данных. При этом индексный регистр, являющийся одновременно и счетчиком цикла, будет указывать на следующий элемент структуры даже при единичном шаге цикла, что чаще всего и встречается. Если при этом в качестве базового индекса будет выбран ВР, то полученный режим адресации будет зависеть от поля Mod предыдущего байта. Возможны следующие варианты: Mod=00b - Смещение32[index], Mod=01b - Смещение8 [ЕВР] [index], Mod=10b - Смещение32[ЕВР] [index]. Cамая полная возможная схема адресации для 32-разрядного режима – это адресация по базе с индексированием и масштабированием. В нее входят как частные все случаи адресации (регистровая адресация, непосредственная адресация, прямая адресация, косвенная адресация, адресация по базе со сдвигом, косвенная адресация с масштабированием, адресация по базе с индексированием). Полный адрес операнда можно записать как выражение, представленное на рис. 3.
Рис. 5. Полная форма адресации Смещение может быть байтом или двойным словом. Если ESP или EBP используются в роли базового регистра, селектор сегмента операнда берется по умолчанию из регистра SS, во всех остальных случаях — из DS.
Дата добавления: 2014-12-10; Просмотров: 1614; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |