Unter Linux strace
können Sie mit dem Dienstprogramm sehen, welche Systemaufrufe von einem Programm ausgeführt werden. Nehmen Sie also ein Programm wie dieses
int main () {
printf ("x");
return 0;
}}
Sagen Sie, Sie kompilieren es als printx
, dann strace printx
gibt
execve ("./ printx", ["./printx"], [/ * 49 vars * /]) = 0
brk (0) = 0xb66000
access ("/ etc / ld.so.nohwcap", F_OK) = -1 ENOENT (Keine solche Datei oder kein solches Verzeichnis)
mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7fa6dc0e5000
access ("/ etc / ld.so.preload", R_OK) = -1 ENOENT (Keine solche Datei oder kein solches Verzeichnis)
open ("/ etc / ld.so.cache", O_RDONLY | O_CLOEXEC) = 3
fstat (3, {st_mode = S_IFREG | 0644, st_size = 119796, ...}) = 0
mmap (NULL, 119796, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa6dc0c7000
close (3) = 0
access ("/ etc / ld.so.nohwcap", F_OK) = -1 ENOENT (Keine solche Datei oder kein solches Verzeichnis)
open ("/ lib / x86_64-linux-gnu / libc.so.6", O_RDONLY | O_CLOEXEC) = 3
Lesen Sie (3, "\ 177ELF \ 2 \ 1 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 3 \ 0> \ 0 \ 1 \ 0 \ 0 \ 0 \ 200 \ 30 \ 2 \ 0 \ 0 \ 0 \ 0 \ 0 "..., 832) = 832
fstat (3, {st_mode = S_IFREG | 0755, st_size = 1811128, ...}) = 0
mmap (NULL, 3925208, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_DENYWRITE, 3, 0) = 0x7fa6dbb06000
mprotect (0x7fa6dbcbb000, 2093056, PROT_NONE) = 0
mmap (0x7fa6dbeba000, 24576, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_DENYWRITE, 3, 0x1b4000) = 0x7fa6dbeba000
mmap (0x7fa6dbec0000, 17624, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0) = 0x7fa6dbec0000
close (3) = 0
mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7fa6dc0c6000
mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7fa6dc0c5000
mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7fa6dc0c4000
arch_prctl (ARCH_SET_FS, 0x7fa6dc0c5700) = 0
mprotect (0x7fa6dbeba000, 16384, PROT_READ) = 0
mprotect (0x600000, 4096, PROT_READ) = 0
mprotect (0x7fa6dc0e7000, 4096, PROT_READ) = 0
Munmap (0x7fa6dc0c7000, 119796) = 0
fstat (1, {st_mode = S_IFCHR | 0620, st_rdev = makedev (136, 0), ...}) = 0
mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7fa6dc0e4000
schreibe (1, "x", 1x) = 1
exit_group (0) =?
Der Gummi trifft beim vorletzten Aufruf der Spur auf die Straße (sortieren, siehe unten) : write(1,"x",1x)
. Zu diesem Zeitpunkt geht das Steuerelement vom Benutzerland printx
zum Linux-Kernel über, der den Rest erledigt. write()
ist eine Wrapper-Funktion, die in deklariert istunistd.h
extern ssize_t write (int __fd, __const void * __ buf, size_t __n) __wur;
Die meisten Systemaufrufe werden auf diese Weise verpackt. Die Wrapper-Funktion ist, wie der Name schon sagt, kaum mehr als eine dünne Codeschicht, die die Argumente in die richtigen Register legt und dann einen Software-Interrupt 0x80 ausführt. Der Kernel fängt den Interrupt ab und der Rest ist Geschichte. Zumindest funktionierte das früher so. Anscheinend war der Overhead des Interrupt-Trapping ziemlich hoch, und wie bereits in einem früheren Beitrag erwähnt, führten moderne CPU-Architekturen sysenter
Assembler-Anweisungen ein, die mit hoher Geschwindigkeit das gleiche Ergebnis erzielen. Diese Seite Systemaufrufe enthält eine schöne Zusammenfassung der Funktionsweise von Systemaufrufen.
Ich habe das Gefühl, dass Sie von dieser Antwort wahrscheinlich ein bisschen enttäuscht sein werden, genau wie ich. In gewissem Sinne ist dies eindeutig ein falscher Grund, da zwischen dem Anruf write()
und dem Punkt, an dem der Anruf getätigt werden muss, noch einige Dinge zu tun sind Der Grafikkarten-Frame-Puffer wurde tatsächlich so geändert, dass der Buchstabe "x" auf Ihrem Bildschirm angezeigt wird. Das Heranzoomen des Kontaktpunkts (um bei der Analogie "Gummi gegen die Straße" zu bleiben) durch Eintauchen in den Kernel ist sicher lehrreich, wenn dies zeitaufwändig ist. Ich vermute, Sie müssten durch mehrere Abstraktionsebenen wie gepufferte Ausgabestreams, Zeichengeräte usw. reisen. Stellen Sie sicher, dass Sie die Ergebnisse veröffentlichen, wenn Sie sich dazu entschließen, dies weiterzuverfolgen :)