Jump to content
  • Advertisement
Sign in to follow this  
MARS_999

__asm lea error?

This topic is 2608 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

Trying to compile this code


__asm
{
lea ecx, s_ticks0 ; get the offset
mov dword ptr [ecx], 0 ; zero the memory
mov dword ptr [ecx+4], 0 ;
rdtsc ; read time-stamp counter
mov [ecx], eax ; store the negative
mov [ecx+4], edx ; in the variable
}


but I get this error under MSVC++ 2010

error C2415: improper operand type

lea ecx, s_ticks0; is the line it stops on....

Thanks!

Share this post


Link to post
Share on other sites
Advertisement
If you are compiling in 64-bit mode, ecx will not be able to hold an address. Perhaps you can use rcx instead.

Share this post


Link to post
Share on other sites

If you are compiling in 64-bit mode, ecx will not be able to hold an address. Perhaps you can use rcx instead.


I did try your suggestion but no dice same error...

I did make the variable static in my class and that allowed me to compile now? Not sure why that is....

Share this post


Link to post
Share on other sites

I did make the variable static in my class and that allowed me to compile now? Not sure why that is....


When the variable is not static, i.e. every instance of your class holds its own copy of the variable, how is the assembler supposed to know which instance you want to load? Just giving it a variable name doesn't connect the variable name to a "this" pointer.

The reason making the variable static works is because you now have one copy of the variable no matter how many instances of your class you create. Since there's only ever one, you can refer to it by name and the compiler knows what you're referring to.

Share this post


Link to post
Share on other sites
Why are you even using inline asm for this? In the first place, Microsoft provides the rdtsc function as an intrinsic. Furthermore, you shouldn't be using the TSC for any sort of reliable timing. Multicore and hyperthreaded CPUs can easily skew the results (since there is no guarantee that the values for each core are synchronized), as can hibernation, power-saving measures on mobile processors, OS scheduling, and out-of-order execution. This is why the QueryPerformanceCounter function exists.

Share this post


Link to post
Share on other sites

Why are you even using inline asm for this? In the first place, Microsoft provides the rdtsc function as an intrinsic. Furthermore, you shouldn't be using the TSC for any sort of reliable timing. Multicore and hyperthreaded CPUs can easily skew the results (since there is no guarantee that the values for each core are synchronized), as can hibernation, power-saving measures on mobile processors, OS scheduling, and out-of-order execution. This is why the QueryPerformanceCounter function exists.


You assume I am only coding for Win32....

Share this post


Link to post
Share on other sites

You assume I am only coding for Win32....


I have a hard time believing whatever platform you are coding for does not have similar functionality to what that post mentions.

edit: I think boost has some similar cross platform stuff also?

Share this post


Link to post
Share on other sites
C variables *are* memory addresses. You don't need to LEA. LEA is a misnomer, it's not used for addressing in modern 32-bit flat-memory-model programs. It's used for fast multiply-by-constant. 16-bit and 64-bit modes use it occasionally.

You don't need to zero the variables first.

You can mov directly to/from a C variable and the assembler will automatically figure out the memory operand to insert (usually an [EBP-X] or [ESP+X] if you have FPO enabled).


VC++ 2008 compiles and runs the following code for me:


int _tmain(int argc, _TCHAR* argv[])
{
unsigned int a;
unsigned int b;

__asm
{
rdtsc
mov a, eax
mov b, edx
}

printf("%08X%08X\n", a, b);

return 0;
}



You could also do this:

LARGE_INTEGER li;

__asm
{
rdtsc
mov li.LowPart, eax
mov li.HighPart, edx
}



Example output disassembly, including a multiply-by-constant to show an example of LEA produced by the compiler:

[source]
int _tmain(int argc, _TCHAR* argv[])
{
01171000 83 EC 08 sub esp,8
unsigned int a;
unsigned int b;

__asm
{
rdtsc
01171003 0F 31 rdtsc
mov a, eax
01171005 89 04 24 mov dword ptr [esp],eax
mov b, edx
01171008 89 54 24 04 mov dword ptr [esp+4],edx
}

a *= 5;
0117100C 8B 04 24 mov eax,dword ptr [esp]

printf("%08X%08X\n", a, b);
0117100F 8B 4C 24 04 mov ecx,dword ptr [esp+4]
01171013 8D 04 80 lea eax,[eax+eax*4]
01171016 51 push ecx
01171017 50 push eax
01171018 68 F4 20 17 01 push 11720F4h
0117101D 89 44 24 0C mov dword ptr [esp+0Ch],eax
01171021 FF 15 A0 20 17 01 call dword ptr ds:[011720A0h]

return 0;
01171027 33 C0 xor eax,eax
}
01171029 83 C4 14 add esp,14h
0117102C C3 ret
[/source]


One thing to note: The compiler does not properly optimize inline assembly. There's no reason for it to store eax and edx back into memory when it's just going to load them up to push them to printf.

Now, take a look at the difference when I use the intrinsic. The compiler has completely optimized out my C variable since it knows that it doesn't need it:

[source]
int _tmain(int argc, _TCHAR* argv[])
{
__int64 a = __rdtsc();
00C11000 0F 31 rdtsc

printf("%I64d\n", a);
00C11002 52 push edx
00C11003 50 push eax
00C11004 68 F4 20 C1 00 push 0C120F4h
00C11009 FF 15 A0 20 C1 00 call dword ptr ds:[00C120A0h]
00C1100F 83 C4 0C add esp,0Ch

return 0;
00C11012 33 C0 xor eax,eax
}
00C11014 C3 ret
[/source]


The inline won't compile in Visual Studio in x64 mode (even though every instruction used here is encodable in 64-bit mode) because it doesn't support inline assembly. The intrinsic DOES compile in x64 mode.

You'll have to #ifdef a few separate ways anyway if you're going cross-platform, since different compilers can have different intrinsics (if they have them at all...).

Also, if you target non-Windows operating systems, be aware that RDTSC can throw an exception if the kernel has restricted access by enabling the CR4.TSD flag and your code is not priv level 0. (You should really use a platform-independent library since they will take care of this for you.)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!