News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Thread Local Storage

Started by jj2007, January 27, 2019, 03:47:17 PM

Previous topic - Next topic

jj2007

Micros**t provides us with a bunch of Tls** functions to ensure that threads get their own local storage. The demo below shows that, as an assembler programmer, you don't need them. In the attached source & exe, I exaggerate a little bit, with 100 parallel threads.

include \masm32\include\masm32rt.inc ; purest Masm32

MyTLS STRUCT
tlsSum dd ?
tlsSleep dd ?
tlsString db 400 dup(?)
MyTLS ENDS

.data?
tls MyTLS 10 dup(<>) ; there it is: THREAD LOCAL STORAGE, enough for 10 threads!!!

.code
MyThreads proc uses ebx edi threadIndex
  imul eax, threadIndex, MyTLS ; get a pointer to the tls structure
  lea ebx, tls[eax] ; ebx points to this thread's data
  invoke GetTickCount ; define the speed of this thread
  and eax, 31
  add eax, 50 ; sleep interval is 50...81
  mov [ebx.MyTLS.tlsSleep], eax
  print str$(eax), 9, "sleep interval for thread #"
  print str$(threadIndex), 13, 10

  lea edi, [ebx.MyTLS.tlsString]

  push 9 ; just a counter for 10 iterations
  .Repeat
invoke Sleep, [ebx.MyTLS.tlsSleep] ; wait some milliseconds
invoke GetTickCount
and eax, 63 ; get a number between 0 and 63
add [ebx.MyTLS.tlsSum], eax ; add it to the sum
invoke lstrcat, edi, str$(eax) ; and store the number into the thread's string
invoke lstrcat, edi, chr$(" ")
dec dword ptr [esp]
  .Until Sign?
  pop edx

  print "Thread "
  print str$(threadIndex), " finished", 13, 10
  ret
MyThreads endp

start:
  xor ebx, ebx
  .Repeat
push eax
invoke Sleep, 20
invoke CreateThread, 0, 0, MyThreads, ebx, 0, esp
pop edx
inc ebx
  .Until ebx>3

  invoke Sleep, 2000 ; wait two seconds, so that all threads have finished
  xor ebx, ebx
  .Repeat
print "results for thread #"
print str$(ebx), ": "
imul eax, ebx, MyTLS ; get a pointer to the tls structure
lea esi, tls[eax]
lea edi, [esi.MyTLS.tlsString]
print edi
print chr$(32, 9, "sum=")
print str$([esi.MyTLS.tlsSum]), 13, 10
inc ebx
  .Until ebx>3

  invoke MessageBox, 0, chr$("All threads finished!!"), chr$("TLS demo:"), MB_OK
  invoke ExitProcess, 0
end start

TBRANSO1

Show off  ;)

I downloaded it, I'll check it out.

TimoVJL

Converted for poasm:;include \masm32\include\masm32rt.inc ; purest Masm32
.386
.model flat

ExitProcess proto stdcall :dword
GetTickCount proto stdcall
Sleep proto stdcall :dword
CreateThread proto stdcall :ptr,:dword,:ptr,:ptr,:dword,:ptr
lstrcat proto C :vararg

MessageBoxA proto stdcall :ptr,:ptr,:ptr,:dword
wsprintfA proto C :vararg
includelib user32.lib

printf proto C :vararg
includelib msvcrt.lib

MyTLS STRUCT
tlsSum dd ?
tlsSleep dd ?
tlsString db 400 dup(?)
MyTLS ENDS

.data
msg1 db "All threads finished!!",0
ttl1 db "TLS demo:",0
fmt1 db "Thread %u finished",13,10,0
fmt2 db "sleep interval for thread #%u",13,10,0
fmt3 db "results for thread #%u: ",0
fmt4 db "%u ",0
fmt_sum db "sum=%u",13,10,0

.data?
tls MyTLS 4 dup(<>) ; there it is: THREAD LOCAL STORAGE, enough for 10 threads!!!

.code
MyThreads proc uses ebx edi threadIndex
  imul eax, threadIndex, MyTLS ; get a pointer to the tls structure
  lea ebx, tls[eax] ; ebx points to this thread's data
  invoke GetTickCount ; define the speed of this thread
  and eax, 31
  add eax, 50 ; sleep interval is 50...81
;  mov [ebx.MyTLS.tlsSleep], eax
  mov [ebx].MyTLS.tlsSleep, eax
;  print str$(eax), 9, "sleep interval for thread #"
;  print str$(threadIndex), 13, 10
  invoke printf, addr fmt2, threadIndex

;  lea edi, [ebx.MyTLS.tlsString]
  lea edi, [ebx].MyTLS.tlsString

  push 9 ; just a counter for 10 iterations
  .Repeat
; invoke Sleep, [ebx.MyTLS.tlsSleep] ; wait some milliseconds
invoke Sleep, [ebx].MyTLS.tlsSleep ; wait some milliseconds
invoke GetTickCount
and eax, 63 ; get a number between 0 and 63
; add [ebx.MyTLS.tlsSum], eax ; add it to the sum
add [ebx].MyTLS.tlsSum, eax ; add it to the sum
; invoke lstrcat, edi, str$(eax) ; and store the number into the thread's string
; invoke lstrcat, edi, chr$(" ")
    invoke wsprintfA, edi, addr fmt4, eax
add edi, eax
dec dword ptr [esp]
  .Until Sign?
  pop edx

;  print "Thread "
;  print str$(threadIndex), " finished", 13, 10
  invoke printf, addr fmt1, threadIndex
  ret
MyThreads endp

start:
  xor ebx, ebx
  .Repeat
push eax
invoke Sleep, 20
invoke CreateThread, 0, 0, MyThreads, ebx, 0, esp
pop edx
inc ebx
  .Until ebx>3

  invoke Sleep, 2000 ; wait two seconds, so that all threads have finished
  xor ebx, ebx
  .Repeat
; print "results for thread #"
; print str$(ebx), ": "
    invoke printf, addr fmt3, ebx
imul eax, ebx, MyTLS ; get a pointer to the tls structure
lea esi, tls[eax]
; lea edi, [esi.MyTLS.tlsString]
lea edi, [esi].MyTLS.tlsString
; print edi
    invoke printf, edi
; print chr$(32, 9, "sum=")
; print str$([esi.MyTLS.tlsSum]), 13, 10
invoke printf, addr fmt_sum, [esi].MyTLS.tlsSum
inc ebx
  .Until ebx>3

;  invoke MessageBox, 0, chr$("All threads finished!!"), chr$("TLS demo:"), MB_OK
  invoke MessageBoxA, 0, addr msg1, addr ttl1, 0
  invoke ExitProcess, 0
end start
Output just differs a bit.
May the source be with you

AK_AK

I agree completely MASM programming doesnt need TLS, and in general i think none of the WIN32 API functions are needed in pure Assembler.

If you have the tools to look around in the DLLs provided with the windows OS you will see that the high level API functions map out to ....DADAH! assembler routines  :eusa_dance:

iI not about to publish MS intellectual property here, so no code for purview.

I think that for the purpose of quick proof of concept design, making call to a [insert API function here] is convenient.
and it is a particular exercise of style, to program in LowLevelLanguage, and reach up into HighLevel language or vice versa.

I see examples of this often along the well beaten path. :biggrin:

Thanx guys.

felipe

Quote from: AK_AK on January 28, 2019, 10:48:35 AM
and in general i think none of the WIN32 API functions are needed in pure Assembler.

I think you should research a little about what system programming means for the intel platform... :idea:

Quote from: AK_AK on January 28, 2019, 10:48:35 AM
If you have the tools to look around in the DLLs provided with the windows OS you will see that the high level API functions map out to ....DADAH! assembler routines  :eusa_dance:
My friend, all existing code in the world will be mapped (even the java crap) to the processor instructions of a particular architecture...:idea:

AK_AK

I live in the bush out here in alaska, and i dont get the chance to have conversations of substance very often, i enjoy the opportunity to practice communicating concepts, in understandable form, eventually ill get the hang of being able to write effectively again if you guys keep it up with the professionally critical review. Its a soothing break from chopping wood, and melting ice into useable water :lol:


I think what i was trying to fart out of my brain was that if you feel like writing larger volumes of assembler mnemonics you can do that, but for convienience, there are often used combinations that are already written, and can be called on "by name".
 
consider  the difference between RISC and CISC:
a RISC instruction set has fewer mnemonics but uses combinations of mnemonics that can be represented by a single  luxury CISC mnemonic .

https://cs.stanford.edu/people/eroberts/courses/soco/projects/risc/risccisc/

windows system programming in loose terms, to me means inducing the windows OS to do things for you.  "Pure assembler" to me means, there is no windows, no kernal no translations,  you are supplying mnemonics directly to the CPU with no handholding from a kernel .

you are using this :  https://en.wikipedia.org/wiki/X86_instruction_listings   , and knowledge of how the CPU must be manually operated as a piece of hardware
and not writing a script that is translated into a queue of CPU functions.

.. even MASM [macro assembler] is not pure assembler mnemonics its a convenient set of libraries  [includes].
i had a fellow scoff at me once for suggesting that writing code in HEX values was superior, and preferable to MASM, the only thing better than hex values was writing straight up binary fields in a file editor. The guy couldnt even write a hello world routine. I finished the pic asm project we had on the bench, and cashed out.  The project, a drum beat counter/"comparator"  was still going strong in Ripleys believe it or not, and Guiness book of world records museums , in Niagara falls Canada.  I fell in love with assembler and embeded device development and came back here to keep my head active, and decided to get into the discussion, rather than lurk the board.

thanx for the chit chat all, felipe

jj2007

Quote from: AK_AK on January 28, 2019, 05:03:52 PM"Pure assembler" to me means, there is no windows, no kernal no translations,  you are supplying mnemonics directly to the CPU with no handholding from a kernel

There is no such thing as pure assembler any more. Instead, you have about 20,000 WinApi functions at your disposal, of which you effectively need less than 20 = 0.1% to build a decent application. But without these 20 functions (RegisterClassEx, CreateWindowEx, GetMessage, TranslateMessage, DispatchMessage, SendMessage, ...) you are naked. No interaction with the OS = no interaction with the user = no "application", whatever that means.

Even in the old DOS days you had interrupts, i.e. the old equivalent to WinApi functions. No interrupts = no printing to the console.

This is why the eternal debate here about "touching the bare metal" and "impure" assembly is so incredibly fake and bulls**t. Macros and libraries like Masm32 or MasmBasic or ObjAsm32 or the CRT are just a logical extension and consequence of the underlying model, which is "you can touch the bare metal with mov eax, 123, but that won't do anything useful, so you must also ask the OS to do its services for you".

felipe



Quote from: AK_AK on January 28, 2019, 05:03:52 PM
I think what i was trying to fart out of my brain was that if you feel like writing larger volumes of assembler mnemonics you can do that, but for convienience, there are often used combinations that are already written, and can be called on "by name".
You mean macros or functions?  :idea:


Quote from: AK_AK on January 28, 2019, 05:03:52 PM
consider  the difference between RISC and CISC:
a RISC instruction set has fewer mnemonics but uses combinations of mnemonics that can be represented by a single  luxury CISC mnemonic .

risc is far from what was intended at the beginning too, it also use (at least the arm architecture) microcode... :idea:

Quote from: AK_AK on January 28, 2019, 05:03:52 PM
windows system programming in loose terms, to me means inducing the windows OS to do things for you.  "Pure assembler" to me means, there is no windows, no kernal no translations,  you are supplying mnemonics directly to the CPU with no handholding from a kernel .
even if you don't want to write your own os, you will write (to use a computer)  assembly programs that goes directly to the cpu, just like does your windows programs. the difference is that you will be using other environment... :idea:

Quote from: AK_AK on January 28, 2019, 05:03:52 PM
you are using this :  https://en.wikipedia.org/wiki/X86_instruction_listings   , and knowledge of how the CPU must be manually operated as a piece of hardware
and not writing a script that is translated into a queue of CPU functions.
when you write an assembly program (even for windows) you need knowledge of the cpu.  the cpu itself will manage the instructions queue. you will need an assembler to translate your programs. don't know what you mean by script here...also cpu manually operated it's a bit a missleading concept, specially if you think that the cpu can't work by its own too...

Quote from: AK_AK on January 28, 2019, 05:03:52 PM
.. even MASM [macro assembler] is not pure assembler mnemonics its a convenient set of libraries  [includes].
this is not true at all. the assembler is the program that translate the mnemonics (search for the meaning of that word) into a sort of machine code...

AK_AK

"Generally, a mnemonic is a symbolic name for a single executable machine language instruction (an opcode)"

https://en.wikipedia.org/wiki/Assembly_language#Opcode_mnemonics_and_extended_mnemonics.

https://www.techopedia.com/definition/3971/assembler

https://www.tutorialspoint.com/assembly_programming/assembly_macros.htm

https://en.wikipedia.org/wiki/Microsoft_Macro_Assembler

Macro assemblers use macros to provide a sequence of mnemonics to be converted to "machine code"

assemblers convert mnemonics to machine code.

MASM is far more convenient than ASM, and does a lot of drudge work.


https://docs.microsoft.com/en-us/cpp/assembler/masm/microsoft-macro-assembler-reference?view=vs-2017

if you want to use the PE specification and avoid windows you will need some sort of PE loading

https://en.wikipedia.org/wiki/Portable_Executable

a PE loader reads the PE file header and loads your PE into memory and makes sure every thing is in the right alignment.

http://win32assembly.programminghorizon.com/pe-tut1.html

as far as an in text example of a stand alone PE loader i dont feel comfortable posting that stuff on this board, as it points to hacker, and RE boards, however they are a google search away, so if anyone wants to look around its out there but not stuff for this board, in my opinion.