Следующие ссылки объясняют x86-32 конвенции системного вызова для обоих UNIX (разновидность BSD) и Linux:
Но каковы x86-64 конвенции системного вызова по обеим UNIX & Linux?
Дополнительные материалы для чтения по любой из тем здесь: Полное руководство по системным вызовам Linux
Я проверил их с помощью GNU Assembler (gas) на Linux.
x86-32, также известное как i386 Соглашение о системном вызове Linux:
В x86-32 параметры системного вызова Linux передаются с использованием регистров. % eax
для syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp используются для передачи 6 параметров системным вызовам.
Возвращаемое значение находится в % eax
. Все остальные регистры (включая EFLAGS) сохраняются в int $ 0x80
.
Я взял следующий фрагмент из Руководства по сборке Linux , но я сомневаюсь в этом. Если бы кто-нибудь мог показать пример, было бы здорово.
Если имеется более шести аргументов,
% ebx
должен содержать место в памяти , где хранится список аргументов , но не Не беспокойтесь об этом , потому что маловероятно, что вы будете использовать системный вызов с более чем шестью аргументами .
Для примера и дополнительной информации обратитесь к http://www.int80h.org/bsdasm/#alternate-calling-convention . Другой пример Hello World для i386 Linux с использованием int 0x80
: Какие части этого ассемблерного кода HelloWorld необходимы, если я буду писать программу на ассемблере?
Есть более быстрый способ сделать 32-битные системные вызовы: используя sysenter
. Ядро отображает страницу памяти в каждый процесс (vDSO) со стороной пользовательского пространства sysenter
dance, которая должна взаимодействовать с ядром, чтобы оно могло найти адрес возврата. Сопоставление аргументов с регистрами такое же, как для int $ 0x80
. Обычно следует вызывать vDSO вместо прямого использования sysenter
. (См. Полное руководство по системным вызовам Linux для получения информации о связывании и вызове vDSO, а также для получения дополнительной информации о sysenter
и обо всем остальном, что связано с системными вызовами.)
x86-32 [Free | Open | Net | DragonFly] Соглашение о системных вызовах BSD UNIX:
Параметры передаются в стек. Поместите параметры (последний параметр помещается первым) в стек.Затем вставьте дополнительные 32-битные фиктивные данные (на самом деле это не фиктивные данные. Для получения дополнительной информации см. Следующую ссылку), а затем дайте команду системного вызова int $ 0x80
http://www.int80h.org / bsdasm / # соглашение о вызовах по умолчанию
x86-64 Mac OS X похожа, но отличается . TODO: проверьте, что делает * BSD.
См. Раздел: «A.2 AMD64 Linux Соглашения о ядре» в Приложение System V для двоичного интерфейса приложения к процессору архитектуры AMD64 . Последние версии psABI для i386 и x86-64 System V можно найти по ссылке на этой странице в репозитории разработчика ABI . (См. Также вики-страницу с тегами x86 для получения обновленных ссылок на ABI и многих других полезных сведений о x86 asm.)
Вот фрагмент из этого раздела:
- Приложения уровня пользователя использовать в качестве целочисленных регистров для передачи последовательности% rdi,% rsi,% rdx,% rcx, % r8 и% r9. Интерфейс ядра использует% rdi,% rsi,% rdx,% r10,% r8 и% r9.
- Системный вызов выполняется с помощью инструкции
syscall
. Этот блокирует% rcx и% r11 , а также возвращаемое значение% rax, но другие регистры сохраняются.- Номер системного вызова должен быть передан в регистр% rax.
- Системные вызовы ограничены шестью аргументами, аргумент не передается непосредственно в стек.
- При возврате из системного вызова регистр% rax содержит результат системного вызова. Значение в диапазоне от -4095 до -1 указывает на ошибку, это
-errno
.- Ядру передаются только значения класса INTEGER или класса MEMORY.
Помните, что это из специального приложения к ABI для Linux, и даже для Linux оно информативно, а не нормативно. (Но на самом деле это так.)
Это 32-bit int $ 0x80
ABI можно использовать в 64-битном коде (но настоятельно не рекомендуется). Что произойдет, если вы используете 32-битный int 0x80 Linux ABI в 64-битном коде? Он по-прежнему усекает свои входные данные до 32-битного, поэтому он не подходит для указателей и обнуляет r8-r11.
Соглашение о вызове функций x86-32:
В x86-32 параметры передавались в стек. Последний параметр был помещен в стек первым до тех пор, пока не будут выполнены все параметры, а затем была выполнена инструкция call
. Это используется для вызова функций библиотеки C (libc) в Linux из сборки.
Современные версии i386 System V ABI (используемые в Linux) требуют 16-байтового выравнивания % esp
перед вызовом
, как всегда x86-64 System V ABI требуется. Вызываемым лицам разрешается предполагать это и использовать 16-байтовые SSE для загрузки / сохранения этой ошибки на невыровненных. Но исторически Linux требовала только 4-байтового выравнивания стека, поэтому требовалась дополнительная работа, чтобы зарезервировать естественно выровненное пространство даже для 8-байтового двойного
или чего-то подобного.
Некоторые другие современные 32-битные системы по-прежнему не требуют выравнивания стека более чем на 4 байта.
x86-64 System V передает аргументы в регистры, что более эффективно, чем соглашение об аргументах стека в i386 System V. Это позволяет избежать задержки и дополнительных инструкций по сохранению аргументов в памяти (кеш) и последующей их загрузке обратно в вызываемый объект.Это хорошо работает, потому что доступно больше регистров, и лучше для современных высокопроизводительных процессоров, где важны задержка и неупорядоченное выполнение. (ABI i386 очень старый).
В этом новом механизме: Сначала параметры делятся на классы. Класс каждого параметра определяет способ, которым он передается вызываемой функции.
Для получения полной информации обратитесь к: «3.2 Последовательность вызова функций» Приложение System V Application Binary Interface к процессору архитектуры AMD64 , которое частично гласит:
После классификации аргументов регистрам присваиваются ( в порядке слева направо) для передачи следующим образом:
- Если класс - MEMORY, передать аргумент в стеке.
- Если класс - INTEGER, используется следующий доступный регистр последовательности % rdi,% rsi,% rdx,% rcx,% r8 и% r9
Итак % rdi, % rsi,% rdx,% rcx,% r8 и% r9
- это регистры в порядке , используемые для передачи целочисленных параметров / указателей (т.е. класса INTEGER) в любую функцию libc из сборки. % rdi используется для первого параметра INTEGER. % rsi для 2-го,% rdx для 3-го и так далее. Затем должна быть дана инструкция call
. Стек (% rsp
) должен быть выровнен по 16B при выполнении вызова
.
Если имеется более 6 параметров INTEGER, седьмой параметр INTEGER и более поздние передаются в стек. (Вызывающий всплывает, то же самое, что и x86-32.)
Первые 8 аргументов с плавающей запятой передаются в% xmm0-7, позже в стеке. Нет векторных регистров с сохранением вызовов.(Функция с комбинацией аргументов FP и целочисленных аргументов может иметь более 8 общих аргументов регистра.)
Функции с переменным числом аргументов ( например printf
) всегда требуют % al
= количество аргументов регистра FP.
Существуют правила упаковки структур в регистры ( rdx: rax
при возврате) или в память. См. Подробности в ABI и проверьте вывод компилятора, чтобы убедиться, что ваш код согласуется с компиляторами о том, как что-то должно передаваться / возвращаться.
Обратите внимание, что соглашение о вызове функций Windows x64 имеет несколько существенных отличий от x86-64 System V, например, теневое пространство, которое должно быть зарезервировано вызывающей стороной (вместо красного - зона), и вызовы с сохранением xmm6-xmm15. И очень разные правила, для которых arg входит в какой регистр.
Возможно, вам нужен x86_64 ABI?
Если это не совсем то, что вам нужно, используйте 'x86_64 abi' в предпочитаемой вами поисковой системе, чтобы найти альтернативные ссылки.