【问题标题】:What are those extra assembly codes put by compiler when compiling a C program for a microcontroller?在为微控制器编译 C 程序时,编译器添加了哪些额外的汇编代码?
【发布时间】:2012-12-02 20:39:43
【问题描述】:

我想用 C 语言为我的 Stellaris 启动板编写一段代码,以通过将库的使用保持在最低限度来打开板载 LED。令我惊讶的是,编译后的代码大小约为 800 字节。因此,为了检查编译器在编译后的代码中添加了什么,我使用反序列化器检查了汇编代码。它有很多我没有编写 C 代码的代码。我想知道这些代码的用途以及它是如何进入编译器设置的。我正在尝试了解编译器的行为方式以及编译器在幕后所做的事情。请帮帮我。

这是我的 C 程序:

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"

#define GPIOFBASE   0x40025000
#define GPIOCLK     *((volatile unsigned long *)(0x400FE000 + 0x608))
#define FDIR        *((volatile unsigned long *)(GPIOFBASE + 0x400))
#define FDEN        *((volatile unsigned long *)(GPIOFBASE + 0x51C))
#define FDATA       *((volatile unsigned long *)(GPIOFBASE + 0x3FF))

void main(void) {

    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    GPIOCLK |= (1<<5);
    FDIR    |=  0xE;
    FDEN    |=  0xE;
    FDATA   |=  0xE;

while (1);

}

我使用的唯一 API 调用是使用片上 ROM 库设置时钟设置。请检查此 pastebin 中的 dissambly 代码:(主要:位于 0x190。)

http://pastebin.com/wNNsBdtT

【问题讨论】:

  • C 中没有 void main 这样的东西。
  • 如果我输入 'int main()',这会以任何方式改变此代码中的结果输出吗?
  • 编译器/链接器可能会看到 main() 这个词并添加额外的东西,使用其他名称(和您自己的引导程序)来避免这个问题。 github.com/dwelch67 有许多裸机臂/拇指微控制器示例,特别是如何从重置/启动到第一个 C 函数。
  • 只是为了澄清这里的术语:hosted 实现是在操作系统上运行的常见类型。像这样在“裸机”上运行的一种是独立实现。
  • 你是如何测量尺寸的?这是链接器报告的代码大小,还是您只是查看输出目标文件的大小?这可能是极端的误导。

标签: c embedded arm microcontroller disassembly


【解决方案1】:

附加代码将是 CPU 初始化和 C 运行时初始化。此启动的源代码可能随您的编译器一起提供。例如在 GCC 中,它通常被称为 crt0.s

根据您的 CPU 和内存,可能需要一些初始化来设置正确的时钟频率、内存时序等。除此之外,C 运行时需要静态数据初始化和堆栈初始化。如果支持 C++,则需要额外的代码来调用任何静态对象的构造函数。

像 Stellaris 这样的 Cortex-M 设备旨在以最小的开销运行 C 代码,并且基本上可以从复位启动 C 代码,但是默认启动状态通常不是您想要运行应用程序的状态,因为例如,这很可能以较低且不太准确的时钟频率运行。


2012 年 12 月 6 日添加

您的启动代码几乎肯定是由 CMSIS 提供的。 CMSIS 文件夹将包含包含启动代码的 CoreSupport 和 DeviceSupport 文件夹。您可以将此代码(或其相关部分)复制到您的项目中,根据需要对其进行修改并链接它以代替提供的代码。 CMSIS 经常更新,因此无论如何都有理由这样做。

您的构建日志和/或映射文件对于确定链接哪些 CMSIS 组件很有用。

【讨论】:

  • 我想自己做所有事情。你能告诉我如何禁用这些启动代码。我正在使用基于 Eclipse Indigo 的 Stellarisware IDE。是否可以用 C 自己编写这些启动代码?
  • 是的,大多数编译器都可以选择跳过通常的启动代码。在 gcc 上,我相信它类似于“-nostartfiles”
  • 这样的选项有时也被称为“最小启动”与“标准启动”。请注意,如果禁用此类选项,代码将不再依赖静态/全局变量的初始化。这意味着您必须在运行时设置静态/全局变量的所有值,您不能再写int my_global = 123;
  • 您的工具链可能会提供一个选项来自动执行此操作,但本质上您只需用您自己的代码替换或修改编译器提供的启动代码并链接。
  • 启动代码正在做重要的事情,初始化设备并使一切进入“安全”稳定的启动状态。在删除它之前,您需要阅读并理解它在做什么。对于运行几行 ASM 的非常小的微型计算机,您可能可以不用它,但对于更复杂的微型计算机,我会非常谨慎地删除它。
猜你喜欢
  • 2016-03-14
  • 2015-07-03
  • 2017-08-17
  • 2011-10-06
  • 2018-10-22
  • 2011-06-14
  • 2017-08-18
  • 1970-01-01
相关资源
最近更新 更多