Im Linux-Benutzerbereich müssen wir häufig Systemaufrufe aufrufen. Nehmen wir Linux Version 2.6.37 als Beispiel, um die Implementierung des Lesesystemaufrufs zu verfolgen. Die Implementierung von Systemaufrufen kann zwischen den Linux-Versionen variieren.
In einigen Anwendungen können wir die folgende Definition sehen:
scssCopy code #define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count)))
Eigentlich wird die Systemfunktion syscall(SYS_read) aufgerufen, also die Funktion sys_read(). In der Linux-Version 2.6.37 wird diese Funktion durch mehrere Makrodefinitionen implementiert.
Linux-Systemaufruf (SCI, Systemaufrufschnittstelle) ist eigentlich ein Prozess der Mehrkanalaggregation und -zerlegung. Der Aggregationspunkt ist der 0x80-Interrupt-Einstiegspunkt (X86-Systemstruktur). Das heißt, alle Systemaufrufe werden vom Benutzerbereich bis zum Interruptpunkt 0x80 aggregiert und gleichzeitig die spezifische Systemaufrufnummer gespeichert. Wenn der 0x80-Interrupt-Handler ausgeführt wird, werden unterschiedliche Systemaufrufe entsprechend der Systemaufrufnummer separat verarbeitet, dh es werden unterschiedliche Kernelfunktionen zur Verarbeitung aufgerufen.
Es gibt zwei Möglichkeiten, Systemaufrufe auszulösen:
(1) int $0×80, dies war die einzige Möglichkeit, in alten Linux-Kernelversionen einen Systemaufruf auszulösen.
(2) Sysenter-Montageanleitung
Im Linux-Kernel können wir die folgenden Makrodefinitionen verwenden, um Systemaufrufe durchzuführen.
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret; }
Die Makrodefinition von SYSCALL_DEFINE3 lautet wie folgt:
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
## bedeutet, die Zeichen im Makro direkt zu ersetzen,
Wenn name = read, dann wird __NR_##name im Makro durch __NR_read ersetzt. NR##Name ist die Systemrufnummer, ## bezieht sich auf zwei Makroerweiterungen. Das heißt, ersetzen Sie „Name“ durch den tatsächlichen Systemaufrufnamen und erweitern Sie dann __NR.... Wenn name == ioctl, ist es __NR_ioctl.
#ifdef CONFIG_FTRACE_SYSCALLS #define SYSCALL_DEFINEx(x, sname, ...) \ static const char *types_##sname[] = { \ __SC_STR_TDECL##x(__VA_ARGS__) \ }; \ static const char *args_##sname[] = { \ __SC_STR_ADECL##x(__VA_ARGS__) \ }; \ SYSCALL_METADATA(sname, x); \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #else #define SYSCALL_DEFINEx(x, sname, ...) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #endif
Unabhängig davon, ob das Makro CONFIG_FTRACE_SYSCALLS definiert ist oder nicht, wird letztendlich die folgende Makrodefinition ausgeführt:
__SYSCALL_DEFINEx(x, sname, VA_ARGS)
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS #define SYSCALL_DEFINE(name) static inline long SYSC_##name #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \ static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \ asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \ { \ __SC_TEST##x(__VA_ARGS__); \ return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \ } \ SYSCALL_ALIAS(sys##name, SyS##name); \ static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)) #else /* CONFIG_HAVE_SYSCALL_WRAPPERS */ #define SYSCALL_DEFINE(name) asmlinkage long sys_##name #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)) #endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
Die folgende Art von Makrodefinition wird schließlich aufgerufen:
asmlinkage long sys##name(__SC_DECL##x(VA_ARGS))
Das ist die Systemfunktion sys_read(), die wir zuvor erwähnt haben.
asmlinkage weist den Compiler an, nur die Argumente der Funktion aus dem Stapel zu extrahieren. Alle Systemaufrufe erfordern dieses Qualifikationsmerkmal! Dies ähnelt der Makrodefinition, die in unserem vorherigen Artikel Quagga erwähnt wurde.
Das heißt, der folgende Code in der Makrodefinition:
struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret;
Code-Analyse:
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
An diesem Punkt ist die Verarbeitung durch die virtuelle Dateisystemschicht abgeschlossen und die Kontrolle wird an die ext2-Dateisystemschicht übergeben.
Das obige ist der detaillierte Inhalt vonSyscall-Systemaufruf-Linux-Kernel-Tracing. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!