diff --git a/20230515/bs-20230515.txt b/20230515/bs-20230515.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f14e3a364f0602129f111d4feae6f83d446d36f --- /dev/null +++ b/20230515/bs-20230515.txt @@ -0,0 +1,294 @@ +Von "Hello, world!n" bis zum Kernel, 15.05.2023, 16:20:31 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +printf ("Hello, world!\n"); wird zu puts ("Hello, world!"); optimiert. + +Quelltext von puts(): apt-get source glibc + +cassini/home/peter/bo/2023ss/bs/20230515/glibc-2.28> find . -name "*puts*.c" +./gshadow/putsgent.c +./gshadow/tst-putsgent.c +./libio/iofputs.c +./libio/iofputs_u.c +./libio/ioputs.c +... + +int _IO_puts (const char *str) + +weak_alias (_IO_puts, puts) + +--> Information für den Linker: + Wenn ein Benutzerprogramm nach "puts()" fragt, gib ihm "_IO_puts()". + +include/libc-symbols.h: + + /* Define ALIASNAME as a weak alias for NAME. + If weak aliases are not available, this defines a strong alias. */ + # define weak_alias(name, aliasname) _weak_alias (name, aliasname) + # define _weak_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))); + + "__attribute__ (( ... ));" ist ein spezieller GCC-Befehl. + Warum 2 Klammern auf und zu? + Wenn ein anderer Compiler diesen Befehl nicht kennt, machen wir: + #define __attribute__ (X) + Mit nur einem Klammerpaar müßten wir zwischen + #define __attribute__ (X) + #define __attribute__ (X,Y) + #define __attribute__ (X,Y,Z) + unterscheiden. Der Präprozessor kennt aber nur eine feste Anzahl von Parametern. + +Warum "weak_alias"? +--> Vermeidung von Namenskonflikten. + Wenn das Benutzerprogramm selbst eine Funktion puts() bereitstellt, + hat diese Vorrang vor der in der glibc. + +puts() ruft _IO_sputn() auf. + +_IO_sputn() ist ein Makro: + + libio/libioP.h: + #define _IO_sputn(__fp, __s, __n) _IO_XSPUTN (__fp, __s, __n) + +Dies ist wahrscheinlich ein "Hook": Durch Umdefinieren des Makros +kann man auf einfache Weise die Funktion auf eine andere "umleiten". + +Dieser ruft einen weiteren Makro auf: + + libio/libioP.h: + #define _IO_XSPUTN(FP, DATA, N) JUMP2 (__xsputn, FP, DATA, N) + +Dieser ruft einen weiteren Makro auf: + + libio/libioP.h: + #define JUMP2(FUNC, THIS, X1, X2) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2) + +Dieser ruft eine Funktion auf, verwendet dabei einen weiteren Makro: + + libio/libioP.h: + # define _IO_JUMPS_FUNC(THIS) \ + (IO_validate_vtable \ + (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \ + + (THIS)->_vtable_offset))) + +"vtable" ist eine virtuelle Methodentabelle. +_IO_puts() ist eine "Methode" der Datei (hier: stdout). + +Vor dem Aufruf der Methode macht glibc eine Laufzeitüberprüfung der +virtuellen Methodentabelle. + +libio/libioP.h enthält eine Typendeklaration struct _IO_jump_t + +grep -ir " _IO_jump_t" * +libio/fileops.c: + + const struct _IO_jump_t _IO_file_jumps libio_vtable = + { + /* Inhalt der vtable ... */ + ... + JUMP_INIT(overflow, _IO_file_overflow), + ... + JUMP_INIT(xsputn, _IO_file_xsputn), + ... + JUMP_INIT(write, _IO_new_file_write), + ... + } + +Funktion: + + size_t + _IO_new_file_xsputn (FILE *f, const void *data, size_t n) + { + ... + } + libc_hidden_ver (_IO_new_file_xsputn, _IO_file_xsputn) + +Diese ruft gegen Ende eine weitere Funktion auf: + + _IO_default_xsputn() + +libio/genops.c: + + _IO_default_xsputn (FILE *f, const void *data, size_t n) + +Diese ruft u.a. einen Makro _IO_OVERFLOW auf. +Dort erfolgt das eigentliche Schreiben. + +libio/libioP.h: + + #define _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH) + +Dies ist also wieder der Aufruf einer virtuellen Methode. + +libio/genops.c: + + int + _IO_new_file_overflow (FILE *f, int ch) + { + ... + } + libc_hidden_ver (_IO_new_file_overflow, _IO_file_overflow) + +Diese ruft u.a. _IO_do_write() auf. +Dort erfolgt das eigentliche Schreiben. + +libio/genops.c: + + versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1); + + int + _IO_new_do_write (FILE *fp, const char *data, size_t to_do) + { + return (to_do == 0 + || (size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF; + } + libc_hidden_ver (_IO_new_do_write, _IO_do_write) + + static size_t + new_do_write (FILE *fp, const char *data, size_t to_do) + { + size_t count; + if (fp->_flags & _IO_IS_APPENDING) + /* On a system without a proper O_APPEND implementation, + you would need to sys_seek(0, SEEK_END) here, but is + not needed nor desirable for Unix- or Posix-like systems. + Instead, just indicate that offset (before and after) is + unpredictable. */ + fp->_offset = _IO_pos_BAD; + else if (fp->_IO_read_end != fp->_IO_write_base) + { + off64_t new_pos + = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1); + if (new_pos == _IO_pos_BAD) + return 0; + fp->_offset = new_pos; + } + count = _IO_SYSWRITE (fp, data, to_do); + if (fp->_cur_column && count) + fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base; + fp->_IO_write_end = (fp->_mode <= 0 + && (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED)) + ? fp->_IO_buf_base : fp->_IO_buf_end); + return count; + } + +new_do_write() ruft u.a. _IO_SYSWRITE() auf. +Dort erfolgt das eigentliche Schreiben. + +libio/libioP.h: + + #define _IO_SYSWRITE(FP, DATA, LEN) JUMP2 (__write, FP, DATA, LEN) + +libio/fileops.h: + + ssize_t + _IO_new_file_write (FILE *f, const void *data, ssize_t n) + { + ssize_t to_do = n; + while (to_do > 0) + { + ssize_t count = (__builtin_expect (f->_flags2 + & _IO_FLAGS2_NOTCANCEL, 0) + ? __write_nocancel (f->_fileno, data, to_do) + : __write (f->_fileno, data, to_do)); + if (count < 0) + { + f->_flags |= _IO_ERR_SEEN; + break; + } + to_do -= count; + data = (void *) ((char *) data + count); + } + n -= to_do; + if (f->_offset >= 0) + f->_offset += n; + return n; + } + +grep -r __write * liefert sehr viele Implementationen von __write() +für verschiedenste Unix-Kernel (u.a. Hurd, linux, ...). +--> Ab jetzt ist der Quelltext plattformabhängig. + +sysdeps/unix/sysv/linux/write.c: + + ssize_t + __libc_write (int fd, const void *buf, size_t nbytes) + { + return SYSCALL_CANCEL (write, fd, buf, nbytes); + } + libc_hidden_def (__libc_write) + + weak_alias (__libc_write, __write) + +sysdeps/unix/sysdep.h: + + #define SYSCALL_CANCEL(...) \ + ({ \ + long int sc_ret; \ + if (SINGLE_THREAD_P) \ + sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ + else \ + { \ + int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \ + sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ + LIBC_CANCEL_RESET (sc_cancel_oldtype); \ + } \ + sc_ret; \ + }) + + #define INLINE_SYSCALL_CALL(...) \ + __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__) + + #define __INLINE_SYSCALL_DISP(b,...) \ + __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +Der Parameter "b" ist "__INLINE_SYSCALL". Dieser ist neu hinzugekommen. +Wir rufen demnach "__INLINE_SYSCALL<n>" auf, wobei <n> für die Anzahl der +Parameter des Syscalls steht. + + #define __INLINE_SYSCALL0(name) \ + INLINE_SYSCALL (name, 0) + #define __INLINE_SYSCALL1(name, a1) \ + INLINE_SYSCALL (name, 1, a1) + #define __INLINE_SYSCALL2(name, a1, a2) \ + INLINE_SYSCALL (name, 2, a1, a2) + ... + + #ifndef INLINE_SYSCALL + #define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args) + #endif + +--> Hier erfolgt der Aufruf der Funktion __syscall_write (fd, buf, nbytes). + +sysdeps/unix/syscalls.list: Liste aller Systemaufrufe mit Namen, Parametern + sowie dem Namen der Funktion innerhalb der glibc. + Daraus werden dann automatisch die Funktionen generiert. + +sysdeps/unix/sysv/linux/x86_64/syscall.S + enthält ein Assembler-Template (".S" steht für Assembler mit Präprozessor) + für den eigentlichen Funktionsaufruf. + Hier also: + + __syscall_write (fd, buf, nbytes) + + %rdi: Nummer des Syscalls (hier: 1(?) für "write") + %rsi, %rdx, %rcx, ...: Parameter des Syscalls (hier: fd, buf, nbytes) + + syscall: ein spezieller Assembler-Befehl für den Aufruf einer Funktion im Kernel + --> Hardware-Unterstützung für den Übergang Kernel<-->Userspace + (früher auf x86-Prozessoren ab dem i386: Software-Interrupt 0x80) + + Rückgabewert des Syscalls: %rax + + cmpq $-4095, %rax /* Check %rax for error. */ + jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ + + Der Sprung erfolgt, wenn %rax zwischen (einschließlich) -1 und -4095 liegt. + Siehe: https://stackoverflow.com/questions/21440403/what-does-the-cmpq-instruction-do + +Vorschlag für die verbleibende Zeit der heutigen Lehrveranstaltung: + + Einblick in die Benutzung eines Debuggers + anhand eines einfachen Programms. + "Nicht so etwas Schwieriges wie 'Hello, world!'" (ME) diff --git a/20230515/demo-01.c b/20230515/demo-01.c new file mode 100644 index 0000000000000000000000000000000000000000..4c81d82adc36a5c67e1c590ef57f0faeb561a449 --- /dev/null +++ b/20230515/demo-01.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main (void) +{ + for (int i = 10; i > 0; i--) + printf ("%d ... ", i); + printf ("Bumm.\n"); + return 0; +} diff --git a/20230515/demo-02.c b/20230515/demo-02.c new file mode 100644 index 0000000000000000000000000000000000000000..8f9923b2590e0a76fe2d09f4529ce2fe8be3d1fe --- /dev/null +++ b/20230515/demo-02.c @@ -0,0 +1,12 @@ +#include <stdio.h> + +int main (void) +{ + for (int i = 10; i > 0; i--) + { + printf ("%d ... ", i); + fflush (stdout); + } + printf ("Bumm.\n"); + return 0; +} diff --git a/20230515/demo-03.c b/20230515/demo-03.c new file mode 100644 index 0000000000000000000000000000000000000000..0fc787aa4489e36ab7d3bb19814212474958cb13 --- /dev/null +++ b/20230515/demo-03.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main (void) +{ + for (int i = 10; i > 0; i--) + printf (i, " ... "); + printf ("Bumm.\n"); + return 0; +} diff --git a/20230515/dev-chardev-01.txt b/20230515/dev-chardev-01.txt new file mode 100644 index 0000000000000000000000000000000000000000..e2f946dad66415deea09930b0a473910e3d12fde --- /dev/null +++ b/20230515/dev-chardev-01.txt @@ -0,0 +1,17 @@ +cassini/home/peter/bo/2023ss/bs/20230424> ls -l /dev/chardev +crw-rw-rw- 1 root root 241, 0 Apr 24 18:31 /dev/chardev +cassini/home/peter/bo/2023ss/bs/20230424> cat /dev/chardev +I already told you 10 times Hello world! +cassini/home/peter/bo/2023ss/bs/20230424> ls -l dev +insgesamt 0 +crw-r--r-- 1 root root 241, 0 Apr 24 17:16 chardev +cassini/home/peter/bo/2023ss/bs/20230424> cat dev/chardev +I already told you 11 times Hello world! +cassini/home/peter/bo/2023ss/bs/20230424> mkdir -p ../20230515/dev +cassini/home/peter/bo/2023ss/bs/20230424> touch ../20230515/dev/chardev +cassini/home/peter/bo/2023ss/bs/20230424> ls -l ../20230515/dev/chardev +-rw-r--r-- 1 peter peter 0 Mai 15 15:56 ../20230515/dev/chardev +cassini/home/peter/bo/2023ss/bs/20230424> cat ../20230515/dev/chardev +cassini/home/peter/bo/2023ss/bs/20230424> cat ../20230424/dev/chardev +I already told you 12 times Hello world! +cassini/home/peter/bo/2023ss/bs/20230424> diff --git a/20230515/dev/chardev b/20230515/dev/chardev new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/20230515/hello-01.c b/20230515/hello-01.c new file mode 100644 index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac --- /dev/null +++ b/20230515/hello-01.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main (void) +{ + printf ("Hello, world!\n"); + return 0; +} diff --git a/20230515/hello-01.s b/20230515/hello-01.s new file mode 100644 index 0000000000000000000000000000000000000000..d28460b3f7c060c295e386c0d45fc075ee693bc3 --- /dev/null +++ b/20230515/hello-01.s @@ -0,0 +1,24 @@ + .file "hello-01.c" + .text + .section .rodata.str1.1,"aMS",@progbits,1 +.LC0: + .string "Hello, world!" + .text + .globl main + .type main, @function +main: +.LFB11: + .cfi_startproc ; #include <stdio.h> + subq $8, %rsp ; + .cfi_def_cfa_offset 16 ; int main (void) + leaq .LC0(%rip), %rdi ; { + call puts@PLT ; printf ("Hello, world!\n"); + movl $0, %eax ; return 0; + addq $8, %rsp ; } + .cfi_def_cfa_offset 8 + ret + .cfi_endproc +.LFE11: + .size main, .-main + .ident "GCC: (Debian 8.3.0-6) 8.3.0" + .section .note.GNU-stack,"",@progbits diff --git a/20230515/hello-02.c b/20230515/hello-02.c new file mode 100644 index 0000000000000000000000000000000000000000..b767f77cd3a7328e5f45b60e674d32a647386509 --- /dev/null +++ b/20230515/hello-02.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main (void) +{ + puts ("Hello, world!"); + return 0; +} diff --git a/20230515/hello-02.s b/20230515/hello-02.s new file mode 100644 index 0000000000000000000000000000000000000000..b8b73c97cd1a7c692229600928d167d6cd12c624 --- /dev/null +++ b/20230515/hello-02.s @@ -0,0 +1,24 @@ + .file "hello-02.c" + .text + .section .rodata.str1.1,"aMS",@progbits,1 +.LC0: + .string "Hello, world!" + .text + .globl main + .type main, @function +main: +.LFB11: + .cfi_startproc ; #include <stdio.h> + subq $8, %rsp ; + .cfi_def_cfa_offset 16 ; int main (void) + leaq .LC0(%rip), %rdi ; { + call puts@PLT ; puts ("Hello, world!"); + movl $0, %eax ; return 0; + addq $8, %rsp ; } + .cfi_def_cfa_offset 8 + ret + .cfi_endproc +.LFE11: + .size main, .-main + .ident "GCC: (Debian 8.3.0-6) 8.3.0" + .section .note.GNU-stack,"",@progbits diff --git a/20230515/hello-03.c b/20230515/hello-03.c new file mode 100644 index 0000000000000000000000000000000000000000..0e56d5a33a3ac5f71ac2f06073beb86162ca8947 --- /dev/null +++ b/20230515/hello-03.c @@ -0,0 +1,7 @@ +#include <unistd.h> + +int main (void) +{ + write (1, "Hello, world!\n", 14); + return 0; +} diff --git a/20230515/hello-03.s b/20230515/hello-03.s new file mode 100644 index 0000000000000000000000000000000000000000..a51ecbf30868f33c7a32781117e1bac6feddb6be --- /dev/null +++ b/20230515/hello-03.s @@ -0,0 +1,26 @@ + .file "hello-03.c" + .text + .section .rodata.str1.1,"aMS",@progbits,1 +.LC0: + .string "Hello, world!\n" + .text + .globl main + .type main, @function +main: +.LFB0: + .cfi_startproc + subq $8, %rsp + .cfi_def_cfa_offset 16 + movl $14, %edx + leaq .LC0(%rip), %rsi + movl $1, %edi + call write@PLT + movl $0, %eax + addq $8, %rsp + .cfi_def_cfa_offset 8 + ret + .cfi_endproc +.LFE0: + .size main, .-main + .ident "GCC: (Debian 8.3.0-6) 8.3.0" + .section .note.GNU-stack,"",@progbits diff --git a/20230515/minor-numbers-01.txt b/20230515/minor-numbers-01.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2e359cad48ce3a67f98ec7481e627a75699d4d3 --- /dev/null +++ b/20230515/minor-numbers-01.txt @@ -0,0 +1,6 @@ +cassini/home/peter/bo/2023ss/bs/20230424> ls -l /dev/sda* +brw-rw---- 1 root disk 8, 0 Apr 20 22:38 /dev/sda +brw-rw---- 1 root disk 8, 1 Apr 20 22:38 /dev/sda1 +brw-rw---- 1 root disk 8, 2 Apr 20 22:38 /dev/sda2 +brw-rw---- 1 root disk 8, 3 Apr 20 22:38 /dev/sda3 +cassini/home/peter/bo/2023ss/bs/20230424>