В общем: без понятия.Даже на i386, если есть 6-й аргумент, он должен быть передан в стек (например, для mmap
).
В частности, для x86_64: введите номер системного вызова в %rax
(будьте осторожны: номера системного вызовараспределяются совершенно по-разному для 32-битных), до 6 аргументов в %rdi
, %rsi
, %rdx
, %r10
, %r8
и %r9
(что почти, но не совсем,такой же, как обычный ABI для передачи параметров в регистрах - обратите внимание на использование %r10
вместо %rcx
) и использование инструкции syscall
.Результат возвращается в %rax
, а %rcx
и %r11
закрыты.
x86_64 Информацию об ABI можно найти по адресу http://www.x86 -64.org / Documentation / abi.pdf ** один тысяча двадцать один;Linux ABI документирован в приложении.(И если вы ищете информацию о ABI x86_64 в другом месте, учтите, что 64-битная Windows использует свой собственный ABI.)
Я не верю, что для фрейма стека пользователя есть какие-либо требования для syscall
для правильной работы.В случае прерывания сигналом для обработчика, очевидно, требуется нормальный стек;но следующий эксперимент, который использует альтернативный стек сигналов и намеренно перебрасывает %rsp
вокруг syscall
, прекрасно работает для меня:
$ cat syscall_sig.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#define __NR_nanosleep 35
static sig_atomic_t alrm = 0;
void handler(int sig)
{
if (sig == SIGALRM)
alrm = 1;
}
int main(void)
{
stack_t ss;
struct sigaction sa;
struct timespec req, rem;
long ret;
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
ss.ss_sp = malloc(ss.ss_size);
sigaltstack(&ss, NULL);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = SA_ONSTACK;
sigaction(SIGALRM, &sa, NULL);
alarm(1);
req.tv_sec = 5;
req.tv_nsec = 0;
asm("xorq $0x12345678, %%rsp ; syscall ; xorq $0x12345678, %%rsp"
: "=a" (ret)
: "0" (__NR_nanosleep), "D" (&req), "S" (&rem)
: "rcx", "r11", "memory");
printf("syscall return code %ld, alarm flag %d\n", ret, alrm);
return 0;
}
$ gcc -Wall -o syscall_sig syscall_sig.c
$ ./syscall_sig
syscall return code -4, alarm flag 1
$