2

我想在静态内存中分配大量类,而不是将堆用于使用 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 将其放置在静态内存中而不是堆中?提前致谢!

4

3 回答 3

3

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

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

于 2013-01-30T15:47:48.687 回答
2

您所有的混乱实际上都来自事实,即您不知道 cfg 是否在堆上分配。只是在启动时在某处调用 malloc 没有任何意义——即使对于 void 程序,libc 也会多次调用 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
[23] .bss              ...  00000000006add00 ... 0000000000014d38
[24] __libc_freeres_pt ...  00000000006c2a38 ... 0000000000000030

并且 __libc_freeres_pt 是具有最大非空地址的最后一段。

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

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

于 2013-01-30T07:03:50.927 回答
0

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

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

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

于 2013-01-29T17:14:00.400 回答