К оглавлению
В GAS операнды используются при выполнение вычислительных операций производимых с помощью инструкций центрального процессора согласно с выбранным режимом адресации и подразделяются на три вида:
- регистровый (регистр),
- непосредственный (константа или явно заданный адрес ячейки памяти),
- адрес памяти.
Синтаксис GAS подразумевает, что инструкция имеет два операнда, даже если они явно не заданы, как например в случае ret или leave. Инструкция оперирует с одним, двумя и тремя аргументами в зависимости от кода операции (opcode), определяющего их состав и порядок использования. Ниже представлен формат записи для инструкции, имеющей не более двух операндов.
mnemonic [scr][,dst]
Здесь mnemonic является мнемоническим обозначением инструкции. Первый операнд (слева) называется источником (src), а второй операнд (справа) приемником (dst). Так же, в документации по GAS различных авторов часто вместо понятия «операнд» используется синоним – аргумент инструкции.
inums_addition: # C-функция int inums_addition ( void ) # pushl %ebp # { movl %esp, %ebp # movzbl $1,%edx # неизбежно приводит к ошибке: # Error: operand type mismatch for `movzbl' movb $1,%dl # /* в регистр EDX кладем первое слагаемое, movzbl %dl,%edx # размерностью 8-мь разрядов c обнулением # старших 24-х разрядов. movzwl $65535,%eax # неизбежно приводит к ошибке: # Error: operand type mismatch for `movzwl' movw $65535,%ax # в регистр EАX кладем второе слагаемое c обнулением movzwl %ax,%eax # старших 16-ти разрядов. # addl %edx,%eax # операция сложения двух 32-х разрядных чисел, # с результатом в регистре EАX */ # leave # return (int)(1+65635); ret # } Размер операнда предопределяется префиксом, информирующего процессор, что нужно переключать размерность операндов в процессе выполнения инструкции. Поэтому, в примере выше, использовалась инструкция целочисленного перемещения беззнаковых целых MOVZBL и MOVZWL для получения предсказуемого результата равным 65636, так как регистры EDX и EАX могут хранить значения, оставшиеся от выполнения предыдущих инструкций. При этом, перефикс 'l' указывает на использование операндов 32-х разрядной размерностью.
Так, если упростить выше представленный пример
movb $1,%dl # /* в регистр EDX кладем первое слагаемое, # размерностью 8-мь разрядов. movw $65535,%ax # в регистр EАX кладем второе слагаемое # размерностью 16-ть разрядов addl %edx,%eax # операция сложения двух 32-х разрядных операндов, # с результатом в регистре EАX */ Вряд ли нам получится с очень большой вероятностью получить результат равным 65636, так как префикс 'b' переключает выполнение инструкции MOV с 8-ю разрядными операндами, а префикс 'w' с 16-ти разрядными операндами. Поэтому, возможность получения неверного результата будет заключаться в старших 24-х разрядах регистра EDX и 16-ти разрядах в регистре EАX, которые при выполнении инструкции MOV остаются неизменными и могут хранить мусор, оставшийся от предыдущей операции. В то время, как инструкция ADD производит операцию сложения с двумя 32-х разрядными операндами включающие в себя необнуленные разряды, как это делали в предыдущем примере с использованием MOVZBL и MOVZWL.
Aдресация памятиВ GAS, обращение по адресу памяти обеспечивается следующим образом:
смещение-в-сегменте:смещение(база,индекс,масштаб) При этом, некоторые части данного объявления могут быть опущены в зависимости от выбранной вами вида адресации.
%es:100(%eax,%ebx,2) Так же нужно помнить, что смещение и масштаб не могут иметь префикс '$'. Более того, при рассмотрении примеров в NASM синтаксисе их нужно отбрасывать.
Пример взят с csiflabs.cs.ucdavis.edu
операнд памяти GAS Операнд памяти NASM Вид адресации ------------------ ------------------- --------------------------- 100 [100] непосредственная адресация %es:100 [es:100] прямая адресация отнсительно сегментного регистра ES (%eax) [eax] косвенная адресация (%eax,%ebx) [eax+ebx] адресация по базе со сдвигом -10(%eax) [eax-10] %ds:-10(%ebp) [ds:ebp-10] (%ecx,%ebx,2) [ecx+ebx*2] адресация по базе с маштабированием и индексированием 2(,%ebx,2) [ebx*2]+2 косвенная адресация с масштабированием В основном примеры кода c использованием GAS приводятся для сегментной модели распределения памяти, в то время как практически все современные операционные системы используют страничную модель памяти, которая больше подходит для реализации мультизадачного взаимодействия в такой операционной системе как GNU/Linux.
Большинство современных процессоров имеют блок управления памятью MMU (Memory Management Unit), используемый для отображения виртуальных адресов памяти (Virtual Address) коих видит процессор и физические адреса (Physical Address) как они фактически распределены в микросхеме-памяти, т.е. основной задачей данного блока является ретрансляция адреса. Кроме того, блок MMU устанавливает один из атрибутов доступа к соответсвующей области виртуальной памяти такой как "Чтение-записи" (Read-Write) или "Только чтение" (Read-Only), или полный запрет доступа.
Поэтому наличие блока управления памятью MMU в современных процессорах поставило точку в использование сегментной модели как основную для семейства процессоров Intel. К слову данная модель широко применялась в процессорах Intel таких как 8086, 8088, 80186, 80286 и поддерживается так же для обратной совместимости начиная c процессора i386. Именно с выходом процессора i386 связано рождение Linux, потому что в нем впервые появился такой блок как MMU, позволяющий ретранслировать виртуальные адреса в физические, а каждому процессу стали доступны страницы размером 4 Кбайт, выделяемые операционной системой.
В конечном счете, на пользовательском уровне программиста не очень заботить какая модель распределения памяти задействована, потому что работа процесса с ней будет происходить внутри выделенных ему операционной системой страниц памяти.
Таким образом, приводимый ранее формат адреса имеет следующий практический смысл:
смещение(база,индекс,масштаб) | |
К оглавлению |