2011-04-26 3 views
3

Windows Mobile 6 ARMV4I 용 Visual Studio 2008 C++을 사용하고 있으며 VS에서 생성 된 ARM 어셈블리 코드를 읽고 응용 프로그램 내에서 비정상적인 버퍼 복사본을 최소화하는 방법을 배우려고합니다. 그래서, 나는이처럼 보이는 테스트 응용 프로그램을 만든 다음 Foo 생성자 또는 컴파일러가 최적화 할 수있는 경우 주어 졌을 때 Create에 의해 반환 된 버퍼가 복사되는 경우 이해하고 싶습니다 어셈블리 코드에서 불필요한 버퍼 복사본 찾기

#include <vector> 

typedef std::vector<BYTE> Buf; 

class Foo 
{ 
public: 
    Foo(Buf b) { b_.swap(b); }; 
private: 
    Buf b_; 
}; 

Buf Create() 
{ 
    Buf b(1024); 
    b[ 0 ] = 0x0001; 
    return b; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Foo f(Create()); 
    return 0; 
} 

멀리 복사하십시오.

class Foo 
{ 
public: 
    Foo(Buf b) { b_.swap(b); }; 
0001112C stmdb  sp!, {r4 - r7, lr} 
00011130 mov   r7, r0 
00011134 mov   r3, #0 
00011138 str   r3, this 
0001113C str   r3, [r7, #4] 
00011140 str   r3, [r7, #8] 
00011144 ldr   r3, this 
00011148 ldr   r2, this 
0001114C mov   r5, r7 
00011150 mov   r4, r1 
00011154 str   r3, this, #4 
00011158 str   r2, this, #4 
0001115C mov   r6, r1 
00011160 ldr   r2, this 
00011164 ldr   r3, this 
00011168 mov   lr, r7 
0001116C str   r3, this 
00011170 str   r2, this 
00011174 ldr   r2, [lr, #8]! 
00011178 ldr   r3, [r6, #8]! 
0001117C str   r3, this 
00011180 str   r2, this 
00011184 ldr   r3, this 
00011188 movs  r0, r3 
0001118C beq   |Foo::Foo + 0x84 (111b0h)| 
00011190 ldr   r3, [r1, #8] 
00011194 sub   r1, r3, r0 
00011198 cmp   r1, #0x80 
0001119C bls   |Foo::Foo + 0x80 (111ach)| 
000111A0 bl   000112D4 
000111A4 mov   r0, r7 
000111A8 ldmia  sp!, {r4 - r7, pc} 
000111AC bl   |stlp_std::__node_alloc::_M_deallocate (11d2ch)| 
000111B0 mov   r0, r7 
000111B4 ldmia  sp!, {r4 - r7, pc} 
--- ...\stlport\stl\_vector.h ----------------------------- 
// snip! 
--- ...\asm_test.cpp 
    private: 
     Buf b_; 
    }; 

Buf Create() 
{ 
00011240 stmdb  sp!, {r4, lr} 
00011244 mov   r4, r0 
    Buf b(1024); 
00011248 mov   r1, #1, 22 
0001124C bl   |  
    b[ 0 ] = 0x0001; 
00011250 ldr   r3, [r4] 
00011254 mov   r2, #1 
    return b; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
00011264 str   lr, [sp, #-4]! 
00011268 sub   sp, sp, #0x18 
    Foo f(Create()); 
0001126C add   r0, sp, #0xC 
00011270 bl   |Create (11240h)| 
00011274 mov   r1, r0 
00011278 add   r0, sp, #0 
0001127C bl   |Foo::Foo (1112ch)| 
    return 0; 
00011280 ldr   r0, argc 
00011284 cmp   r0, #0 
00011288 beq   |wmain + 0x44 (112a8h)| 
0001128C ldr   r3, [sp, #8] 
00011290 sub   r1, r3, r0 
00011294 cmp   r1, #0x80 
00011298 bls   |wmain + 0x40 (112a4h)| 
0001129C bl   000112D4 
000112A0 b   |wmain + 0x44 (112a8h)| 
000112A4 bl   |stlp_std::__node_alloc::_M_deallocate (11d2ch)| 
000112A8 mov   r0, #0 
} 

나는 Buf 구조가 복사되는 위치를 이해하는 어셈블리 코드에서 어떤 패턴을 볼 수 : 최적화가 켜져와 릴리스에서이 같은 어셈블리를 생성, 구축

+2

C++ 코드에서보기가 쉽지 않습니까? 모든 사본을 예측할 수 있습니다. –

+1

C++ 코드를 살펴보면'Buf'가'Foo' 생성자와'Create' 함수에서 반환 될 때 두 곳에서 복사된다는 것을 알 수 있습니다. –

+0

@Etienne de Martel - create 함수가 반환 한'Buf'는 RVO에 의해 최적화되어야합니다. 컴파일러는'Foo' 생성자에서도 복사본을 최적화 할 수 있습니다. 나는 모른다. 최적화를 적용 할 수있는 어셈블리를 어떻게 읽을 수 있는지 이해하려고합니다. – PaulH

답변

0

Create을 분석하는 것은 코드가 매우 짧기 때문에 매우 간단합니다. NRVO는 return 문에서 지침이 생성되지 않았으므로 분명히 여기에 적용되었으며 반환 값은 r0에서 그대로 구성됩니다.

Foo::Foo에 대한 일어날 사본의 패스에 의해 값 매개 변수를 분석 할 약간 어렵습니다,하지만 복사가 수행해야 CreateFoo::Foo에 대한 호출 사이에 아주 작은 코드가, 그리고 아무것도 그 std::vector의 사본을 작성합니다. 복사가 제거 된 것처럼 보입니다. 다른 가능성은 Foo::Foo에 대한 사용자 지정 호출 규칙입니다. 인수는 실제로 참조로 전달되고 함수 내에서 복사됩니다. ARM 어셈블리 분석을 더 깊이 할 수있는 사람이 필요합니다.

-2

버퍼가 복사됩니다. 당신은 C++의 값에 의한 의미 전달을 사용하고 있습니다; 컴파일러는 그것을 최적화하지 않습니다. 그 복사 방법은 std :: vector의 복사 생성자에 의존합니다.

+0

C++ 표준은 특히 복사 생성자 호출의 추출을 허용합니다. –

+0

http://itackoverflow.com/questions/2143787/what-is-copy-elision-and-how-does-it-optimize-the-copy-and-swap-idiom – tworivers

+2

@ user539312 : 복사 elision은 몇 가지 최적화가 동작을 변경할 수 있습니다. "특정 기준이 충족되면 객체의 복사/이동 생성자 및/또는 소멸자에 부작용 **이 있어도 구현시 클래스 객체 **의 복사/이동 구성을 생략 할 수 있습니다.이 경우, 구현은 생략 된 복사/이동 작업의 소스와 대상을 동일한 객체를 참조하는 두 가지 다른 방법으로 취급하며 두 객체 최적화없이 파괴되었을 것입니다. " –

관련 문제