View Full Version : Assembly!
Doomulation
June 13th, 2004, 21:19
Finally, I'm messing with assembly on my own :whistling
But, I couldn't get some things to work. Maybe you can help me out here...
See, I'm using a threaded approach with trying to communicate over functions by returning a value by processor registers. It doesn't work very well, though.
The thread is run for 1000 ms, then terminated by the TerminateThread api.
This is my approach to the asm within the function. Note that I've tried several registers without any luck. Here's my typical code so far:
...create thread...
...set priority & resume...
Sleep(1000);
TerminateThread(hThread);
int var;
__asm mov var, edi;
void func()
{
__asm pop edi;
for(;;) __asm inc edi;
}
Either the register will be used for something else or it will be nullified when trying to access the data. I suppose I could push it onto the stack when done, but then I will have to use a more refined method than TerminateThread. And I'm not too terribly good at using check instructions in asm. It would also mean to add one other instruction in the loop.
Any suggestions? And ideas?
BGNG
June 14th, 2004, 01:35
A lot depends, here... Firstly, are you using C/C++ as a compiler? Secondly, make sure you're ASM-ing for the right processor... Thirdly, are you sure all your ASM code fits in a block and isn't thinking it goes somewhere else?
smcd
June 14th, 2004, 02:11
I dont understand your question or what you want to do, aside from storing a value in a register to be accessed elsewhere?
euphoria
June 14th, 2004, 12:10
Functions return a value in (e)ax register. I think that it is the only register that is guaranteed to be untouched. And pushing to stack might not work because then it cannot find the return address because of it.
All this is what i recall from the x86 assembler programming that i did years ago, so this might not be 100% accurate.
Please, correct if im wrong since this a interesting topic.
Btw. why not just allocate memory and use a global pointer to it and use it to communicate?
Edit: i just noticed that your mov is wrong. it should be:
mov edi, var
because target is the left parameter.
smcd
June 14th, 2004, 17:05
To put something on the stack to save for later from inside a function you'd need to pop the return address & store it somewhere temporarily, push on the value you want to save, then push the return address back onto the stack.
However (I'm not sure) since this is between 2 threads, it might be handled differently and this might not work properly...
Doomulation
June 20th, 2004, 14:04
Okay time to answer some questions here...
I did a lot of experimenting when ET was down and have some new clues, however...
A lot depends, here... Firstly, are you using C/C++ as a compiler? Secondly, make sure you're ASM-ing for the right processor... Thirdly, are you sure all your ASM code fits in a block and isn't thinking it goes somewhere else?
Yes, it's Visual C++ NET. Lol, this is typical x86 asm afaik. No, the asm is correct wher it is ;)
I dont understand your question or what you want to do, aside from storing a value in a register to be accessed elsewhere?
Trying to store the value in a register to access it outside the function when it's terminated is what I'm trying to do.
Functions return a value in (e)ax register. I think that it is the only register that is guaranteed to be untouched. And pushing to stack might not work because then it cannot find the return address because of it.
All this is what i recall from the x86 assembler programming that i did years ago, so this might not be 100% accurate.
Please, correct if im wrong since this a interesting topic.
Hmm well, I dunno much about the stack...I never really tried this approach though so may be right. But you know that the eax register is an all-purpose register and is used all the time. It is gauranteed TO BE altered.
Btw. why not just allocate memory and use a global pointer to it and use it to communicate?
The soley purpose of the asm code and storing in register is speed. Reading/writing memory is a LOT SLOWER than writing to registers.
Edit: i just noticed that your mov is wrong. it should be:
mov edi, var
because target is the left parameter.
You are right on how it's done, but the code is correct I assure you. I'm trying to move the value of edi into a variable.
To put something on the stack to save for later from inside a function you'd need to pop the return address & store it somewhere temporarily, push on the value you want to save, then push the return address back onto the stack.
However (I'm not sure) since this is between 2 threads, it might be handled differently and this might not work properly...
Hmm, so at the end of the function, the return address must be on top of the stack, correct?
Btw...I've thought about this and found some intresting facts as well.
It seems that diffrent threads have their diffrent stack (this I knew) AND registers. Modifying a register in a diffrent thread doesn't affect the register in another. I tried...
So, this absolutely makes writing to a register in the thread and getting it later impossible... however, I talked to dave and he suggested a variable... oh indeed, I'd use a test condition to terminate to loop and then move the value to a global variable... the only thing we didn't think about was the registers on diffrent threads approach...
Now I'm clueless... I don't want to write to memory if possible. I don't want any function calls if possible (this is even worse than writing to memory!). And I don't want to get rid of the thread if possible.
Anyone has an idea? Or is it the impossible I ask for?
Cyberman
June 20th, 2004, 22:09
Well yes you can do that to a global, IF you use thread synchronization.
Now threads are basically SEPERATE processes within the same application. Think of them as coroutines. This is why they have seperate stacks and 'registers' because they have a seperate memory space. When one thread is stoped and another executed (the just SEEM simultaneous but they aren't), the information for the one threads state must be preserved. Make sense?
In order to access the same information between two threads you should look at thread safe manners to do this. You should never have two threads modify the same variable unless you are CERTAIN they will never try to do so at the same time. However it's just plain stupid to try it. You have a chicken egg problem with this. You should only modify the variable in ONE thread and read it in many, that is thread safe.
It's draconian rule but it will save you a LOT of grief ;)
Cyb
Doomulation
June 20th, 2004, 23:43
Yeah I know about thread synchronization and issues... but it still doesn't solve me problem =)
I need somehow to avoid writing memory and calling functions to do the operations, if possible :evil:
But I suppose I could rid the thread by turning up the process priority. But the real problem still remains.
And I do get your point. Perfecly clear.
euphoria
June 21st, 2004, 12:29
euphoria
June 21st, 2004, 12:36
Hmm well, I dunno much about the stack...I never really tried this approach though so may be right. But you know that the eax register is an all-purpose register and is used all the time. It is gauranteed TO BE altered.
Yes i know how eax is used, but after a return from function the "return'ed" value is in the eax register and ofcourse you lose it if you don't save to somewhere.
Here's C code
int func(void)
{
return 0x66666666;
}
int main(int argc, char **args)
{
int a = func();
}
Here's the assembly generated by MSVC6
; Listing generated by Microsoft (R) Optimizing Compiler Version 12.00.9044.0
TITLE C:\devel\C\src\projects\MSVC\ret_val.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS ENDS
$$TYPES SEGMENT BYTE USE32 'DEBTYP'
$$TYPES ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
; COMDAT _func
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
; COMDAT _main
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
INCLUDELIB LIBCD
INCLUDELIB OLDNAMES
PUBLIC _func
; Function compile flags: /Odt /GZ /ZI
; File C:\devel\C\src\projects\MSVC\ret_val.c
; COMDAT _func
_TEXT SEGMENT
_func PROC NEAR ; COMDAT
; 4 : {
push ebp
mov ebp, esp
sub esp, 64 ; 00000040H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-64]
mov ecx, 16 ; 00000010H
mov eax, -858993460 ; ccccccccH
rep stosd
; 5 : return 0x66666666;
mov eax, 1717986918 ; 66666666H
; 6 : }
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
_func ENDP
_TEXT ENDS
PUBLIC _main
EXTRN __chkesp:NEAR
; Function compile flags: /Odt /GZ /ZI
; COMDAT _main
_TEXT SEGMENT
_a$ = -4
_main PROC NEAR ; COMDAT
; 9 : {
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd
; 10 : int a = func();
call _func
mov DWORD PTR _a$[ebp], eax
; 11 : }
xor eax, eax
pop edi
pop esi
pop ebx
add esp, 68 ; 00000044H
cmp ebp, esp
call __chkesp
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
Here you can see how the value 0x66666666 is returned through eax. This uses __cdecl calling convention... don't know about the others.
One thing that comes to mind is that you could write the pointer of the thread context of the 1st thread to some global variable. Then when you want to give a variable of another thread to 1st thread you take the context pointer and write to the location of say eax register. This way you would save a few memory read's.
Ofcourse the chances that this would work are quite slim. And you'd have to make sure that the 1st thread is not changing it's context (it would have to be stopped, i suppose)
It looks like you're out of luck...
Doomulation
June 21st, 2004, 20:50
Yes it does, doesn't it?
Hmmmm... but, but, but, but... if I do a simple test of how many loops per second it does with normal memory writes and then do it with registers... i could use the previous information and multiply it with two or something and count the loops (like a normal loop), break later and save the information...
I suppose this would be the best way to do it, huh?
Ie:
int i = 0; // Global var
...
// Here starts some thread
for(; i < 10000000; i++) { } // 10 million
// end thread
I'd terminate this after 1000 ms. Then multiply the value with two. When doing the rest, I use this.
mov eax, i;
inc eax;
; some test code to check if loop condition has been met
That's what I can think of now, and seems the best solution to this problem?
I'd simply time how long it takes.
Powered by vBulletin® Version 4.1.10 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.