读取函数runtime·rt0_go时,如何理解宏get_tls和标识符TLS?

问题描述

最近想了解一下Go程序启动的详细过程,但是看了一些关于线程本地存储的代码,就糊涂了。以下代码片段来自名为 runtime/asm_amd64.s 的源文件的第 183 至 198 行:

    LEAQ    runtime·m0+m_tls(SB),DI
    CALL    runtime·settls(SB)

    // store through it,to make sure it works
    get_tls(BX)
    MOVQ    $0x123,g(BX)
    MOVQ    runtime·m0+m_tls(SB),AX
    CMPQ    AX,$0x123
    JEQ 2(PC)
    CALL    runtime·abort(SB)
    ok:
    // set the per-goroutine and per-mach "registers"
    get_tls(BX)
    LEAQ    runtime·g0(SB),CX
    MOVQ    CX,g(BX)
    LEAQ    runtime·m0(SB),AX

要将g0放入TLS,需要执行标签“ok”后面的三行代码

get_tls(BX)
LEAQ runtime·g0(SB),CX
MOVQ CX,g(BX)

但是当我找到“get_tls”的定义,它来自runtime/go_tls.h的第9到12行,我无法理解宏get_tls:

#ifdef GOARCH_amd64
#define get_tls(r)  MOVQ TLS,r
#define g(r)    0(r)(TLS*1)
#endif

什么是“TLS”?不知道是不是amd64架构的寄存器?程序如何通过它获取线程本地存储?

感谢您的回答。

解决方法

我相信在拥有足够数量寄存器的架构上(例如 amd64 但不是 i386),一个 CPU 寄存器会永久保存一个指向线程本地存储区域的指针。

对于其他架构,有一种不同的(较慢的)路径可以避免永久使用寄存器。