Apakah setiap wilayah dalam diagram adalah segmen?
Ini adalah 2 penggunaan yang hampir sama sekali berbeda dari kata "segmen"
- register segmentasi / segmentasi x86: OS x86 modern menggunakan model memori datar di mana semua segmen memiliki basis yang sama = 0 dan batas = maks dalam mode 32-bit, sama dengan perangkat keras yang menerapkannya dalam mode 64-bit , menjadikan segmentasi semacam peninggalan . (Kecuali untuk FS atau GS, digunakan untuk penyimpanan thread-lokal bahkan dalam mode 64-bit.)
- Bagian / segmen tautan program / pemuat program. ( Apa perbedaan bagian dan segmen dalam format file ELF )
The penggunaan memiliki asal usul yang sama: jika Anda sedang menggunakan model memori tersegmentasi (terutama tanpa memori virtual paged), Anda mungkin memiliki data dan alamat BSS menjadi relatif terhadap DS dasar segmen, tumpukan relatif terhadap basis SS, dan kode relatif terhadap Alamat dasar CS.
Jadi banyak program yang berbeda dapat dimuat ke alamat linear yang berbeda, atau bahkan dipindahkan setelah memulai, tanpa mengubah offset 16 atau 32-bit relatif terhadap basis segmen.
Tetapi kemudian Anda harus tahu segmen mana yang relatif menjadi pointer, sehingga Anda memiliki "pointer jauh" dan seterusnya. (Sebenarnya program 16-bit x86 sering tidak perlu mengakses kode mereka sebagai data, sehingga dapat menggunakan segmen kode 64k di suatu tempat, dan mungkin blok 64k lainnya dengan DS = SS, dengan tumpukan yang tumbuh dari offset tinggi, dan data di bagian bawah atau model kode kecil dengan semua basis segmen sama).
Bagaimana segmentasi x86 berinteraksi dengan paging
Pemetaan alamat dalam mode 32/64-bit adalah:
- segment: offset (basis segmen tersirat oleh register yang memegang offset, atau diganti dengan awalan instruksi)
- Alamat virtual linear 32 atau 64-bit = base + offset. (Dalam model memori datar seperti yang digunakan Linux, pointer / offset = alamat linear juga. Kecuali ketika mengakses TLS relatif ke FS atau GS.)
tabel halaman (di-cache oleh TLB) memetakan linear ke 32 (mode legacy), 36 (legacy PAE), atau alamat fisik 52-bit (x86-64). ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).
Langkah ini opsional: paging harus diaktifkan selama bootup dengan mengatur sedikit dalam register kontrol. Tanpa paging, alamat linear adalah alamat fisik.
Perhatikan bahwa segmentasi tidak memungkinkan Anda menggunakan lebih dari 32 atau 64 bit ruang alamat virtual dalam satu proses (atau utas) , karena ruang alamat datar (linier) semuanya dipetakan ke dalam hanya memiliki jumlah bit yang sama seperti offset sendiri. (Ini tidak berlaku untuk 16-bit x86, di mana segmentasi sebenarnya berguna untuk menggunakan lebih dari 64k memori dengan sebagian besar register dan offset 16-bit.)
CPU cache cache segmen yang dimuat dari GDT (atau LDT), termasuk basis segmen. Saat Anda menentukan referensi sebuah pointer, tergantung pada register yang mana, itu default ke DS atau SS sebagai segmen. Nilai register (pointer) diperlakukan sebagai offset dari basis segmen.
Karena basis segmen biasanya nol, CPU melakukan hal khusus ini. Atau dari perspektif lain, jika Anda memang memiliki basis segmen yang tidak nol, beban memiliki latensi tambahan karena kasus "khusus" (normal) untuk memintas menambahkan penambahan alamat basis tidak berlaku.
Bagaimana Linux mengatur register segmen x86:
Basis dan batas CS / DS / ES / SS semuanya 0 / -1 dalam mode 32 dan 64-bit. Ini disebut model memori datar karena semua pointer menunjuk ke ruang alamat yang sama.
(Arsitek AMD CPU mensegmentasi segmentasi dengan memberlakukan model memori datar untuk mode 64-bit karena OS mainstream tidak menggunakannya, kecuali untuk perlindungan no-exec yang disediakan dengan cara yang jauh lebih baik dengan paging dengan PAE atau x86- Format 64 halaman-tabel.)
TLS (Thread Local Storage): FS dan GS tidak diperbaiki pada base = 0 dalam mode panjang. (Mereka baru dengan 386, dan tidak digunakan secara implisit oleh instruksi apa pun, bahkan rep
instruksi -string yang menggunakan ES). x86-64 Linux menetapkan alamat dasar FS untuk setiap utas ke alamat blok TLS.
misal mov eax, [fs: 16]
memuat nilai 32-bit dari 16 byte ke blok TLS untuk utas ini.
deskriptor segmen CS memilih mode apa yang digunakan CPU (mode terproteksi 16/32/64-bit / mode panjang). Linux menggunakan entri GDT tunggal untuk semua proses ruang pengguna 64-bit, dan entri GDT lain untuk semua proses ruang pengguna 32-bit. (Agar CPU berfungsi dengan benar, DS / ES juga harus diatur ke entri yang valid, dan begitu juga SS). Ia juga memilih level privilege (kernel (ring 0) vs. user (ring 3)), sehingga bahkan ketika kembali ke ruang pengguna 64-bit, kernel masih harus mengatur agar CS berubah, menggunakan iret
atau sysret
bukannya normal. lompat atau ret instruksi.
Di x86-64, syscall
titik masuk digunakan swapgs
untuk membalikkan GS dari ruang pengguna GS ke kernel, yang digunakannya untuk menemukan tumpukan kernel untuk utas ini. (Kasus khusus penyimpanan thread-lokal). The syscall
instruksi tidak mengubah stack pointer ke titik di stack kernel; itu masih menunjuk ke tumpukan pengguna ketika kernel mencapai titik masuk 1 .
DS / ES / SS juga harus diatur ke deskriptor segmen yang valid agar CPU berfungsi dalam mode terproteksi / mode lama, meskipun basis / batas dari deskriptor tersebut diabaikan dalam mode panjang.
Jadi pada dasarnya segmentasi x86 digunakan untuk TLS, dan untuk hal-hal wajib x86 osdev yang diperlukan oleh perangkat keras untuk Anda lakukan.
Catatan Kaki 1: Riwayat menyenangkan: ada arsip milis pesan antara devs kernel dan arsitek AMD dari beberapa tahun sebelum silikon AMD64 dirilis, menghasilkan perubahan pada desain syscall
sehingga dapat digunakan. Lihat tautan dalam jawaban ini untuk detailnya.