A cosa è destinato il registro “FS” / “GS”?


103

Quindi so quali dovrebbero essere i seguenti registri e i loro usi:

  • CS = Segmento di codice (utilizzato per IP)

  • DS = Segmento dati (utilizzato per MOV)

  • ES = Segmento di destinazione (utilizzato per MOVS, ecc.)

  • SS = Stack Segment (usato per SP)

Ma a cosa servono i seguenti registri?

  • FS = "Segmento di file"?

  • GS = ???

Nota: io sto , non chiedendo un particolare sistema operativo - che sto chiedendo a quello che erano destinati ad essere utilizzati per la CPU, se non altro.


24
Per quanto ne so, la F e la G in questi due non significano nulla. È solo che c'era spazio sulla CPU (e nel set di istruzioni) per sei registri di segmento specificabili dall'utente, e qualcuno ha notato che oltre al segmento "S", le lettere "C" e "D" (codice e dati) erano in sequenza, quindi "E" era il segmento "extra", e poi "F" e "G" sono stati seguiti.
torek

3
Potrebbe essere stato, è sempre difficile sapere cosa stava succedendo nella testa di qualcun altro a meno che tu non fossi lì in quel momento (e io ero sull'altra costa, non vicino al team di progettazione di Intel).
torek

20
Basti pensare a quanto avremmo potuto divertirci con il registro BS: -}
Ira Baxter

5
Ho sempre usato GS come "segmento grafico". :-)
Brian Knoblauch

2
Che ne dici di "G" eneral "S" egment?
SS Anne

Risposte:


110

C'è quello per cui erano destinati e per cosa sono usati da Windows e Linux.

L'intenzione originale dietro i registri di segmento era di consentire a un programma di accedere a molti segmenti di memoria diversi (grandi) che dovevano essere indipendenti e parte di un archivio virtuale persistente. L'idea è stata presa dal sistema operativo Multics del 1966 , che trattava i file come semplici segmenti di memoria indirizzabili. No BS "Apri file, scrivi record, chiudi file", semplicemente "Memorizza questo valore in quel segmento di dati virtuali" con lo svuotamento della pagina sporca.

I nostri attuali sistemi operativi 2010 sono un gigantesco passo indietro, motivo per cui sono chiamati "eunuchi". È possibile affrontare solo il vostro singolo segmento di spazio di processo, dando una cosiddetta "flat (IMHO opaca) spazio degli indirizzi". I registri dei segmenti sulla macchina x86-32 possono ancora essere utilizzati per i registri dei segmenti reali, ma nessuno si è preoccupato (Andy Grove, ex presidente di Intel, ha avuto un incontro pubblico piuttosto famoso il secolo scorso quando ha capito che dopo tutti quegli ingegneri Intel speso energia e i suoi soldi per implementare questa funzione, che nessuno l'avrebbe usata. Vai, Andy!)

AMD nell'andare a 64 bit ha deciso che non gli importava se avesse eliminato Multics come scelta (questa è l'interpretazione caritatevole; quella non caritatevole è che non avevano idea di Multics) e quindi disabilitato la capacità generale dei registri di segmento in modalità 64 bit. C'era ancora bisogno di thread per accedere all'archivio locale del thread, e ogni thread necessitava di un puntatore ... da qualche parte nello stato del thread immediatamente accessibile (ad esempio, nei registri) ... per l'archivio locale del thread. Poiché Windows e Linux hanno utilizzato sia FS che GS (grazie Nick per il chiarimento) per questo scopo nella versione a 32 bit, AMD ha deciso di lasciare che i registri di segmento a 64 bit (GS e FS) siano usati essenzialmente solo per questo scopo (penso che tu possa falli puntare ovunque nel tuo spazio di elaborazione; non so se il codice dell'applicazione può caricarli o meno).

Sarebbe stato architettonicamente più bello IMHO fare in modo che la mappa di memoria di ogni thread avesse un indirizzo virtuale assoluto (ad esempio, 0-FFF diciamo) che fosse la sua memoria locale del thread (nessun puntatore di registro [segmento] necessario!); L'ho fatto in un sistema operativo a 8 bit negli anni '70 ed è stato estremamente utile, come avere un altro grande stack di registri su cui lavorare.

Quindi, i registri dei segmenti ora sono un po 'come la tua appendice. Hanno uno scopo rudimentale. Alla nostra perdita collettiva.

Quelli che non conoscono la storia non sono destinati a ripeterla; sono condannati a fare qualcosa di più stupido.


11
@supercat: Uno schema più semplice e brillante che avrebbe permesso loro di indirizzare 65536 volte più spazio di archiviazione, sarebbe stato quello di trattare i registri di segmento come un'estensione completa a 16 bit superiori dei 16 bit inferiori, che è in sostanza ciò che i 286, 386 e Multics lo fecero.
Ira Baxter

4
@IraBaxter: Il problema con questo approccio è che i segmenti in stile 80286 hanno un overhead sufficientemente alto di quanto uno finisce per dover memorizzare molti oggetti in ogni segmento, e quindi memorizzare sia il segmento che l'offset su ogni puntatore. Al contrario, se si desidera arrotondare le allocazioni di memoria fino a multipli di 16 byte, la segmentazione in stile 8086 consente di utilizzare il segmento da solo come mezzo per identificare un oggetto. Arrotondare le allocazioni fino a 16 byte avrebbe potuto essere leggermente fastidioso nel 1980, ma rappresenterebbe una vittoria oggi se riducesse la dimensione di ogni riferimento a un oggetto da 8 a quattro byte.
supercat

3
Questi registri vengono utilizzati nei sistemi operativi moderni. Sono principalmente dedicati a indicare le informazioni sui blocchi di controllo delle attività, almeno nei due principali sistemi operativi ora disponibili per i chip x86. E, poiché non sono più "generici" anche per il loro intento originale, non puoi usarli per molto. È meglio fingere sui sistemi x86-64 che semplicemente non esistono fino a quando non hai bisogno delle informazioni che ti consentono di accedere nei blocchi di controllo del thread.
Ira Baxter

5
L'analogia dell'appendice è davvero pessima basata su una scienza obsoleta; è correlato al sistema immunitario, quindi decisamente non "vestigiale". Dimentica il post effettivo. A parte questo, è una buona risposta.
code_dredd

5
Grazie per il trattamento divertente e senza esclusione di colpi della memoria segmentata rispetto a quella piatta :) Avendo anche scritto codice su 6809 (con e senza memoria di paging), 6502, z80, 68k e 80 [123]? 86, la mia prospettiva è quella segmentata la memoria è uno spettacolo dell'orrore e sono contento che sia stato consegnato nella pattumiera della storia. L'utilizzo di FS e GS per un accesso efficiente ai dati thread_local è una felice conseguenza non intenzionale di un errore storico.
Richard Hodges

44

I registri FSe GSsono registri di segmento. Non hanno uno scopo definito dal processore, ma invece lo scopo è dato dal sistema operativo che li esegue. In Windows a 64 bit il GSregistro viene utilizzato per puntare a strutture definite dal sistema operativo. FSe GSsono comunemente usati dai kernel del sistema operativo per accedere alla memoria specifica del thread. In Windows, il GSregistro viene utilizzato per gestire la memoria specifica del thread. Il kernel Linux utilizza GSper accedere alla memoria specifica della CPU.


1
Se fossero destinati ad essere utilizzati per scopi definiti dal sistema operativo, o per facilitare il codice che deve fare qualcosa del genere *dest++ = lookup[*src++];che altrimenti sarebbe piuttosto imbarazzante se dest, lookup e src fossero in tre posizioni non correlate.
supercat

8
Su Windows FS è effettivamente per l'archiviazione specifica del thread. Vedi la mappa documentata del blocco indicato da FS qui en.wikipedia.org/wiki/Win32_Thread_Information_Block
Nedko

2
Non è solo su Windows. GS viene utilizzato anche per TLS su OS X. GS viene anche utilizzato dai kernel a 64 bit per tenere traccia delle strutture di sistema durante i cambi di contesto. Il sistema operativo utilizzerà SWAPGS in tal senso.
ET

13

FS viene utilizzato per puntare al TIB (thread information block) sui processi Windows.

un tipico esempio è ( SEH ) che memorizza un puntatore a una funzione di callback in FS:[0x00].

GS è comunemente usato come puntatore a una memoria locale di thread (TLS). e un esempio che potresti aver visto prima è lo stack canary protection (stackguard), in gcc potresti vedere qualcosa del genere:

mov    eax,gs:0x14
mov    DWORD PTR [ebp-0xc],eax

2
Questo in realtà non risponde alla domanda. La domanda afferma : Nota: non sto chiedendo informazioni su un particolare sistema operativo - sto chiedendo cosa avrebbero dovuto essere usati dalla CPU, se non altro.
Michael Petch

10
@MichaelPetch ya so che voglio solo aggiungere questo come una buona informazione per coloro che leggono questo q / s in SO
zerocool

3

Secondo il manuale Intel, nella modalità a 64 bit questi registri devono essere utilizzati come registri di base aggiuntivi in ​​alcuni calcoli di indirizzo lineare. Ho estratto questo dalla sezione 3.7.4.1 (pag.86 nel set di 4 volumi). Di solito quando la CPU è in questa modalità, l'indirizzo lineare è lo stesso dell'indirizzo effettivo, poiché spesso la segmentazione non viene utilizzata in questa modalità.

Quindi, in questo spazio di indirizzamento piatto, FS e GS svolgono un ruolo nell'affrontare non solo i dati locali ma alcune strutture dati del sistema operativo (pag.2793, sezione 3.2.4) quindi questi registri erano destinati ad essere utilizzati dal sistema operativo, tuttavia quei particolari progettisti determinare.

Ci sono alcuni trucchi interessanti quando si usano gli override in entrambe le modalità a 32 e 64 bit, ma questo implica software privilegiato.

Dal punto di vista delle "intenzioni originali", è difficile dire se non sono solo registri extra. Quando la CPU è in modalità indirizzo reale , è come se il processore funzioni come un 8086 ad alta velocità e questi registri devono essere esplicitamente accessibili da un programma. Per il bene della vera emulazione 8086 faresti funzionare la CPU in modalità virtual-8086 e questi registri non verrebbero usati.


2

TL; DR;

A cosa è destinato il registro “FS” / “GS”?

Semplicemente per accedere ai dati oltre il segmento di dati predefinito (DS). Esattamente come ES.


La lunga lettura:

Quindi so quali dovrebbero essere i seguenti registri e i loro usi:

[...]

Beh, quasi, ma DS non è "un po '" di segmento di dati, ma quello predefinito. Tutte le operazioni sono state eseguite per impostazione predefinita (* 1). Qui si trovano tutte le variabili predefinite, essenzialmente datae bss. È in qualche modo parte del motivo per cui il codice x86 è piuttosto compatto. Tutti i dati essenziali, a cui si accede più spesso (più codice e stack), si trovano a una distanza abbreviata di 16 bit.

ES è utilizzato per accedere a tutto il resto (* 2), tutto oltre i 64 KiB di DS. Come il testo di un elaboratore di testi, le celle di un foglio di calcolo oi dati dell'immagine di un programma di grafica e così via. A differenza di quanto spesso si presume, questi dati non sono molto accessibili, quindi la necessità di un prefisso fa meno male rispetto all'utilizzo di campi indirizzo più lunghi.

Allo stesso modo, è solo un piccolo fastidio che DS ed ES debbano essere caricati (e ricaricati) quando si eseguono operazioni sulle stringhe - questo almeno è compensato da uno dei migliori set di istruzioni per la gestione dei caratteri del suo tempo.

Ciò che fa veramente male è quando i dati utente superano i 64 KiB e le operazioni devono essere avviate. Mentre alcune operazioni vengono eseguite semplicemente su un singolo elemento di dati alla volta (pensa A=A*2), la maggior parte richiede due ( A=A*B) o tre elementi di dati ( A=B*C). Se questi elementi risiedono in segmenti diversi, ES verrà ricaricato più volte per operazione, aggiungendo un bel po 'di overhead.

All'inizio, con piccoli programmi dal mondo a 8 bit (* 3) e set di dati altrettanto piccoli, non era un grosso problema, ma presto divenne un collo di bottiglia per le prestazioni principali - e ancor più un vero rompicoglioni per programmatori (e compilatori). Con il 386 Intel ha finalmente fornito sollievo aggiungendo altri due segmenti, quindi qualsiasi operazione unaria , binaria o ternaria in serie, con elementi sparsi in memoria, potrebbe avvenire senza ricaricare ES tutto il tempo.

Per la programmazione (almeno in assembly) e la progettazione del compilatore, questo è stato un bel vantaggio. Certo, avrebbe potuto esserci anche di più, ma con tre il collo di bottiglia era praticamente sparito, quindi non c'è bisogno di esagerare.

Dal punto di vista del nome, le lettere F / G sono semplicemente continuazioni alfabetiche dopo E. Almeno dal punto di vista della progettazione della CPU non è associato nulla.


* 1 - L'utilizzo di ES per la destinazione della stringa è un'eccezione, poiché sono necessari semplicemente due registri di segmento. Senza non sarebbero molto utili o avrebbero sempre bisogno di un prefisso di segmento. Il che potrebbe uccidere una delle caratteristiche sorprendenti, l'uso di istruzioni stringa (non ripetitive) con conseguente prestazioni estreme a causa della loro codifica a byte singolo.

* 2 - Quindi, col senno di poi, "Tutto il resto" sarebbe stato un nome migliore rispetto a "Segmento extra".

* 3 - È sempre importante tenere presente che l'8086 era inteso solo come misura di stop gap fino a quando l' 8800 non era finito e principalmente destinato al mondo embedded per mantenere i clienti 8080/85 a bordo.


1
Wow, grazie per aver spiegato tutto questo! Questo spiega molto e ha molto senso! +1
user541686
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.