C++ 我可以在编译或链接时从gcc获取单例的地址吗?

C++ 我可以在编译或链接时从gcc获取单例的地址吗?,c++,gcc,embedded,C++,Gcc,Embedded,我正在从事一个嵌入式项目,并问我,是否有可能在编译或链接期间获得单例类的地址 #include <new> extern unsigned char placeA[]; class A { public: static A& get() { static A *p_instance; if(!p_instance) { p_instance = new(placeA) A(); }

我正在从事一个嵌入式项目,并问我,是否有可能在编译或链接期间获得单例类的地址

#include <new>

extern unsigned char placeA[];

class A {
public:
    static A& get()
    {
        static A *p_instance;
        if(!p_instance) {
            p_instance = new(placeA) A();
        }
        return *p_instance;
    }
};

unsigned char placeA[sizeof(A)] __attribute__ ((aligned (__BIGGEST_ALIGNMENT__)));
为了创建我的singleton,我使用以下代码,并对实例的地址感兴趣

当然,我想做的是使用调试探测从外部更改值,而不是使用真正的调试会话

致意
Andreas不确定这是否是您想要做的,但是在gcc中使用“-S”将在编译阶段后停止所有操作。这样,您就可以深入汇编代码并计算变量。以下是手册页摘录:

If you only want some of the stages of compilation, you can use -x (or
filename suffixes) to tell gcc where to start,
and one of the options -c, -S, or -E to say where gcc is to stop.  Note that
some combinations (for example, -x cpp-output -E) instruct gcc to do nothing at all.

-c  Compile or assemble the source files, but do not link.  The linking stage simply is not done.  The ultimate
    output is in the form of an object file for each source file.

    By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.

    Unrecognized input files, not requiring compilation or assembly, are ignored.

-S  Stop after the stage of compilation proper; do not assemble.  The output is in the form of an assembler code file
    for each non-assembler input file specified.

    By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.

    Input files that don't require compilation are ignored.

-E  Stop after the preprocessing stage; do not run the compiler proper.  The output is in the form of preprocessed
    source code, which is sent to the standard output.

    Input files which don't require preprocessing are ignored.

不完全确定这是否是您要做的,但是在gcc中使用“-S”将在编译阶段后停止所有操作。这样,您就可以深入汇编代码并计算变量。以下是手册页摘录:

If you only want some of the stages of compilation, you can use -x (or
filename suffixes) to tell gcc where to start,
and one of the options -c, -S, or -E to say where gcc is to stop.  Note that
some combinations (for example, -x cpp-output -E) instruct gcc to do nothing at all.

-c  Compile or assemble the source files, but do not link.  The linking stage simply is not done.  The ultimate
    output is in the form of an object file for each source file.

    By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.

    Unrecognized input files, not requiring compilation or assembly, are ignored.

-S  Stop after the stage of compilation proper; do not assemble.  The output is in the form of an assembler code file
    for each non-assembler input file specified.

    By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.

    Input files that don't require compilation are ignored.

-E  Stop after the preprocessing stage; do not run the compiler proper.  The output is in the form of preprocessed
    source code, which is sent to the standard output.

    Input files which don't require preprocessing are ignored.

如果不知道您正在使用什么样的开发工具、硬件体系结构等,很难说您应该做什么,但通常可以将某些变量指定给特定的数据段或特定代码段中的函数,然后在链接阶段为该段分配一个特定地址

例如,您可以使用:

然后在a中使用相同的节名,将其放置到“正确”的地址

大多数(合理的)嵌入式工具链都会以某种方式支持这一点,但具体的实现方式差异很大

另一个选项是使用placement
new

MyObj *obj = new ((void *)0x11220000) MyObj(args);

如果不知道您正在使用什么样的开发工具、硬件体系结构等,很难说您应该做什么,但通常可以将某些变量指定给特定的数据段或特定代码段中的函数,然后在链接阶段为该段分配一个特定地址

例如,您可以使用:

然后在a中使用相同的节名,将其放置到“正确”的地址

大多数(合理的)嵌入式工具链都会以某种方式支持这一点,但具体的实现方式差异很大

另一个选项是使用placement
new

MyObj *obj = new ((void *)0x11220000) MyObj(args);

您可以将placement new与地址在编译或链接时可用的缓冲区一起使用

#include <new>

extern unsigned char placeA[];

class A {
public:
    static A& get()
    {
        static A *p_instance;
        if(!p_instance) {
            p_instance = new(placeA) A();
        }
        return *p_instance;
    }
};

unsigned char placeA[sizeof(A)] __attribute__ ((aligned (__BIGGEST_ALIGNMENT__)));
#包括
外部无符号字符位置a[];
甲级{
公众:
静态A&get()
{
静态A*p_实例;
if(!p_实例){
p_instance=new(placeA)A();
}
返回*p_实例;
}
};
无符号字符placeA[sizeof(A)]\uuuuu属性(对齐(\uuuu最大值\uu对齐));

您可以将placement new与地址在编译或链接时可用的缓冲区一起使用

#include <new>

extern unsigned char placeA[];

class A {
public:
    static A& get()
    {
        static A *p_instance;
        if(!p_instance) {
            p_instance = new(placeA) A();
        }
        return *p_instance;
    }
};

unsigned char placeA[sizeof(A)] __attribute__ ((aligned (__BIGGEST_ALIGNMENT__)));
#包括
外部无符号字符位置a[];
甲级{
公众:
静态A&get()
{
静态A*p_实例;
if(!p_实例){
p_instance=new(placeA)A();
}
返回*p_实例;
}
};
无符号字符placeA[sizeof(A)]\uuuuu属性(对齐(\uuuu最大值\uu对齐));

通常,调试探测只看到物理地址,而用户应用程序只在虚拟地址上运行,虚拟地址在加载应用程序时会不断变化,因此链接器技巧不会起作用。你没有说你用的是哪个操作系统,但我猜是Linux。如果是这样,您可以这样做:为自己保留一个草稿行内存区域,您知道它的物理地址,但操作系统不使用它。例如,如果您的SoC有一个嵌入式静态内存,那么就使用它,如果不只是询问您当地的Linux专家如何在内核内存配置中保留一页RAM的话

然后阅读本文,了解如何将物理地址映射到应用程序的虚拟内存空间:


在获得草稿行区域的虚拟地址后,应用程序可以在那里读/写它想要的任何内容。调试探测将能够读/写物理地址所在的同一区域。

通常,调试探测只看到物理地址,而用户应用程序只在虚拟地址上运行,虚拟地址在加载应用程序的所有时间都会发生变化,因此链接器技巧不会起作用。你没有说你用的是哪个操作系统,但我猜是Linux。如果是这样,您可以这样做:为自己保留一个草稿行内存区域,您知道它的物理地址,但操作系统不使用它。例如,如果您的SoC有一个嵌入式静态内存,那么就使用它,如果不只是询问您当地的Linux专家如何在内核内存配置中保留一页RAM的话

然后阅读本文,了解如何将物理地址映射到应用程序的虚拟内存空间:


在获得草稿行区域的虚拟地址后,应用程序可以在那里读/写它想要的任何内容。调试探测器将能够读取/写入物理地址所在的同一区域。

是否可以使用自定义分配器和/或?或者重载运算符new并提供特定的地址?如果singleton对象具有静态存储持续时间,那么您当然可以在编译时获取它的地址。我不知道调试探测业务。@flatmouse我知道可以指定地址并将其用于存储在电池缓冲区中的某些特殊数据。但是我不想一个人做所有关于记忆的事情。重载新运算符无效,因为我不使用动态内存。@user207933我编辑了我的问题以使其更精确。您能给我一个提示,如何获取实例地址。@AndreasWalter您的
get
每次调用都返回一份副本。您可能打算返回引用,对吗?可能使用自定义分配器和/或?或者重载运算符new并提供特定的地址?如果singleton对象具有静态存储持续时间,那么您当然可以在编译时获取它的地址。我不知道这件事