syscall - indirekter Systemaufruf
Standard-C-Bibliothek (
libc,
-lc)
#include <sys/syscall.h> /* Definition der SYS_*-Konstanten */
#include <unistd.h>
long syscall(long Nummer, …);
syscall():
Seit Glibc 2.19:
_DEFAULT_SOURCE
Vor Glibc 2.19:
_BSD_SOURCE || _SVID_SOURCE
syscall() ist eine kleine Bibliotheksfunktion, die den Systemaufruf
auslöst, dessen Assemblersprachen-Schnittstelle in
Nummer mit
den festgelegten Argumenten angegeben wurde. Der Einsatz von
syscall()
ist beispielsweise hilfreich, wenn ein Systemaufruf ausgelöst werden
soll, der in der C-Bibliothek keine Wrapper-Funktion hat.
syscall() speichert CPU-Register vor der Durchführung des
Systemaufrufs, stellt die Register nach der Rückkehr von dem
Systemaufruf wieder her und speichert alle vom Systemaufruf
zurückgelieferten Fehler in
errno(3).
Die symbolischen Konstanten für die Systemaufrufnummern können in
der Header-Datei
<sys/syscall.h> gefunden werden.
Der Rückgabewert wird durch den ausgelösten Systemaufruf
definiert. Im Allgemeinen zeigt ein Rückgabewert 0 einen Erfolg an. Ein
Rückgabewert -1 zeigt einen Fehler und eine Fehlernummer wird in
errno gespeichert.
syscall() erschien erstmalig in 4BSD.
Jede Architektur-ABI hat ihre eigenen Anforderungen, wie Argumente für
Systemaufrufe an den Kernel übergeben werden. Für Systemaufrufe
mit Glibc-Wrapper (beispielsweise die meisten Systemaufrufe) handhabt Glibc
die Details des Kopierens der Argumente in die richtigen Register auf eine
Weise, die für die Architektur angemessen ist. Wird allerdings
syscall() zum Durchführen eines Systemaufrufs verwandt,
könnte der Aufrufende die architekturabhängigen Details selber
handhaben müssen. Diese Anforderung wird auf bestimmten
32-bit-Architekturen am häufigsten angetroffen.
Auf dem ABI der eingebetteten ARM-Architektur (EABI) muss beispielsweise ein
64-bit-Wert (z.B.
long long) an ein gerades Registerpaar ausgerichtet
werden. Wird daher
syscall() anstelle des von Glibc bereitgestellten
Wrappers verwandt, müsste der Systemaufruf
readahead(2) in der
folgenden Weise auf der ARM-Architektur mit dem ABI im Modus »little
endian« ausgelöst werden:
syscall(SYS_readahead, fd, 0,
(unsigned int) (offset & 0xFFFFFFFF),
(unsigned int) (offset >> 32),
count);
Da das Argument »offset« 64 bit beträgt und das erste
Argument (
fd) an
r0 übergeben wird, muss der aufrufende
den 64-bit-Wert manuell zerteilen und ausrichten, so dass er an das
Register-Paar
r2/
r3 übergeben wird. Das bedeutet, dass
ein Blindwert in
r1 (dem zweiten Argument von 0) eingefügt
werden muss. Es muss auch darauf geachtet werden, dass die Zerteilung den
Endian-Konventionen folgt (gemäß der C-ABI dieser Plattform).
Ähnliche Probleme können auf MIPS mit dem O32-ABI, auf PowerPC und
Parisc mit dem 32-bit-ABI und auf Xtensa auftreten.
Beachten Sie, dass das Parisc-C-ABI zwar auch ausgerichtete Registerpaare
verwendet, aber eine Ausgleichs-Schicht verwendet, um das Problem vor dem
Anwendungsraum zu verstecken.
Die betroffenen Systemaufrufe sind
fadvise64_64(2),
ftruncate64(2),
posix_fadvise(2),
pread64(2),
pwrite64(2),
readahead(2),
sync_file_range(2) und
truncate64(2).
Dies betrifft Systemaufrufe, die manuell 64-bit-Werte auseinandernehmen und
zusammensetzen, wie
_llseek(2),
preadv(2),
preadv2(2),
pwritev(2) und
pwritev2(2), nicht. Willkomen in der wundervollen
Welt der historischen Altlasten.
Jede Architektur hat ihre eigene Art, den Kernel aufzurufen und Argumente zu
übergeben. Die Details für die verschiedenen Architekturen sind
in zwei nachfolgenden Tabellen dargestellt.
Die erste Tabelle führt die Anweisungen auf, die zum Übergang in
den Kernelmodus verwandt werden (dies könnte nicht die schnellste oder
beste Art zum Übergang in den Kernel sein, bitte schauen Sie auch in
vdso(7)), das Register, das zur Angabe der Systemaufrufnummer, das oder
die Register, die zur Rückgabe des Ergebnisses des Systemaufrufs und
das Register, das zur Signalisierung eines Fehlers verwandt wird.
Arch/ABI |
Anweisung |
System |
Rück |
Rück |
Fehler |
Hinweise |
|
|
Aufruf # |
Wert |
Wert2 |
|
|
|
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 |
Nios II |
trap |
r2 |
r2 |
- |
r7 |
|
PA-RISC |
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 |
- |
- |
|
Hinweise:
- •
- Auf einigen Architekturen wird ein Register als logischer
Wert verwandt (0 zeigt an, dass kein Fehler vorliegt und -1 zeigt Fehler
an), um mitzuteilen, dass der Systemaufruf fehlschlug. Der
tatsächliche Fehlerwert ist weiterhin in dem
Rückliefer-Register enthalten. Auf Sparc wird das
Zweierübergangsbit ( csr) im Prozessorstatusregister
(psr) anstelle eines vollständigen Registers verwandt. Auf
PowerPC64 wird das zusammenfassende Überlaufbit ( SO) im
Feld 0 des Bedingungsregisters ( cr0) verwandt.
- •
-
NR ist die Nummer des Systemaufrufs.
- •
- Für S390 und S390x kann NR (die Nummer des
Systemaufrufs) direkt mit svc NR übergeben werden,
falls sie kleiner als 256 ist.
- •
- Auf SuperH werden aus historischen Gründen
zusätzliche Nummern für Ausnahmebehandlungen
unterstützt, aber trapa#31 ist die empfohlene
»vereinigte« ABI.
- •
- Das x32-ABI nutzt die Systemaufruf-Tabelle der x86-64-ABI
mit, es gibt aber kleine Nuancen:
- •
- Um anzuzeigen, dass ein Systemaufruf unter der x32-ABI
erfolgt, wird ein zusätzliches Bit ( __X32_SYSCALL_BIT)
durch ein bitweises ODER mit der Systemaufrufnummer verknüpft. Das
von einem Prozess verwandte ABI betrifft einige Prozessverhalten,
einschließlich der Signalverarbeitung oder dem Neustarten von
Systemaufrufen.
- •
- Da x32 andere Größen für long
und Zeigertypen hat, ist das Layout einiger Strukturen (aber nicht aller:
struct timeval oder struct rlimit sind beispielsweise 64
bit) anders. Um damit umzugehen, werden zusätzliche Systemaufrufe
zu der Systemaufruftabelle hinzugefügt, beginnend bei Nummer 512
(ohne das __X32_SYSCALL_BIT). Beispielsweise ist __NR_readv
als 19 für das x86-64-ABI und als __X32_SYSCALL_BIT |
515 für das x32-ABI definiert. Die meisten dieser
zusätzlichen Systemaufrufe sind tatsächlich zu den
Systemaufrufen, die zur Bereitstellung der i386-Kompatibilität
verwandt werden, identisch. Es gibt allerdings ein paar bemerkenswerte
Ausnahmen, wie preadv2(2), das Einheiten struct iovec mit
4-byte-Zeigern und Größen (»compat_iovec« in
der Kernelsprache) verwendet, aber ein 8-byte Argument pos in einem
einzelnen Register (und nicht in zweien) übergibt, wie dies in
jedem anderen ABI erfolgt.
- •
- Einige Architekturen (konkret Alpha, IA-64, MIPS, SuperH,
Sparc/32 und Sparc/64) verwenden ein zweites Register
(»Rückwert2« in der obigen Tabelle), um einen zweiten
Rückgabewert von dem Systemaufruf pipe(2)
zurückzugeben. Alpha verwendet diese Technik auch in den
architekturspezifischen Systemaufrufen getxpid(2),
getxuid(2) und getxgid(2). Andere Architekturen verwenden
das zweite Rückgaberegister in der Systemaufrufschnittstelle nicht,
selbst wenn es in der System-V-ABI definiert ist.
Die zweite Tabelle zeigt die Register, die zur Übergabe der
Systemaufrufargumente verwandt werden.
Arch/ABI |
Arg1 |
Arg2 |
Arg3 |
Arg4 |
Arg5 |
Arg6 |
Arg7 |
Hinweise |
|
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 |
- |
|
Nios II |
r4 |
r5 |
r6 |
r7 |
r8 |
r9 |
- |
|
PA-RISC |
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 |
- |
|
Hinweise:
- •
- Die Systemaufrufkonvention von MIPS/o32 übergibt die
Argumente 5 bis 8 über den Benutzer-Stack.
Beachten Sie, dass diese Tabellen nicht die gesamte Aufrufkonvention
abdecken–einige Architekturen könnten rücksichtslos
andere, hier nicht aufgeführte Register belegen.
#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)
Die deutsche Übersetzung dieser Handbuchseite wurde von Helge Kreutzmann
<
[email protected]> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die
GNU
General Public License Version 3 oder neuer bezüglich der
Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken
Sie bitte eine E-Mail an die
Mailingliste
der Übersetzer