Là mỗi khu vực trong sơ đồ một phân khúc?
Đây là 2 cách sử dụng gần như hoàn toàn khác nhau của từ "phân khúc"
- Các thanh ghi phân đoạn / phân đoạn x86: Các hệ điều hành x86 hiện đại sử dụng mô hình bộ nhớ phẳng trong đó tất cả các phân đoạn có cùng cơ sở = 0 và giới hạn = tối đa trong chế độ 32 bit, giống như phần cứng thực thi ở chế độ 64 bit , tạo ra loại phân đoạn . (Ngoại trừ FS hoặc GS, được sử dụng cho lưu trữ cục bộ luồng ngay cả ở chế độ 64 bit.)
- Phần / phân đoạn trình liên kết / chương trình nạp. ( Sự khác biệt của phần và phân đoạn trong định dạng tệp ELF )
Các cách sử dụng có nguồn gốc chung: nếu bạn đang sử dụng mô hình bộ nhớ được phân đoạn (đặc biệt là không có bộ nhớ ảo phân trang), bạn có thể có dữ liệu và địa chỉ BSS có liên quan đến cơ sở phân đoạn DS, xếp chồng so với cơ sở SS và mã liên quan đến Địa chỉ cơ sở CS.
Vì vậy, nhiều chương trình khác nhau có thể được tải đến các địa chỉ tuyến tính khác nhau hoặc thậm chí được di chuyển sau khi bắt đầu mà không thay đổi độ lệch 16 hoặc 32 bit so với cơ sở phân đoạn.
Nhưng sau đó bạn phải biết một con trỏ có liên quan đến phân khúc nào, vì vậy bạn có "con trỏ xa", v.v. (Các chương trình x86 16 bit thực tế thường không cần truy cập vào mã của họ dưới dạng dữ liệu, do đó, có thể sử dụng phân đoạn mã 64k ở đâu đó và có thể là một khối 64k khác với DS = SS, với ngăn xếp tăng dần từ độ lệch cao và dữ liệu tại phía dưới. Hoặc một mô hình mã nhỏ với tất cả các cơ sở phân khúc bằng nhau).
Cách phân đoạn x86 tương tác với phân trang
Ánh xạ địa chỉ ở chế độ 32/64-bit là:
- phân đoạn: offset (cơ sở phân đoạn ngụ ý bởi thanh ghi giữ phần bù hoặc được ghi đè bằng tiền tố lệnh)
- Địa chỉ ảo tuyến tính 32 hoặc 64 bit = cơ sở + bù. (Trong mô hình bộ nhớ phẳng như Linux sử dụng, con trỏ / offset = địa chỉ tuyến tính cũng vậy. Ngoại trừ khi truy cập TLS liên quan đến FS hoặc GS.)
bảng trang (được lưu trữ bởi TLB) ánh xạ tuyến tính thành 32 (chế độ kế thừa), 36 (PAE kế thừa) hoặc địa chỉ vật lý 52 bit (x86-64). ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).
Bước này là tùy chọn: phân trang phải được bật trong khi khởi động bằng cách đặt một chút trong thanh ghi điều khiển. Không có phân trang, địa chỉ tuyến tính là địa chỉ vật lý.
Lưu ý rằng phân đoạn không cho phép bạn sử dụng hơn 32 hoặc 64 bit không gian địa chỉ ảo trong một quy trình (hoặc luồng) duy nhất , bởi vì không gian địa chỉ phẳng (tuyến tính), mọi thứ được ánh xạ vào chỉ có cùng số bit như độ lệch. (Đây không phải là trường hợp của x86 16 bit, trong đó phân đoạn thực sự hữu ích cho việc sử dụng hơn 64k bộ nhớ với hầu hết các thanh ghi và phần bù 16 bit.)
CPU lưu trữ các bộ mô tả phân đoạn được tải từ GDT (hoặc LDT), bao gồm cả cơ sở phân khúc. Khi bạn hủy đăng ký một con trỏ, tùy thuộc vào đăng ký của nó, nó sẽ mặc định là DS hoặc SS là phân đoạn. Giá trị thanh ghi (con trỏ) được coi là phần bù từ cơ sở phân đoạn.
Vì cơ sở phân khúc thường bằng không, CPU thực hiện trường hợp đặc biệt này. Hoặc từ góc độ khác, nếu bạn làm có một phân khúc cơ sở khác không, tải có thêm độ trễ vì "đặc biệt" (bình thường) trường hợp bỏ qua việc thêm địa chỉ cơ sở không được áp dụng.
Cách Linux thiết lập các thanh ghi phân đoạn x86:
Cơ sở và giới hạn của CS / DS / ES / SS đều là 0 / -1 ở chế độ 32 và 64 bit. Đây được gọi là mô hình bộ nhớ phẳng vì tất cả các con trỏ trỏ vào cùng một không gian địa chỉ.
(AMD CPU kiến trúc sư thiến Phân khúc bởi thực thi một mô hình bộ nhớ phẳng cho chế độ 64-bit vì hệ điều hành chủ đạo đã không sử dụng nó dù sao, ngoại trừ không exec bảo vệ được cung cấp trong một cách tốt hơn bằng cách phân trang với PAE hoặc x86- Định dạng bảng 64 trang.)
TLS (Lưu trữ cục bộ luồng): FS và GS không được cố định tại cơ sở = 0 ở chế độ dài. (Chúng mới với 386 và không được sử dụng hoàn toàn bởi bất kỳ hướng dẫn nào, thậm chí không phải là rep
hướng dẫn chuỗi sử dụng ES). x86-64 Linux đặt địa chỉ cơ sở FS cho mỗi luồng thành địa chỉ của khối TLS.
ví dụ: mov eax, [fs: 16]
tải giá trị 32 bit từ 16 byte vào khối TLS cho luồng này.
bộ mô tả phân đoạn CS chọn chế độ CPU ở chế độ nào (chế độ được bảo vệ 16/32/64-bit / chế độ dài). Linux sử dụng một mục nhập GDT duy nhất cho tất cả các quy trình không gian người dùng 64 bit và một mục nhập GDT khác cho tất cả các quy trình không gian người dùng 32 bit. (Để CPU hoạt động bình thường, DS / ES cũng phải được đặt thành các mục hợp lệ và SS cũng vậy). Nó cũng chọn mức đặc quyền (kernel (ring 0) so với user (ring 3)), vì vậy ngay cả khi trở về không gian người dùng 64 bit, kernel vẫn phải sắp xếp để CS thay đổi, sử dụng iret
hoặc sysret
thay vì bình thường hướng dẫn nhảy hoặc ret.
Trong x86-64, syscall
điểm vào sử dụng swapgs
để lật GS từ GS của không gian người dùng sang kernel, mà nó sử dụng để tìm ngăn xếp kernel cho luồng này. (Một trường hợp chuyên biệt của lưu trữ luồng cục bộ). Lệnh syscall
không thay đổi con trỏ ngăn xếp để trỏ vào ngăn xếp kernel; nó vẫn trỏ đến ngăn xếp người dùng khi kernel đạt đến điểm vào 1 .
DS / ES / SS cũng phải được đặt thành các bộ mô tả phân đoạn hợp lệ để CPU hoạt động ở chế độ được bảo vệ / chế độ dài, mặc dù cơ sở / giới hạn từ các bộ mô tả đó bị bỏ qua ở chế độ dài.
Vì vậy, về cơ bản phân đoạn x86 được sử dụng cho TLS và cho các công cụ osdev x86 bắt buộc mà phần cứng yêu cầu bạn phải làm.
Chú thích 1: Lịch sử thú vị: có kho lưu trữ danh sách thư giữa các nhà phát triển kernel và kiến trúc sư AMD từ một vài năm trước khi silicon AMD64 được phát hành, dẫn đến việc điều chỉnh thiết kế syscall
để có thể sử dụng được. Xem các liên kết trong câu trả lời này để biết chi tiết.