Автор: lonesome TSH/Digital Daemons
Дата: .02.2003
Раздел: Низкоуровневое программирование в Linux
Иногда (особенно часто это случается при разработке ОС) перед программистом встает задача обеспечения взаимодействия между различными модулями, одна часть которых написана на ассемблере для повышения быстродействия, а другая - на Си (или каком-нибудь другом высокоуровневом языке программирования). Взаимодействие между ними (скомпилированными как разные объектные файлы) осуществляется следующим образом (я покажу на примере NASM и GCC):
Для того чтобы функция, написанная на NASM стала доступна из GCC, ее необходимо объявить глобальной: global function_name
Если же программа на ассемблере использует какую-нибудь функцию экспортируемую из модуля, написанного на Си, то ее необходимо объявить внешней: extern function_name
Конвенции вызова функций
Конвенция вызова функций используемая в Си предполагает передачу аргументов в стеке в обратном порядке, т.е., например, вместо printf("%i",value);
на ассемблере необходимо написать:
push dword value
push dword format
call printf
К тому же вызванная функция не очищает стек от параметров, поэтому это должна сделать вызывающая функция, например: add esp, 8 - если были переданы два параметра
Доступ к параметрам
Если функция, написанная на ассемблере, была вызвана из программы, написанной на Си, то доступ к переданным параметрам можно получить следующим образом: push ebp - EBP будет использоваться mov ebp, esp - сохранить значение ESP mov eax, [ebp+8] - для того, чтобы запросить последний параметр из списка, к нему надо обратиться как к ebp+8 (первые четыре байта в стеке - это адрес возврата, помещенный туда командой call, а вторые четыре байта - это сохраненный в начале функции регистр EBP), для получения второго - ebp+12 и т.д.
Значение esp необходимо сохранять, потому что в процессе исполнения функции оно может меняться
Такая функция должна завершиться командами pop ebp и ret
В некоторых форматах объектных файлов, компилятор будет добавлять подчеркивание к адресу функции, поэтому чтобы функция, написанная на ассемблере, была доступна как function_name, ее необходимо объявить как _function_name