I'm working on small project and trying to get some hardcoded values to inline assembly. For doing that I'm using templates. I have created a code snip to show what I'm seeing
#include <iostream>
template <size_t T>
struct MyClass
{
size_t myValue = T;
void doSomething()
{
size_t value = T;
__asm
{
mov eax, [T]
mov [value], eax
}
std::cout << value << std::endl;
}
};
int main()
{
auto o = new MyClass<999>();
o->doSomething();
return 0;
}
It turns out that for the assembly code it is trying to use the data segment instead "pasting the number there directly"
; 25 : {
push ebp
mov ebp, esp
push ecx
; 26 : auto o = new MyClass<999>();
push 4
call ??2@YAPAXI@Z ; operator new
add esp, 4
; 14 : size_t value = T;
mov DWORD PTR _value$2[ebp], 999 ; 000003e7H
; 26 : auto o = new MyClass<999>();
mov DWORD PTR [eax], 0
mov DWORD PTR [eax], 999 ; 000003e7H
; 15 : __asm
; 16 : {
; 17 : mov eax, [T]
mov eax, DWORD PTR ds:0
; 18 : mov [value], eax
mov DWORD PTR _value$2[ebp], eax
; 19 : }
; 20 : std::cout << value << std::endl;
I'm using Visual Studio 2015. Is there any other way to achieve this.
Ahh, what a lovely and twisted question!
I tried a constexpr variable initialized with T. The result was the same - value loaded from memory. Macros can be used to pass literals to inline assembly, but they don't mix well with templates.
Initializing an enum inside the class using T should in theory work (https://msdn.microsoft.com/en-us/library/ydwz5zc6.aspx mentions enums can be used in inline assembly), but using that in the inline assembly crashes the visual studio 2015 compiler :-).
What seems to work is a function template that declares an enum using the template parameter, and then using that enum in the inline assembly. If you must have it in a templated class, you can instantiate the template function inside the class like this:
#include <iostream>
template <size_t T> void dosomething() {
enum { LOCALENUM = T };
size_t value = 0;
__asm
{
mov eax, LOCALENUM
mov[value], eax
}
std::cout << value << std::endl;
}
template <size_t T>
struct MyClass
{
size_t myValue = T;
void doSomething()
{
::dosomething<T>();
}
};
int main()
{
//dosomething<999>();
auto o = new MyClass<999>();
o->doSomething();
return 0;
}
This results in the following assembly code:
auto o = new MyClass<999>();
001B1015 mov dword ptr [eax],0
001B101B mov dword ptr [eax],3E7h
o->doSomething();
001B1021 mov eax,3E7h <--- Victory!
001B1026 mov dword ptr [ebp-4],eax
001B1029 mov ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (01B2048h)]
001B102F push offset std::endl<char,std::char_traits<char> > (01B1050h)
001B1034 push dword ptr [ebp-4]
001B1037 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (01B2044h)]