在汇编代码中查找不必要的缓冲区副本
Looking for unnecessary buffer copies in assembly code
我正在使用Visual Studio 2008 c++ for Windows Mobile 6 ARMV4I,我正在学习阅读由VS生成的ARM汇编代码,以尽量减少应用程序中不必要的缓冲区副本。因此,我创建了一个测试应用程序,如下所示:
#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;
}
我想了解Create
返回的缓冲区是否在给定给Foo
构造函数时被复制,或者编译器是否能够优化该复制。在启用了优化的发布版本中,这会生成如下的程序集:
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}
--- ...stlportstl_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
结构被复制的位置?
分析Create
相当简单,因为代码很短。这里显然应用了NRVO,因为返回语句没有生成指令,返回值是在r0
中就地构造的。
对Foo::Foo
的按值传递参数进行的复制稍微难以分析,但是在调用Create
和Foo::Foo
之间很少有代码需要进行复制,并且没有任何代码会对std::vector
进行深度复制。所以看起来这个拷贝也被消除了。另一种可能性是Foo::Foo
的自定义调用约定,其中参数实际上是通过引用传递的,并在函数内部复制。你需要一个能够更深入地分析ARM汇编的人,我要排除这种可能性。
缓冲区将被复制;你正在使用c++的按值传递语义;没有编译器会为你优化。如何复制取决于std::vector的复制构造函数。
相关文章:
- C++字符*缓冲区的大小
- 为什么msgrcv()将垃圾字符馈送到缓冲区
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- ostream过载时的缓冲区冲洗
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- Xaudio2在更改缓冲区或循环时弹出声音
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 用callgrind追踪不必要的副本
- 多线程双缓冲区
- Android P-9.0.0_r53 Logcat主缓冲区超出定义大小
- 套接字读取后,我在缓冲区中看到意外输入
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- std::带有自定义缓冲区的 iostream 不允许我写入
- 如何避免将数据缓冲区的额外副本复制到字符串?
- 为什么无法创建流缓冲区的副本?
- 字符串副本表示缓冲区太小,strcpy_s源问题
- 在汇编代码中查找不必要的缓冲区副本