1

次の C 関数は、スレッド ローカル ストレージ変数を使用して、スレッド セーフな方法でマルチコア コードの再帰を防止しようとします。ただし、やや複雑な理由により、この関数を X64 アセンブラー (Intel X86 / AMD 64 ビット) で記述し、VC2010 の ml64.exe でアセンブルする必要がありますグローバル変数を使用している場合にこれを行う方法は知っていますが、__declspec(thread) を持つ TLS 変数で適切に行う方法がわかりません。

__declspec(thread) int tls_VAR = 0;
void norecurse(  )
{
    if(0==tls_VAR)
    {
        tls_VAR=1;
        DoWork();
        tls_VAR=0;
    }
}

注: これは、VC2010 が機能のためにキックアウトするものです。gs:88ただし、MASM (ml64.exe) は、またはOFFSET FLAT:コードの一部をサポートしていません。

; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.40219.01 

include listing.inc

INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES

PUBLIC  norecurse
EXTRN   DoWork:PROC
EXTRN   tls_VAR:DWORD
EXTRN   _tls_index:DWORD
pdata   SEGMENT
$pdata$norecurse DD imagerel $LN4
    DD  imagerel $LN4+70
    DD  imagerel $unwind$norecurse
pdata   ENDS
xdata   SEGMENT
$unwind$norecurse DD 040a01H
    DD  06340aH
    DD  07006320aH
; Function compile flags: /Ogtpy
xdata   ENDS
_TEXT   SEGMENT
norecurse PROC
; File p:\hackytests\64bittest2010\64bittest\64bittest.cpp
; Line 19
$LN4:
    mov QWORD PTR [rsp+8], rbx
    push    rdi
    sub rsp, 32                 ; 00000020H
; Line 20
    mov ecx, DWORD PTR _tls_index
    mov rax, QWORD PTR gs:88
    mov edi, OFFSET FLAT:tls_VAR
    mov rbx, QWORD PTR [rax+rcx*8]
    cmp DWORD PTR [rbx+rdi], 0
    jne SHORT $LN1@norecurse
; Line 22
    mov DWORD PTR [rbx+rdi], 1
; Line 23
    call    DoWork
; Line 24
    mov DWORD PTR [rbx+rdi], 0
$LN1@norecurse:
; Line 26
    mov rbx, QWORD PTR [rsp+48]
    add rsp, 32                 ; 00000020H
    pop rdi
    ret 0
norecurse ENDP
_TEXT   ENDS
END
4

3 に答える 3

1

この問題をハックすることができました。次の 2 つのアドレッシング モードの使用方法を理解できなかったため、assember での私の実装は C コンパイラで生成されたコードよりも効率的ではありません。

  1. mov rax, QWORD PTR gs:88
  2. mov edi, OFFSET FLAT:tls_VAR

(1) の場合、88 を rax にロードし、gs:[rax] を使用してスレッドの TLS ベースにアクセスする必要がありました。

(2) についてはOFFSET FLAT、MASM (ml64.exe) に が含まれていないため、より賢くする必要がありました。_tls_startスレッド ローカル値にアクセスするためにアセンブラーで TLS 変数に適用できるスレッドの TLS ベースから減算してオフセットを計算しました。

PUBLIC  norecurse
EXTRN   _tls_index:DWORD
EXTRN   _tls_start:DWORD
EXTRN   tls_VAR:DWORD
EXTRN   DoWork:PROC

_TEXT   SEGMENT

norecurse           PROC
    ; non-volatile
    push            rbx
    sub             rsp,32

    ; The gs segment register refers to the base address of the TEB on x64.
    ; 88 (0×58) is the offset in the TEB for the ThreadLocalStoragePointer member on x64
    mov             rax,88
    mov             edx, DWORD PTR _tls_index
    mov             rax, gs:[rax]
    mov             r11, QWORD PTR [rax+rdx*8]
    lea             r10, _tls_start
    ; r11 will be the the offset-adjusted TLS-Base
    sub             r11, r10

    ; ebx will be the the thread local address of tls_VAR
    lea             rdx, tls_VAR
    lea             rbx,[r11+rdx]

    cmp             DWORD PTR [rbx], 0
    jne             @F

    mov             DWORD PTR [rbx], 1

    call            DoWork

    mov             DWORD PTR [rbx], 0
@@:

    add             rsp,32
    pop             rbx

    ret
norecurse       ENDP

_TEXT   ENDS

    END

ただし、MASM (ml64.exe) では理解できなかった 2 つのアドレッシング モードを実際に使用する方法について、より効率的な方法またはポインターを参照してください。

于 2012-04-26T16:30:36.623 に答える
0

TlsGetValue、 TlsSetvalue などをチェックしてください。

于 2012-04-20T16:30:30.190 に答える