Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Инструкции с фиксированной точкой
РРС не имеет вычислительных инструкций для изменения хранимых данных. Вся работа должна выполняться в одном из 32 регистров общего назначения (general-purpose registers, GPRs). Инструкции доступа к хранимым данным могут получать байты, полуслова, слова и двойные слова в обратном порядке байтов (Big Endian). При использовании расширенных мнемоник дополнительно доступны множество инструкций загрузки, сохранения, арифметические и с фиксированной точкой, а также специальные инструкции для перемещения из системных регистров или в них. Инструкции с плавающей точкой Инструкции с плавающей точкой можно разделить на две категории: вычислительные, включающие арифметические, трассировочные, преобразующие сравнительные; и невычислительные, включающие перемещение из хранящих или других регистров или в них. Доступно 32 регистра с плавающей точкой общего назначения; каждый может содержать данные в формате с плавающей точкой удвоенной точности. Ассемблер Обратный порядок байтов/прямой порядок байтов (Big Endian/Litle Endian) В процессорной архитектуре порядок байтов (Endianness) означает порядок следования байтов и операций. PowerPC работает с обратным порядком байтов, это значит, что самый старший байт имеет меньший адрес, а оставшиеся 3 байта следуют за ним (для 32-битового слова). Прямой порядок байтов принят в х86-архитектуре и означает противоположный порядок. Младший значащий байт имеет наименьший адрес, а оставшиеся 3 байта следуют за ним. Давайте рассмотрим это на примере представления числа 0x12345678 (рис. 2.5). Обратный 32 битный порядок следования байтов (РРС)
0 7 8 1516 23 24 31 Прямой 32 битный порядок следования байтов (х86)
0 7 8 15 16 23 24 31 Рис. 2.5. Прямой и обратный порядок следования байтов Споры о том, какая система лучше, выходят за рамки данной книги, тем не менее вам важно помнить, на какой системе вы пишете и отлаживаете свой код. Для примера ошибки, связанной с последовательностью байтов, можно привести драйвер РО-устройства, используемый на архитектуре с другой последовательностью байтов. Термины Big Endian и Little Endian (тупоконечный и остроконечный) були придуманы Джонатаном Свифтом в Путешествии Гулливера. В этой истории Гулливер знакомился с двумя нациями, воевавшими из-за разногласия по поводу того, с какой стороны есть яйцо -с острой или с тупой. Х86 Архитектура х86 является архитектурой с полным набором вычислительных инструкций Complex Instruction Set Computing (CISC). Инструкции имеют различную длину в зависимости от назначения. В классе процессоров х86 Pentium существует три типа регистров: общего назначения, сегмента и статуса/управления. Далее описывается их базовый набор. Вот 8 регистров общего назначения и соглашение по их использованию: • ЕАХ. Аккумулятор общего назначения. • ЕВХ • Указатель на данные. • ЕСХ. Счетчик цикловых операций. • EDX. Указатель ввода-вывода. • ESI. Указатель на данные в сегменте DS. Глава 2 • Исследовательский инструментарий • EDI. Указатель на данные в сегменте ES. • ESP. Указатель на стек. • ЕВР. Указатель на данные в стеке. Шесть сегментных регистров используются в реальном (real) режиме адресации, когда память адресуется блоками. При этом каждый байт в памяти доступен по отступу из данного сегмента [например, ES: EDI указывает на память в ES (дополнительном сегменте) с отступом к значению в EDI]: • CS. Сегмент кода. • SS. Сегмент стека. • ES# DS# FS, GS. Сегмент данных. Регистр FLAGS показывает состояние процессора после каждой инструкции. Он может хранить такие результаты, как нуль (zero), переполнение (overflow) или перенос (carry). EIP - это регистр зарезервированного указателя, обозначающий отступ к текущей инструкции процессора. Обычно он используется с регистром сегмента кода для формирования полного адреса (например, CS: EIP): • EFLAGS. Статус, управление и системные флаги. • EIP. Указатель на инструкции, содержащие отступ от CS. В архитектуре х86 используется прямой порядок следования данных. Доступ к памяти осуществляется порциями по байту (8 бит), слову (16 бит), двойному слову (32 бита) или учетверенному слову (64 бита). Преобразование адресов (и связанных регистров) описывается в гл. 4, но для этого раздела достаточно знать, что в архитектуре х86 код и данные делятся на три категории: управляющие, арифметические и данные. 2.2.2.1 Управляющие инструкции Управляющие инструкции похожи на управляющие инструкции в РРС, позволяющие изменять поток выполнения программы. Архитектура х86 использует различные инструкции перехода («jump») и метки на выполняемый код, основанные на значениях регистра EFLAGS. В табл. 2.3 перечислены наиболее часто используемые из них. Коды состояния condition codes устанавливаются в соответствии с исходом определенных инструкций. Например, когда инструкция стр (сравнение) обрабатывает два целых операнда, он модифицирует следующие флаги в регистре EFLAGS: OF (переполнение), SF (знаковый флаг), ZF (флаг нуля), PF (флаг четности) и CF (флаг переноса). Таким при вычислении значения инструкции стр устанавливается нулевой флаг. Ассемблер Таблица 2.3. Наиболее распространенные инструкции перехода
В ассемблерном коде х86 метки состоят из уникальных имен, после которых ставится двоеточие. Метка может быть использована везде в ассемблерной программе и имеет тот же адрес, что и следующая за ней строка кода. Следующий код использует условный переход и метку: 100 pop eax 101 1оор2 102 pop ebx 103 cmp eax, ebx 104 jge loop2 Строка 100 Получение значения из верха стека и помещение его в еах. Строка 101 Это метка с именем 1оор2. Строка 102 Получение значения из верха стека и помещение его в ebx. Строка 103 Сравнение значений еах и ebx. Строка 104 Переход, если еах больше или равно ebx. Еще одним способом передачи программного управления являются инструкции call и ret. Обратимся к следующей строке ассемблерного кода: call my_routine Глава 2 • Исследовательский инструментарий Инструкция call передает программное управление на метку my_routine, передавая адрес инструкции, следующей в стеке сразу за инструкцией call. Инструкция ret (исполняемая из my_routine) извлекает возвращаемый адрес и осуществляет переход по нему. 2.2.2.2 Арифметические инструкции Наиболее известны арифметические инструкции add, sub, imul (целочисленное умножение), idiv (целочисленное деление) и логические операторы and, or, not и xor. Х86-инструкции с плавающей точкой и связанные с ними регистры выходят за рамки этой книги. Различные расширения архитектур Intel и AMD, такие, как ММХ, SSE, 3dNow, SIMD и SSE2/3, значительно ускоряют приложения с интенсивными вычислениями, такие, как графические и аудио-вычисления. 2.2.2.3 Инструкции для работы с данными Данные могут перемещаться между регистрами, между регистрами и памятью и из константы в регистр или память, но не из одного места в памяти в другое. Ниже приведено несколько примеров. 100 mov eax, ebx 101 mov еах, WORD PTR[data3] 102 mov BYTE PTR[char1], al 103 mov eax, Oxbeef 104 mov WORD PTR [my_data], Oxbeef Строка 100 Передача 32 бит данных из ebx в eax. Строка 101 Передача 32 бит данных из переменной data3 в памяти в еах. Строка 102 Передача 8 бит данных из переменной charl в памяти в al. Строка 103 Передача значения константы Oxbeef в еах. Строка 104 Передача значения константы Oxbeef в переменную в памяти my_data. Как видно из предыдущего примера, push, pop и их длинные версии lpush, lpop перемещают данные в стек и из него (по указателю SS: ESP). Подобно инструкции mov, операции push и pop могут применяться к регистрам, данным и константам. Пример языка ассемблера Пример языка ассемблера Мы можем написать простую программу, чтобы увидеть архитектурные различия преобразования одного и того же С-кода в ассемблер. Для этого эксперимента мы используем компилятор дсс, поставляемый с Red Hat 9, и gcc-кросс-компилятор для PowerPC. Мы приведем С-программу и затем для сравнения код для х86 и PowerPC. Вас может озадачить количество ассемблерного кода, генерируемого из нескольких строк С. Так как мы просто компилируем из С в ассемблер, мы не будем связывать его ни с каким кодом окружения, таким, как С-библиотеки времени исполнения или создание-уничтожение локального стека, поэтому результат будет значительно меньше, чем настоящий ELF-исполнимый файл. Помните, что в ассемблере вы приближаетесь к тому, что именно делает процессор цикл за циклом. Еще можно сказать, что вы получаете полный контроль над кодом и системой. Важно помнить, что даже при нахождении инструкций в памяти в определенном порядке, они не обязательно будут прочитаны именно в такой порядке. Некоторые архитектуры выстраивают операции загрузки и хранения отдельно. Вот пример С-кода: Count.с Int main() 2 { 3 int i, j=0; 4
5 for(i=0; i< 8; i++) 6 j=j+i; 7
8 return 0; 9 } Строка 1 Здесь объявляется функция main. Строка 3 Здесь инициализируются нулем переменные i и j. Строка 5 Цикл for: пока значение i находится в интервале от 0 до 7, установить j равным j плюс i. Строка 8 Метка перехода назад в вызывающую программу. Глава 2 • Исследовательский инструментарий Пример х86-ассемблера Вот код, сгенерированный для х86 с помощью команды gcc -S count. с из командной строки. После ввода кода база стека указывает на ss: ebp. Код выполнен в формате «AT& T», в котором регистры имеют префикс %, а константы - префикс $. Пример ассемблерных инструкций приведен в этом разделе для того, чтобы подготовить вас к будущим примерам программ, но перед этим нам нужно обсудить непрямую адресацию. Для обозначения позиции в памяти (например, стека) ассемблер использует специальный синтаксис для индексированной адресации. Базовый регистр помещается в круглые скобки, а индекс ставится перед скобками. Результирующий адрес находится добавлением индекса к значению регистра. Например, если %ebp присвоено значение 20, эффективный адрес -8 (%ebp) будет (-8)+(20)= 12: count.s 1.file " count.с" 2.version " 01.01" 3 gcc2_compiled.: 4.text 5.align 4 6.globl main 7.type main, @function 8 main: #Создание локальной области в памяти из 8 байт для for i и j. 9 pushl %ebp 10 movl %esp, %ebp 11 subl $8, %esp инициализация i (ebp-4) и j (ebp-8) нулем. 12 movl $0, -8(%ebp) 13 movl $0, -4(%ebp) 14.p2align 2 15.L3: #Проверка для цикла for 16 cmpl $7, -4(%ebp) 17 jle.L6 18 jmp.L4 19.p2align 2 20.L6: #Это тело цикла for-loop 21 movl -4(%ebp)/ %eax 22 leal -8(%ebp)/ %edx 23 addl %eax, (%edx) 24 leal -4(%ebp), %eax Пример языка ассемблера 25 incl (%eax) 26 jmp.L3 27.p2align 2 28.L4: #Конструкция для вызова из функции 29 movl $0, %еах 31 ret Строка 9 Установка базового стекового указателя на стек. Строка 10 Перемещение указателя на стек в базовый указатель. Строка 11 Получение 8 байт стека mem начиная с ebp. Строка 12 Помещение 0 в адрес ebp-8 (j ). Строка 13 Помещение 0 в адрес ebp-4 (i). Строка 14 Ассемблерная директива, обозначающая выровненную по полуслову инструкцию. Строка 15 Созданная на ассемблере метка с именем.L3. Строка 16 Эта инструкция сравнивает значения i с 7. Строка 17 Переход на метку.L6, если -4 (%ebp) меньше или равно 7. Строка 18 В противном случае выполняется переход на метку.L4. Строка 19 Выравнивание. Строка 20 Метка.L6. Глава 2 • Исследовательский инструментарий Строка 21 Перемещение i в еах. Строка 22 Загрузка адреса j в edx. Строка 23 Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 740; Нарушение авторского права страницы