1
2;--- sample demonstrates how to
3;--- + define static TLS variables ( "__declspec(thread)" in MSC) in assembly.
4;--- + access static thread variables.
5;--- + use OPTION CODEVIEW to make debugger access the items correctly.
6
7;--- from an assembly point of view, there is not much gained with
8;--- static TLS. Unlike in C, access isn't transparent, it's quite similiar
9;--- to variables allocated vis TlsAlloc().
10
11;--- assemble: jwasm -coff win32tls.asm
12;--- link:     link win32tls.obj /subsystem:console kernel32.lib msvcrt.lib
13
14	.386
15	.model FLAT, stdcall
16	option casemap:none
17
18;--- TLS directory definition from PE/COFF specification (32-bit)
19IMAGE_TLS_DIRECTORY32  struct
20StartAddressOfRawData  DWORD ?
21EndAddressOfRawData    DWORD ?
22AddressOfIndex         DWORD ?
23AddressOfCallBacks     DWORD ?
24SizeOfZeroFill         DWORD ?
25Characteristics        DWORD ?
26IMAGE_TLS_DIRECTORY32  ends
27
28HANDLE typedef ptr
29
30;--- Win32 functions used in this program
31CloseHandle  proto :ptr
32CreateMutexA proto :ptr, :dword, :ptr
33CreateThread proto :ptr, :dword, :ptr, :ptr, :dword, :ptr
34ExitProcess  proto :dword
35ReleaseMutex proto :ptr
36Sleep        proto :dword
37WaitForMultipleObjects proto :dword, :ptr, :dword, :dword
38WaitForSingleObject    proto :ptr, :dword
39
40;--- CRT functions used in this program
41memset proto c :ptr, :dword, :dword
42printf proto c :vararg
43
44;--- macro to define a text constant
45CStr macro Text:VARARG
46local szText
47    .const
48szText  db Text,0
49    .code
50    exitm <offset szText>
51endm
52
53;--- macro to access thread variables
54TLSACC macro var
55	mov eax,fs:[2Ch]	;this is Win32-specific
56	mov edx,tls_index
57	mov eax,[eax+edx*4]
58	exitm <[eax + sectionrel var]>
59endm
60
61ifdef __JWASM__
62;--- if option -Zi is set and debugger is to show correct value
63;--- of static thread variables, option codeview:1 must be set.
64	option codeview:1
65endif
66
67_TLS segment dword alias(".tls") public 'TLS'
68tls_start label byte ;start of initialized thread variables
69var1 DD -1
70tls_end label byte   ;end of initialized thread variables
71_TLS ends
72
73	.const
74
75;--- the important thing is public "_tls_used".
76;--- if the linker finds this global label, it will set the TLS data
77;--- directory entry in the PE binary.
78
79	public _tls_used	;tell the linker that a TLS directory is wanted
80_tls_used IMAGE_TLS_DIRECTORY32 <tls_start, tls_end, tls_index, tls_cb_array>
81
82;--- zero-terminated array of TLS callbacks
83tls_cb_array label ptr
84	dd tls_callback
85	dd 0
86
87	.data
88
89tls_index dd -1	;this variable will receive the index allocated by the loader
90
91	.data?
92
93g_hMutex HANDLE ?
94
95	.code
96
97	assume fs:nothing
98
99;--- thread callback - does nothing
100tls_callback proc hMod:HANDLE, Reason:dword, Reserved:ptr
101;	invoke printf, CStr("tls_callback: reason=%d",10), Reason
102	ret
103tls_callback endp
104
105;--- thread procedure
106
107threadproc proc uses ebx lParam:dword
108
109;--- use mutex to serialize access to printf (not needed for msvcrt)
110	invoke WaitForSingleObject, g_hMutex, 5000
111	lea eax, TLSACC(var1)
112	mov ecx, TLSACC(var1)
113	invoke printf, CStr("thread(%u): init var1=%d &var1=%Xh",10), lParam, ecx, eax
114	invoke ReleaseMutex, g_hMutex
115
116;--- release time slice so the other threads will get a chance to run
117	invoke Sleep, 0
118;--- modify the thread variable
119	mov ecx, lParam
120	mov TLSACC(var1), ecx
121
122;--- use mutex to serialize access to printf (not needed for msvcrt)
123	invoke WaitForSingleObject, g_hMutex, 5000
124	mov ecx, TLSACC(var1)
125	invoke printf, CStr("thread(%u): mod. var1=%d",10), lParam, ecx
126	invoke ReleaseMutex, g_hMutex
127
128	ret
129	align 4
130
131threadproc endp
132
133
134start:
135
136mainCRTStartup proc
137
138local hConInp:HANDLE
139local hThread[10]:HANDLE
140
141	invoke printf, CStr("main: tls_index=%d",10), tls_index
142
143;--- create a mutex to synchronize access to printf()
144	invoke CreateMutexA, 0, 0, 0
145	mov g_hMutex, eax
146
147;--- reset thread handles
148	invoke memset, addr hThread, 0, sizeof hThread
149
150;--- start threads
151	mov esi,0
152	lea ebx, hThread
153	.while esi < lengthof hThread
154		invoke CreateThread, 0, 4000h, offset threadproc, esi, 0, 0
155		mov [ebx], eax
156		inc esi
157		;invoke printf, CStr("main: %u. CreateThread()=%X",10), esi, eax
158		add ebx, sizeof HANDLE
159	.endw
160
161;--- wait until all threads are done
162	invoke WaitForMultipleObjects, lengthof hThread, addr hThread, 1, 5000
163
164	invoke CloseHandle, g_hMutex
165
166	mov ecx, TLSACC(var1)
167	lea eax, TLSACC(var1)
168	invoke printf, CStr("main: var1=%d &var1=%X",10), ecx, eax
169
170	invoke ExitProcess, 0
171	ret
172	align 4
173mainCRTStartup endp
174
175	END start
176