使用GCC在静态内存中分配C ++类

时间:2013-01-29 16:58:18

标签: c++ gcc heap

我想在静态内存中分配许多类,而不是使用堆来使用C ++进行嵌入式项目。目前,我们在专门用于静态分配的类的单独CPP文件中对类进行以下操作:

Config cfg(spi);

这可以从我所知道的分配到堆上。单步执行汇编代码,我看到malloc最终被调用。堆栈跟踪如下所示:

malloc()
__register_exitproc()
__static_initialization_and_destruction_0()
_GLOBAL__sub_I_periodic()
__libc_init_array
<reset vector>

Config类如下所示:

class Config
{
   public:
      Config(SPIDriver &spi);
      virtual ~Config();
   private:
      SPIDriver *_spi;
}

然后实现如下:

Config::Config(SPIDriver &spi)
: _spi(&spi) {}
Config::~Config() {_spi = NULL;}

有没有办法强制GCC将它放在静态内存而不是堆上?提前谢谢!

3 个答案:

答案 0 :(得分:3)

我终于找到了我的问题。 Zack是对的,正在调用__register_exitproc,并将析构函数注册到链表中。这就是调用malloc的原因,因此为链表分配空间。我们的程序运行在裸机ARM(Cortex M4)上。所以这些课程永远不会被破坏,因为当我们断电时,电力将会丢失。幸运的是__register_exitproc是一个弱函数,所以我创建了这个函数的另一个版本,什么都不做。动态内存分配没有任何问题,这是有效的,但由于某种原因,在__register_exitproc中,它试图从具有奇数(字面)地址的内存位置将32位值加载到ARM GPR中。这会导致引发硬故障异常。通过重写__register_exirproc,我们可以防止发生此异常。另外,我们摆脱了系统启动时的动态内存分配。

希望这有助于其他人。一如既往,谢谢或帮助!!!

答案 1 :(得分:2)

你所有的混乱都是事实,你不知道cfg是在堆上分配还是不分配。只是在启动时调用malloc意味着什么 - libc甚至为void程序调用malloc几次。

让我向您解释如何确定数据的位置。

让我们从您的代码开始,修改一些:

#include "stdlib.h"

class Config
{
   public:
     Config(int spi) {_spi = &spi;}
     virtual ~Config() {;}
   private:
     int *_spi;
};

Config cfg(2);

int
main(void)
{
  int *x = new int(2);
  return 0;
}

现在让我们用g++ -g -O0 statstorage.cpp -static

编译它

你有一个.out文件。现在我们必须查看您的数据实际位置。首先使用命令行调用gdb,如下所示:

echo -e "start\nstep\np/x &cfg\np/x x\nquit" > .gdbinit && gdb a.out

你会得到这样的输出:

$1 = 0x6add50
$2 = 0x6c5670

其中0x6add50是cfg的地址,0x6c5670是动态分配的x指针的地址。

现在让我们调用readelf,就像readelf -S a.out

一样

看看各个部分。输出是(对于我的电脑)38个部分。我们需要的只是Address字段和Size字段。我有:

                                Address               Size
[23] .bss              ...  00000000006add00 ... 0000000000014d38
[24] __libc_freeres_pt ...  00000000006c2a38 ... 0000000000000030

__libc_freeres_pt是最后一个非空地址最大的部分。

我们可以看到,0x6c5670在加载的二进制文件之外(在堆本身中),而cfg在bss部分内。

这会产生,taht cfg 是静态分配的。

答案 2 :(得分:0)

如果你还没有“获得”malloc [和相关的gubbins],那么你将需要实现自己的全局新函数,并使用例如大量的char作为你的“堆”。

here是上一个问题,解释了如何编写自己的新/删除功能。您还应该能够编写mallocfree函数来实现C样式分配的相同功能。

另一种选择当然是重写glibc或你正在使用的库是如何工作的。如果你只做一些非常简单的事情,也可以选择。但我的猜测是,迟早你需要动态分配,所以我认为自己编写[或改编现有的]是你最好的选择。