Archived

This topic is now archived and is closed to further replies.

accessing member vars in assembly

This topic is 5572 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

In a member function, why isn't it possible to access meber variables directly? for instance: void someclass::foor() { __asm mov ebx,m_iVariable } do I have to do this:? void someclass::foor() { int iVar = iVariable; __asm mov ebx,iVar } If you can't tell, I'm new to assembly Oh yea, one other thing while I'm asking newbie questions. I have this code: double distx = 5.0; double radius; __asm { mov ax, distx mov cx, ax // error C2443: operand size conflict mul cx mov ax, bx mov radius, bx } Which gives me the error on the line above. Why is this? [edited by - Mulligan on September 9, 2002 7:15:30 PM]

Share this post


Link to post
Share on other sites
When you access member variables in c++ code, you''re implicitly accessing them through the this pointer. My guess is that you need to do that explicitly in the assembly code. I think the syntax is:

__asm mov ebx, someclass PTR [this].m_iVariable

Share this post


Link to post
Share on other sites
To answer you second question:

I think the error you are getting is not on the line you indicated, but on the line above. You are trying to assign a double value to a 16-bit integer register. Obviously this will not work.

try something like this (may not compile! use as an example and go look it up )



double distx = 5.0;
double radius;
__asm
{
fld [distx]
fmul [distx]
fstp [radius]
}



There are different types of registers in the cpu. Some store whole integer value, some store floating point (fractional) values. Your code was trying to assign a fractional value to an integer register. For more information, go to the developers section on the intel web site and download a few manuals.


[edited by - Jx on September 10, 2002 8:48:15 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Mulligan
Oh yea, one other thing while I''m asking newbie questions. I have this code:

double distx = 5.0;
double radius;
__asm
{
mov ax, distx
mov cx, ax // error C2443: operand size conflict
mul cx
mov ax, bx

mov radius, bx
}

Which gives me the error on the line above. Why is this?



As far as I can remember, cx is an 16 bit register. Try replacing cx with ecx( as ecx is supposed to be the 32 bit equivalent of cx ). I''m a bit rusty in assembler...
That should work for you though...










find your element
at mutedfaith.com.
<º>


Cyberdrek

Share this post


Link to post
Share on other sites
quote:
Original post by daerid
I always wanted to know how you determined which register to use in assembly. That part always confused me.


use eax, ebx, ecx, edx when storing 32 bit values

use ax, bx, cx, dx when storing 16 bit values

use ah, al etc when storing 8 bit values

use MM0 - MM7 for MMX registers

use XMM0 - XMM7 for SSE registers

use ST0 - ST7 for FPU registers

use ebp and esp to access the stack

use eip rarely it is the instruction pointer

use ds, es, fs, gs when you need segments in 16bit code or as a segment selector in 32bits. you shouldn''t need to play with these at all really

There are a few other registers which are special so I won''t go into them here...

When deciding, just pick which data type you need really. Of course, if you perform an instruction using EAX it affects AX, AH and AL because AX is actually just the lower 16 bits of EAX. AH is the higher 8 bits of AX, and AL is the lower 8 bits of AX.

Phew.. hope that gets the point across

Share this post


Link to post
Share on other sites
Thanks, explained much. Now I can do floating point arithmitic on 'float's but not 'double's. Any bigger better registers for that?
Anyway, this compiles bacause i changed everything to 'float':
__asm
{
mov eax, distx
mov ebx, eax
mul ecx
mov ebx, eax

mov eax, disty
mov ecx, eax
mul ecx
add ebx, eax

mov eax, distz
mov ecx, eax
mul ecx
add ebx, eax

mov dRadius, ebx
}

this block represents the C++ form of this:
dRadius = distx*distx + distz*distz + disty*disty;

...but it doesn't work. I'm still an seembly idiot, so let into me if im doing really stupid mistakes.

One last question, which may answer the question above, when I execute the command "mul eax" which registers are multiplied? The result is left in eax, correct?

[edited by - Mulligan on September 11, 2002 11:22:53 PM]

Share this post


Link to post
Share on other sites
I belive i see your problem (assuming that was a copy and paste)
in the first block you are moving eax into ebx but then mul eax by ecx, which is either gonna be zero or a random value depending

also, as a side note, isnt it good practise with asm routines to push onto the stack any registers you plan on using and then poping them off at the end, as the process or is probably using ''em to hold data


Share this post


Link to post
Share on other sites
quote:
Original post by _the_phantom_
I belive i see your problem (assuming that was a copy and paste)
in the first block you are moving eax into ebx but then mul eax by ecx, which is either gonna be zero or a random value depending

also, as a side note, isnt it good practise with asm routines to push onto the stack any registers you plan on using and then poping them off at the end, as the process or is probably using ''em to hold data





Yeah, normally it is good practice - but... in the VC++ help files it says (and i know these are not to be taken as gospel) that certain registers can be used without saving and restoring them. Obviously I know that under certain conditions, this does not hold true, but for his case i''m sure it''s fine.

Share this post


Link to post
Share on other sites
quote:
Original post by Mulligan
Thanks, explained much. Now I can do floating point arithmitic on 'float's but not 'double's. Any bigger better registers for that?
Anyway, this compiles bacause i changed everything to 'float':
__asm
{
mov eax, distx
mov ebx, eax
mul ecx
mov ebx, eax

mov eax, disty
mov ecx, eax
mul ecx
add ebx, eax

mov eax, distz
mov ecx, eax
mul ecx
add ebx, eax

mov dRadius, ebx
}

this block represents the C++ form of this:
dRadius = distx*distx + distz*distz + disty*disty;

...but it doesn't work. I'm still an seembly idiot, so let into me if im doing really stupid mistakes.

One last question, which may answer the question above, when I execute the command "mul eax" which registers are multiplied? The result is left in eax, correct?

[edited by - Mulligan on September 11, 2002 11:22:53 PM]




Ok - you are still missing the point. If you look at the numbers you are using, they are decimal values - regardless of wether they are doubles or floats. These values _cannot_ be stored in EAX, EBX, ECX etc etc. They can only be stored in the floating point unit's registers which I have already mentioned are ST0 - ST7 (or something similar at least).

The registers EAX, EBX, ECX etc can only be used for storing whole numbers like 4, 32, 65536 etc etc. The floating point registers are used for holding values like 3.14159, -0.910192 etc.

So....

Going back to my first answer - i'll comment the code a little more:


double distx = 5.0;
double radius;
__asm{
fld [distx] ; this line loads your distx into ST0
fmul [distx] ; this line multiplies distx by ST0 - or effectively, by itself - and stores the result back into ST0
fstp [radius] ; this line takes the result from ST0 and puts it into radius
}



Do you see?

Also - you can tell i'm using floating point instructions because they are all prefixed by the letter "f". For example "fmul" as opposed to the "mul" instruction you are using.

I thank the others for trying to help you, but the reason that your code doesn't work isn't that your using ecx by mistake or whatever - it's that your using the wrong registers all together.

Take a look at the post where i outline what registers to use for certain values. See where I say "use ST0 - ST7 for FPU registers"? That is what you need.....


I've really got to finish this article about assembly....

[edited by - Jx on September 11, 2002 12:07:40 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Jx
Yeah, normally it is good practice - but... in the VC++ help files it says (and i know these are not to be taken as gospel) that certain registers can be used without saving and restoring them. Obviously I know that under certain conditions, this does not hold true, but for his case i''m sure it''s fine.


I think, personaly, I''d push/pop ''em anyways, at least during testing.

That said, I personal wouldnt use assember any more (unless it was an small mircoprocessor) because i''m pretty certain the compiler can turn my C/C++ into better assembler than I could write

(that said, learning assembler is a nice exercise and does give you a better insight into how it all works and can help you write code a bit)

Share this post


Link to post
Share on other sites
quote:
Original post by _the_phantom_

That said, I personal wouldnt use assember any more (unless it was an small mircoprocessor) because i''m pretty certain the compiler can turn my C/C++ into better assembler than I could write




Most of the time, you may be right and I certainly wouldn''t advocate writing all your functions in assembly, BUT: according to my knowledge, my MSVC++ compiler doesn'' optimize for MMX, 3DNow!, SSE/SSE2 etc so the only way to use these powerful instructions is to hand code the functions. Not only that, but sometimes the compiler does make stupid decisions when optimizing functions - but you really should follow that age old phrase: "Profile before you optimize"

In other words: why spend time optimizing your opengl initialization code when it''s only going to get called once? take a look at which parts of the code get called most and a) see if any algorithmic changes could speed them up, and b) make sure you are not performing any unnecessary calculations or allocations within the loop. If you still have a bottleneck - think about breaking out the assembler....

_the_phantom: I know you probably know all this so it wasn''t aimed at you - more people like Mulligan who are new to assembly.

Share this post


Link to post
Share on other sites
quote:
according to my knowledge, my MSVC++ compiler doesn'' optimize for MMX, 3DNow!, SSE/SSE2 etc so the only way to use these powerful instructions is to hand code the functions

It provides relatively high-level class wrappers for the MMX/SSE/SSE2/3DNow! packed datatypes, which may do the job for you.

Share this post


Link to post
Share on other sites
quote:
Original post by Jx
I''ve really got to finish this article about assembly....

Please do! =) I used to write EVERYTHING in assembly back in the DOS days. Then I started using C++ to create the main structure of the program. Then I started writing most of my functions in C++. Then CPU power boomed, I got lazy and stopped using ASM altogether. Now, we''re several processors in the future, using 32-bit values AND addressing and I''m completely lost now that I want to get back into using assembly.

Not only that, but just UNDERSTANDING assembly is important for programmers. There''s another thread here titled "Are recursive functions limited? Yes." The poster didn''t know that the stack was being used in every function call and thus crashing their machine. An article on this topic would greatly help a lot of people since not many people really know what''s going on under the hood.

- Jay

"I have head-explody!!!" - NNY

Get Tranced!

Share this post


Link to post
Share on other sites
quote:
Original post by coderx75
Please do! =)


I''ve started it, but it''s coming along rather slowly at the moment as I''ve got a lot of other stuff to do right now.


By the way - your music is good! I''ve been listening to it for a little while now, even before I saw the link in your posts. I didn''t realise that "coderx75" and "Jay Flaherty" were the same person until now

Share this post


Link to post
Share on other sites
No $hit?! COOL! =) And thanks, you''re the first here to mention it. Yes, my sig is a shameless plug =)

Where did you originally find my music if not here in the forum? It''s strange but I keep running into people that know who I am from the music. I dig it! =D

- Jay

"I have head-explody!!!" - NNY

Get Tranced!

Share this post


Link to post
Share on other sites
Erm - not sure, but I think you remixed someone else I listened to on MP3.com or something... if not then i probably just got your name of the charts at mp3.com...

[edited by - Jx on September 12, 2002 2:46:26 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Jx
The registers EAX, EBX, ECX etc can only be used for storing whole numbers like 4, 32, 65536 etc etc. The floating point registers are used for holding values like 3.14159, -0.910192 etc.
The type of data should be pretty irrelevant. You should be fine putting floats, ints, strings, pointers, and whatever in e(a|b|c|d)x as long as they are 32 bits. Although, one should be careful what operations you do to them

quote:
Original post by _the_phantom_
That said, I personal wouldnt use assember any more (unless it was an small mircoprocessor) because i'm pretty certain the compiler can turn my C/C++ into better assembler than I could write

??? I highly doubt that, not knowing your assembly skills though. MSVC++ seems to have extremely bad common sense, escpecially when it comes to utilizing registers and hold their values. Instead it constantly "resolves" indirections etc.

This piece of crap came to mind now. It is a part of my line routine for drawing a horizontal line. The first column is the C code, second the assembly MSVC++ produced, the third is how I would have implement it in Motorola 680x0 assembly. If I tried, I'm sure could reduce the x86 assembly a lot.

if(nPixelCountY == 0) [4] cmp DWORD PTR _nPixelCountY$[ebp], 0 [2] tst.l d1
[2] jne SHORT $L667 [2] bne.b .type2
while(nPixelCountX--) [3] mov edx, DWORD PTR _nPixelCountX$[ebp]
[3] mov eax, DWORD PTR _nPixelCountX$[ebp]
[3] sub eax, 1
[3] mov DWORD PTR _nPixelCountX$[ebp], eax
[2] test edx, edx
[2] je SHORT $L670
*pAddress++ = dwColorARGB32; [3] mov ecx, DWORD PTR _pAddress$[ebp]
[3] mov edx, DWORD PTR _dwColorARGB32$[ebp]
[2] mov DWORD PTR [ecx], edx [2] move.l d2,(a0)+
[3] mov eax, DWORD PTR _pAddress$[ebp]
[3] add eax, 4
[3] mov DWORD PTR _pAddress$[ebp], eax
[2] jmp SHORT $L669 [4] dbra d0,.type1_loop
EDIT: The number inside the brackets are the instruction size. And the labels I've used: .type2 is somewhere after this stuff, and .type1_loop is pointing to the previous move.l instruction

EDIT 2: The disgusting part of this is that this routine should be able to run without any memory access but when putting the pixel there. Instead it is 5 read accesses and 3 writes (including the pixel putting).

[edited by - CWizard on September 12, 2002 5:23:32 PM]

Share this post


Link to post
Share on other sites
Would this work?

mov eax, DWORD PTR nPixelCountY
cmp eax, 0
je done
mov ecx, DWORD PTR nPixelCountX
mov ebx, DOWRD PTR pAddress
mov eax, DWORD PTR dwColorARGB32
loop:
mov DWORD PTR [ebx], eax
add ebx, 4
dec ecx
jnz loop
done:


I''m just trying to pick up assembly too

Share this post


Link to post
Share on other sites