The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: tomson123 on February 05, 2012, 03:32:36 PM

Title: WinApi+Asm Multithreading?
Post by: tomson123 on February 05, 2012, 03:32:36 PM
Hello again :)
Once more I turn to you for help... Your previous hints and suggestions were incredibly helpful, especially this tutorial on masm32. It really moved all my work forward :) But now I have a different problem. The situation goes like this:
I have a program which calculates a group of linear equations in form of a matrix. All the GUI is written in raw WinApi and the algorithm is in C++. With your help I was able to write the exact same algorithm, but this time in masm assemby. Now i wanted to add multithreading(WinApi) to it. Pretty simple, nothing really sophisticated. You just write the number of threads you want and then my program runs the procedure for the algorithm just as many times. To simplify, one thread, one whole procedure. Basically it's just doing the same thing n times, simultaneously.
When using the C++ code, everything worked nice. But when I used my asm code (it is the exact duplicate of c++, but in assembly), it just crashed saying the same old stuff we've heard thousands of times - heap corruption. Now I have a pretty good idea of what heap corruption while using threads may look like, but I have absolutely no concept of how to prevent it from happening...
So my question is, does assembly require any additional... well, stuff...? To be used in multithreading?

Thank you again for all your help :)

PS I am wondering if I should store all the registers on a stack at the begining of my asm function and then pop them back... I thought this would be done automatically for me ^_^ If that is the case then please, nevermind this post, because I will feel like a total idiot for not thinking of this before :P

UPDATE: I've  used pushad and popad. Also the FPU st registers are clean. Now I get an error about overwriting protected memory while trying to call the asm function... It doesn't even go inside. I'll look into it but I'm a bit surprised, since the asm code worked fine on it's own...
Title: Re: WinApi+Asm Multithreading?
Post by: mkey on February 05, 2012, 04:55:12 PM
Hello,

are you using the CreateThread function to create threads (a bit noobish question lol but it is what it is)? Do all the threads write in the same memory structure at the same time?
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 05, 2012, 04:58:01 PM
Yes, I am a bit new to writing multithreaded programs and I am using the CreateThread function.
As to memory structures, every thread has pointers to it's own memory, allocated prior to calling the thread. I've searched for any places where i might be overwriting the same part of memory but I couldn't find any. I'm pretty sure threads do not have any shared memory part except one, from which they only read.
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 05, 2012, 05:10:07 PM
it is all about the allocated memory
depending on how you allocate it, the block may not be accessible by multiple threads

certainly, things get a little tedious if multiple threads are allocating and free'ing blocks from the same heap
i doubt that's the issue

i am guessing the main thread of the process is where you allocate and free the memory
which Alloc function are you using ?
Title: Re: WinApi+Asm Multithreading?
Post by: mkey on February 05, 2012, 05:12:23 PM
OK, so you have a program written in C++ calling a function which runs CreateThread a user selected number of times which in turn starts a number new threads from the assembly written function?  Is the function which creates threads written in asm or c++? Have you tried using an empty function instead of the algorithm function?
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 05, 2012, 05:19:26 PM
I'm using new().
I tried using my C++ procedure, but not an empty asm function. I will give it a try.
The function creating threads is written in C++

UPDATE: I've just tried and empty asm function with exactly the same argument list. It worked fine.
I suppose this means that something is wrong with my asm function...

Sorry for not thinking of checking this before, i feel really ashamed...
I guess I'll just try adding my asm function step after step :)
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 05, 2012, 05:29:07 PM
new() is not a good way to allocate
try HeapAlloc/HeapFree
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 05, 2012, 05:34:09 PM
My C++ function uses new() as well and it works just fine... And I'm allocating memory for the asm function before creating a thread, not inside the asm function. What would make HeapAlloc better than new(), which is sufficient in former, C++ code?
Title: Re: WinApi+Asm Multithreading?
Post by: mkey on February 05, 2012, 05:51:41 PM
Access is the problem, in the multithreaded environment. Don't know it compiling the program with MT option on would help the compiler figure out what you want to do. Instead of just doing it manually :P
Title: Re: WinApi+Asm Multithreading?
Post by: MichaelW on February 05, 2012, 06:12:02 PM
Also, if anything is writing to the shared memory and the writes or reads cannot be done in single atomic operations, you'll need to implement some sort of synchronization.
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 05, 2012, 06:14:13 PM
Alright, so I've tried to construct my asm file from the beginning, chunk of code after chunk of code. I stopped at about 1/4th. The problem is, one time it works, another it crashes with heap corruption... I have no idea what is going on...

I think i will call it a day. I've been trying to solve this for almost all day and I'm pretty much fed up with it...

Thank you for all your help. I will continue to tackle my problem tomorrow... If you have any more suggestions, please, let me know :)

Edit: There is no shared memory. Each thread has a set of pointers to it's own place in memory.
Title: Re: WinApi+Asm Multithreading?
Post by: mkey on February 05, 2012, 07:05:16 PM
Like dave said, you'll have to use some other function to allocate memory. For instance, GlobalAlloc will work well with threads. To make things (possibly) simple, just alloc the stuff you need from ASM.
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 05, 2012, 07:09:02 PM
that was my first thought, as well
however, when he's done, he'll want the allocated block available in his C code
best to allocate and free from the same scope and context

there shouldn't be a problem allocating a block of memory with one of the API functions from C,
as opposed to using new() - these C guys - everything needs to be an "object" - lol
Title: Re: WinApi+Asm Multithreading?
Post by: mkey on February 05, 2012, 08:33:25 PM
Well, he needs to wait for all of his threads to exit so he can do the cleanup, no? Why not do everything in asm :D
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 12:38:54 PM
Thank you for your advice! It was most helpful :)
To finish what I have begun, there is only 1 thing left...

Can you tell me how to pass a float argument to assembly? And vice versa...
My function call from C looks something like that

asmFunction(float * pointer1, float * pointer2, ...);

Where pointer1 and pointer2 are pointers to arrays of floats.
I need to pass those arrays as floats to FPU, process them and then return as floats to my C program.
For some reason it is not sufficient to do fld real4 ptr [address] since it returns a huge number instead of my float(which I presume, is some way of representing that float).
To make matters worse, uncle Google isn't much of a help here...

Sorry for troubling you again...
Title: Re: WinApi+Asm Multithreading?
Post by: hutch-- on February 07, 2012, 01:28:29 PM
MASM will accept REAL4, REAL8 and REAL10 so its a matter of matching the data SIZE of your C FLOATs to the FP register size in the ASM proc you are calling. I think from memory that a C double is 64 bit (REAL8) but of course you can also pass an address of a C float to an ASM proc as long as you handle the address in such a way as to read the REAL8 value correctly.
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 01:35:41 PM
I try to pass float and then treat it as REAL4 so the data size is correct i think...
And as I said before, I treat the adress with fld real4 ptr [address].
Let's say I want to pass 5.32.
When I use fild real4 ptr [address] I get 5.
When I use fld real4 ptr [address] I get something like 12733527354
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 01:56:14 PM
you are passing a pointer to the float, correct ?
see if this helps...
        mov     edx,[address]
        fld real4 ptr [edx]
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 02:00:41 PM
Well, to be honest, that's exactly what I'm doing. I'm calculating my address in EAX (adding required offsets to a base address to be in correct place in my array) and then calling fld real4 ptr [eax]. I forgot to mention that "address" was only symbolic... The address is 100% correct (i get 5 when i call fild real4 ptr [eax])
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 02:29:38 PM
no - that does not seem to be correct
FILD loads integers - so the value is seen as an integer   :bg
a dword integer with the value 5 looks like this, in bytes...
        db      5,0,0,0

5.23 looks like this
        db      29h,5Ch,0A7h,40h

if you load that as an integer, it would be 1084709929

i don't read C code very well - lol
it may be you are passing the real4, directly
show us some code - we can't see what you have going on

for REAL4's, it may be prefered to pass the value directly
it sounds like you are passing the address of an array of values
if that's the case, you can't pass directly
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 02:44:21 PM
The most simplified version without unnecessary things would be this:


MyProcedure proc srcArrayPointer: DWORD, dstArrayPointer: DWORD, ...(other parameters)

finit
mov ESI, srcArrayPointer
mov EDI, dstArrayPointer
fld real4 ptr [ESI]
fld real4 ptr [ESI+4]     ;4 byte value
fmulp                         ;now let's say I want to multiply them
fstp real4 ptr [EDI]       ; and store in another array


It isn't obligatory for me to pass the value as float or long or any other 4 byte value, it can be even 8 byte double, just as long as it's floating point.
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 03:09:22 PM
that looks ok
i assume you preserve EBX, ESI, EDI, EBP, if used, though  :P
EAX, ECX, EDX may be trashed
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 03:16:03 PM
It depends what do you mean by "when used".
I keep addresses in them, but when i need them for something else, i push them on stack and pop when i'm done :)
I also do pushad and popad :)
As to my problem, the code below:


mov ESI, srcArrayPointer
fld real4 ptr [ESI]


now returns 1.401e-045#DEN instead of 1(i used a sample value in my program), for whatever reason :/
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 03:21:20 PM
it may simplify your trouble-shooting efforts if you get away from floating point data, for a moment
just pass a pointer - to a string of recognizable text, for example
it will make it easier to see what is passed and what you are getting   :P

you should be able to print out the address of a string in C
then print out the address passed to the routine

it may be that the C code is passing you a pointer to a pointer
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 03:26:01 PM
MyProcedure PROC USES ESI EDI srcArrayPointer:DWORD,dstArrayPointer:DWORD

        mov     esi,srcArrayPointer
        mov     edi,dstArrayPointer
        INVOKE  MessageBox,NULL,uhex$(esi),uhex$(edi),MB_OK
        ret

MyProcedure ENDP


creates a message box
it will have the destination array address in the title bar
and the source array address in the message text
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 03:27:07 PM
I already checked the pointer to a pointer scenario earlier :) It gives me a memory access error, so it isn't a pointer to a pointer :)

EDIT: I feel really stupid asking for this... but could you also write all the necessary code pieces to run a winapi asm program? I haven't played with winapi in assembly yet..
Also, will it be possible to call MessageBox when my main c file from which I call my asm function is a console app?

    include c:\masm32\include\windows.inc   
    include c:\masm32\include\user32.inc
    include c:\masm32\include\kernel32.inc
    includelib c:\masm32\lib\gdi32.lib
    includelib c:\masm32\lib\user32.lib
    includelib c:\masm32\lib\kernel32.lib

The above give me more than 100 errors...
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 03:36:17 PM
if the adresses look kosher, next step:
MyProcedure PROC USES ESI EDI srcArrayPointer:DWORD,dstArrayPointer:DWORD

        mov     esi,srcArrayPointer
        mov     edi,dstArrayPointer
        INVOKE  MessageBox,NULL,uhex$(esi),uhex$(edi),MB_OK
        mov     esi,[esi]
        mov     edi,[edi]
        INVOKE  MessageBox,NULL,uhex$(esi),uhex$(edi),MB_OK
        ret

MyProcedure ENDP
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 03:40:54 PM
yes - you can use MessageBox in a console app

here is a simple console example...
        INCLUDE \masm32\include\masm32rt.inc

        .DATA

szMessage db 'Message',0
szTitle   db 'Title',0

        .CODE

_main   PROC

        INVOKE  MessageBox,NULL,offset szMessage,offset szTitle,MB_OK
        inkey
        exit

_main   ENDP

        END     _main

notice that you should assemble it as a console app:
ml /c /coff MyProg.asm
Link /SUBSYSTEM:CONSOLE /OPT:NOREF MyProg.obj
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 03:48:22 PM
    include c:\masm32\include\windows.inc   
    include c:\masm32\include\user32.inc
    include c:\masm32\include\kernel32.inc
    includelib c:\masm32\lib\gdi32.lib
    includelib c:\masm32\lib\user32.lib
    includelib c:\masm32\lib\kernel32.lib


you are probably missing the processor, model and casemap

have a look at the file:
\masm32\include\masm32rt.inc

it does all that for you

sometimes, you may want to modify it a bit:
        INCLUDE \masm32\include\masm32rt.inc
        .586
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 03:50:04 PM
Alright, it looks like the fun starts for good...
As I said before, it probably isn't a pointer to a pointer, because even trying to mov a second time gives me a memory access error because of trying to read protected memory.
But I tried to display the value under that address in a MessageBox and... I got 00000001!
Seeing as 1.401e-045#DEN is more or less 49, then it looks like i'm getting an ASCII number of my, well, number! O_o

Edit: I have them all except for casemap, which I thought was not necessary.
Edit2: When I try to pass 1.43 it still gives me 00000001... :(
Title: Re: WinApi+Asm Multithreading?
Post by: qWord on February 07, 2012, 03:52:03 PM
hi,
Quote from: tomson123 on February 07, 2012, 12:38:54 PMMy function call from C looks something like that

asmFunction(float * pointer1, float * pointer2, ...);

you may try to assemble the following test-code and link the object file to you c program (console prog.):
include \masm32\include\masm32rt.inc

;// asmFunction(float *paf,int n);
asmFunction proto c paf: ptr REAL4,n:DWORD
.code
asmFunction proc c uses edi esi ebx paf: ptr REAL4,n:DWORD
LOCAL tmp:REAL4

mov esi,paf
xor ebx,ebx
.while ebx < n
fld REAL4 ptr [esi+ebx*4]
fmul FP4(100.0)
fstp tmp
print real4$(tmp),13,10
lea ebx,[ebx+1]
.endw

ret

asmFunction endp
end
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 04:00:54 PM
the address should be something like 00400000 +
Title: Re: WinApi+Asm Multithreading?
Post by: qWord on February 07, 2012, 04:02:48 PM
Quote from: dedndave on February 07, 2012, 04:00:54 PM
the address should be something like 00400000 +
only if his system does not use ASLR. (or linker option: /FIXED)
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 04:08:15 PM
well - it won't be 1   :bg

i am guessing it may be a calling convention problem
like - his C compiler is trying to use C calling convention and the ASM code is trying to use StdCall
i don't play with C enough to know the ins and outs
Title: Re: WinApi+Asm Multithreading?
Post by: qWord on February 07, 2012, 04:14:27 PM
you can call a C function as sdtcall and vice versa - the problem occurs after/while the function return: for C function the caller must  clean up the stack, stdcall-function must clean up the stack themself.
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 04:17:06 PM
Dave, get your firearms ready, because you will probably want to kill me for what I am about to say right now...
I found the solution (qWord has given me a clue with his code), and turns out the problem would be solved in 1 minute if I only sent you my code with externs for c/asm...

I have been passing my pointers as DWORD's since that's what my collegue did and it worked perfectly well for him (although he didn't use FPU...) Turns out that I should've taken a little time to think on my own and passed them as float * instead of just assuming that he was right. Thank you both for all your help, if not for you I would probably still be stuck :) I wish I could buy you a beer... :P

Still, i am happy that all of this happened, because i learned a lot from it. I hope I didn't waste too much of your time :/
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 04:22:03 PM
glad you fixed it   :U
in ASM, it would be proper to type that as an LPVOID (which is an alias for DWORD)

MyProcedure PROTO :LPVOID,:LPVOID

MyProcedure PROC USES ESI EDI srcArrayPointer:LPVOID,dstArrayPointer:LPVOID

        mov     esi,srcArrayPointer
        mov     edi,dstArrayPointer
        INVOKE  MessageBox,NULL,uhex$(esi),uhex$(edi),MB_OK
        mov     esi,[esi]
        mov     edi,[edi]
        INVOKE  MessageBox,NULL,uhex$(esi),uhex$(edi),MB_OK
        ret

MyProcedure ENDP
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 04:24:23 PM
Funny that, just recently I was searching for any information about LPVOID because of your suggestion concerning HeapAlloc, and until now, no one could give a percise answer ;)
Title: Re: WinApi+Asm Multithreading?
Post by: dedndave on February 07, 2012, 04:26:24 PM
LP means it's a long pointer
LPVOID means it is a long pointer to some unknown data tpe
i dunno - there may be an LPREAL4 type   :P

the ASM code wasn't the problem, anyways
Title: Re: WinApi+Asm Multithreading?
Post by: tomson123 on February 07, 2012, 04:28:14 PM
Now that I think about it, LPVOID's name describes it's function pretty well :) Thank you again for all your help :)