địa chỉ bộ nhớ int [10] luôn kết thúc bằng 060


17

Tôi có chương trình ac trông như thế này

C chính

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

và xuất kết quả này khi tôi chạy chương trình được biên dịch một vài lần

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

Tại sao nó luôn kết thúc vào 060? Và là mảng được lưu trữ trong heap?

Chỉnh sửa: Tôi đang dùng Linux và tôi có ASLR. Tôi đã biên dịch chương trình bằng gcc


2
Hệ điều hành nào? Trình biên dịch gì?
Andrew Henle

2
Biến không nằm trong heap, nó nằm trong phần dữ liệu hoặc bss của không gian địa chỉ của chương trình, xem en.wikipedia.org/wiki/Static_variable . Tôi đoán là chương trình sẽ luôn được đặt tại một địa chỉ bộ nhớ ở một ranh giới nhất định, ví dụ: chia cho 0x1000 và biến được trình biên dịch đặt ở vị trí bù cố định trong không gian địa chỉ của chương trình.
Bodo

Câu trả lời:


15

Các địa chỉ khác nhau vì ASLR (Phân chia bố cục không gian địa chỉ). Sử dụng điều này, nhị phân có thể được ánh xạ tại các vị trí khác nhau trong không gian địa chỉ ảo.

Biến heaplà - trái ngược với tên của nó - không nằm trên heap, mà là trên bss. Do đó, phần bù trong không gian địa chỉ là không đổi.

Các trang được ánh xạ ở mức độ chi tiết của trang, là 4096 byte (hex: 0x1000) trên nhiều nền tảng. Đây là lý do, tại sao ba chữ số hex cuối cùng của địa chỉ giống nhau.

Khi bạn thực hiện tương tự với biến stack , địa chỉ thậm chí có thể thay đổi ở các chữ số cuối cùng trên một số nền tảng (cụ thể là linux với các nhân gần đây), bởi vì stack không chỉ được ánh xạ ở một nơi khác mà còn nhận được phần bù ngẫu nhiên khi khởi động.


ASLR ngẫu nhiên hóa cơ sở tải như tôi nhớ. Địa chỉ phần được dựa trên địa chỉ đó.
Afshin

Tôi đang sử dụng một cuốn sách về lập trình ANSI-C hướng đối tượng của Axel-Thobias Schreiner. Cuốn sách được viết trong một cái gì đó giống như năm 1993. Bạn có biết cách bố trí bộ nhớ đã khác trước không? Nếu không, tại sao anh ta có thể đặt tên biến heapkhi nó không thành đống?
linuxlmao

4096 có dịch sang 060 theo cách nào đó hay 0x1000 dịch thành 060 nếu không tôi không hiểu ý của bạn là gì vì đó là lý do cho kết thúc? Tôi nghĩ rằng nó có thể phải làm với kích thước của mảng là thứ được dịch thành 060 theo hệ thập lục phân từ, ví dụ: thập phân
linuxlmao

2
@linuxlmao Phần bù là ví dụ 14060, vì vậy khi bạn thêm bội số của kích thước trang (0x1000), ba chữ số cuối cùng vẫn còn 060.
Ctx

4

Nếu bạn đang sử dụng Windows, lý do là cấu trúc PE .

heapBiến của bạn được lưu trữ trong .dataphần của tệp và địa chỉ của nó được tính dựa trên phần bắt đầu của phần này. Mỗi phần được tải trong một địa chỉ một cách độc lập, nhưng địa chỉ bắt đầu của nó là nhiều kích thước trang. Vì bạn không có biến nào khác, nên địa chỉ của nó có thể là phần bắt đầu của .dataphần, vì vậy địa chỉ của nó sẽ có nhiều kích thước khối.

Ví dụ: đây là bảng của phiên bản Windows đã biên dịch mã của bạn: phần Phần .textnày là mã được biên dịch của bạn và .datachứa heapbiến của bạn . Khi PE của bạn được tải vào bộ nhớ, các phần được tải ở các địa chỉ khác nhau và được trả về bởi VirtualAlloc()và sẽ có nhiều kích thước trang. Nhưng địa chỉ của từng biến có liên quan đến phần bắt đầu của phần hiện là kích thước trang. Vì vậy, bạn sẽ luôn thấy một số cố định trên các chữ số thấp hơn. Vì địa chỉ tương đối heaptừ đầu phần dựa trên trình biên dịch, tùy chọn biên dịch, v.v., bạn sẽ thấy số khác nhau từ cùng một mã nhưng trình biên dịch khác nhau, nhưng mỗi lần in sẽ được sửa.

Khi tôi biên dịch mã, tôi nhận thấy heapđược đặt trên 0x8B0byte sau khi bắt đầu .dataphần. Vì vậy, mỗi khi tôi chạy mã này, địa chỉ của tôi sẽ kết thúc 0x8B0.


Tôi đang sử dụng một cuốn sách về lập trình ANSI-C hướng đối tượng của Axel-Thobias Schreiner. Cuốn sách được viết trong một cái gì đó giống như năm 1993. Bạn có biết cách bố trí bộ nhớ đã khác trước không? Nếu không, tại sao anh ta có thể đặt tên biến heapkhi nó không thành đống?
linuxlmao

2
@linuxlmao Nó có thể đã khác. Vào năm 1993, Windows là một hệ điều hành 16 bit, với phân đoạn bộ nhớ và đủ thứ khó hiểu. Nó không phải là một kiến ​​trúc bộ nhớ phẳng 32 bit như bây giờ. Nhưng những loại điều này là lý do tại sao hỏi / trả lời các câu hỏi chung về cách bố trí nhị phân chương trình trong bộ nhớ không hữu ích. Hiểu những gì tiêu chuẩn ngôn ngữ C đảm bảo cho bạn nói chung và đó là tất cả những gì bạn cần biết. Chỉ lo lắng về bố cục thực tế nếu bạn đang gỡ lỗi một vấn đề cụ thể, sau đó sử dụng trình gỡ lỗi
Cody Grey

không, biến không nên được tạo trên heap ngay cả trên các hệ thống cũ vì nó không được phân bổ với malloc và có thời gian lưu trữ tĩnh
phuclv

@Afshin Tôi đang giải quyết nhận xét của OP ở trên
phuclv

@phuclv xin lỗi, vì bạn không đề cập đến anh ấy, tôi nghĩ bạn đang giải quyết cho tôi. :)
Afshin

4

Trình biên dịch tình cờ đặt heapoffset 0x60 byte trong phân đoạn dữ liệu, có thể do trình biên dịch có một số nội dung khác trong 0x60 byte đầu tiên, chẳng hạn như dữ liệu được sử dụng bởi mã bắt đầu mainthường trình. Đó là lý do tại sao bạn nhìn thấy 06060; nó chỉ là nơi nó xảy ra, và không có ý nghĩa lớn đối với nó.

Ngẫu nhiên bố trí không gian địa chỉ thay đổi (các) địa chỉ cơ sở được sử dụng cho các phần khác nhau của bộ nhớ chương trình, nhưng nó luôn làm như vậy trong các đơn vị 0x1000 byte (vì điều này tránh gây ra sự cố với căn chỉnh và các vấn đề khác). Vì vậy, bạn thấy các địa chỉ dao động theo bội số của 0x1000, nhưng ba chữ số cuối cùng không thay đổi.

Định nghĩa static int heap[SOME_VAR];xác định heapvới thời gian lưu trữ tĩnh. Các triển khai C điển hình lưu trữ nó trong một phần dữ liệu chung, không phải trong heap. Heap liền là một cách viết sai cho bộ nhớ được sử dụng để phân bổ động. (Đây là một nhầm lẫn bởi vì mallochiện thực có thể sử dụng một loạt các cấu trúc dữ liệu và thuật toán, không giới hạn đống. Họ thậm chí có thể sử dụng nhiều phương pháp trong một thực hiện.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.