Wofür ist das Register „FS“ / „GS“ vorgesehen?


102

Ich weiß also, wie die folgenden Register und ihre Verwendung aussehen sollen:

  • CS = Codesegment (für IP verwendet)

  • DS = Datensegment (für MOV verwendet)

  • ES = Zielsegment (wird für MOVS usw. verwendet)

  • SS = Stapelsegment (für SP verwendet)

Aber wofür sollen die folgenden Register verwendet werden?

  • FS = "Dateisegment"?

  • GS = ???

Hinweis: Ich frage nicht nach einem bestimmten Betriebssystem - ich frage nach dem, wofür sie von der CPU verwendet werden sollen, wenn überhaupt.


24
Soweit ich weiß, stehen F und G in diesen beiden für nichts. Es ist nur so, dass auf der CPU (und im Befehlssatz) Platz für sechs benutzerdefinierbare Segmentregister war, und jemand bemerkte, dass neben dem "S" -Tack-Segment die Buchstaben "C" und "D" (Code und Daten) waren in der Reihenfolge, also war "E" das "zusätzliche" Segment, und dann folgten einfach "F" und "G".
Torek

3
Könnte sein, es ist immer schwer zu wissen, was in einem anderen Kopf vorging, es sei denn, Sie waren zu der Zeit dort (und ich war an der anderen Küste, nicht in der Nähe von Intels Designteam).
Torek

20
Denken Sie nur daran, wie viel Spaß wir mit dem BS-Register hätten haben können: -}
Ira Baxter

5
Ich habe immer GS als "Grafiksegment" verwendet. :-)
Brian Knoblauch

2
Wie wäre es mit "G" eneral "S" egement?
SS Anne

Antworten:


109

Es gibt das, wofür sie gedacht waren und wofür sie von Windows und Linux verwendet werden.

Die ursprüngliche Absicht hinter den Segmentregistern war es, einem Programm den Zugriff auf viele verschiedene (große) Speichersegmente zu ermöglichen, die unabhängig und Teil eines dauerhaften virtuellen Speichers sein sollten. Die Idee stammt aus dem Multics-Betriebssystem von 1966 , das Dateien als einfach adressierbare Speichersegmente behandelte. Keine BS "Datei öffnen, Datensatz schreiben, Datei schließen", nur "Diesen Wert in diesem virtuellen Datensegment speichern" mit fehlerhafter Seitenbereinigung.

Unsere aktuellen 2010-Betriebssysteme sind ein großer Rückschritt, weshalb sie "Eunuchen" genannt werden. Sie können nur das einzelne Segment Ihres Prozessraums adressieren , wodurch ein sogenannter "flacher (IMHO langweilig) Adressraum" entsteht. Die Segmentregister auf der x86-32-Maschine können weiterhin für echte Segmentregister verwendet werden, aber niemand hat sich darum gekümmert (Andy Grove, ehemaliger Intel-Präsident, hatte im letzten Jahrhundert eine ziemlich berühmte öffentliche Passform, als er herausfand, dass all diese Intel-Ingenieure Energie und Energie aufgewendet hatten sein Geld, um diese Funktion zu implementieren, dass niemand sie nutzen würde. Los, Andy!)

AMD entschied, dass es ihnen egal war, ob sie Multics als Wahl eliminierten (das ist die gemeinnützige Interpretation; die gemeinnützige ist, dass sie keine Ahnung von Multics hatten), und deaktivierte daher die allgemeine Fähigkeit von Segmentregistern im 64-Bit-Modus. Es bestand immer noch ein Bedarf an Threads, um auf den lokalen Thread-Speicher zuzugreifen, und jeder Thread benötigte einen Zeiger ... irgendwo im sofort zugänglichen Thread-Status (z. B. in den Registern) ..., um den lokalen Speicher zu fädeln. Da Windows und Linux in der 32-Bit-Version FSand GS (danke Nick für die Klarstellung) für diesen Zweck verwendeten, entschied sich AMD, die 64-Bit-Segmentregister (GS und FS) im Wesentlichen nur für diesen Zweck zu verwenden (ich denke, Sie können Stellen Sie sicher, dass sie auf eine beliebige Stelle in Ihrem Prozessbereich verweisen (keine Ahnung, ob der Anwendungscode sie laden kann oder nicht).

Es wäre meiner Meinung nach architektonisch schöner gewesen, die Speicherzuordnung jedes Threads mit einer absoluten virtuellen Adresse (z. B. 0-FFF) zu versehen, die sein lokaler Thread-Speicher war (kein [Segment] -Registerzeiger erforderlich!). Ich habe dies in den 1970er Jahren in einem 8-Bit-Betriebssystem gemacht und es war äußerst praktisch, als hätte man einen weiteren großen Stapel von Registern zum Arbeiten.

Die Segmentregister ähneln nun Ihrem Anhang. Sie dienen einem Überbleibsel. Zu unserem kollektiven Verlust.

Diejenigen, die die Geschichte nicht kennen, sind nicht dazu verdammt, sie zu wiederholen. Sie sind dazu verdammt, etwas Dümmeres zu tun.


10
@supercat: Ein einfacheres, brillanteres Schema, mit dem sie 65536-mal so viel Speicher adressieren könnten, wäre gewesen, die Segmentregister als vollständige obere 16-Bit-Erweiterung der unteren 16-Bit zu behandeln, was im Wesentlichen dem 286, 386 entspricht und Multics taten es.
Ira Baxter

3
@IraBaxter: Das Problem bei diesem Ansatz besteht darin, dass Segmente im 80286-Stil einen ausreichend hohen Overhead haben, als dass viele Objekte in jedem Segment gespeichert werden müssen und somit sowohl Segment als auch Offset auf jedem Zeiger gespeichert werden müssen. Wenn man dagegen bereit ist, Speicherzuordnungen auf ein Vielfaches von 16 Bytes zu runden, kann man durch Segmentierung im 8086-Stil das Segment allein als Mittel zur Identifizierung eines Objekts verwenden. Das Runden von Zuordnungen auf 16 Bytes war 1980 vielleicht etwas lästig, würde aber heute einen Gewinn darstellen, wenn die Größe jeder Objektreferenz von 8 Bytes auf vier reduziert würde.
Supercat

3
Diese Register werden in modernen Betriebssystemen verwendet. Sie dienen hauptsächlich dazu, auf Informationen zu Task-Steuerungsblöcken zu verweisen, zumindest in den beiden Hauptbetriebssystemen, die jetzt für x86-Chips verfügbar sind. Und da sie selbst für ihre ursprüngliche Absicht nicht mehr "Allzweck" sind, können Sie sie nicht für viel verwenden. Stellen Sie sich auf x86-64-Systemen besser vor, dass sie einfach nicht existieren, bis Sie die Informationen benötigen, auf die Sie in den Thread-Steuerblöcken zugreifen können.
Ira Baxter

5
Die Anhang-Analogie ist aufgrund veralteter Wissenschaft wirklich schlecht. es hängt mit dem Immunsystem zusammen, also definitiv nicht "rastlos". Es beeinträchtigt den tatsächlichen Beitrag. Davon abgesehen ist es eine gute Antwort.
code_dredd

5
Vielen Dank für die amüsante, uneingeschränkte Behandlung von segmentiertem und flachem Speicher :) Nachdem ich auch Code auf 6809 (mit und ohne ausgelagertem Speicher), 6502, z80, 68k und 80 [123] 86 geschrieben habe, ist meine Perspektive die segmentierte Erinnerung ist eine Horrorshow und ich bin froh, dass sie in den Mülleimer der Geschichte geworfen wurde. Die Verwendung von FS und GS für den effizienten Zugriff auf thread_local-Daten ist eine erfreuliche unbeabsichtigte Folge eines historischen Fehlers.
Richard Hodges

44

Die Register FSund GSsind Segmentregister. Sie haben keinen prozessordefinierten Zweck, sondern werden von den Betriebssystemen, auf denen sie ausgeführt werden, zweckgebunden. In Windows 64-Bit wird das GSRegister verwendet, um auf vom Betriebssystem definierte Strukturen zu verweisen. FSund GSwerden häufig von Betriebssystemkernen verwendet, um auf threadspezifischen Speicher zuzugreifen. In Windows wird das GSRegister zum Verwalten des threadspezifischen Speichers verwendet. Der Linux-Kernel verwendet GSden Zugriff auf den CPU-spezifischen Speicher.


1
Wären sie dazu bestimmt, für vom Betriebssystem definierte Zwecke verwendet zu werden oder um Code zu vereinfachen, der so etwas tun muss, wie *dest++ = lookup[*src++];es sonst ziemlich umständlich wäre, wenn sich dest, lookup und src an drei nicht miteinander verbundenen Orten befinden würden.
Supercat

8
Unter Windows FS ist in der Tat für threadspezifischen Speicher. Siehe dokumentierte Karte des Blocks, auf den FS zeigt, hier en.wikipedia.org/wiki/Win32_Thread_Information_Block
Nedko

2
Es ist nicht nur unter Windows. GS wird auch für das TLS unter OS X verwendet. GS wird auch von 64-Bit-Kerneln verwendet, um die Systemstrukturen während der Kontextwechsel zu verfolgen. Das Betriebssystem verwendet zu diesem Zweck SWAPGS.
ET

11

FS wird verwendet, um auf den Thread Information Block (TIB) in Windows-Prozessen zu verweisen.

Ein typisches Beispiel ist ( SEH ), in dem ein Zeiger auf eine Rückruffunktion gespeichert ist FS:[0x00].

GS wird üblicherweise als Zeiger auf einen Thread Local Storage (TLS) verwendet. und ein Beispiel, das Sie vielleicht schon einmal gesehen haben, ist der Stack Canary Protection (Stackguard). In gcc sehen Sie möglicherweise Folgendes:

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

2
Dies beantwortet die Frage nicht wirklich. In der Frage heißt es : Hinweis: Ich frage nicht nach einem bestimmten Betriebssystem - ich frage nach dem, wofür sie von der CPU verwendet werden sollen, wenn überhaupt.
Michael Petch

9
@ MichaelPetch ya ich weiß, ich möchte dies nur als gute Information für diejenigen hinzufügen, die diese q / s in SO lesen
zerocool

2

Laut Intel-Handbuch sollen diese Register im 64-Bit-Modus als zusätzliche Basisregister in einigen linearen Adressberechnungen verwendet werden. Ich habe dies aus Abschnitt 3.7.4.1 (S. 86 im 4-Band-Set) gezogen. Wenn sich die CPU in diesem Modus befindet, entspricht die lineare Adresse normalerweise der effektiven Adresse, da in diesem Modus häufig keine Segmentierung verwendet wird.

In diesem flachen Adressraum spielen FS & GS also eine Rolle bei der Adressierung nicht nur lokaler Daten, sondern bestimmter Betriebssystemdatenstrukturen (S. 2793, Abschnitt 3.2.4). Daher sollten diese Register vom Betriebssystem verwendet werden, jedoch von diesen speziellen Designern bestimmen.

Bei der Verwendung von Überschreibungen im 32- und 64-Bit-Modus gibt es einige interessante Tricks, bei denen es sich jedoch um privilegierte Software handelt.

Aus der Perspektive der "ursprünglichen Absichten" ist das schwer zu sagen, außer dass es sich nur um zusätzliche Register handelt. Wenn die CPU in ist Realadreßmodus , das ist wie der Prozessor wird als High - Speed - 8086 laufen und diese Register müssen explizit durch ein Programm zugegriffen werden. Für eine echte 8086-Emulation würden Sie die CPU im virtuellen 8086-Modus ausführen und diese Register würden nicht verwendet.


2

TL; DR;

Wofür ist das Register „FS“ / „GS“ vorgesehen?

Einfach, um auf Daten außerhalb des Standarddatensegments (DS) zuzugreifen. Genau wie ES.


Die lange Lektüre:

Ich weiß also, wie die folgenden Register und ihre Verwendung aussehen sollen:

[...]

Nun, fast aber DS ist nicht 'irgendein' Datensegment, sondern das Standard. Wurden alle Operationen standardmäßig durchgeführt (* 1)? Hier befinden sich alle Standardvariablen - im Wesentlichen dataund bss. Dies ist in gewisser Weise ein Grund dafür, dass x86-Code ziemlich kompakt ist. Alle wesentlichen Daten, auf die am häufigsten zugegriffen wird (plus Code und Stapel), befinden sich innerhalb einer 16-Bit-Kurzschriftentfernung.

ES wird verwendet, um auf alles andere (* 2) zuzugreifen, alles über die 64 KiB von DS hinaus. Wie der Text eines Textverarbeitungsprogramms, die Zellen einer Tabelle oder die Bilddaten eines Grafikprogramms und so weiter. Anders als oft angenommen, wird auf diese Daten nicht so oft zugegriffen, sodass die Notwendigkeit eines Präfixes weniger schmerzt als die Verwendung längerer Adressfelder.

Ähnlich ist es nur ein kleiner Ärger, dass DS und ES möglicherweise geladen (und neu geladen) werden müssen, wenn Zeichenfolgenoperationen ausgeführt werden - dies wird zumindest durch einen der besten Zeichensatz-Befehlssätze seiner Zeit ausgeglichen.

Was wirklich weh tut, ist, wenn Benutzerdaten 64 KB überschreiten und der Betrieb aufgenommen werden muss. Während einige Vorgänge jeweils nur für ein einzelnes Datenelement ausgeführt werden (think A=A*2), erfordern die meisten zwei ( A=A*B) oder drei Datenelemente ( A=B*C). Wenn sich diese Elemente in verschiedenen Segmenten befinden, wird ES mehrmals pro Vorgang neu geladen, was einen erheblichen Overhead verursacht.

Am Anfang war es mit kleinen Programmen aus der 8-Bit-Welt (* 3) und ebenso kleinen Datenmengen keine große Sache, aber es wurde bald zu einem großen Flaschenhals - und vor allem zu einem echten Ärgernis für Programmierer (und Compiler). Mit dem 386 sorgte Intel schließlich für Erleichterung, indem zwei weitere Segmente hinzugefügt wurden, sodass jede unäre , binäre oder ternäre Serienoperation mit im Speicher verteilten Elementen stattfinden konnte, ohne ES ständig neu zu laden.

Für die Programmierung (zumindest in der Assembly) und das Compiler-Design war dies ein ziemlicher Gewinn. Natürlich hätte es noch mehr geben können, aber bei drei war der Flaschenhals im Grunde genommen weg, so dass es nicht nötig war, es zu übertreiben.

In Bezug auf die Benennung sind die Buchstaben F / G einfach alphabetische Fortsetzungen nach E. Zumindest vom Standpunkt des CPU-Designs ist nichts zugeordnet.


* 1 - Die Verwendung von ES als Zeichenfolgenziel ist eine Ausnahme, da lediglich zwei Segmentregister benötigt werden. Ohne wären sie nicht sehr nützlich - oder benötigen immer ein Segmentpräfix. Was eines der überraschenden Merkmale zunichte machen könnte, ist die Verwendung von (nicht sich wiederholenden) Zeichenfolgenbefehlen, die aufgrund ihrer Einzelbyte-Codierung zu einer extremen Leistung führen.

* 2 - Im Nachhinein wäre "Alles andere Segment" eine viel bessere Benennung gewesen als "Zusätzliches Segment".

* 3 - Es ist immer wichtig zu bedenken, dass die 8086 nur als Stop-Gap-Maßnahme bis zur Fertigstellung der 8800 gedacht war und hauptsächlich für die Embedded-Welt gedacht war, um 8080/85-Kunden an Bord zu halten.


1
Wow, danke, dass du das alles erklärt hast! Das erklärt viel und macht so viel Sinn! +1
user541686
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.