替换裸机嵌入式系统中的启动文件

时间:2014-07-15 11:42:54

标签: c gcc embedded startup sparc

我正在使用gcc交叉编译器用于LEON2处理器(Sparc v8),但是在检查启动代码之后我想出于各种原因提供我自己的代码(我们正在空间应用程序中工作并且代码不符合在我看来标准也很复杂。我觉得这部分非常有趣)。因为我们只使用移植的newlib并且没有RTOS,所以我认为没有太多工作就可以实现。

为了做到这一点,我使用-nostartfiles编译了我的应用程序,因此我提供了自己的开始入口点等...代码来自实际的启动文件,并对我进行了一些修改。

这似乎有效但是我现在卡在我应该初始化newlib的部分。

为了理解这是如何工作的,我使用和不使用-nostartfiles标志编译来查找差异。我只是在gcc调用collect2时显示最后一部分,因为其他部分不相关。

这是一个没有-nostartfiles构建的简单应用程序

/opt/sparc-elf-4.4.2/bin/../libexec/gcc/sparc-elf/4.4.2/collect2
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/../../../../sparc-elf/lib/locore_mvt.o 
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/../../../../sparc-elf/lib/crt0.o
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crti.o
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crtbegin.o
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/../../../../sparc-elf/lib/pnpinit_simple.o
-L/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2 
-L/opt/sparc-elf-4.4.2/bin/../lib/gcc 
-L/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/../../../../sparc-elf/lib 
/tmp/ccCfxzLR.o 
-lgcc
--start-group -lc -lgcc -lleonbare --end-group
-lgcc 
--start-group -lc -lgcc -lleonbare --end-group
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crtend.o
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crtn.o

经过一些调整后,我设法为我的应用程序获得了类似的东西。

/opt/sparc-elf-4.4.2/bin/../libexec/gcc/sparc-elf/4.4.2/collect2
-o debug/BSW 
-L../../drv_EEPROM/SRC/debug 
-L/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2 
-L/opt/sparc-elf-4.4.2/bin/../lib/gcc 
-L/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/../../../../sparc-elf/lib 
-Map BSW_memory.map 
debug/trap_table.o 
debug/trap_reset.o 
debug/trap_access_exception.o 
debug/trap_fp_disabled.o 
debug/trap_window_overflow.o 
debug/trap_window_underflow.o 
debug/cpu_info.o 
debug/cpu_init.o 
debug/init_hooks.o 
debug/start_sequence.o 
debug/main.o 
debug/pnpinit_simple.o 
debug/register_atexit.o 
-lDrvEEPROM 
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crti.o 
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crtbegin.o 
-lgcc -lc -lgcc -lleonbare -lgcc -lc -lgcc -lleonbare 
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crtend.o 
/opt/sparc-elf-4.4.2/bin/../lib/gcc/sparc-elf/4.4.2/crtn.o 
-Tlinkbootram

我在GDB中调试了这个,我可以看到我的代码正确执行,至少看起来,直到调用main。只需调用printf,我的主要内容非常简单。可悲的是,这种对printf的调用永远不会回来,似乎永远循环。所以我猜有些初始化没有正确完成。

我正在努力了解事情是如何完成的,但所有这些内容都非常模糊,并且似乎没有很多文档可用。我还在学习,所以我可能错过了一些重要的东西,但也许一些知识渊博的人可以提供一些前进的方法?感谢。

1 个答案:

答案 0 :(得分:1)

有一些关于移植Newlib here的好文档,包括C Runtime initialisation的实现。 CRT任务包括:

  • 以一致的状态设置目标平台。例如,设置适当的异常向量。
  • 初始化堆栈和帧指针
  • 调用静态数据初始化,包括静态对象的C ++构造函数。
  • 执行任何进一步的平台特定初始化。
  • 调用C main函数。
  • 从main()退出时调用C ++静态对象析构函数。
  • 退出时使用main()退出时提供的返回码。

目前尚不清楚你是如何确定的,而不是printf()没有返回,但是有很多可能性,例如堆栈不足,或者实际上它确实返回但是当printf()调用返回main()时会退出然后会发生什么事情取决于你的C运行时 - 可能它会无限循环?如果从main()退出禁用中断并且printf()输出被缓冲并且中断驱动,则可能看不到任何输出。另一种可能性是,作为main()中的最后一个语句,printf()调用返回可以通过"合并"来优化。它与main()返回。我建议你至少在main()的末尾放置一个for(;;);来阻止它返回。

printf()本身有点重量级作为测试的起点;它需要大量的堆栈空间和stdout和系统调用的工作支持。我可能从更低级别和更简单的东西开始,对库的依赖性更少或没有依赖性,例如切换GPIO或无缓冲的串行输出。