【问题标题】:Looking for unnecessary buffer copies in assembly code在汇编代码中寻找不必要的缓冲区副本
【发布时间】:2026-02-07 03:45:02
【问题描述】:

我正在使用适用于 Windows Mobile 6 ARMV4I 的 Visual Studio 2008 C++,我正在尝试学习阅读 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} 
--- ...\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 结构被复制到哪里?

【问题讨论】:

  • 仅通过查看 C++ 代码,我可以看到 Buf 在两个位置被复制:Foo 构造函数,以及从 Create 函数返回时。
  • @Etienne de Martel - 创建函数返回的Buf 应该被 RVO 优化掉。编译器也可以优化 Foo 构造函数中的副本。我不知道。我试图了解如何阅读程序集以了解应用了哪些优化。
  • @Heandel - 如果没有应用优化,或者如果您知道编译器可以应用的所有优化以及它们将在什么情况下应用,这可能是正确的。我没有。
  • @PaulH 你在做微优化吗?
  • @Etienne - 对 OP 上一个问题的回复建议在 Create 调用中使用参考以避免其中一个副本,仅供参考。 RVO 可能会避免第二个,具体取决于编译器。

标签: c++ optimization assembly windows-mobile arm


【解决方案1】:

分析Create 相当简单,因为代码很短。 NRVO 显然已经应用在这里,因为 return 语句没有生成任何指令,返回值是在r0 中就地构造的。

对于 Foo::Foo 的传递值参数将进行的复制稍微难以分析,但在对 CreateFoo::Foo 的调用之间,复制必须采用的代码很少地方,没有什么可以做一个std::vector的深拷贝。所以看起来那个副本也被淘汰了。另一种可能性是Foo::Foo 的自定义调用约定,其中参数实际上是通过引用传递并在函数内部复制。您需要能够进行更深入的 ARM 汇编分析的人来排除这种可能性。

【讨论】:

    【解决方案2】:

    缓冲区将被复制;您正在使用 c++ 的按值传递语义;没有编译器会为您优化。它的复制方式将取决于 std::vector 的复制构造函数。

    【讨论】:

    • C++ 标准特别允许省略复制构造函数调用。
    • @user539312:复制省略是少数允许改变行为的优化之一。 “当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数有副作用。在这样的情况下在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本应被销毁的较晚时间优化。”