2014-05-13 1 views
0

편집은 ASM 코드

나는 13 바이트 기능과 사제 나던 비교 추가 지침을 양조 집에 memcmp는로 전환을 이해하려고 노력. 따라서 추측 할 수있는 것은 추가 어셈블리가 옵티 마이저의 결함 일 뿐이라는 것입니다. 최초의 MOV 과거를 확인하지 않을 경우에도 처음에 3 MOVS를 않기 때문에

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) 

내 사제는이 경우 완벽하지 않습니다. 나는 그 부분에 대해 연구해야한다.

원래 질문 여기

는 (이 경우, 13 바이트)은 작은 고정 된 크기를 optimze memcmp는 방법을 나타내는 MSVC 2010 ASM 코드이다. 나는이 유형의 최적화를 코드에서 많이 보았지만 마지막 6 행에서는 결코 사용하지 않았다. 누구나 왜 어셈블리의 마지막 6 라인이 거기에 있는지 말해 줄 수 있습니까? TransferItem은 13 바이트이므로 QWORD, DWORD, 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) 

또한 XOR의 EAX, 우리는 0이됩니다 알고 EAX의 포인트는 무엇이며, 그 다음 라인 2bb7에 제로 것으로 알려져 그것에 대해 그 테스트?

가 여기에 전체 기능

// 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)) 

입니다 그리고 여기에 전체 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 
} 
+0

아마도 마지막 6 행은 이미 다른 소스 행을위한 것이고, 나는 또한 그것들이 반복문의 일부라고 추측합니다. 따라서 첫 번째 반복 동안 겉보기에 무의미한 테스트입니다. – Jester

+0

루프가 없습니다. 함수가 종료됩니다. 함수의 전체 코드를 추가해야합니까? – johnnycrash

+1

귀하의 질문은 실제로 어셈블리 코드를 이해하는 것이 아니라 옵티마이 저가 여기서 다소 차선의 코드를 생성하는 이유를 이해하는 것입니다. 거기에 대한 흥미로운 대답이있을 수 있습니다,하지만 나는 추측 만있을 것으로 판단됩니다. –

답변

-1

테스트 EAX의, EAX는 EAX 및 EAX == 0은 다음 JE가 제로 경우 이동합니다 여부를 테스트합니다.

xor eax, eax는 "eax = 0"을 인코딩하는 효율적인 방법입니다. mov eax보다 더 효율적입니다. 0

EDIT : 처음에는 질문을 읽지 않습니다. "TSccIter :: SetTi + 0A7h"에서 값이 변경되어야합니다.

http://compgroups.net/comp.lang.asm.x86/trick-with-sbb-instruction/20164

+1

이것이 사실이지만, 질문에 대답하지 않습니다. 이것이 알려진 0 값을 테스트하는 이유입니다. – Jester

+0

@Jester. 감사. 정식 주목. 편집을 참조하십시오. –

+0

'+ 0A7h'은 '2BB7'이며 0을 테스트합니다. 그 사이에 'eax'를 바꿀 수있는 것은 없습니다. – Jester

0

마지막 6 개 라인들이 일치 EAX == 0의 값을 반환하고, 또한 설정 :

또한 반송를 복제 SBB 트릭 (2BB2-2BB4)는 여기 설명 SF 및 ZF 조건 코드

+0

답변 해 주셔서 감사합니다! 이제 전체 코드 블록에 추가했습니다. 이 포인터를 rax에 반환하지만 r10으로 덮어 쓰면 0을 요구하지 않습니다. 나는 생각한다. .. 내가 묻고있는 thats thats! – johnnycrash

+0

조건 플래그를 설정하면 if가 je 행과 비교 한 결과를 테스트 할 수 있습니다. eax가 사용되지 않는 것처럼 보이므로 eax는 단지 임시 값입니다. – stark

0

2bb7는 다른 코드 경로에 의해 도달 될 수 촬영 2b99, 2ba22bac에서 점프뿐만 아니라 직접 조건부 점프 전혀 취하지 비아. xor eax,eax은 마지막 경로에서만 실행되며 eax이 0인지 확인합니다. 그렇지 않은 경우에는 그렇지 않습니다.

+1

그래도 괜찮지 만'2BB0'에서'2BB7'로 점프 할 시점이 없기 때문에 바로'2BDC'로 가야합니다. – Jester

+0

답변 주셔서 감사하지만 Jester가 옳습니다. 컴파일 타임에 답변을 알고있을 때 비교를 수행하는 데있어 옵티 마이저가 아닌 다른 이유가 있는지 알고 싶습니다 (괴짜 유머). – johnnycrash