Các ví dụ có thể chạy tối thiểu của Linux với phân tích tháo gỡ
Vì đây là một chi tiết triển khai không được quy định bởi các tiêu chuẩn, chúng ta hãy xem trình biên dịch đang làm gì trên một triển khai cụ thể.
Trong câu trả lời này, tôi sẽ liên kết đến các câu trả lời cụ thể thực hiện phân tích hoặc cung cấp phân tích trực tiếp tại đây và tóm tắt tất cả các kết quả tại đây.
Tất cả các phiên bản này đều có các phiên bản Ubuntu / GCC khác nhau và kết quả có thể khá ổn định giữa các phiên bản, nhưng nếu chúng tôi tìm thấy bất kỳ biến thể nào, hãy chỉ định các phiên bản chính xác hơn.
Biến cục bộ bên trong hàm
Có thể là nó main
hoặc bất kỳ chức năng nào khác:
void f(void) {
int my_local_var;
}
Như được hiển thị tại: <value được tối ưu hóa> có nghĩa là gì trong gdb?
-O0
: cây rơm
-O3
: đăng ký nếu chúng không tràn, chồng khác
Để biết động lực tại sao ngăn xếp tồn tại, hãy xem: Chức năng của các lệnh đẩy / pop được sử dụng trên các thanh ghi trong cụm x86 là gì?
Biến toàn cục và static
biến hàm
/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;
/* DATA */
int my_global_implicit_explicit_1 = 1;
void f(void) {
/* BSS */
static int my_static_local_var_implicit;
static int my_static_local_var_explicit_0 = 0;
/* DATA */
static int my_static_local_var_explicit_1 = 1;
}
char *
và char c[]
Như được hiển thị tại: Các biến tĩnh được lưu trữ trong C và C ++ ở đâu?
void f(void) {
/* RODATA / TEXT */
char *a = "abc";
/* Stack. */
char b[] = "abc";
char c[] = {'a', 'b', 'c', '\0'};
}
TODO sẽ chuỗi ký tự rất lớn cũng sẽ được đưa vào ngăn xếp? Hay là .data
? Hay việc biên dịch thất bại?
Hàm đối số
void f(int i, int j);
Phải thông qua quy ước gọi có liên quan, ví dụ: https://en.wikipedia.org/wiki/X86_calling_conventions cho X86, trong đó chỉ định các thanh ghi cụ thể hoặc vị trí ngăn xếp cho từng biến.
Sau đó, như được hiển thị tại <value được tối ưu hóa> có nghĩa là gì trong gdb? , -O0
sau đó nhét mọi thứ vào ngăn xếp, trong khi -O3
cố gắng sử dụng các thanh ghi càng nhiều càng tốt.
Tuy nhiên, nếu chức năng được nội tuyến, chúng được xử lý giống như người dân địa phương thông thường.
const
Tôi tin rằng nó không có gì khác biệt vì bạn có thể đánh máy nó đi.
Ngược lại, nếu trình biên dịch có thể xác định rằng một số dữ liệu không bao giờ được ghi vào, về lý thuyết nó có thể đặt nó .rodata
ngay cả khi không phải là const.
Phân tích TODO.
Con trỏ
Chúng là các biến (chứa địa chỉ, là số), giống như tất cả các phần còn lại :-)
trung tâm thương mại
Câu hỏi không có nhiều ý nghĩa đối với malloc
, vì malloc
là một hàm và trong:
int *i = malloc(sizeof(int));
*i
là một biến chứa địa chỉ, vì vậy nó thuộc trường hợp trên.
Về cách malloc hoạt động bên trong, khi bạn gọi nó là nhân Linux đánh dấu một số địa chỉ nhất định là có thể ghi trên cấu trúc dữ liệu bên trong của nó và khi chúng bị chương trình chạm vào ban đầu, một lỗi xảy ra và kernel cho phép các bảng trang, cho phép truy cập xảy ra mà không có segfaul: Làm thế nào để phân trang x86 hoạt động?
Tuy nhiên, xin lưu ý rằng về cơ bản, đây chính xác là những gì tòa nhà exec
chọc trời thực hiện khi bạn cố chạy một tệp thực thi: nó đánh dấu các trang mà nó muốn tải và viết chương trình ở đó, xem thêm: Làm thế nào để kernel có được tệp nhị phân thực thi chạy bên dưới linux? Ngoại trừ exec
có một số hạn chế bổ sung về nơi tải đến (ví dụ: mã không thể di chuyển được ).
Các syscall chính xác sử dụng cho malloc
là mmap
vào năm 2020 triển khai hiện đại, và trong quá khứ brk
đã được sử dụng: Liệu malloc () sử dụng brk () hoặc mmap ()?
Thư viện động
Về cơ bản có được mmap
ed vào bộ nhớ: /unix/226524/what-system-call-is- used-to-load-lologists-in-linux / 462710 # 462710
biến envinroment và main
'sargv
Trên ngăn xếp ban đầu: /unix/75939/where-is-the-envir-opes-actual-stored TODO tại sao không ở .data?