Inlining and static function call operators - c++

I have a function template parameterized by a template parameter T to give it different behavior depending on what T it is instantiated with. The specific variations desired are very simple, a call to a static function T::foo(some_args) would suffice, because no state is involved.
However I do not want to that foo to appear in the body of the function template.
I would rather call T(some_args);to avoid syntactic noise. I believe declaring the function call operator () to be static is not possible (or is it ?). T has no state, therefore no instance specific variables.
In the event the above is not possible, what has more chance of getting inlined / optimized (in G++, Clang, ICC)
T::foo(some_args); // foo being a static function
or
T()(some_args); // operator () declared inline
I dont know assembly to check the output, and the question is more from an academic/curiosity point of view than actual performance.
Does T()(some_args) really allocate an object at runtime ? or is it typically optimized away ?

Simple example:
struct T
{
int operator()(int i) const {
return i+1;
}
};
int main()
{
return T()(1);
}
Compiled with -O2 this will yield:
(gdb) disassemble main
Dump of assembler code for function main():
0x0000000000400400 <+0>: mov eax,0x2
0x0000000000400405 <+5>: ret
End of assembler dump.
Even with -O0 this will not create a temporary in case you use the implicit default constructor in T:
(gdb) disassemble main
Dump of assembler code for function main():
0x00000000004004ec <+0>: push rbp
0x00000000004004ed <+1>: mov rbp,rsp
0x00000000004004f0 <+4>: sub rsp,0x10
0x00000000004004f4 <+8>: lea rax,[rbp-0x1]
0x00000000004004f8 <+12>: mov esi,0x1
0x00000000004004fd <+17>: mov rdi,rax
0x0000000000400500 <+20>: call 0x400508 <T::operator()(int) const>
0x0000000000400505 <+25>: leave
0x0000000000400506 <+26>: ret
End of assembler dump.

Related

C++ Nullptr vs Null-Object for potential noop function arguments?

TL;DR : Should we use fn(Interface* pMaybeNull) or fn(Interface& maybeNullObject) -- specifically in the case of "optional" function arguments of a virtual/abstract base class?
Our code base contains various forms of the following pattern:
struct CallbackBase {
virtual ~CallbackBase() = default;
virtual void Hello(/*omitted ...*/) = 0;
};
...
void DoTheThing(..., CallbackBase* pOpt) {
...
if (pOpt) { pOpt->Hello(...); }
}
where the usage site would look like:
... {
auto greet = ...;
...
DoTheThing(..., &greet);
// or if no callback is required from call site:
DoTheThing(..., nullptr);
}
It has been proposed that, going forward, we should use a form of the Null-Object-Pattern. like so:
struct NoopCall : public CallbackBase {
virtual void Hello(/*omitted ...*/) { /*noop*/ }
};
void DoTheThing2(..., CallbackBase& opt) {
...
opt.Hello(...);
}
... {
NoopCall noop;
// if no callback is required from call site:
DoTheThing2(..., noop);
}
Note: Search variations yield lots of results regarding Null-Object (many not in the C++ space), a lot of very basic treatment of pointer vs. references and if you include the word "optional", as-in the parameter is optional, you obviously get a lot of hits regarding std::optional which, afaik, is unsuitable for this virtual interface use case.
I couldn't find a decent comparison of the two variants present here, so here goes:
Given C++17/C++20 and a halfway modern compiler, is there any expected difference in the runtime characteristics of the two approaches? (this factor being just a corollary to the overall design choice.)
The "Null Object" approach certainly "seems" more modern and safer to me -- is there anything in favor of the pointer approach?
Note:
I think it is orthogonal to the question posed, whether it stands as posted, or uses a variant of overloading or default arguments.
That is, the question should be valid, regardless of:
//a
void DoTheThing(arg);
// vs b
void DoTheThing(arg=nullthing);
// vs c
void DoTheThing(arg); // overload1
void DoTheThing(); // overload0 (calling 1 internally)
Performance:
I inspected the code on godbolt and while MSVC shows "the obvious", the gcc output is interesting (see below).
// Gist for a MCVE.
"The obvious" is that the version with the Noop object contains an unconditional virtual call to Hello and the pointer version has an additional pointer test, eliding the call if the pointer is null.
So, if the function is "always" called with a valid callback, the pointer version is a pessimization, paying an additional null check.
If the function is "never" called with a valid callback, the NullObject version is a (worse) pessimization, paying a virtual call that does nothing.
However, the object version in the gcc code contains this:
WithObject(int, CallbackBase&):
...
mov rax, QWORD PTR [rsi]
...
mov rax, QWORD PTR [rax+16]
(!) cmp rax, OFFSET FLAT:NoopCaller::Hello(HelloData const&)
jne .L31
.L25:
...
.L31:
mov rdi, rsi
mov rsi, rsp
call rax
jmp .L25
And while my understanding of assembly is certainly near non existent, this looks like gcc is comparing the call pointer to the NoopCaller::Hello function, and eliding the call in this case!
Conclusion
In general, the pointer version should produce more optimal code on the micro-level. However, compiler optimizations might make any difference near non-observable.
Think about using the pointer version if you have a very hot path where the callback is null.
Use the null object version otherwise, as it is arguably safer and more maintainable.

Passing integer to x86 ASM in C++

I am trying to do some script hooking in C++, and have setup a simple test function for this case.
void __declspec(naked) testFunct()
{
int myInt;
myInt = 2000;
__asm{
mov eax, myInt
jmp [jmp_back_address]
}
}
when using this to pass in the integer, the function fails when it is called and the project crashes. However, when using this instead, without an integer value, it successfully passes through.
void __declspec(naked) testFunct()
{
__asm{
mov eax, 2000
jmp [jmp_back_address]
}
}
How can I successfully pass the integer?
The correct solution for my situation was to simply do everything within the ourFunct() through ASM instead, as mixing both C++ and ASM for passing variables was creating buggy assembly code. Example with a function call that works:
int CalculateTotalScore()
{
return (int)*Game::current_speed_score;
}
DWORD jmpBackAddress;
void __declspec(naked) ourFunct()
{
__asm{
call CalculateTotalScore
jmp [jmpBackAddress]
}
}
The assembler doesn't know what "myInt" means. Most compilers support inline assembly with the possibility to pass values. For instance, with GCC, you may try to define a macro like
#define MY_ASM_MACRO(myInt) ({ asm volatile("mov eax,%0\n\t \
jmp [jmp_back_address]" : : "r"(myInt) : ); })
And use it like
void __declspec(naked) testFunct()
{
int myInt;
myInt = 2000;
MY_ASM_MACRO(myInt)
}

c++: Why is constructor called here

I have a deep copy method in a custom container myCont. I have an instance of an unsorted container that I need to sort and dump. I create a temp container with sorted flag on, call the copy method and Dump. But the app code below creates an empty container and passes that rather than my (loaded) container. Need help figuring out what is going on here. Thanks in advance
void myCont::Copy(const myCont& srcCont)
{
// code to deep copy from srcCont
}
App Code:
fn(x, z, z) {
myCont dC();
dC.setSorted(true);
dC.Copy(sC);
dC.DumpCont();
}
Assembly:
myCont dC();
0000000140323068 mov dl,1
000000014032306A lea rcx,[dC]
0000000140323072 call myCont::myCont (0141E1A01Ah)
0000000140323077 nop
dSet.Copy(sC);
0000000140323078 cmp qword ptr [sC],0
0000000140323081 je CR::evaluate+6FDh (014032308Dh)
0000000140323083 mov byte ptr [rsp+0C2h],1
000000014032308B jmp CR::evaluate+705h (0140323095h)
000000014032308D mov byte ptr [rsp+0C2h],0
0000000140323095 movzx edx,byte ptr [rsp+0C2h]
000000014032309D lea rcx,[rsp+6F0h]
00000001403230A5 call myCont::myCont (0141E1A01Ah) <-WHY THIS CTROL CALL ????????????
00000001403230AA nop
00000001403230AB lea rdx,[rsp+6F0h]
00000001403230B3 lea rcx,[dC]
00000001403230BB call myCont::Copy (0141E1A188h)
00000001403230C0 nop
00000001403230C1 lea rcx,[rsp+6F0h]
00000001403230C9 call myCont::~my Cont(0140009280h)
dC.DumpCont();
00000001403230CE lea rcx,[dC]
00000001403230D6 call myCont::DumpCont(014019B240h)
This is not a complete example, but since you provided the assembly, I think I can tell what is going on.
sC is converting to a bool (cmp to zero, then set either a one or a zero). You must have an implicit constructor in the myCont class that can convert from a bool. sC is apparently not of type myCont. Is sC a myCont * by any chance?
From the little bit of code you posted:
void myCont::Copy(const myCont& srcCont)
{
// code to deep copy from srcCont
}
this indicates that myCont::Copy() doesn't return a new myCont object and it can't modify the srcCont object. So it's not clear what the Copy() function is actually supposed to be doing.
Also, myCont dC(); is an instance of the most vexing parse - it's a nop.

Inconsistent member offset computation in MFC class

In our VS2013 MFC Project, the CWinApp application class has a CWordArray member.
Looking at the dissassembly we can tell that the offset of this member is 21Eh.
This is the call to SetSize assembly code called from within the CwinApp:
m_arrayDefInd.SetSize(64, 1);
00F36D0F push 1
00F36D11 push 40h
00F36D13 mov ecx,dword ptr [this]
00F36D16 add ecx,21Eh <<<<<< NOTE OFFSET
00F36D1C call CWordArray::SetSize (0FC25E0h)
However, in a CView class, we retrieve the CwinApp pointer and reference this same member. When we look at the dissassembly code in the CView class, the compiler has set the offset at 230h.
CMyApp *pApp = (CMyApp *)AfxGetApp();
int size = pApp->m_arrayDefInd.GetSize();
00F2DA42 mov ecx,dword ptr [ebp-20h]
00F2DA45 add ecx,230h <<<<<< NOTE OFFSET
00F2DA4B call CWordArray::GetSize (0FC225Ch)
00F2DA50 mov dword ptr [ebp-24h],eax
We have done the obvious – clean, rebuild all. We have ensured both compilation units are using the same application header file.
The above was ported from a VS6 application that handles this correctly.
We're at a loss to explain the above. Can anyone help?

Arbitrary pointer to unknown class function - invalid type conversion

I have a hack program; it injects some functions into a target process to control it. The program is written in C++ with inline assembly.
class GameProcMain {
// this just a class
};
GameProcMain* mainproc; // there is no problem I can do =(GameProcMain*)0xC1EA90
Now I want to define a class function (which set ecx to class pointer) instead of writing assembly.
PPLYDATA GetNearblyMob(__Vector3* cordinate) {
__asm {
mov ecx, 0xC1EA90
enter code here
push cordinate
mov edi, 0x4A8010
call edi
}
}
I want to define it and call it like.
PPLYDATA (DLPL::*GetNearblyMob)(__Vector3* cordinate);
mainproc->GetNearblyMob(ADDR_CHRB->kordinat)
When I try GetNearblyMob=(PPLYDATA (DLPL::*)(__Vector3*)) 0x4A8010;
It says something like error: invalid type conversion: "int" to "PPLYDATA (DLPL::*)(int, int)"
but I can do this to set the pointer:
void initializeHack() {
__asm {
LEA edi, GetNearblyMob
MOV eax, 0x4A8010
MOV [edi], eax
}
}
Now I want to learn "how I can set GetNearblyMob without using assembly and legitimately in C++".
The problem is that member functions automatically get an extra parameter for the this pointer. Sometimes you can cast between member and non-member functions, but I don't see the need to cast anything.
Typically it's easier to reverse-engineer into C functions than into C++. C typically has a more straightforward ABI, so you can keep the data structures straight as you work them out.
So, I would recommend
PPLYDATA (*GetNearblyMob)(DLPL *main_obj, __Vector3* cordinate) = 0x12345UL;
and then define your own function
class DLPL {
GetNearblyMob( __Vector3* cordinate ) {
return ::GetNearblyMob( this, cordinate );
}
// ... other program functions
};
I am a bit surprised that it won't you cast like that.
You can try to do something like
GetNearblyMob=reinterpret_cast<PPLYDATA (DLPL::*)(__Vector3*)> (0x4A8010);
If that still does not work, try
*(int*)(&GetNearblyMob) = 0x4A8010;