C++ C++ C# C# ASP.NET Security ASP.NET Security ASM ASM Скачать Скачать Поиск Поиск Хостинг Хостинг  
  Программа для работы с LPT портом...
Язык: .NET — ©Alexey...
  "ASP.NET Atlas" – AJAX в исполнении Micro...
Язык: .NET — ©legigor@mail.ru...
  "Невытесняющая" Многопоточность...
Язык: C/C++ — ©...
  01.05.2010 — Update World C++: Сборник GPL QT исходников
  15.12.2007 — Весь сайт целиком можно загрузить по ссылкам из раздела Скачать
Хостинг:
Windows 2003, ASP.NET 2.0
бесплатный и от 80 руб./мес


   Отправить письмо
Кулабухов Артем, Беларусь




 ASM под Unix / Иное / Ассемблер в C/C++

.. ASM под Unix  //dev0id

"Как вы думаете, какой язык программирование является лучшим?" - на этот вопрос можно можно наткнутся во многих голосовалках и форумах. Конечно же это вопрос риторический, но все же, давайте подумаем. Как известно, для каждой цели хорошо свое решение, так и в программировании: для написания скриптов используют перл, пхп, асп... для написания более сложных прикладных программ-языки высокого уровня, такие как паскаль, делфи... для написания низкоуровневых приложений используют С/С++, асм. Мы поговорим об ассемблере. В переводе на русский это слово переводится как "сборка", "конструирование"... Данный язык восновном применяется для написания программ работающих вплотную с оборудованием. Для доса и виндоус этот язык вообще незаменим, так как сама операционная система писалась на нем. Но мы поговорим об ассемблере под юникс-подобные операционные системы. Все мы знаем, что юникс писался на С, следовательно этот язык является низкоуровневым в этой системе (на С можно делать обсолютно все в юниксе, даже читать побайтно с жесткого диска, так как все устройства являются файлами, то и обращение к ним через системный вызов SYS_open()). "Но причем тогда здесь ассемблер?" - спросите вы. А все очень просто. Дело в том, что на асме мы попрежнему можем очень тесно работать с процессором, как то: работа с регистрами, стэком... ну и конечно же переводить его в защищенный режим. На С все это можно было делать вставляя инструкции на том же асме (пусть это и называлось по другому, но в заголовочных файлах все открыто и ясно) - вспомните функцию __asm(); И так, начнем.

Конечно же ассемблер под юникс отличается от ассемблера под до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. Так же стоит заметить, что программирование и компиляция программ, написанных под разные *никс системы, немного отличается, так что я не буду указывать на различия, вам будет полезнее почитать такие документы как man страницы и HOW-TO документы.