syscall - appel système indirect
Bibliothèque C standard (
libc,
-lc)
#include <sys/syscall.h> /* Définition des constantes SYS_* */
#include <unistd.h>
long syscall(long numéro, ...);
syscall()
Depuis la glibc 2.19:
_DEFAULT_SOURCE
Avant la glibc 2.19:
_BSD_SOURCE || _SVID_SOURCE
syscall() est une petite fonction de bibliothèque qui invoque
l'appel système dont l'interface en assembleur a le
numéro indiqué avec les arguments donnés.
L'utilisation de
syscall() est pratique, par exemple, pour invoquer un
appel système qui n'a pas de fonction d'enveloppe dans la
bibliothèque C.
syscall() sauve les registres du processeur avant de faire l'appel
système, restaure les registres au retour de l'appel système et
stocke tous les codes d'erreur renvoyés par l'appel système dans
errno(3).
Les constantes symboliques correspondant aux appels système sont dans le
fichier d'en-tête
<sys/syscall.h>.
La valeur de retour est définie par l'appel système
invoqué. En général, une valeur de retour
0
indique une réussite. Une valeur de retour de
-1 indique une
erreur, et un code d'erreur est fourni dans
errno.
syscall() est apparu dans BSD 4.
L'ABI de chaque architecture possède ses propres exigences sur la
façon dont les paramètres des appels système sont
passés au noyau. Pour les appels système qui ont une fonction
d'enveloppe de la glibc (comme par exemple la plupart des appels
système), la glibc s'occupe des détails pour copier les
arguments dans les bons registres d'une manière adaptée à
chaque architecture. Cependant, en utilisant
syscall() pour effectuer
un appel système, l'appelant peut avoir besoin de gérer certains
détails dépendants de l'architecture ; cette exigence est
en particulier rencontrée sur certaines architectures 32 bits.
Par exemple, pour l'Embedded ABI (EABI) de l'architecture ARM, une valeur
64 bits (c'est-à-dire un
long long) doit être
alignée sur une paire de registres paire. Ainsi, en appelant
syscall() au lieu de la fonction d'enveloppe fournie par la glibc,
l'appel système
readahead() devrait être effectué
ainsi sur l'architecture ARM avec l'EABI :
syscall(SYS_readahead, fd, 0,
(unsigned int) (offset & 0xFFFFFFFF),
(unsigned int) (offset >> 32),
count);
Comme le paramètre offset est 64 bits, et le premier argument (
fd) est passé dans
r0, l'appelant doit manuellement
découper et aligner la valeur 64 bits afin de la passer dans la
paire de registres
r2/
r3. Cela implique de passer une valeur
fantôme dans
r1 (le second argument, qui vaut
0). Il faut
également veiller à ce que la division respecte les conventions
endian (selon l'ABI C de la plateforme).
Des problèmes similaires peuvent survenir sur MIPS avec l'ABI O32, sur
PowerPC avec l'ABI 32 bits, et sur Xtensa.
Notez qu'alors que l'ABI parisc C utilise aussi des paires de registres
alignés, il utilise une couche shim pour cacher le résultat de
l'espace utilisateur.
Les appels système concernés sont
fadvise64_64(2),
ftruncate64(2),
posix_fadvise(2),
pread64(2),
pwrite64(2),
readahead(2),
sync_file_range(2) et
truncate64(2).
Cela n'affecte pas les appels système qui séparent et assemblent
manuellement les valeurs 64 bits telles que
_llseek(2),
preadv(2),
preadv2(2),
pwritev(2) et
pwrite2(2).
Bienvenue dans le monde fanstastique du bagage historique.
Chaque architecture possède sa façon propre d'invoquer et de
passer des paramètres au noyau. Les détails pour diverses
architectures sont donnés dans les deux tableaux ci-dessous.
Le premier tableau liste l'instruction utilisée pour passer en mode noyau
(qui n'est pas forcément la méthode la meilleure ou la plus
rapide, vous devriez consulter
vdso(7)), le registre (ou les registres)
utilisé(s) pour indiquer le numéro de l'appel système, et
le registre utilisé comme code de retour de l'appel système, et
le registre utilisé pour signaler une erreur.
Arch/ABI |
Instruction |
Appel |
Ret |
Ret |
Erreur |
Notes |
|
|
système n° |
val |
val2 |
|
|
|
alpha |
callsys |
v0 |
v0 |
a4 |
a3 |
1, 6 |
arc |
trap0 |
r8 |
r0 |
- |
- |
|
arm/OABI |
swi NR |
- |
r0 |
- |
- |
2 |
arm/EABI |
swi 0x0 |
r7 |
r0 |
r1 |
- |
|
arm64 |
svc #0 |
w8 |
x0 |
x1 |
- |
|
blackfin |
excpt 0x0 |
P0 |
R0 |
- |
- |
|
i386 |
int $0x80 |
eax |
eax |
edx |
- |
|
ia64 |
break 0x100000 |
r15 |
r8 |
r9 |
r10 |
1, 6 |
loongarch |
syscall 0 |
a7 |
a0 |
- |
- |
|
m68k |
trap #0 |
d0 |
d0 |
- |
- |
|
microblaze |
brki r14,8 |
r12 |
r3 |
- |
- |
|
mips |
syscall |
v0 |
v0 |
v1 |
a3 |
1, 6 |
nios2 |
trap |
r2 |
r2 |
- |
r7 |
|
parisc |
ble 0x100(%sr2, %r0) |
r20 |
r28 |
- |
- |
|
powerpc |
sc |
r0 |
r3 |
- |
r0 |
1 |
powerpc64 |
sc |
r0 |
r3 |
- |
cr0.SO |
1 |
riscv |
ecall |
a7 |
a0 |
a1 |
- |
|
s390 |
svc 0 |
r1 |
r2 |
r3 |
- |
3 |
s390x |
svc 0 |
r1 |
r2 |
r3 |
- |
3 |
superh |
trapa #31 |
r3 |
r0 |
r1 |
- |
4, 6 |
sparc/32 |
t 0x10 |
g1 |
o0 |
o1 |
psr/csr |
1, 6 |
sparc/64 |
t 0x6d |
g1 |
o0 |
o1 |
psr/csr |
1, 6 |
tile |
swint1 |
R10 |
R00 |
- |
R01 |
1 |
x86-64 |
syscall |
rax |
rax |
rdx |
- |
5 |
x32 |
syscall |
rax |
rax |
rdx |
- |
5 |
xtensa |
syscall |
a2 |
a2 |
- |
- |
|
Notes :
- •
- Sur quelques architectures, un registre est utilisé
comme un boléen ( 0 indiquant aucune erreur et -1
indiquant une erreur) pour signaler que l'appel système a
échoué. La valeur de l'erreur actuelle est toujours contenue
dans le registre renvoyé. Sur sparc, le bit de transport (carry
bit, csr) dans le registre d'état du processeur (psr)
est utilisé au lieu d'un registre entier. Sur powerpc64, le bit de
débordement (overflow bit) sommaire ( SO) dans le
champ 0 du registre de condition ( cr0) est
utilisé.
- •
-
NR est le numéro de l'appel
système.
- •
- Pour s390 et s390x, NR (le numéro de l'appel
système) peut être passé directement avec
svc NR s'il est inférieur à 256.
- •
- Sur SuperH, des numéros de capture
(« trap ») supplémentaires sont pris en
charge pour des raisons historiques mais trapa#31 est l'ABI
« unifiée » recommandée.
- •
- Les ABI x32 partagent la table syscall avec l'ABI x86-64,
mais avec quelques nuances :
- •
- De manière à indiquer qu'un appel
système est appelé sous une ABI x32, un bit additionnel,
_X32_SYSCALL_BIT, est associé par un OU binaire avec
le numéro d'appel système. L'ABI utilise un processus qui
influe sur le comportement des processus, comme le traitement des signaux
ou redémarrage d'un appel système.
- •
- Comme x32 a des tailles différentes pour long
et les types « pointeur », les dispositions de
quelques structures (mais pas toutes ; struct timeval ou
struct rlimit sont en 64 bits, par exemple) sont
différentes. Pour manipuler cela des appels système
supplémentaires sont ajoutés à la table d'appel
système, commençant au numéro 512 (sans le
_X32_SYSCALL BIT). Par exemple, _NR_ready est défini
à 19 pour l'ABI x86-64 et comme _X32_SYSCALL_BIT |
515 pour l'ABI x32. La plupart de ces appels système
additionnels sont actuellement identiques aux appels système
utilisés pour fournir la compatibilité i386. Cependant, il y
a quelques exceptions notables, comme avec prreadv2(2), qui
utilisent une entité struct iovec avec des pointeurs et des
tailles (« compat_iovec » au niveau du noyau)
en 4 bits, mais passe un argument pos 8 bits dans un
seul registre et non deux comme il est fait dans toute autre ABI.
- •
- Quelques architectures (nommément : Alpha,
IA-64, MIPS, SuperH, sparc/32 et sparc/64) utilisent un registre
additionnel (« Retval2 » dans la table
ci-dessus) pour renvoyer une deuxième valeur de renvoi de l'appel
système pipe(2) ; Alpha utilise aussi cette technique
pour les appels système getxgid(2), getxuid(2) et
getxpid(2) spécifiques à l'architecture. Les autres
architectures n'utilisent pas le registre de la seconde valeur
renvoyée dans l'interface de l'appel système, même
s'il est défini dans l'ABI de System V.
Le second tableau montre les registres utilisés pour passer les
paramètres de l'appel système.
Arch/ABI |
arg1 |
arg2 |
arg3 |
arg4 |
arg5 |
arg6 |
arg7 |
Notes |
|
alpha |
a0 |
a1 |
a2 |
a3 |
a4 |
a5 |
- |
|
arc |
r0 |
r1 |
r2 |
r3 |
r4 |
r5 |
- |
|
arm/OABI |
r0 |
r1 |
r2 |
r3 |
r4 |
r5 |
r6 |
|
arm/EABI |
r0 |
r1 |
r2 |
r3 |
r4 |
r5 |
r6 |
|
arm64 |
x0 |
x1 |
x2 |
x3 |
x4 |
x5 |
- |
|
blackfin |
R0 |
R1 |
R2 |
R3 |
R4 |
R5 |
- |
|
i386 |
ebx |
ecx |
edx |
esi |
edi |
ebp |
- |
|
ia64 |
out0 |
out1 |
out2 |
out3 |
out4 |
out5 |
- |
|
loongarch |
a0 |
a1 |
a2 |
a3 |
a4 |
a5 |
a6 |
|
m68k |
d1 |
d2 |
d3 |
d4 |
d5 |
a0 |
- |
|
microblaze |
r5 |
r6 |
r7 |
r8 |
r9 |
r10 |
- |
|
mips/o32 |
a0 |
a1 |
a2 |
a3 |
- |
- |
- |
1 |
mips/n32, 64 |
a0 |
a1 |
a2 |
a3 |
a4 |
a5 |
- |
|
nios2 |
r4 |
r5 |
r6 |
r7 |
r8 |
r9 |
- |
|
parisc |
r26 |
r25 |
r24 |
r23 |
r22 |
r21 |
- |
|
powerpc |
r3 |
r4 |
r5 |
r6 |
r7 |
r8 |
r9 |
|
powerpc64 |
r3 |
r4 |
r5 |
r6 |
r7 |
r8 |
- |
|
riscv |
a0 |
a1 |
a2 |
a3 |
a4 |
a5 |
- |
|
s390 |
r2 |
r3 |
r4 |
r5 |
r6 |
r7 |
- |
|
s390x |
r2 |
r3 |
r4 |
r5 |
r6 |
r7 |
- |
|
superh |
r4 |
r5 |
r6 |
r7 |
r0 |
r1 |
r2 |
|
sparc/32 |
o0 |
o1 |
o2 |
o3 |
o4 |
o5 |
- |
|
sparc/64 |
o0 |
o1 |
o2 |
o3 |
o4 |
o5 |
- |
|
tile |
R00 |
R01 |
R02 |
R03 |
R04 |
R05 |
- |
|
x86-64 |
rdi |
rsi |
rdx |
r10 |
r8 |
r9 |
- |
|
x32 |
rdi |
rsi |
rdx |
r10 |
r8 |
r9 |
- |
|
xtensa |
a6 |
a3 |
a4 |
a5 |
a8 |
a9 |
- |
|
Notes :
- •
- La convention d'appel système mips/o32 passe les
arguments 5 à 8 sur la pile utilisateur.
Notez que ces tableaux ne couvrent pas l'ensemble des conventions d'appel
système, certaines architectures peuvent écraser sans
distinction d'autres registres non listés ici.
#define _GNU_SOURCE
#include <signal.h>
#include <sys/syscall.h>
#include <unistd.h>
int
main(void)
{
pid_t tid;
tid = syscall(SYS_gettid);
syscall(SYS_tgkill, getpid(), tid, SIGHUP);
}
_syscall(2),
intro(2),
syscalls(2),
errno(3),
vdso(7)
La traduction française de cette page de manuel a été
créée par Christophe Blaess
<
https://www.blaess.fr/christophe/>, Stéphan Rafin
<
[email protected]>, Thierry Vignaud
<
[email protected]>, François Micaux, Alain Portal
<
[email protected]>, Jean-Philippe Guérard
<
[email protected]>, Jean-Luc Coulon (f5ibh)
<
[email protected]>, Julien Cristau
<
[email protected]>, Thomas Huriaux <
[email protected]>,
Nicolas François <
[email protected]>, Florentin
Duneau <
[email protected]>, Simon Paillard
<
[email protected]>, Denis Barbier
<
[email protected]>, David Prévot <
[email protected]> et
bubu <
[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter
à la
GNU
General Public License version 3 concernant les conditions de copie
et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
[email protected]