Như Mads đã chỉ ra, để nắm bắt hầu hết các truy cập thông qua các con trỏ null, các hệ thống giống Unix có xu hướng làm cho trang tại địa chỉ zero "chưa được ánh xạ". Do đó, truy cập ngay lập tức kích hoạt một ngoại lệ CPU, nói cách khác là một segfault. Điều này là khá tốt hơn cho phép các ứng dụng đi giả mạo. Tuy nhiên, bảng vectơ ngoại lệ có thể ở bất kỳ địa chỉ nào, ít nhất là trên các bộ xử lý x86 (có một thanh ghi đặc biệt cho nó, được nạp bằng mã opcode lidt
).
Địa chỉ điểm xuất phát là một phần của tập hợp các quy ước mô tả cách bộ nhớ được đặt ra. Trình liên kết, khi nó tạo ra một nhị phân thực thi, phải biết các quy ước này, vì vậy chúng không có khả năng thay đổi. Về cơ bản, đối với Linux, các quy ước bố trí bộ nhớ được kế thừa từ các phiên bản Linux đầu tiên, vào đầu những năm 90. Quá trình phải có quyền truy cập vào một số khu vực:
- Mã phải nằm trong phạm vi bao gồm điểm xuất phát.
- Phải có ngăn xếp.
- Phải có một đống, với giới hạn được tăng lên với các cuộc gọi hệ thống
brk()
và sbrk()
.
- Phải có một số phòng cho
mmap()
cuộc gọi hệ thống, bao gồm cả tải thư viện được chia sẻ.
Ngày nay, heap, nơi malloc()
được bật, được hỗ trợ bởi mmap()
cuộc gọi có khối bộ nhớ tại bất kỳ địa chỉ nào mà hạt nhân thấy phù hợp. Nhưng trong thời đại cũ hơn, Linux giống như các hệ thống giống Unix trước đây, và đống của nó đòi hỏi một khu vực rộng lớn trong một đoạn không bị gián đoạn, có thể phát triển theo hướng tăng địa chỉ. Vì vậy, bất cứ điều gì đã được quy ước, nó đã để nhồi mã và ngăn xếp đối với địa chỉ thấp, và cung cấp cho mỗi đoạn của không gian địa chỉ sau một điểm nhất định cho đống.
Nhưng cũng có ngăn xếp, thường khá nhỏ nhưng có thể tăng lên đáng kể trong một số trường hợp. Ngăn xếp phát triển và khi ngăn xếp đầy, chúng tôi thực sự muốn quy trình dự đoán sự cố thay vì ghi đè một số dữ liệu. Vì vậy, phải có một diện tích rộng cho ngăn xếp, với, ở cuối thấp của khu vực đó, một trang chưa được ánh xạ. Và lo! Có một trang chưa được ánh xạ tại địa chỉ 0, để bắt các tham số con trỏ null. Do đó nó đã được xác định rằng ngăn xếp sẽ nhận được 128 MB đầu tiên của không gian địa chỉ, ngoại trừ trang đầu tiên. Điều này có nghĩa là mã phải đi sau 128 MB đó, tại một địa chỉ tương tự như 0x080xxxxx.
Như Michael chỉ ra, "mất" 128 MB không gian địa chỉ là không lớn vì không gian địa chỉ là rất lớn liên quan đến những gì có thể thực sự được sử dụng. Vào thời điểm đó, hạt nhân Linux đã hạn chế không gian địa chỉ cho một quá trình duy nhất đến 1 GB, vượt quá tối đa 4 GB cho phép bởi phần cứng và điều đó không được coi là một vấn đề lớn.
Nếu '0x08048000' từng là' STACK_TOP', nó đã là _very_ lâu rồi. Cái sau là 'TASK_SIZE' tất cả đường đến [2.0.40] (http://lxr.free-electrons.com/source/include/asm-i386/a.out.h?v=2.0.40#L22) . –