Конечно же ассемблер под юникс отличается от ассемблера под доc или виндоуз. В то время как в асме под эти операциоyные системы использовался синтаксис навязанный интеллом, изобилующий разными неопределенностями (неоднозначностями, если хотите), решающимися за счет приведения типа (byte ptr, word ptr, dword ptr), в асме под никс использовался сиснтексис AT&T и SysV/386, который разрабатывался специально для устранения неоднозначности толкования команд. Конечно же существуют ассемблеры, под юникс с интелловским синтаксисом, такие как NASM, но в данной статье будет рассмотрен синтаксис ассемблеров стандартных для данной платформы.
Вообще, конечно же стоило бы начать с правил. Мы так и поступим. В ассемблере, использующем AT&T синтаксы, для работы используются все латинские буквы, цифры, а также дополнительные символы, такие как процент, запятая, точка, подчеркивание, звездочка, значек доллара. Команды процессора: любая последовательность разрешенных символов, начинающаяся не со спец.знака либо цифры и не заканчивающаяся двоеточием, считается ассемблером командой процессора:
//останов процессора
hlt
если же такая последовательность начинается со знака процента, то это регистр процессора:
pushl %eax
// помещает содержимое регистра %eax в стэка если начинается с доллара ($), то это непосредственный операнд. Нижеприведенный код помещает в стэк число 0, 10h, и адрес переменной qwerty:
pushl $0
pushl $0x10
pushl $qwerty
если последовательность начинается с точки, то это считается дерриктивой ассемблера:
.aling 2
ну а если последовательность заканчивается двоеточием, то это метка (используется точно также как и в ассемблере под доc и виндоуз). Стоит отметить специальную метку точка — эта метка, как и в асме под доc характеризует текущий адрес.
Команды преобразованя типов в синтексисе AT&T имеют названия из четырех букв: С, размер источника, Т, размер приемника:
//cbw
cbtw
//cwde
cwtl
//cwd
cwtl
//cdq
cltd
где:
b- байт
w- слово
l- двойное слово
q- учетверенное слово
s- 32битное число с плавающей запятой
l-64битное число с плавайющей запятой
t- 80битное число с плавайщей запятой
Одно из важнейших отличий в ассемблерах это запись премника и источника, а отличае от дос-асма, в юниксе операнд-источник записывается всегда на первой позиции
//mov ax,bx
movw %bx,%ax
//imul eax,ecx,16
imull $16,%ecx,%eax
Виды адресаций: как уже говорилось ранее, регистровый операнд и непосредственный различаются прейиксами % и $:
//xor ebx,ebx
xorl %ebx,%ebx
//mov edx,offset qwerty
movl $qwerty,%edx
При косвенной адресации используется немодифицированное имя переменной, как это было в интелловском варианте:
//push dword ptr qwerty
pushl $qwerty
Более сложные способы адресации лучше рассматривать на базе операций со сдвигом, по базе и индексированием:
//mov eax,base_addr[ebx+edi*4]
movl base_addr(%ebx+%edi*4),%eax
//lea eax,[eax,eax*4]
leal (%eax,%eax*4),%eax
//mov ax,word ptr [bp-2]
movw -2(%ebp),%ax
//mov edx,dword ptr [edi*2]
movl (%edi*2),%edx
Непосредственно сам процесс программирования разделяется на программирование с использованием библиотеки libc и на программирование без ее использования. Так как сама система написанна на С и многие функции обращаются к этой библиотеке, то и программы написанные на ассемблере имеют возможность обращаться к ней. Вызов библиотечной функции осуществляется при помощи команды call. Но есть одна проблема: так как не все юникс системы схожи, то в некоторых системах перед библиотечной функцией нужно ставить знак подчеркивания. Рассмотрим следующую программу, выводящую знаменитую фразу:
.text
.globl main
main:
pushl $message
call puts
popl %ebx
ret
.data
message:
.string "Hello world!"
Без использования glibc программа будет выглядить слудующим образом:
.text
.globl _start
_start:
movl $4,eax
xorl %ebx.%ebx
incl %ebc
movl $message,%ecx
movl $mesg_len,%edx
int $0x80
xorl %eax,%eax
incl %eax
xorl %ebx,%ebx
int $0x80
hlt
.data
message:
.string "Hello World!12"
mesg_len= .-message
В данном примере мы ипользовали для вывода на экран два системных вызова: write и exit. Вызову write соответсвует помещение в регистр %eax значения 4-значения под которым данная функция записанна в таблице системных вызовов.
Вызывается данная функция путем вызова прерывания $0x80 Выходу из программы, т.е. ее завершению соответсвует системный вызов $1.
Автор: GuMondi