C++ inline Assembler help. (error c2400) - c++

I'm using Visual Studio 2010. I wrote a program that does a simple Binary Search algorithm. I'm trying to convert it into assemble code. I used the Disassembler to get the assembly code. I'm trying to paste it into _asm. I've tried so many ways and it's just not working.
I tried
_asm(" . . . .");
_asm( );
_asm{ } <--- -Currently going with this way for c++. seems to work well.
seen somewhere online people saying put '\' at the end of each line. That hasn't worked for me.
Here's the code. I'll comment where the errors are. well, I have 13 as of now. Some I won't list because they're the same as other errors. Once I fix one or 2 I should be able to fix them all. The orignal c++ code for the function is also in there.It's commented out.
bool binarySearch(int searchNum,int myArray[],int size){
_asm{
push ebp
mov ebp,esp
sub esp,0F0h
push ebx
push esi
push edi
lea edi,[ebp-0F0h]
mov ecx,3Ch
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
// 217: int first=0,last=size-1,middle;
mov dword ptr [first],0
mov eax,dword ptr [size] // ERROR! Error 2 error C2400: inline assembler syntax error in 'second operand'; found ']'
sub eax,1
mov dword ptr [last],eax
// 218: bool found = false;
mov byte ptr [found],0
// 220: while (first <= last)
mov eax,dword ptr [first]
cmp eax,dword ptr [last]
jg binarySearch+80h (0B51970h) //ERROR! Error 4 error C2400: inline assembler syntax error in 'second operand'; found '('
// 222: middle = (first + last)/2;
mov eax,dword ptr [first] ; // Error 5 error C2400: inline assembler syntax error in 'opcode'; found '('
add eax,dword ptr [last] ;
cdq
sub eax,edx
sar eax,1
mov dword ptr [middle],eax
// 224: if(searchNum > myArray[middle])
mov eax,dword ptr [middle]
mov ecx,dword ptr [myArray]
mov edx,dword ptr [searchNum]
cmp edx,dword ptr [ecx+eax*4]
jle binarySearch+61h (0B51951h) // Error 8 error C2400: inline assembler syntax error in 'opcode'; found '('
// 226: first = middle +1;
mov eax,dword ptr [middle]
add eax,1
mov dword ptr [first],eax
jmp binarySearch+7Eh (0B5196Eh)
// 228: else if (searchNum < myArray[middle])
mov eax,dword ptr [middle]
mov ecx,dword ptr [myArray]
mov edx,dword ptr [searchNum]
cmp edx,dword ptr [ecx+eax*4]
jge binarySearch+7Ah (0B5196Ah)
// 230: last = middle -1;
mov eax,dword ptr [middle]
sub eax,1
mov dword ptr [last],eax
// 232: else
jmp binarySearch+7Eh (0B5196Eh) // Error 18 error C2400: inline assembler syntax error in 'second operand'; found '('
// 233: return true;
mov al,1 // Error 19 error C2400: inline assembler syntax error in 'opcode'; found '('
jmp binarySearch+82h (0B51972h)
jmp binarySearch+32h (0B51922h) // Error 22 error C2400: inline assembler syntax error in 'opcode'; found '('
// 236: return false;
xor al,al
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
};
/*
int first=0,last=size-1,middle;
bool found = false;
while (first <= last)
{
middle = (first + last)/2;
if(searchNum > myArray[middle])
{
first = middle +1;
}
else if (searchNum < myArray[middle])
{
last = middle -1;
}
else
return true;
}
return false;
*/
}

Here is the (almost 1:1) working code you posted for a standalone assembly.
binsearch.cpp
extern "C"
{
bool BinSearch(int searchNum, int myArray[], int arraySize);
};
// This is the inlined version.
bool BinSearchInline(int searchNum, int myArray[], int arraySize)
{
int middle;
int first;
int last;
char found;
_asm
{
push ebx
push esi
push edi
mov first,0
mov eax, arraySize
sub eax,1
mov last ,eax
mov found,0
LocalLoop:
mov eax, first
cmp eax, last
jg NotFound
mov eax, first
add eax, last
cdq
sub eax,edx
sar eax,1
mov middle,eax
mov eax,middle
mov ecx,myArray
mov edx,searchNum
cmp edx, dword ptr [ecx+eax*4]
jle MaybeLower
mov eax, middle
add eax,1
mov first, eax
jmp WhileLoop
MaybeLower:
mov eax, middle
mov ecx, myArray
mov edx, searchNum
cmp edx,dword ptr [ecx+eax*4]
jge Found
mov eax, middle
sub eax,1
mov last, eax
jmp WhileLoop
Found:
mov al,1
jmp Done
WhileLoop:
jmp LocalLoop
NotFound:
xor al,al
Done:
pop edi
pop esi
pop ebx
};
}
int main(int argc, char*arg[])
{
int testvalues[7];
for(int i = 0; i < 7; i++)
testvalues[i] = i;
bool b = BinSearch(8, testvalues, 7); // false, value not in array
b = BinSearch(3, testvalues, 7); // true, value is in array.
b = BinSearchInline(8, testvalues, 7); // false
b = BinSearchInline(3, testvalues, 7); // true
return 0;
}
binsearch.asm
.486
.model flat, C
option casemap :none
.code
BinSearch PROC, searchNum:DWORD, myArray:PTR DWORD, arraySize:DWORD
LOCAL first:DWORD
LOCAL middle:DWORD
LOCAL last:DWORD
LOCAL found:BYTE
push ebx
push esi
push edi
; This block is only for debugging stack errors and should be removed.
; lea edi,[ebp-0F0h]
; mov ecx,3Ch
; mov eax,0CCCCCCCCh
; rep stos dword ptr es:[edi]
mov dword ptr [first],0
mov eax,dword ptr [arraySize]
sub eax,1
mov dword ptr [last],eax
mov byte ptr [found],0 ; not even used.
##Loop:
mov eax,dword ptr [first]
cmp eax,dword ptr [last]
jg ##NotFound
mov eax,dword ptr [first]
add eax,dword ptr [last]
cdq
sub eax,edx
sar eax,1
mov dword ptr [middle],eax
mov eax,dword ptr [middle]
mov ecx,dword ptr [myArray]
mov edx,dword ptr [searchNum]
cmp edx,dword ptr [ecx+eax*4]
jle ##MaybeLower
mov eax,dword ptr [middle]
add eax,1
mov dword ptr [first],eax
jmp ##WhileLoop
##MaybeLower:
mov eax,dword ptr [middle]
mov ecx,dword ptr [myArray]
mov edx,dword ptr [searchNum]
cmp edx,dword ptr [ecx+eax*4]
jge ##Found
mov eax,dword ptr [middle]
sub eax,1
mov dword ptr [last],eax
jmp ##WhileLoop
##Found:
mov al,1
jmp ##Done
##WhileLoop:
jmp ##Loop
##NotFound:
xor al,al
##Done:
pop edi
pop esi
pop ebx
ret
BinSearch ENDP
END

Related

is Visual C++ actually generating blatantly incorrect code?

So I'm debugging my DPLL implementation and it's not quite working right so I step through the code line by line in the debugger, it gets to a return statement but the thing is it doesn't return, it just keeps on executing the same function. WTF I thought, am I really seeing this? So I looked at the dissasembly and sure enough one of the return statements jumps to the wrong place. Never have I seen VS generate incorrect code so I'm wondering if I screwed up somewhere but I can't find anything. The jump is incorrect even when compiling with all optimizations off.
This illustrates whats going on.
bool dpll(std::vector<clause> f)
{
unitPropagate(f);
if(checkFalseClause(f))
{
return false; //je dpll+5Fh (0C01D1Fh) <-- Totally wrong jump adress
}
else if(checkAllClausesTrue(f))
{
return true; //jmp dpll+206h (0C01EC6h) <-- this is fine
}
else
{
atom l = chooseLiteral(f); //this is where the jump ends up (0C01D1Fh)
std::vector<clause> a = makeDuplicate(f);
replaceInstancesOf(a, l, true);
std::vector<clause> b = makeDuplicate(f);
replaceInstancesOf(b, l, false);
return dpll(a) | dpll(b);
}
//this is where the jump is supposed to go (0C01EC6h)
}
So my question is, is Visual Studio actually broken or have I misunderstood something? Has anyone run into something like this before?
The version is Visual Studio Enterprise 2015 if that makes a difference, the code is generated for x86_32.
Here's the full dissasembly if anyone's interested:
00C01CC0 push ebp
00C01CC1 mov ebp,esp
00C01CC3 push 0FFFFFFFFh
00C01CC5 push 0C08FF0h
00C01CCA mov eax,dword ptr fs:[00000000h]
00C01CD0 push eax
00C01CD1 sub esp,40h
00C01CD4 mov eax,dword ptr [__security_cookie (0C0D008h)]
00C01CD9 xor eax,ebp
00C01CDB mov dword ptr [ebp-10h],eax
00C01CDE push ebx
00C01CDF push esi
00C01CE0 push eax
00C01CE1 lea eax,[ebp-0Ch]
00C01CE4 mov dword ptr fs:[00000000h],eax
bool dpll(std::vector<clause> f)
00C01CEA lea ecx,[f]
00C01CED mov dword ptr [ebp-4],0
00C01CF4 call unitPropagate (0C01950h)
{
unitPropagate(f);
00C01CF9 lea ecx,[f]
00C01CFC call checkFalseClause (0C01660h)
00C01D01 test al,al
00C01D03 je dpll+4Ch (0C01D0Ch)
00C01D05 xor bh,bh
00C01D07 jmp dpll+206h (0C01EC6h)
if(checkFalseClause(f))
{
return false;
00C01D0C lea ecx,[f]
00C01D0F call checkAllClausesTrue (0C014F0h)
00C01D14 test al,al
00C01D16 je dpll+5Fh (0C01D1Fh)
}
else if(checkAllClausesTrue(f))
00C01D18 mov bh,1
00C01D1A jmp dpll+206h (0C01EC6h)
{
return true;
}
else
00C01D1F lea edx,[f]
00C01D22 lea ecx,[l]
00C01D25 call chooseLiteral (0C013D0h)
00C01D2A mov byte ptr [ebp-4],1
{
atom l = chooseLiteral(f);
00C01D2E lea edx,[f]
00C01D31 xorps xmm0,xmm0
00C01D34 mov dword ptr [ebp-20h],0
00C01D3B lea ecx,[a]
00C01D3E movq mmword ptr [a],xmm0
00C01D43 call makeDuplicate (0C01A30h)
00C01D48 mov byte ptr [ebp-4],2
00C01D4C sub esp,20h
00C01D4F mov esi,esp
00C01D51 mov bl,1
00C01D53 mov dword ptr [ebp-4Ch],esi
00C01D56 lea ecx,[esi+4]
00C01D59 mov al,byte ptr [l]
00C01D5C mov byte ptr [esi],al
00C01D5E mov dword ptr [ecx+14h],0Fh
00C01D65 mov dword ptr [ecx+10h],0
00C01D6C cmp dword ptr [ecx+14h],10h
00C01D70 jb dpll+0B6h (0C01D76h)
00C01D72 mov eax,dword ptr [ecx]
00C01D74 jmp dpll+0B8h (0C01D78h)
00C01D76 mov eax,ecx
00C01D78 push 0FFFFFFFFh
00C01D7A mov byte ptr [eax],0
00C01D7D lea eax,[ebp-44h]
00C01D80 push 0
00C01D82 push eax
00C01D83 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (0C02A80h)
00C01D88 mov al,byte ptr [ebp-2Ch]
00C01D8B lea ecx,[a]
00C01D8E mov byte ptr [esi+1Ch],al
00C01D91 mov dl,bl
00C01D93 mov al,byte ptr [ebp-2Bh]
00C01D96 mov byte ptr [esi+1Dh],al
00C01D99 call replaceInstancesOf (0C017D0h)
00C01D9E xorps xmm0,xmm0
00C01DA1 mov dword ptr [ebp-14h],0
std::vector<clause> a = makeDuplicate(f);
replaceInstancesOf(a, l, true);
00C01DA8 lea edx,[f]
std::vector<clause> a = makeDuplicate(f);
replaceInstancesOf(a, l, true);
00C01DAB movq mmword ptr [b],xmm0
00C01DB0 lea ecx,[b]
00C01DB3 call makeDuplicate (0C01A30h)
00C01DB8 mov esi,esp
00C01DBA mov byte ptr [ebp-4],3
00C01DBE mov dword ptr [ebp-4Ch],esi
00C01DC1 lea ecx,[esi+4]
00C01DC4 mov al,byte ptr [l]
00C01DC7 xor bl,bl
00C01DC9 push 0FFFFFFFFh
00C01DCB mov byte ptr [esi],al
00C01DCD lea eax,[ebp-44h]
00C01DD0 push 0
00C01DD2 mov dword ptr [ecx+14h],0Fh
00C01DD9 mov dword ptr [ecx+10h],0
00C01DE0 push eax
00C01DE1 mov byte ptr [ecx],bl
00C01DE3 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (0C02A80h)
00C01DE8 mov al,byte ptr [ebp-2Ch]
00C01DEB lea ecx,[b]
00C01DEE mov byte ptr [esi+1Ch],al
00C01DF1 mov dl,bl
00C01DF3 mov al,byte ptr [ebp-2Bh]
00C01DF6 mov byte ptr [esi+1Dh],al
00C01DF9 call replaceInstancesOf (0C017D0h)
std::vector<clause> b = makeDuplicate(f);
replaceInstancesOf(b, l, false);
00C01DFE add esp,14h
00C01E01 lea eax,[a]
00C01E04 mov ecx,esp
00C01E06 push eax
00C01E07 call std::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > >::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > > (0C02420h)
00C01E0C call dpll (0C01CC0h)
00C01E11 mov bl,al
00C01E13 mov ecx,esp
00C01E15 lea eax,[b]
00C01E18 push eax
00C01E19 call std::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > >::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > > (0C02420h)
00C01E1E call dpll (0C01CC0h)
00C01E23 mov ecx,dword ptr [b]
00C01E26 mov bh,al
00C01E28 add esp,0Ch
00C01E2B or bh,bl
00C01E2D test ecx,ecx
00C01E2F je dpll+1B4h (0C01E74h)
00C01E31 push dword ptr [ebp-4Ch]
00C01E34 mov edx,dword ptr [ebp-18h]
00C01E37 push ecx
00C01E38 call std::_Destroy_range1<std::allocator<std::vector<atom,std::allocator<atom> > >,std::vector<atom,std::allocator<atom> > *> (0C035E0h)
00C01E3D mov ecx,dword ptr [ebp-14h]
00C01E40 mov eax,2AAAAAABh
00C01E45 mov esi,dword ptr [b]
00C01E48 add esp,8
00C01E4B sub ecx,esi
00C01E4D imul ecx
00C01E4F sar edx,1
00C01E51 mov eax,edx
00C01E53 shr eax,1Fh
00C01E56 add eax,edx
00C01E58 push eax
00C01E59 push esi
00C01E5A call std::_Wrap_alloc<std::allocator<std::vector<atom,std::allocator<atom> > > >::deallocate (0C02D20h)
00C01E5F mov dword ptr [b],0
00C01E66 mov dword ptr [ebp-18h],0
00C01E6D mov dword ptr [ebp-14h],0
00C01E74 mov ecx,dword ptr [a]
00C01E77 test ecx,ecx
00C01E79 je dpll+1FEh (0C01EBEh)
00C01E7B push dword ptr [ebp-4Ch]
00C01E7E mov edx,dword ptr [ebp-24h]
00C01E81 push ecx
00C01E82 call std::_Destroy_range1<std::allocator<std::vector<atom,std::allocator<atom> > >,std::vector<atom,std::allocator<atom> > *> (0C035E0h)
00C01E87 mov ecx,dword ptr [ebp-20h]
00C01E8A mov eax,2AAAAAABh
00C01E8F mov esi,dword ptr [a]
00C01E92 add esp,8
00C01E95 sub ecx,esi
00C01E97 imul ecx
00C01E99 sar edx,1
00C01E9B mov eax,edx
00C01E9D shr eax,1Fh
00C01EA0 add eax,edx
00C01EA2 push eax
00C01EA3 push esi
00C01EA4 call std::_Wrap_alloc<std::allocator<std::vector<atom,std::allocator<atom> > > >::deallocate (0C02D20h)
00C01EA9 mov dword ptr [a],0
00C01EB0 mov dword ptr [ebp-24h],0
00C01EB7 mov dword ptr [ebp-20h],0
00C01EBE lea ecx,[ebp-44h]
00C01EC1 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (0C027A0h)
00C01EC6 mov ecx,dword ptr [f]
00C01EC9 test ecx,ecx
00C01ECB je dpll+23Bh (0C01EFBh)
00C01ECD push dword ptr [ebp-4Ch]
00C01ED0 mov edx,dword ptr [ebp+0Ch]
00C01ED3 push ecx
00C01ED4 call std::_Destroy_range1<std::allocator<std::vector<atom,std::allocator<atom> > >,std::vector<atom,std::allocator<atom> > *> (0C035E0h)
00C01ED9 mov ecx,dword ptr [ebp+10h]
00C01EDC mov eax,2AAAAAABh
00C01EE1 mov esi,dword ptr [f]
00C01EE4 add esp,8
00C01EE7 sub ecx,esi
00C01EE9 imul ecx
00C01EEB sar edx,1
00C01EED mov ecx,edx
00C01EEF shr ecx,1Fh
00C01EF2 add ecx,edx
00C01EF4 push ecx
00C01EF5 push esi
00C01EF6 call std::_Wrap_alloc<std::allocator<std::vector<atom,std::allocator<atom> > > >::deallocate (0C02D20h)
00C01EFB mov al,bh
00C01EFD mov ecx,dword ptr [ebp-0Ch]
00C01F00 mov dword ptr fs:[0],ecx
00C01F07 pop ecx
00C01F08 pop esi
00C01F09 pop ebx
00C01F0A mov ecx,dword ptr [ebp-10h]
00C01F0D xor ecx,ebp
00C01F0F call __security_check_cookie (0C080CCh)
00C01F14 mov esp,ebp
00C01F16 pop ebp
00C01F17 ret
The source interleaving is wrong. This is the correct place you want to look at:
00C01CFC call checkFalseClause (0C01660h)
00C01D01 test al,al
00C01D03 je dpll+4Ch (0C01D0Ch)
00C01D05 xor bh,bh
00C01D07 jmp dpll+206h (0C01EC6h)
As you can see, it goes to the expected address if the return value was nonzero.
The part you looked at is actually for the else if(checkAllClausesTrue(f)) and the jump is the one going to the else clause because the compiler negated the condition.

c++ for loop efficiency: body vs. afterthought

I found something interesting while on leetcode and wish someone can help explain the cause:
I was basically doing merge sort and used the fast slow pointer to find the mid pointer. Here're two versions of such code snippets:
1. update in afterthought
for (ListNode* fast=head;
fast->next && fast->next->next;
fast = fast->next->next, slow = slow->next) { }
2. update in body
for (ListNode* fast=head; fast->next && fast->next->next; ) {
fast = fast->next->next;
slow = slow->next;
}
Why is version 2 faster than the first one?
Compiler: g++ 4.9.2
It is unlikely that comma operation can significantly reduce the speed of for-loop.
I have made both variants and opened disassembly (in Visual Studio 2012) for them to see difference.
looks as:
for (ListNode* fast = head;
0022545E mov eax,dword ptr [head]
00225461 mov dword ptr [ebp-2Ch],eax
fast->next && fast->next->next;
00225464 jmp main+17Bh (022547Bh)
fast = fast->next->next, slow = slow->next) {
00225466 mov eax,dword ptr [ebp-2Ch]
00225469 mov ecx,dword ptr [eax+4]
0022546C mov edx,dword ptr [ecx+4]
0022546F mov dword ptr [ebp-2Ch],edx
00225472 mov eax,dword ptr [slow]
00225475 mov ecx,dword ptr [eax+4]
00225478 mov dword ptr [slow],ecx
0022547B mov eax,dword ptr [ebp-2Ch]
0022547E cmp dword ptr [eax+4],0
00225482 je main+192h (0225492h)
00225484 mov eax,dword ptr [ebp-2Ch]
00225487 mov ecx,dword ptr [eax+4]
0022548A cmp dword ptr [ecx+4],0
0022548E je main+192h (0225492h)
}
is:
for (ListNode* fast = head; fast->next && fast->next->next;) {
0024545E mov eax,dword ptr [head]
00245461 mov dword ptr [ebp-2Ch],eax
00245464 mov eax,dword ptr [ebp-2Ch]
00245467 cmp dword ptr [eax+4],0
0024546B je main+190h (0245490h)
0024546D mov eax,dword ptr [ebp-2Ch]
00245470 mov ecx,dword ptr [eax+4]
00245473 cmp dword ptr [ecx+4],0
00245477 je main+190h (0245490h)
fast = fast->next->next;
00245479 mov eax,dword ptr [ebp-2Ch]
0024547C mov ecx,dword ptr [eax+4]
0024547F mov edx,dword ptr [ecx+4]
00245482 mov dword ptr [ebp-2Ch],edx
slow = slow->next;
00245485 mov eax,dword ptr [slow]
00245488 mov ecx,dword ptr [eax+4]
0024548B mov dword ptr [slow],ecx
}
Only one jmp is the distinction.
Sorry, but I cannot see significant differences, so perhaps the performance problem is not in the place of that two statements.

Trying to understand ASM code

EDIT
I switched from memcmp to a home brewed 13 byte compare function and the homebrew doesnt have the extra instructions. So all I can guess is that the extra assembly is just a flaw in the optimizer.
if (!EQ13(&ti, &m_ti)) { // in 2014, memcmp was not being optimzied here
000007FEF91B2CFE mov rdx,qword ptr [rsp]
000007FEF91B2D02 movzx eax,byte ptr [rsp+0Ch]
000007FEF91B2D07 mov ecx,dword ptr [rsp+8]
000007FEF91B2D0B cmp rdx,qword ptr [r10+28h]
000007FEF91B2D0F jne TSccIter::SetTi+9Dh (7FEF91B2D1Dh)
000007FEF91B2D11 cmp ecx,dword ptr [r10+30h]
000007FEF91B2D15 jne TSccIter::SetTi+9Dh (7FEF91B2D1Dh)
000007FEF91B2D17 cmp al,byte ptr [r10+34h]
000007FEF91B2D1B je TSccIter::SetTi+0B1h (7FEF91B2D31h)
My homebrew isn't perfect in this case since it does 3 movs at the start even though it is unlikely to ever check past the first mov. I need to work on that part.
ORIGINAL QUESTION
Here is asm code from msvc 2010 showing how it can optimze a small, fixed-sized memcmp (in this case, 13 bytes). I've seen this type of optimization a lot in our code, but never with the last 6 lines. Can anyone tell me why the last 6 lines of assembly are there? TransferItem is 13 bytes so that explains the QWORD, DWORD, then BYTE cmps.
struct TransferItem {
char m_szCxrMkt1[3];
char m_szCxrOp1[3];
char m_chDelimiter;
char m_szCxrMkt2[3];
char m_szCxrOp2[3];
};
...
if (memcmp(&ti, &m_ti, sizeof(TransferItem))) {
2B8E lea rax,[rsp]
2B92 mov rdx,qword ptr [rax]
2B95 cmp rdx,qword ptr [r10+28h]
2B99 jne TSccIter::SetTi+0A2h (7FEF9302BB2h)
2B9B mov edx,dword ptr [rax+8]
2B9E cmp edx,dword ptr [r10+30h]
2BA2 jne TSccIter::SetTi+0A2h (7FEF9302BB2h)
2BA4 movzx edx,byte ptr [rax+0Ch]
2BA8 cmp dl,byte ptr [r10+34h]
2BAC jne TSccIter::SetTi+0A2h (7FEF9302BB2h)
2BAE xor eax,eax
2BB0 jmp TSccIter::SetTi+0A7h (7FEF9302BB7h)
2BB2 sbb eax,eax
2BB4 sbb eax,0FFFFFFFFh
2BB7 test eax,eax
2BB9 je TSccIter::SetTi+0CCh (7FEF9302BDCh)
Also what is the point of xor eax,eax which we know will be zero and then testing that for that known to be zero on line 2bb7?
Here is the whole function
// fWildCard means match certain fields to '**' in the db
// szCxrMkt1,2 are required and cannot be null, ' ', or '\0\0'.
// szCxrOp1,2 can be null, ' ', or '\0\0'.
TSccIter& SetTi(bool fWildCard, LPCSTR szCxrMkt1, LPCSTR szCxrOp1, LPCSTR szCxrMkt2, LPCSTR szCxrOp2) {
if (m_fSkipSet)
return *this;
m_iSid = -1; // resets the iterator to search from the start
// Pad the struct to 16 bytes so we can clear it with 2 QWORDS
// We use a temp, ti, to detect if the new transferitem has changed
class TransferItemPadded : public TransferItem {
char padding[16 - sizeof(TransferItem)]; // get us to 16 bytes
} ti;
U8(&ti) = U8(BUMP(&ti, 8)) = 0x2020202020202020; // 8 spaces
// copy in the params
CPY2(ti.m_szCxrMkt1, szCxrMkt1);
if (szCxrOp1 && *szCxrOp1)
CPY2(ti.m_szCxrOp1, szCxrOp1);
ti.m_chDelimiter = (fWildCard) ? '*' : ':'; // this controls wild card matching
CPY2(ti.m_szCxrMkt2, szCxrMkt2);
if (szCxrOp2 && *szCxrOp2)
CPY2(ti.m_szCxrOp2, szCxrOp2);
// see if different
if (memcmp(&ti, &m_ti, sizeof(TransferItem))) {
memcpy(&m_ti, &ti, sizeof(TransferItem));
m_fQryChanged = true;
}
return *this;
}
typedef unsigned __int64 U8;
#define CPY2(a,b) ((*(WORD*)a) = (*(WORD*)b))
And here's the whole asm
TSccIter& SetTi(bool fWildCard, LPCSTR szCxrMkt1, LPCSTR szCxrOp1, LPCSTR szCxrMkt2, LPCSTR szCxrOp2) {
2B10 sub rsp,18h
if (m_fSkipSet)
2B14 cmp byte ptr [rcx+0EAh],0
2B1B mov r10,rcx
return *this;
2B1E jne TSccIter::SetTi+0CCh (7FEF9302BDCh)
m_iSid = -1;
class TransferItemPadded : public TransferItem {
char padding[16 - sizeof(TransferItem)];
} ti;
U8(&ti) = U8(BUMP(&ti, 8)) = 0x2020202020202020;
2B24 mov rax,2020202020202020h
2B2E mov byte ptr [rcx+36h],0FFh
2B32 mov qword ptr [rsp],rax
2B36 mov qword ptr [rsp+8],rax
CPY2(ti.m_szCxrMkt1, szCxrMkt1);
2B3B movzx eax,word ptr [r8]
2B3F mov word ptr [rsp],ax
if (szCxrOp1 && *szCxrOp1)
2B43 test r9,r9
2B46 je TSccIter::SetTi+47h (7FEF9302B57h)
2B48 cmp byte ptr [r9],0
2B4C je TSccIter::SetTi+47h (7FEF9302B57h)
CPY2(ti.m_szCxrOp1, szCxrOp1);
2B4E movzx eax,word ptr [r9]
2B52 mov word ptr [rsp+3],ax
ti.m_chDelimiter = (fWildCard) ? '*' : ':';
2B57 mov eax,3Ah
2B5C mov ecx,2Ah
2B61 test dl,dl
2B63 cmovne eax,ecx
2B66 mov byte ptr [rsp+6],al
CPY2(ti.m_szCxrMkt2, szCxrMkt2);
2B6A mov rax,qword ptr [szCxrMkt2]
2B6F movzx ecx,word ptr [rax]
if (szCxrOp2 && *szCxrOp2)
2B72 mov rax,qword ptr [szCxrOp2]
2B77 mov word ptr [rsp+7],cx
2B7C test rax,rax
2B7F je TSccIter::SetTi+7Eh (7FEF9302B8Eh)
2B81 cmp byte ptr [rax],0
2B84 je TSccIter::SetTi+7Eh (7FEF9302B8Eh)
CPY2(ti.m_szCxrOp2, szCxrOp2);
2B86 movzx eax,word ptr [rax]
2B89 mov word ptr [rsp+0Ah],ax
if (memcmp(&ti, &m_ti, sizeof(TransferItem))) {
2B8E lea rax,[rsp]
2B92 mov rdx,qword ptr [rax]
2B95 cmp rdx,qword ptr [r10+28h]
2B99 jne TSccIter::SetTi+0A2h (7FEF9302BB2h)
2B9B mov edx,dword ptr [rax+8]
2B9E cmp edx,dword ptr [r10+30h]
2BA2 jne TSccIter::SetTi+0A2h (7FEF9302BB2h)
2BA4 movzx edx,byte ptr [rax+0Ch]
2BA8 cmp dl,byte ptr [r10+34h]
2BAC jne TSccIter::SetTi+0A2h (7FEF9302BB2h)
2BAE xor eax,eax
2BB0 jmp TSccIter::SetTi+0A7h (7FEF9302BB7h)
2BB2 sbb eax,eax
2BB4 sbb eax,0FFFFFFFFh
2BB7 test eax,eax
2BB9 je TSccIter::SetTi+0CCh (7FEF9302BDCh)
memcpy(&m_ti, &ti, sizeof(TransferItem));
2BBB mov rax,qword ptr [rsp]
m_fQryChanged = true;
2BBF mov byte ptr [r10+0E9h],1
2BC7 mov qword ptr [r10+28h],rax
2BCB mov eax,dword ptr [rsp+8]
2BCF mov dword ptr [r10+30h],eax
2BD3 movzx eax,byte ptr [rsp+0Ch]
2BD8 mov byte ptr [r10+34h],al
}
return *this;
2BDC mov rax,r10
}
2bb7 can be reached by different code paths: via taken jumps at 2b99, 2ba2 and 2bac, as well as directly when none of the conditional jumps is taken. The xor eax,eax is only executed at the last path, and it ensures that eax is 0 - which is apparently not the case otherwise.
The last 6 lines return the value in eax == 0 for a match, and also set the SF and ZF condition codes.
test eax, eax will test whether eax AND eax == 0. The following je will jump if zero.
And xor eax, eax is an efficient way to encode "eax = 0". It is more efficient than mov eax, 0
EDIT: Initially misread the question. It looks like something will happen at "TSccIter::SetTi+0A7h" which should change the value?
Also, the SBB trick to replicate the carry(2BB2-2BB4) is explained here:
http://compgroups.net/comp.lang.asm.x86/trick-with-sbb-instruction/20164

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call

#include<stdio.h>
int a[100];
int main(){
char UserName[100];
char *n=UserName;
char *q=NULL;
char Serial[200];
q=Serial;
scanf("%s",UserName);
//this is about
__asm{
pushad
mov eax,q
push eax
mov eax,n
push eax
mov EAX,EAX
mov EAX,EAX
CALL G1
LEA EDX,DWORD PTR SS:[ESP+10H]
jmp End
G1:
SUB ESP,400H
XOR ECX,ECX
PUSH EBX
PUSH EBP
MOV EBP,DWORD PTR SS:[ESP+40CH]
PUSH ESI
PUSH EDI
MOV DL,BYTE PTR SS:[EBP]
TEST DL,DL
JE L048
LEA EDI,DWORD PTR SS:[ESP+10H]
MOV AL,DL
MOV ESI,EBP
SUB EDI,EBP
L014:
MOV BL,AL
ADD BL,CL
XOR BL,AL
SHL AL,1
OR BL,AL
MOV AL,BYTE PTR DS:[ESI+1]
MOV BYTE PTR DS:[EDI+ESI],BL
INC ECX
INC ESI
TEST AL,AL
JNZ L014
TEST DL,DL
JE L048
MOV EDI,DWORD PTR SS:[ESP+418H]
LEA EBX,DWORD PTR SS:[ESP+10H]
MOV ESI,EBP
SUB EBX,EBP
L031:
MOV AL,BYTE PTR DS:[ESI+EBX]
PUSH EDI
PUSH EAX
CALL G2
MOV AL,BYTE PTR DS:[ESI+1]
ADD ESP,8
ADD EDI,2
INC ESI
TEST AL,AL
JNZ L031
MOV BYTE PTR DS:[EDI],0
POP EDI
POP ESI
POP EBP
POP EBX
ADD ESP,400H
RETN
L048:
MOV ECX,DWORD PTR SS:[ESP+418H]
POP EDI
POP ESI
POP EBP
MOV BYTE PTR DS:[ECX],0
POP EBX
ADD ESP,400H
RETN
G2:
MOVSX ECX,BYTE PTR SS:[ESP+4]
MOV EAX,ECX
AND ECX,0FH
SAR EAX,4
AND EAX,0FH
CMP EAX,0AH
JGE L009
ADD AL,30H
JMP L010
L009:
ADD AL,42H
L010:
MOV EDX,DWORD PTR SS:[ESP+8]
CMP ECX,0AH
MOV BYTE PTR DS:[EDX],AL
JGE L017
ADD CL,61H
MOV BYTE PTR DS:[EDX+1],CL
RETN
L017:
ADD CL,45H
MOV BYTE PTR DS:[EDX+1],CL
RETN
End:
mov eax,eax
popad
}
printf("%s\n",Serial);
return 0;
}
Can you help me?
this problem about Asm,I don't know why cause this result.
this program is very easy,and it about a program of internal code.
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
It seems the two parameters which are pushed onto the stack before the call to G1 are never popped from the stack.
Possibly it happens because at the beginning of the function G1 you SUB ESP,400H, after L031 you make ADD ESP,8 and at the end you ADD ESP,400H. It seems like ESP before the G1 call is by 8 less then after call.
EDIT: Regarding to the coding style of assembly function please see this. Here briefly described what are the caller's responsibilities and what are callee's responsibilities, that are regarded to ESP.

Default initialization with default constructor for primitive data types

Are there any drawbacks / disadvantages using the default constructor for default initialization for primitive data types?
For example
class MyClass
{
public:
MyClass();
private:
int miInt;
double mdDouble;
bool mbBool;
};
Using this constructor:
MyClass::MyClass()
: miInt(int())
, mdDouble(double())
, mbBool(bool())
{}
instead of this:
MyClass::MyClass()
: miInt(0)
, mdDouble(0.0)
, mbBool(false)
{}
No, and the compiler will most probably generate the same code for both.
With optimization off, the following code is generated:
MyClass::MyClass()
: miInt(0)
, mdDouble(0.0)
, mbBool(false)
{}
012313A0 push ebp
012313A1 mov ebp,esp
012313A3 sub esp,0CCh
012313A9 push ebx
012313AA push esi
012313AB push edi
012313AC push ecx
012313AD lea edi,[ebp-0CCh]
012313B3 mov ecx,33h
012313B8 mov eax,0CCCCCCCCh
012313BD rep stos dword ptr es:[edi]
012313BF pop ecx
012313C0 mov dword ptr [ebp-8],ecx
012313C3 mov eax,dword ptr [this]
012313C6 mov dword ptr [eax],0
012313CC mov eax,dword ptr [this]
012313CF fldz
012313D1 fstp qword ptr [eax+8]
012313D4 mov eax,dword ptr [this]
012313D7 mov byte ptr [eax+10h],0
012313DB mov eax,dword ptr [this]
012313DE pop edi
012313DF pop esi
012313E0 pop ebx
012313E1 mov esp,ebp
012313E3 pop ebp
012313E4 ret
and
MyClass::MyClass()
: miInt(int())
, mdDouble(double())
, mbBool(bool())
{}
001513A0 push ebp
001513A1 mov ebp,esp
001513A3 sub esp,0CCh
001513A9 push ebx
001513AA push esi
001513AB push edi
001513AC push ecx
001513AD lea edi,[ebp-0CCh]
001513B3 mov ecx,33h
001513B8 mov eax,0CCCCCCCCh
001513BD rep stos dword ptr es:[edi]
001513BF pop ecx
001513C0 mov dword ptr [ebp-8],ecx
001513C3 mov eax,dword ptr [this]
001513C6 mov dword ptr [eax],0
001513CC mov eax,dword ptr [this]
001513CF fldz
001513D1 fstp qword ptr [eax+8]
001513D4 mov eax,dword ptr [this]
001513D7 mov byte ptr [eax+10h],0
001513DB mov eax,dword ptr [this]
001513DE pop edi
001513DF pop esi
001513E0 pop ebx
001513E1 mov esp,ebp
001513E3 pop ebp
001513E4 ret
As you can see, it's identical.
There is more consistent syntax for creating default objects:
MyClass::MyClass()
: miInt()
, mdDouble()
, mbBool()
{
}
That is, don't pass anything. Just write T() and the object will be created with default value. It is also consistent with class types (think of POD types)!