Низкоуровневое программирование для Дzenствующих

Вид материалаДокументы

Содержание


Большое Космическое Яйцо (0 Абсолютного Времени)
Ассемблер в Unix #Введение
Общие сведения
0x80 (чаще всего). К сожалению, (а может и к счастью) существует несколько конвенций вызова, что приводит к несовместимости кода
FreeBSD поддерживает конвенцию вызова, применяемую в linux
LinuxВ линуксе используется fastcall
Подобный материал:
1   ...   21   22   23   24   25   26   27   28   ...   42

Большое Космическое Яйцо (0 Абсолютного Времени)


- Эти прыжки в течении триллиардов лет меня окончательно за... Не дерись, Герми, все равно кроме нас пока никого нет, почему бы и не выражаться, как хочется? Ну ладно, тронулись! Вот главная отправная точка, а там что получится, то и получится. Да будет свет!

И стал свет.

КОНЕЦ. Конец? Это только начало!


Marlyn

Ассемблер в Unix

#Введение


Так исторически сложилось, что программирование на ассемблере под unix почти не востребовано, и занимаются им только кодеры-маньяки, дзен-буддисты и прочие настоящие ассемблерщики.

Настоящий ассемблерщик - зверь крайне редкий, практически нигде и не встретишь его, разве что в заповеднике - ссылка скрыта. Unix-ассемблерщик еще более редкий подвид, практически вымерший, если не считать, западный, ссылка скрыта.

Для исправления такой плачевной ситуации, и была написана эта статья, а точнее цикл статей, которые по задумке автора, должны привлечь в ряды адептов-юникс-дзена множество новых членов.

В первой части (которую вы сейчас читаете) я имею честь познакомить вас с прекрасным миром unix-программирования, что выльется в написание простейшего helloworld. В следующей части - мы разберем несколько, более сложных примеров. И под конец, наверное, будет программирование под x-windows.

#Инструменты


Для нормально функционирования нам понадобятся следующие вещи:
  1. Собственно какая-либо unix-совместимая ось. (например linux, или лучше FreeBSD ),
  2. Компилятор fasm. ( ссылка скрыта )
  3. Линкер ld ( есть почти в любом дистрибутиве unix ),
  4. Особый склад ума, причем последнее - самое главное. Если у вас этого нет, то ни один, даже самый последний RedHat на пару со свежим fasm'ом вам не поможет.

И еще, о компиляторах - в unix обычно используются AS с AT&T синтаксисом, который для многих людей, выросших на tasm'е и masm'е, кажется полной абракадаброй. Поэтому, для начала, мы будем использовать привычные компиляторы с Intel'овским синтаксисом (fasm или nasm). Хотя позже, если найдутся желающие, можно будет рассмотреть и AT&T asm.

#Общие сведения


Unix, который мы будем использовать - 32 битная система, работающая в защищенном режиме, и использующая плоскую модель памяти.

Как и большинство операционных систем, Unix предоставляет программе набор различных функций (по другому - Api). Но, в отличие от, например, WinAPI, где вызовы производятся с помощью call'ов, в unix - больше свободы: можно вызывать функция ядра напрямую, а можно использовать многочисленные библиотеки. Рассмотрим для начала первый способ.

Системный вызов производится с помощью прерывания 0x80 (чаще всего). К сожалению, (а может и к счастью) существует несколько конвенций вызова, что приводит к несовместимости кода между многими unix-like осями. Я рассмотрю только две, самые популярные платформы: Linux и *BSD.

FreeBSD (а также OpenBSD и NetBSD)

Эта система использует традиционную unix конвенцию вызова: номер функции помещается в eax, параметры в стек, вызов производится с помощью функции содержащей int 0x80, а результат возвращается в eax.
Наверное, понятнее будет, если рассмотреть это на примере:

sys_call:
int 0x80
ret
start:
push msg_len ; размер строки
push msg ; адрес строки
push 1 ; stdout
mov eax,4 ; номер системной функции - sys_write
call sys_call
add esp,4*3 ; очищаем за собой стек

Впрочем, от функции sys_call можно отказаться, достаточно просто помещать в стек лишний dword:

start:
push msg_len ; размер строки
push msg ; адрес строки
push 1 ; stdout
mov eax,4 ; номер системной функции - sys_write
push eax ; все что угодно
int 0x80
add esp,4*3 ; очищаем за собой стек


Также FreeBSD поддерживает конвенцию вызова, применяемую в linux. Для это необходимо включить linux emulation. Еще эта эмуляция потребуется для запуска fasm. А еще нужна утилита brandelf (наверняка она у вас есть). Дело в том, что пока не существует версии fasm’а конкретно для BSD систем. Но это легко исправить, вот так:

Brandelf –t Linux fasm

Если это не сработает (а такое возможно из-за не совместимости форматов), придется перекомпилировать fasm, заменив формат файла “format PE executable” на простой “format ELF”, а потом слинковать ld.

 

Linux
В линуксе используется fastcall конвенция. Номер функции, все так же,
помещается в eax, а вот параметры, вместо стека, помещаются в регистры. Пример:

mov edx,msg_len
mov ecx,msg
mov ebx,1
mov eax,4
int 0x80

Порядок размещения параметров такой:

№ параметра

Регистры

1

ebx

2

ecx

3

edx

4

esi

5

edi

6

ebp

Как видите максимальное количество параметров - 6. Если их больше,
приходиться помещать все параметры в структуру и передавать ее адрес в ebx.