Professional Documents
Culture Documents
#max.s - Find the maximum value //max.c - Find the maximum value
.section .data #include <stdlib.h>
array: int main(void) {
.int 7, 9, 24, 15, 11, 13 int array[] = {7, 9, 24, 15, 11, 13};
size: int i, max, size = 6;
.int 6 max = array[0];
.section .text for (i = 1; i < size; i++)
.globl _start if (max < array[i])
_start: max = array[i];
movl array, %ebx exit(max);
movl $1, %eax }
for:
cmpl size, %eax
jb forcode
jmp exit
forcode:
cmpl %ebx, array(, %eax, 4)
cmova array(, %eax, 4), %ebx
incl %eax
jmp for
exit:
movl $1, %eax
int $0x80
.section name
, где name это имя секции, которое и указывает предназначение секции. Основными
секциями являются:
• .data — секция инициализированных данных (например переменных или констант);
• .bss — секция неинициализированных данных;
• .text — секция кода.
Директиву «.section» в программе можно опускать и писать сразу название секции,
например вместо «.section .data» писать просто «.data». Также вы можете оставлять
секцию пустой, тогда она просто не включается в исполняемый файл и соответственно
места в памяти не занимает (рис.1).
array: size:
.int 7, 9, 24, 15, 11, 13 .int 6
Рис.1. Секция данных не включена в исполняемый файл
array и size это всего лишь метки, которые предназначены для того, чтобы к данным
можно было обратиться по имени, другими словами метка это адрес первого элемента
(если элементов данных несколько, то они перечисляются через запятую), который за ней
следует. Сами метки не занимают места в памяти. Вы можете и не задавать имя метки, но
тогда для обращения к данным вам придется вычислять их адрес, который может
изменяться.
Теперь поговорим о типах данных. Основные типы данных представлены ниже:
• .ascii — текстовая строка;
• .asciz — текстовая строка с добавлением нулевого символа в конец строки;
• .byte — значение длиной в один байт;
• .short (.word) — значение длиной в два байта (слово);
• .int (.long) — значение длиной в четыре байта (двойное слово)
• .quad — значение длиной в восемь байт;
• .octa — значение длиной в шестнадцать байт;
• .float (.single) — вещественное число одинарной точности;
• .double — вещественное число двойной точности.
Для текстовых строк, заданных с помощью директивы «.ascii», следующие
обозначения эквивалентны:
str1: str2:
.ascii "a", "b", "c" .ascii "abc"
Но при использовании директивы «.asciz» они уже не будут эквивалентными, так как
добавляется признак конца строки, т.е. в первом случае он будет добавлен после каждого
символа, а во втором только после последнего символа:
value:
.data_type num [, num_2, num_3, .......]
.section .text
.globl _start
_start:
.byte 0xB8
.int 1
.byte 0xBB
.int 0
.byte 0xCD, 0x80
На первый взгляд нет ни одной инструкции, но на самом деле это не так, в чем
можно убедиться, взглянув на код в HT Editor:
Про использование опкодов можно почитать в цикле статей Aquila «Заклинание кода»
value:
.int 1
...
movl value, %eax #поместить 1 в регистр eax
Если нужно поместить адрес элемента, то перед «value» нужно поставить знак долара «$»
Любое из значений может быть опущено, если опущены все значения, то остается
только базовый_адрес и, таким образом, получается прямая адресация.
value:
.int 1
...
movl $value, %eax #поместить адрес value в регистр %eax
movl (%eax), %ebx #поместить значение по адресу в %eax в регистр %ebx
movx источник, приемник или, чтобы было проще запомнить movx что, куда
• регистры общего назначения (РОН) — EAX (Accumulator), EBX (Base Register), ECX
(Counter Register), EDX (Data Register);
• регистры указателей — EIP (Instruction Pointer), ESP (Stack Pointer), EBP (Base Pointer);
• регистры индексов — ESI (Source Index), EDI (Destination Index).
• регистр флагов — EFLAGS;
• сегментные регистры — CS, DS, SS, FS, ES, GS;
31 15 7 0
%EAX
%AX
%AH %AL
loop адрес
, где адрес это место в программе куда следует перейти. Регистр «%ecx» выступает
в роли счетчика, в него помещается значение равное количеству итераций, которое
необходимо совершить, например:
После выполнения всех инструкций регистр «%eax» будет содержать «50». Каждое
выполнение инструкции «loop» уменьшает значение регистра «%ecx» на единицу и
сравнивает его с нулем (именно в таком порядке: уменьшить — сравнить), если значение
«%ecx» равно нулю, то продолжить выполнение следующей за «loop» инструкции, иначе
перейти на метку.
Остальные регистры будут описаны по мере их использования.
Снова вернемся к программе. Регистр «%eax» выступает в роли счетчика цикла и
предварительно устанавливается равным единице. Далее идет сам цикл. Для того чтобы
лучше понять работу цикла «for» представим его в виде цикла «while» на С:
i = 1;
while (i < size) {
//тело цикла
i++;
}
jxx адрес
jmp адрес
, где адрес также, как и в инструкции «jxx» место в программе (адрес в памяти) куда
следует перейти.
И в который раз возращаясь к программе. Итак мы перешли в тело цикла, где
должно происходить сравнение текущего максимального элемента (который храниться в
регистре «%ebx») с элементом массива (к элементам массива мы обращаемся используя
индексную адресацию). Это делает инструкция «cmpl %ebx, array(, %eax, 4)». Теперь,
если значение в регистре «%ebx» меньше, чем значение элемента массива, то «%ebx»
присваивается новый максимальный элемент. Можно было бы воспользоваться уже
описанными инструкциями, но есть специально предназначенная инструкция для условного
перемещения — CMOV (Conditional Move). Формат инструкции такой: