Часто задаваемые вопросы по использованию ассемблера в юниксах. Прим.: ○ Далее под термином "юникс" подразумеваются такие операционные системы как FreeBSD, Linux и тп. ○ Данный FAQ ориентирован на русскоязычных пользователей. ○ Изначальный адрес этого документа в интернет http://stakanov.nm.ru/as/asm_unix_faq.html ○ Составители:A.STAKANOV, rgo с форума WASM.UNIX, cresta с форума WASM.UNIX ○ Особая благодарность участникам фидошной эхи RU.UNIX.PROG ○ Использованы материалы с сайта http://wasm.ru ○ Последние изменения: 25.11.2005 01:39 MSK Q: Какие ассемблеры бывают в юникс и где их взять? A: • AS: Во FreeBSD as и все утилиты из пакета binutils присутвуют в системе по умолчанию. В Linux потребуется дополнительно установить пакет binutils (формат пакета зависит от дистрибутива) или скачать его с ftp://ftp.gnu.org/gnu/binutils/. • NASM: Во FreeBSD установите порт /usr/ports/devel/nasm/. В Linux установите из соответвующего пакета или скачайте с сайта http://www.kernel.org/pub/software/devel/nasm/ (или http://sourceforge.net/projects/nasm/). • FASM: Скачайте с официального сайта http://www.flatassembler.net/ Важно! AS использует синтаксис AT&T, а NASM и FASM синтаксис Intel. Q: У юникса есть API ? A: Да. Называется это системные вызовы (syscalls). Осуществляются они путем вызова прерывания номер 0x80. Кроме того, практически везде действует "lcall $7,$0" ("call 7:0" в синтаксисе интел) как его полный аналог. Так же в системе обязательно присутствует библиотека libc. Q: Как передаются параметры системных вызовов? A: Во FreeBSD параметры передаются через стек, сначала последний, затем предпоследний и первый параметр помещается в стек последним. Так же при испотьзовании прерывания необходимо поместить в стек любое 32-битное значение. В Linux через регистры по порядку первый в EBX, и тд - ECX, EDX, ESI, EDI, EBP. Если количество параметров больше 6, то в памяти формируется структура с параметрами и в EBP помещается адрес этой стурктуры. В EAX в обоих случаях номер системного вызова. Если хотите использовать функции из libc, то передача параметров при этом осуществляется так как принято в Си (в мире Windows такой способ известен как CDECL). Результат всегда возвращается в EAX. Q: Где узнать номера системных вызовов? A: Самый простой способ для FreeBSD(должны быть установлены исходники системы!) - смотреть файл /usr/srs/sys/kern/syscalls.master. Там и номера и параметры. Способ для Linux - /usr/src/linux/arc/i386/kernel/syscall_table.S или файл entry.S из того же каталога для версий 2.4 и 2.6. Q: Где найти описания системный вызовов или функций libc? A: Как обычно в юникс - справочник man (например man 2 write) или info. Q: Покажите маленькую программку типа "Hello,world!" A: См. примеры в архиве (~4K, http://stakanov.nm.ru/as/unixwasmfaq.zip) • Вариант 1 (as,FreeBSD) - hello.s • Вариант 2 (fasm,FreeBSD) - hello.asm • Вариант 3 (as, все платформы, используем libc) - hello-world.s • Вариант 4 (nasm, Linux) - hello-nasm.asm Q: Как ее запустить (слинковать, ассемблировать)? A: • Вариант 1: Код (Text): as hello.s -o hello.o ld -s hello.o -o hello ./hello • Вариант 2: Код (Text): fasm hello.asm hello.o ld -s hello.o -o hello ./hello • Вариант 3: Код (Text): as hello-world.s -o hello-world.o gcc -Wl,-s hello-world.o -o hello-world ./hello-world • Вариант 4: Код (Text): nasm -f elf hello-nasm.asm ld -s hello-nasm.asm -o hello-nasm ./hello-nasm Q: А покажите "Hello,world!" с GUI. A: Примеры в том-же файле (http://stakanov.nm.ru/as/unixwasmfaq.zip) что и консольные • Вариант 1 (as, все платформы) - hello-gui.s • Вариант 2 (fasm, все платформы) - gui_fasm.asm Собирать и запускать так: • Вариант 1: Код (Text): as hello-gui.s -o hello-gui.o gcc -Wl,-s hello-gui.o -lX11 -L/usr/X11R6/lib -o hello-gui ./hello-gui • Вариант 2: Код (Text): fasm gui_fasm.asm gcc -Wl,-s gui_fasm.o -lX11 -L/usr/X11R6/lib -o gui_fasm ./gui_fasm Q: Как мне получить аргументы командной строки и переменные окружения? A: В точке входа в программу (_start в стеке содержатся следующие данные • AT&T - Intel - Описание • (%esp) - dword [esp] - n, количество аргументов командной строки • 4(%esp)- dword [esp+4] - адрес первого аргумента, имя программы • 4*2(%esp) - dword [esp+4*2] - адрес второго аргумента • ... • 4*n(%esp) - dword [esp+4*n] - адрес последнено аргумента • 4*n+4(%esp) - dword [esp+4*n+4] - нулевой адрес (NULL) • 4*n+8(%esp) - dword [esp+4*n+8] - адрес переменных окружения Q: Какие порекомендуете ссылки? A: • GNU Binutils (англ) - http://www.gnu.org/software/binutils • NASM (рус) - http://www.opennet.ru/docs/RUS/nasm/ • GNU AS(рус) - http://www.opennet.ru/docs/RUS/gas • FASM (рус) - http://mythrillus.land.ru/tajga-tut/index.html • Форум WASM.UNIX (рус) на http://wasm.ru/forum • Справочник man (рус, англ) http://man.opennet.ru • Архитектура операционной системы UNIX (пер. с THE DESIGN OF THE UNIX OPERATING SYSTEM by Maurice J. Bach)
Еще есть YASM: Yasm is a complete rewrite of the NASM assembler under the new" BSD Licens (some portions are under other licenses, see COPYING for details). It is designed from the ground up to allow for multiple assembler syntaxes to be supported (eg, NASM, TASM, GAS, etc.) in addition to multiple output object formats and even multiple instruction sets. Another primary module of the overall design is an optimizer module.
Последняя версия AS поддерживает синтаксис Intel. Для этого предусмотрена директива ".intel_syntax". Я бы не советовал использовать LD напрямую, как указано в вариантах 1 и 2 (и 4, но в нём есть ошибка). Проще использовать gcc для линковки, т.к. gcc обычно правильно настроен и автоматически задаёт имена динамического линкера и crt-файлов, если нужно. Те имена, которые используются по умолчанию LD, не всегда соответсвуют системным и экзешник потом не запускается (такое наблюдается на разных версиях FreeBSD и некоторых Linux'ах). Поэтому лучше использовать вариант №3.
Quantum, я как то столкнулся с такой проблемой, и просто бросил сее дело не додумав пропустить через гцц будте добры по подробнее опишите как что, да почему... и я, и ногие "начинающие" будут Вам благодарны
NoResponse Первым делом собираем обьектник: Код (Text): FASM: fasm test.asm test.o NASM: nasm -O3 -felf -otest.o test.asm GAS: as -o test.o test.s Получаем test.o. Далее линкуем gcc: Код (Text): gcc -s -nostdlib test.o -o test Опция -nostdlib отключает использование CRT. Конечно, если мы используем стандартные main(), _exit() и т.д. отключать CRT нельзя. Опция -s указывает линкеру, что экзешник желательно избавить от лишнего веса (strip the executable). Если прога использует сишные функции, нужно включить в опции цишную либу: -lc Код (Text): gcc -s -nostdlib test.o -o test -lc Если вдруг пакет libc6-dev не установлен (в таком случае компилятор скажет, что файл -lc не найден), то вместо -lc нужно указать полный путь к динамической библиотеке: Код (Text): gcc -s -nostdlib test.o -o test /usr/lib/libc.so.6 -s действует не очень эффективно. Поэтому получившийся экзешник можно ещё немного почикать командой strip: Код (Text): strip -R .comment -R .gnu.version test Можете воспользоваться утилитой objdump чтобы посмотреть какие ещё секции там лишние и их тоже можно стрипнуть: Код (Text): objdump -x test | less Наконец можно ещё скачать утилиту sstrip, которая убирает из экзешника заголовок таблицы секций, т.к. этот заголовок в экзешниках не используется: Код (Text): sstrip test Или же можно попробовать собрать полностью статический экзешник вручную на фасме или насме (без линкера). Примеры для фасма можно найти в самом дистрибутиве фасма и на форуме, а тут есть минимальный пример для насма: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html Но по ряду причин этот пример не будет грузиться на ядре 2.6.x, т.к. требования нового загрузчика ужесточились: секция bss должна быть последней в файле, секции не могут пересекаться (т.е. не может быть участка файла, принадлежащего более чем одной секции и это распространяется даже на заголовок), первая секция (а, следовательно, и все остальные) не может начинаться по нулевому адресу в файле, т.е. заголовок ELF уже не может входить в первую секцию. Рабочие безлинкерные примеры на насме и фасме под ядра 2.4.x и 2.6.x можно найти в последнем релизе uFMOD 1.20 под Linux. Чтобы не учитывать все эти тонкости можно просто использовать gcc в качестве линкера (вернее фронтэнда для линкера). Цена удобства не так уж и велика - пара сотен лишних байт (учитывая -s, strip и sstrip).
изначально линк был такой http://www.linuxassembly.org/resources.html там стоит редирект на http://asm.sourceforge.net//resources.html именно с двумя //
_ir4_Y_ Не все номера и есть ошибки, но удобнее, чем копаться в заголовочных сишных файлах: http://www.lxhp.in-berlin.de/lhpsyscal.html
_ir4_Y_ aptget'ом из самого линукса качается вместе с пакетом binutils. Отдельно врядли можно скачать.
Скажите как выделить динамическую память не используя стандартные сишные функции ? Заранее благодарен)
Через mmap() кусками по 4 Кб (4096 б): Код (Text): ; В eax - размер буфера. push edi push ebx xor edi,edi mov edx,eax push edi ; offset add edx,4095 push -1 ; fd and edx,-4096 push 22h ; flags <- MAP_ANONYMOUS | MAP_PRIVATE push 3 ; prot <- PROT_READ | PROT_WRITE push edx ; length push edi ; start mov ebx,esp sub edx,eax lea eax,[edi+90] ; #90 == mmap int 80h ; mmap ; Test for error condition cmp eax,-4096 ja alloc_error ; В eax - указатель на буфер. Через brk() ещё можно.