Contoh runnable minimal
Jika suatu konsep tidak jelas, ada contoh sederhana yang belum Anda lihat yang menjelaskannya.
Dalam hal ini, contoh itu adalah hello world assembly x86_64 freestanding (no libc) hello world:
hello.S
.text
.global _start
_start:
/* write */
mov $1, %rax /* syscall number */
mov $1, %rdi /* stdout */
mov $msg, %rsi /* buffer */
mov $len, %rdx /* buffer len */
syscall
/* exit */
mov $60, %rax /* exit status */
mov $0, %rdi /* syscall number */
syscall
msg:
.ascii "hello\n"
len = . - msg
GitHub hulu .
Merakit dan menjalankan:
as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out
Output yang diharapkan:
hello
Sekarang mari kita gunakan strace pada contoh itu:
env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log
Kita gunakan:
strace.log sekarang mengandung:
execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6) = 6
exit(0) = ?
+++ exited with 0 +++
Dengan contoh minimal seperti itu, setiap karakter tunggal dari output jelas:
execvebaris: menunjukkan bagaimana stracedieksekusi hello.out, termasuk argumen dan lingkungan CLI seperti yang didokumentasikan diman execve
writeline: menunjukkan panggilan sistem tulis yang kami buat. 6adalah panjang dari string "hello\n".
= 6adalah nilai balik dari panggilan sistem, yang seperti yang didokumentasikan man 2 writeadalah jumlah byte yang ditulis.
exitline: menunjukkan panggilan keluar sistem yang kami buat. Tidak ada nilai balik, karena program berhenti!
Contoh yang lebih kompleks
Penerapan strace tentu saja untuk melihat sistem mana yang memanggil program kompleks yang sebenarnya dilakukan untuk membantu men-debug / mengoptimalkan program Anda.
Khususnya, sebagian besar panggilan sistem yang mungkin Anda temui di Linux memiliki pembungkus glibc, banyak dari mereka dari POSIX .
Secara internal, pembungkus glibc menggunakan perakitan inline kurang lebih seperti ini: Bagaimana menjalankan panggilan sistem melalui sysenter dalam perakitan inline?
Contoh selanjutnya yang harus Anda pelajari adalah writedunia hello POSIX :
main.c
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *msg = "hello\n";
write(1, msg, 6);
return 0;
}
Kompilasi dan jalankan:
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Kali ini, Anda akan melihat bahwa banyak panggilan sistem sedang dilakukan oleh glibc sebelum mainmenyiapkan lingkungan yang bagus untuk main.
Ini karena kita sekarang tidak menggunakan program berdiri bebas, melainkan program glibc yang lebih umum, yang memungkinkan fungsionalitas libc.
Kemudian, di setiap akhir, strace.logberisi:
write(1, "hello\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++
Jadi kami menyimpulkan bahwa writefungsi POSIX menggunakan, kejutan !, Linuxwrite panggilan sistem .
Kami juga mengamati bahwa return 0mengarah pada exit_grouppanggilan alih-alih exit. Ha, saya tidak tahu tentang yang ini! Inilah mengapa stracesangat keren. man exit_groupkemudian menjelaskan:
Panggilan sistem ini setara dengan keluar (2) kecuali bahwa itu tidak hanya mengakhiri utas panggilan, tetapi semua utas dalam grup utas proses panggilan itu.
Dan di sini adalah contoh lain di mana saya mempelajari yang dlopenmenggunakan sistem panggilan : /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710
Diuji di Ubuntu 16.04, GCC 6.4.0, kernel Linux 4.4.0.