[Назад] [Далее]

11.4. Программирование с использованием libc

Все программы для UNIX, написанные на С, постоянно обращаются к различным функциям, находящимся в libc.so или других стандартных или нестандартных библиотеках. Программы и процедуры на ассемблере, естественно, могут делать то же самое. Вызов библиотечной функции выполняется обычной командой call, а передача параметров осуществляется в соответствии с С-конвенцией: параметры помещают в стек справа налево и очищают стек после вызова функции. Единственная сложность здесь состоит в том, что к имени вызываемой функции в некоторых системах, например FreeBSD, приписывается в начале символ подчеркивания, в то время как в других (Linux и Solaris) имя не изменяется. Если имена в системе модифицируются, имена процедур, включая main(), написанных на ассемблере, также должны быть изменены заранее.

Посмотрим на примере программы, выводящей традиционное сообщение «Hello world», как это делается:

// helloelf.s
// Минимальная программа, выводящая сообщение "Hello world"
// Для компиляции в формат ELF
//
// Компиляция:
// as -о helloelf.o helloelf.s
// Компоновка:
// (пути к файлу crt1.o могут отличаться на других системах)
// Solaris с SunPro С
// ld -s -о helloelf.sol helloelf.o /opt/SUNWspro/SC4.2/lib/crt1.о -lс
// Solaris с GNU С
// ld -s -o helloelf.gso helloelf.o
// /opt/gnu/lib/gcc-lib/i586-cubbi-solaris2.5.1/2.7.2.3.f.1/crt1.о -lс
// Linux
// ld -s -m elf_i386 -o helloelf.lnx /usr/lib/crt1.o /usr/lib/crti.o
// -L/usr/lib/gcc-lib/i586-cubbi-linuxlibc1/2.7.2 helloelf.o -lc -lgcc
// /usr/lib/crtn.o
//
        .text
// код, находящийся в файлах crt*.o, передаст управление на процедуру main
// после настройки всех параметров
        .globl     main
main:
// поместить параметр (адрес строки message) в стек
        pushl      $message
// вызвать функцию puts (message)
        call       puts
// очистить стек от параметров
        popl       %ebx
// завершить программу
        ret

        .data
message:
        .string    "Hello world\0"

В случае FreeBSD придется внести всего два изменения — добавить символ подчеркивания в начало имен функций puts и main и заменить директиву .string на .ascii, так как версия ассемблера, обычно распространяемого с FreeBSD, .string не понимает.

// hellocof.s
// Минимальная программа, выводящая сообщение "Hello world"
// Для компиляции в вариант формата COFF, используемый во FreeBSD
// Компиляция для FreeBSD:
// as -о hellocof.o hellocof.s
// ld -s -о hellocof.bsd /usr/lib/crt0.o hellocof.o -lc

        .text
        .globl     _main
_main:
        pushl      $message
        call       _puts
        popl       %ebx
        ret

        .data
message:
        .ascii     "Hello world\0"

Пользуясь этой техникой, можно создавать программы точно так же, как и на С, но выигрыш за счет того, что на ассемблере можно соптимизировать программу на несколько процентов лучше, чем это сделает компилятор с С (с максимальной оптимизацией), оказывается незначительным по сравнению с потерей переносимости. Кроме того, при написании любой сколько-нибудь значительной программы целиком на ассемблере мы столкнемся с тем, что, как и в случае с Win32, нам придется создавать собственные включаемые файлы с определениями констант и структур, взятых из включаемых файлов для С. А так как эти ассемблеры не умеют работать со структурами данных, необходимо описывать их средствами используемого препроцессора — срр или m4.

Лучшее применение ассемблера для UNIX (кроме собственно разработки ядра системы) все-таки остается за небольшими процедурами, требующими большой вычислительной мощности, — кодированием, архивированием, преобразованиями типа Фурье, которые не очень сложны и при необходимости могут быть легко переписаны заново на ассемблере для другого процессора или на С.


п»ї
"target=_blank><\/a>") //-->