.s 文件在 C 项目中的作用是啥?
Posted
技术标签:
【中文标题】.s 文件在 C 项目中的作用是啥?【英文标题】:What is the role of .s files in a C project?.s 文件在 C 项目中的作用是什么? 【发布时间】:2012-04-05 18:55:34 【问题描述】:我正在使用 ARM Cortex M3 芯片 (STM32F2),ST 提供了一个“标准外设库”。它有一些有用的 .c 和 .h 文件。它也有 .s 文件。
这些 .s 文件在 C 项目上下文中的用途是什么?如何获取我的编译器/链接器/?将它们考虑在内?
【问题讨论】:
【参考方案1】:.s 扩展名是 GNU 和许多其他工具链用于汇编文件的约定。
最后我查看了 STM32 标准外设库本身不包含汇编文件,但是 CMSIS 库包含各种 STM32 部件的启动代码,例如 startup_stm32f2xx.s 是所有 STM32F2xx 系列器件的启动代码。不同的工具链有不同的实现;您需要构建和链接与您的特定零件和工具链关联的文件。如果您正在使用构建和运行的示例项目或为您创建特定于部件的项目的 IDE,那么这可能已经完成 - 如果您有运行它的代码肯定有。
如何构建和链接代码取决于您使用的工具链。大多数基于 IDE 的工具将自动识别扩展名并调用汇编程序来生成一个目标文件,该文件将像任何其他文件一样被链接。工具链版本之间的确切内容略有不同,但主要创建 C 运行时环境(堆栈和堆)、初始化处理器、定义初始中断/异常向量表、初始化静态数据并跳转到 main()。
例如,Keil/ARM RealView 版本的文件核心如下所示:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
Reset_Handler
是处理器复位后将设置的地址程序计数器 (PC) 寄存器。
SystemInit
是一个外部 C 代码函数,它完成了大部分初始化工作 - 这可能需要针对您的硬件进行定制。 Cortex-M 的不寻常之处在于它可以在复位后立即开始运行 C 代码,因为向量表包括复位地址和初始堆栈指针地址,复位时会自动加载到 SP 寄存器中。因此,您不需要太多的汇编知识即可运行。
__main()
是编译器为您的 C 代码提供的入口点。它不是您编写的 main() 函数,而是在调用“main()”函数之前对标准库、静态数据、堆进行初始化。
GCC 版本涉及更多,因为它完成了 Keil/ARM RealView 版本中 __main()
所做的大部分工作,但本质上它执行相同的功能。
请注意,在 CMSIS 中SystemInit()
是在 system_stm32f2xx.c 中定义的,并且可能需要针对您的板进行定制(正确的晶体频率、PLL 设置、外部 SRAM 配置等)。因为这是 C 代码,并且注释很好,所以您可能会更适应它。
【讨论】:
除了我刚刚注意到您指定了 STM32F2xx。答案仍然适用,除了在您的情况下各自的文件名是 startup_stm32f2xx.s 和 system_stm32f2xx.c 。我修改了答案,使其更具体到 STM32F2。 Clifford - 在 ARM 网站上的文档中,它提到 startup_xxx.s 中的另一个例程 __user_initial_stack_heap 不应使用超过 88 字节的堆栈。你知道这个限制来自哪里吗?见infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0099a/… @NickHalden:您认为这是否值得单独作为一个问题发布?这个问题已经有两年多了,甚至不是你的问题。这不是他 cmets 部分的用途 - 所以不是讨论论坛。除了;这样你会得到更多的观众。 @Clifford 好吧,您正在解释我引用的确切文件,所以我认为这并不过分,但我承认我没有注意到它有多旧。我在这里提出了一个新问题:***.com/questions/26643465/arm-cortex-m3-startup-code。如果可能,请在那里回答,谢谢。【参考方案2】:它们通常包含汇编代码。汇编器将它们转换为目标文件,然后由链接器将其与主要内容链接。但我想它确实取决于编译器、工具链等。
【讨论】:
【参考方案3】:.s 文件通常包含向量表。它定义了发生中断时系统应该做什么。该表(代码)放置在您在链接器文件中定义的内存地址中。例如,每次重置发生时,您的处理器应该从哪里开始,或者更确切地说应该从哪里开始,它应该运行什么代码。同样,还有其他处理程序(中断向量)。在 STM32 中,控制器通常在特定的处理程序上循环。 如下例所示:See this link for detailed explanation
.section INTERRUPT_VECTOR, "x"
.global _Reset
_Reset:
B Reset_Handler /* Reset */
B . /* Undefined */
B . /* SWI */
B . /* Prefetch Abort */
B . /* Data Abort */
B . /* reserved */
B . /* IRQ */
B . /* FIQ */
Reset_Handler:
LDR sp, =stack_top
BL c_entry
B .
此汇编代码稍后会转换为目标文件并与您的 .c 文件和 .ld 链接以创建 .elf 或 .bin 文件。
【讨论】:
【参考方案4】:您的 ST 套件可能已经有了基于 Keil 的开发环境。根据编译器的版本,项目文件应该有不同的 C、C++ 和汇编代码部分。在您的 IDE 中,打开您的项目并查找“项目属性”或类似的内容。
您可以在汇编代码中导入和导出符号,以便它与 C/C++ 代码链接。使用 Keil,这一切都可以很好地集成。
EXPORT 指令告诉汇编器公开指定的符号,以便您的 C/C++ 代码可以链接到它。
IMPORT 指令告诉汇编器指定的符号是在别处定义的,并将在链接时解析。
【讨论】:
以上是关于.s 文件在 C 项目中的作用是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 项目属性中的各种“构建操作”设置是啥?它们的作用是啥?