我可以在编译期间或 link 期间从 gcc 获取单例的地址吗?
Can I get the address of a singleton during compile or link time from gcc?
我正在做一个嵌入式项目,问我,是否有可能在编译或 link 期间获取单例 class 的地址。
为了创建我的单例,我使用了以下代码并且对 实例 的地址感兴趣。
class A
{
public:
static A& get()
{
static A instance;
return instance;
}:
我想做的,当然是使用调试探针从外部更改值,而不是使用真正的调试会话。
此致
安德烈亚斯
不确定这是否是您要执行的操作,但是在 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 section attribute:
int init_data __attribute__ ((section ("INITDATA")));
或
MyObj obj __attribute__((section ("BATTERY_BACKED")));
然后在 linker script 中使用相同的部分名称将其放置到 "right" 地址。
大多数(合理的)嵌入式工具链都会以某种方式支持这一点,但具体的实现方式差异很大。
另一种选择是使用展示位置 new
:
MyObj *obj = new ((void *)0x11220000) MyObj(args);
您可以将 placement-new 与地址在编译或 link 时可用的缓冲区一起使用。
#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__)));
通常调试探测器只能看到物理地址,而用户应用程序只能在虚拟地址上运行,虚拟地址会在应用程序加载时发生变化,因此没有任何链接器技巧会起作用。你没有说你用的是哪个OS,但我猜是Linux。如果是这样,你可以这样做:为自己保留一个暂存器内存区域,你知道它的物理地址并且没有被 OS 使用。例如,如果您的 SoC 具有嵌入式静态内存,请使用它,如果不只是询问您当地的 Linux 专家如何将一页 RAM 保留到内核内存配置中。
然后查看这篇文章以了解如何将物理地址映射到应用程序的虚拟内存 space:
how to access kernel space from user space(in linux)?
获得暂存器区域的虚拟地址后,您的应用程序可以read/write在那里随心所欲。调试器将能够 read/write 进入与物理地址相同的区域。
我正在做一个嵌入式项目,问我,是否有可能在编译或 link 期间获取单例 class 的地址。
为了创建我的单例,我使用了以下代码并且对 实例 的地址感兴趣。
class A
{
public:
static A& get()
{
static A instance;
return instance;
}:
我想做的,当然是使用调试探针从外部更改值,而不是使用真正的调试会话。
此致 安德烈亚斯
不确定这是否是您要执行的操作,但是在 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 section attribute:
int init_data __attribute__ ((section ("INITDATA")));
或
MyObj obj __attribute__((section ("BATTERY_BACKED")));
然后在 linker script 中使用相同的部分名称将其放置到 "right" 地址。
大多数(合理的)嵌入式工具链都会以某种方式支持这一点,但具体的实现方式差异很大。
另一种选择是使用展示位置 new
:
MyObj *obj = new ((void *)0x11220000) MyObj(args);
您可以将 placement-new 与地址在编译或 link 时可用的缓冲区一起使用。
#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__)));
通常调试探测器只能看到物理地址,而用户应用程序只能在虚拟地址上运行,虚拟地址会在应用程序加载时发生变化,因此没有任何链接器技巧会起作用。你没有说你用的是哪个OS,但我猜是Linux。如果是这样,你可以这样做:为自己保留一个暂存器内存区域,你知道它的物理地址并且没有被 OS 使用。例如,如果您的 SoC 具有嵌入式静态内存,请使用它,如果不只是询问您当地的 Linux 专家如何将一页 RAM 保留到内核内存配置中。
然后查看这篇文章以了解如何将物理地址映射到应用程序的虚拟内存 space:
how to access kernel space from user space(in linux)?
获得暂存器区域的虚拟地址后,您的应用程序可以read/write在那里随心所欲。调试器将能够 read/write 进入与物理地址相同的区域。