Was sind die tatsächlichen ELF TLS ABI Anforderungen für jeden CPU-Arch?

9

Ulrich Dreppers Beitrag zum Thread-Local-Storage umreißt den TLS-ABI für mehrere verschiedene CPU-Architekturen, aber ich ' Ich finde es aus zwei Gründen unzureichend, um TLS zu implementieren:

  1. Es enthält eine Reihe von wichtigen Archs wie ARM, MIPS usw. (und enthält eine Reihe von komplett irrelevanten wie Itanium)
  2. Noch wichtiger ist, dass es viele Implementierungsdetails mit ABI vermischt, so dass es schwer ist zu sagen, welche Eigenschaften für die Interoperabilität benötigt werden und welche nur Aspekte seiner Implementierung sind.

Als Beispiel sind die einzigen tatsächlichen ABI-Anforderungen für i386:

  • %gs:0 zeigt auf einen Zeiger auf sich selbst.
  • Das TLS-Segment der Haupt-Executable muss (falls vorhanden) an einem festen (durch den Linker negativen) Offset von dieser Adresse liegen.
  • Alle anderen TLS-Segmente für anfänglich geladene Bibliotheken müssen eine Laufzeitkonstante (dh für jeden Thread dieselben, aber nicht notwendigerweise die gleichen über verschiedene Programmläufe) aufweisen, die relativ zu dieser Adresse sind (und der dynamische Linker muss füllen können) in Verlagerungen mit diesen Offsets).
  • ___tls_get_addr und __tls_get_addr Funktionen müssen mit der korrekten Semantik zum Nachschlagen beliebiger TLS-Segmente existieren.

Insbesondere ist das Vorhandensein oder Layout eines DTV nicht Teil des ABI, und auch die Anordnung / Anordnung der TLS-Segmente ist nicht das Hauptprogramm.

Es scheint, dass jeder Bogen, der "TLS-Variante II" verwendet, ungefähr die obigen ABI-Anforderungen hat. Aber ich verstehe die Anforderungen der "TLS-Variante I" überhaupt nicht sehr gut, und aus den Quellen (in uClibc und glibc) scheint es, dass es sogar mehrere Varianten der "Variante I" geben kann.

Gibt es bessere Dokumente, die ich mir ansehen sollte, oder kann jemand, der mit der Funktionsweise von TLS vertraut ist, die ABI-Anforderungen für mich erklären?

    
R.. 14.10.2012, 02:03
quelle

1 Antwort

3

Das Beste, was ich bisher sammeln konnte, ist:

Für jede TLS-Variante müssen __tls_get_addr oder andere architekturspezifische Funktionen vorhanden sein und die korrekte Semantik zum Nachschlagen eines TLS-Objekts haben, und der relative Versatz zwischen zwei beliebigen TLS-Segmenten muss eine Laufzeitkonstante sein (jeweils gleicher Offset) Thread).

Für TLS-Variante II (i386, etc.), das "Thread-Pointer-Register" (das möglicherweise kein Register ist, aber vielleicht ein Mechanismus wie %gs:0 oder sogar ein Trap in den Kernel-Bereich; der Einfachheit halber lassen Sie uns nur anrufen Es ist ein Register) zeigt direkt hinter dem Ende des TLS-Segments für die Hauptdatei, wobei "kurz nach dem Ende" das Runden auf das nächste Vielfache der Ausrichtung des TLS-Segments einschließt.

Bei der TLS-Variante I zeigt das "Thread Pointer Register" auf einen festen Offset vom Anfang des TLS-Segments für die Haupt-Executable. Dieser Offset variiert je nach Bogen. (Es wurde auf einigen hässlichen RISC Archs gewählt, um die Menge an TLS zu maximieren, die über vorzeichenbehaftete 16-Bit-Offsets zugänglich ist, was mir extrem unbrauchbar erscheint, da der Compiler keine Möglichkeit hat, zu wissen, ob der verschobene Offset in 16 Bits passen wird erzeuge immer den langsameren, größeren 32-Bit-Offset-Code mit load-upper / add-Anweisungen.

Soweit ich das beurteilen kann, ist nichts über TCBs, DTVs usw. Teil des ABI, in dem Sinne, dass Anwendungen nicht auf diese Strukturen zugreifen dürfen, ebenso wenig wie der Speicherort eines anderen TLS-Segments als der Hauptdatei Teil der ABI. In beiden Varianten I und II ist es sinnvoll, implementierungsinterne Informationen für den Thread mit einem festen Abstand zum "Thread Pointer Register" zu speichern, unabhängig davon, wie das TLS-Segment sicher überlappt.

    
R.. 15.10.2012, 01:03
quelle