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:
execve
baris: menunjukkan bagaimana strace
dieksekusi hello.out
, termasuk argumen dan lingkungan CLI seperti yang didokumentasikan diman execve
write
line: menunjukkan panggilan sistem tulis yang kami buat. 6
adalah panjang dari string "hello\n"
.
= 6
adalah nilai balik dari panggilan sistem, yang seperti yang didokumentasikan man 2 write
adalah jumlah byte yang ditulis.
exit
line: 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 write
dunia 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 main
menyiapkan 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.log
berisi:
write(1, "hello\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++
Jadi kami menyimpulkan bahwa write
fungsi POSIX menggunakan, kejutan !, Linuxwrite
panggilan sistem .
Kami juga mengamati bahwa return 0
mengarah pada exit_group
panggilan alih-alih exit
. Ha, saya tidak tahu tentang yang ini! Inilah mengapa strace
sangat keren. man exit_group
kemudian 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 dlopen
menggunakan 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.