Ví dụ runnable tối thiểu
Nếu một khái niệm không rõ ràng, có một ví dụ đơn giản hơn mà bạn chưa từng thấy giải thích nó.
Trong trường hợp này, ví dụ đó là thế giới tự do lắp ráp Linux x86_64 (không có libc) hello world:
xin chào
.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 ngược dòng .
Lắp ráp và chạy:
as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out
Đầu ra dự kiến:
hello
Bây giờ hãy sử dụng strace trên ví dụ đó:
env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log
Chúng tôi sử dụng:
strace.log
hiện chứa:
execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6) = 6
exit(0) = ?
+++ exited with 0 +++
Với một ví dụ tối thiểu như vậy, mọi ký tự đầu ra đều hiển nhiên:
execve
dòng: hiển thị cách strace
thực thi hello.out
, bao gồm các đối số CLI và môi trường như được ghi lại tạiman execve
write
dòng: hiển thị cuộc gọi hệ thống ghi mà chúng tôi đã thực hiện. 6
là độ dài của chuỗi "hello\n"
.
= 6
là giá trị trả về của lệnh gọi hệ thống, như được ghi trong tài liệu man 2 write
là số byte được ghi.
exit
dòng: hiển thị cuộc gọi hệ thống thoát mà chúng tôi đã thực hiện. Không có giá trị trả lại, kể từ khi chương trình bỏ!
Ví dụ phức tạp hơn
Tất nhiên, ứng dụng của strace để xem hệ thống nào gọi các chương trình phức tạp đang thực sự làm để giúp gỡ lỗi / tối ưu hóa chương trình của bạn.
Đáng chú ý, hầu hết các cuộc gọi hệ thống mà bạn có khả năng gặp phải trong Linux đều có các trình bao bọc glibc, nhiều trong số chúng từ POSIX .
Trong nội bộ, các trình bao bọc glibc sử dụng lắp ráp nội tuyến ít nhiều như thế này: Làm thế nào để gọi một cuộc gọi hệ thống thông qua sysenter trong lắp ráp nội tuyến?
Ví dụ tiếp theo bạn nên học là một write
thế giới xin chào POSIX :
C chính
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *msg = "hello\n";
write(1, msg, 6);
return 0;
}
Biên dịch và chạy:
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Lần này, bạn sẽ thấy rằng một loạt các cuộc gọi hệ thống đang được glibc thực hiện trước đó main
để thiết lập một môi trường tốt đẹp cho chính.
Điều này là do chúng tôi hiện không sử dụng chương trình tự do, mà là chương trình glibc phổ biến hơn, cho phép chức năng libc.
Sau đó, ở mọi đầu, strace.log
chứa:
write(1, "hello\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++
Vì vậy, chúng tôi kết luận rằng write
chức năng POSIX sử dụng, thật bất ngờ!, write
Cuộc gọi hệ thống Linux .
Chúng tôi cũng quan sát return 0
dẫn đến một exit_group
cuộc gọi thay vì exit
. Ha, tôi không biết về cái này! Đây là lý do tại sao strace
là rất mát mẻ. man exit_group
sau đó giải thích:
Cuộc gọi hệ thống này tương đương với lối ra (2) ngoại trừ việc nó chấm dứt không chỉ chuỗi cuộc gọi, mà tất cả các luồng trong nhóm luồng của quy trình gọi.
Và đây là một ví dụ khác mà tôi đã nghiên cứu cách gọi hệ thống nào dlopen
sử dụng: /unix/226524/what-system-call-is- used-to-load-lologists-in-linux / 462710 # 462710
Đã thử nghiệm trong Ubuntu 16.04, GCC 6.4.0, nhân Linux 4.4.0.