c++全局对象方法未链接

c++ global object methods not linked

本文关键字:链接 方法 对象 全局 c++      更新时间:2023-10-16

我在STM32 ARM micro的C++项目中遇到问题。我创建了一个实现状态机的类。这个类有一些方法不是由其他方法直接调用的,而是由函数指针调用的:

// Foo.h
class Foo
{
public:
    typedef void(Foo::*State)(void);
    State state;
    void init();
    virtual void poll();
    void state1();
    void state2();
    Foo();
    virtual ~Foo() {}
};
// Foo.cpp
#include "Foo.h"
#define ASSIGN_STATE(X,Y) 
X = &Foo::state ## Y;
void Foo::init()
{
    ASSIGN_STATE(state, 1);
}
void Foo::state1()
{
    ASSIGN_STATE(state, 2);
}
void Foo::state2()
{
    ;
}
void Foo::poll()
{
    (this->*state)();
}
Foo::Foo()
{
    this->init();
}

我安装了一个具有全局作用域的此类对象:

Foo foo;
int main()
{
    foo.init();
    while(1)
        foo.poll();
    return(1);
}

如果我编译项目,其他方法(state1()state2())没有直接调用的方法不会链接,并且固件在调用它们时会崩溃。

相反,如果我在main()中实例化它们,则这些方法是链接的,并且一切都正常工作。

int main()
{
    Foo foo;
    foo.init();
    while(1)
        foo.poll();
    return(1);
}

编译器和链接器标志:

COMPILER_FLAGS = $(DEBUG_FLAGS) -mcpu=cortex-m3 -mthumb -Wall -mlittle-endian -MD -MP -MF $(DEPS)/$(@F:%.o=%.d) -fno-strict-aliasing -fsigned-char -ffunction-sections -fdata-sections $(DEFINES) $(INCLUDES)
CPPCOMPILER_FLAGS =  $(DEBUG_FLAGS) -mcpu=cortex-m3 -mthumb -Wall -mlittle-endian -MD -MP -MF $(DEPS)/$(@F:%.o=%.d) -fno-strict-aliasing -fsigned-char -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions $(DEFINES) $(INCLUDES)
LINKER_FLAGS = -mcpu=cortex-m3 -mthumb -specs=nano.specs -lnosys -L$(LINKERSCRIPT_DIR) -T$(LINK_SCRIPT) -Wl,--gc-sections $(DEFINES)

该项目是C/C++混合的。我使用GCC ARM TOOLS工具链在Windows7操作系统下进行编译。

我尝试使用不同的编译器标志和不同的优化选项,但没有任何变化。你知道我为什么会有这种行为,或者我该如何调查它的原因吗?

发生的情况是,您的部分代码被链接器收集到垃圾,因为它认为它在任何地方都没有被引用。我在只从ISR访问的代码中看到过这种情况,因为gcc看不到主代码和ISR之间的任何引用。

当您指定-ffunction-sections-fdata-sections时,将为项目中的每个函数和数据项创建一个自动命名的部分。然后,当它到达链接器时,就得到了-Wl,--gc-sections。这会导致链接器从输出中删除所有未引用的节。在MCU上,这是一件非常好的事情,因为它可以最大限度地减少程序内存的使用。不幸的是,正如我所描述的,编译器在检测未使用的代码时并不是绝对正确的。

在过去,我曾通过在代码中声明一个指向丢失对象的指针来解决这个问题,并确保我在主代码中初始化它。编译器看到传出引用,函数/数据不会被垃圾收集。

您还可以通过将丢失的数据/函数移动到一个从未使用gcc section属性进行垃圾收集的部分来解决此问题。例如,要移动一个函数,可以在上面使用__attribute__((section(".text")))