Как стать автором
Обновить

ASM в Unix

Время на прочтение3 мин
Количество просмотров12K
Конечно же ассемблер под юникс отличается от ассемблера под до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!\0"


Без использования 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!\012"
mesg_len= .-message


В данном примере мы ипользовали для вывода на экран два системных вызова: write и exit. Вызову write соответсвует помещение в регистр %eax значения 4-значения под которым данная функция записанна в таблице системных вызовов.

Вызывается данная функция путем вызова прерывания $0x80 Выходу из программы, т.е. ее завершению соответсвует системный вызов $1.
Теги:
Хабы:
Всего голосов 41: ↑22 и ↓19+3
Комментарии16

Публикации