C++11 当硬编码字节数组的长度超过0xF时,它将作为数据结束

C++11 当硬编码字节数组的长度超过0xF时,它将作为数据结束,c++11,gcc,clang,c++14,llvm,C++11,Gcc,Clang,C++14,Llvm,我的目标是让我的.rdata部分包含尽可能少的内容,并让编译器尽可能使用文本/代码部分。现在我有一个小问题,我希望有人能帮助我。在CLAN和GCC中,当您编译以下C++代码时(注意数组长度为15字节): #包括 void_start(){ 无符号字符字节[]={0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF}; MessageBoxA(空ptr,(char*)字节,“Hi”,MB_OK); } 这是我想要的编译。所有硬编码

我的目标是让我的
.rdata
部分包含尽可能少的内容,并让编译器尽可能使用文本/代码部分。现在我有一个小问题,我希望有人能帮助我。在CLAN和GCC中,当您编译以下C++代码时(注意数组长度为15字节):

#包括
void_start(){
无符号字符字节[]={0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF};
MessageBoxA(空ptr,(char*)字节,“Hi”,MB_OK);
}
这是我想要的编译。所有硬编码数据都很好地嵌入到代码本身中(它使用即时MOV),因此不会向任何数据节添加任何内容,也不会引用任何数据节。以下是IDA PRO反编译:

如果将另一个字节添加到数组中,并使其长度超过15个字节(现在总共16个字节),如下所示:

#include <windows.h>

void _start() {
  unsigned char bytes[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10};
  MessageBoxA(nullptr, (char*)bytes, "Hi", MB_OK);
}
#包括
void_start(){
无符号字符字节[]={0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10};
MessageBoxA(空ptr,(char*)字节,“Hi”,MB_OK);
}
然后编译器以我想要摆脱的方式运行。也就是说,它不再将其嵌入到代码中,而是将所有内容移动到数据部分中(位于
.rdata
中的
unk_100402000
):

我在多个编译器上测试了这段代码。MSVC总是将这些硬编码字节数组很好地嵌入到代码本身中,不管它有多长。既然我真的想继续使用Clang和GCC,我希望有一个解决方案

我需要限制
.rdata
部分的使用的原因是,我正在做一个实验项目,在这个项目中,文本/代码部分之外的任何引用或访问都将导致性能严重下降。在文本/代码部分之外,每次访问速度大约慢1000倍。因此,我确实需要让编译器尽可能多地使用文本/代码部分

问题: 如何使Clang/GCC编译15+长硬编码字节数组,以便它在堆栈上使用即时mov操作,而不是使用
.rdata
部分?如果无法通过编译器选项进行更改,是否可以通过编译器过程更改此行为?我也很好,任何肮脏的黑客,我需要申请到叮当声,以使这项工作

我知道我可以将较长的字节数组拆分为较小的单个字节数组,但这不是我正在寻找的解决方案

提前感谢您提供的任何帮助

叮当声版本:4.0.1

目前的最佳解决方案 如下图所示。大的硬编码字节数组被编译为堆栈上的多条立即mov指令,因此从不引用数据段中的任何内容。这正是我要找的。是否有多种方法可以实现相同的行为

如果数据是静态的(不是功能范围的本地数据),则可以执行以下操作:

 void Check( unsigned const char* x);

 void Do() {
   static const unsigned char bytes[] __attribute__((section(".text"))) =
   {
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
       0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10
   };
   Check( bytes );
 }

 int main()
 {
     Do();
 }
结果是:

Disassembly of section .text:
     08048580 <Do()>:
  8048580:  83 ec 18                sub    $0x18,%esp
  8048583:  68 a0 85 04 08          push   $0x80485a0
  8048588:  e8 e3 ff ff ff          call   8048570 <Check(unsigned char const*)>
  804858d:  83 c4 1c                add    $0x1c,%esp
  8048590:  c3                      ret

  ... much other disassembled code follows ...

 080485a0 <Do()::bytes>:
  80485a0:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  80485b0:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  80485c0:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  80485d0:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  80485e0:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  80485f0:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  8048600:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
  8048610:  01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10     ................
节的反汇编。文本:
08048580 :
8048580:83 ec 18子$0x18,%esp
8048583:68 a0 85 04 08推送$0x80485a0
8048588:e8 e3 ff ff ff呼叫8048570
804858d:83 c4 1c添加$0x1c,%esp
8048590:c3 ret
... 许多其他反汇编代码如下。。。
080485a0:
80485a0:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
80485b0:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
80485c0:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
80485d0:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
80485e0:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
80485f0:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
8048600:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
8048610:01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10。。。。。。。。。。。。。。。。
所有内容仅在.text节中

如果数据必须是本地数据,您只需使用以下命令手动复制:

void Check( unsigned const char* x); 

template< typename IN, typename OUT, unsigned int size >
void Cpy( IN (&in)[size], OUT (&out)[size] )
{   
    static_assert( sizeof( IN) == sizeof( OUT ) );
    memcpy( out, in, size * sizeof(OUT) );
}   

void Do() {
  static const unsigned char static_bytes[] __attribute__((section(".text"))) = 
  {   
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10
  };  

  unsigned char bytes[ sizeof( static_bytes )]; 
  Cpy( static_bytes, bytes );


  Check( bytes );
}   

int main()
{   
    Do();
}
无效检查(无符号常量字符*x);
模板
无效Cpy(输入(&IN)[大小],输出(&OUT)[大小])
{   
静态断言(sizeof(IN)=sizeof(OUT));
memcpy(输出、输入、大小*尺寸f(输出));
}   
void Do(){
static const unsigned char static_bytes[]___属性__((节(“.text”))=
{   
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10,
0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8、0x9、0xA、0xB、0xC、0xD、0xE、0xF、0x10
};  
无符号字符字节[sizeof(static_字节)];
Cpy(静态字节,字节);
检查(字节);
}   
int main()
{   
Do();
}

所有内容仍在.text部分中,但您必须自己将数据复制到本地上下文中。我无法强迫编译器自己这么做。

如果你负担得起性能损失,类似这样的东西似乎对clang有效;在我的测试中,它编译为一组即时mov(在修复属性后,gcc也可以工作):

模板
结构noopt{[[clang::optnone]]无符号字符运算符()()常量{return C;};
#定义NODATA(v)(noopt{}())
int main(){
无符号字符字节[]={NODATA(0x1)、NODATA(0x2)、NODATA(0x3)、NODATA(0x4),};
// ...
}
void Check( unsigned const char* x); 

template< typename IN, typename OUT, unsigned int size >
void Cpy( IN (&in)[size], OUT (&out)[size] )
{   
    static_assert( sizeof( IN) == sizeof( OUT ) );
    memcpy( out, in, size * sizeof(OUT) );
}   

void Do() {
  static const unsigned char static_bytes[] __attribute__((section(".text"))) = 
  {   
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10,
      0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10
  };  

  unsigned char bytes[ sizeof( static_bytes )]; 
  Cpy( static_bytes, bytes );


  Check( bytes );
}   

int main()
{   
    Do();
}
template <unsigned char C>
struct noopt { [[clang::optnone]] unsigned char operator()() const { return C; } };

#define NODATA(v) (noopt<(v)>{}())

int main(){
    unsigned char bytes[] = { NODATA(0x1), NODATA(0x2), NODATA(0x3), NODATA(0x4), };

    // ...
}
#include <iostream>
#include <cstring>

void f(int num) {
    char r0[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    char r1[15] = {1,2,9,4,5,6,7,3,9,10,11,12,13,14,15};
    char r2[14] = {3,9,2,3,4,5,6,7,8,9,10,11,12};

    char r[44];

    std::memcpy(r, r0, 15);
    std::memcpy(r + 15, r1, 15);
    std::memcpy(r + 30, r2, 14);

    std::cout << r;
}