用汇编程序编写可以减少代码大小和执行时间。但是假设我有足够的记忆和足够的时间。我可以只使用 C 代码并启动设备吗?我的意思是,从开机,直接运行C代码。我对 ARM 处理器特别感兴趣。
4 回答
实际上,您可以为 ARM 的Cortex-M3 微控制器制作纯 C 固件。因为它的向量表包含堆栈指针的条目,它的值将由处理器初始化,您可以在复位后立即使用编译代码。您仍然需要设置外设并初始化 C 库环境,但您不必在汇编程序中进行。Cortex-M3 还会在中断处理程序入口自动保存易失性寄存器,因此它们也可以直接用 C 语言编写。
也就是说,大多数编译器供应商仍然提供用汇编程序编写的启动,因为它提供了最多的控制。
如前所述,cortex-m3 是特殊的,并且允许这样的事情,除了一个例外,你仍然需要一些 asm 或其他一些魔法来构建向量表来调用 C 代码。
一般来说,答案是否定的,需要进行一些组装。处理器是通用的,它们通常不知道您为程序和数据以及堆栈设置的地址空间等,寄存器,特别是堆栈指针,通常被初始化为某个已知值,例如零。处理器通常已知有一个启动序列,要么是它开始执行的地址,要么是它找到开始执行的地址的地址。该地址表,一个用于复位,一个用于中断等,由引导代码的程序员放置在那里,虽然可以在 C 中管理,但不值得努力,更容易编写几行 asm 来构建该向量桌子。(皮质-m就是这种情况)
所以至少你需要设置一个堆栈指针,然后分支到入口 C 代码,从那里你可能可以摆脱运行 C。现在,如果这是一个手臂而不是一个 cortex-m,那么你有多个堆栈要设置(如果您想使用中断、处理故障等)并且您必须使用特定的 asm 指令才能执行该设置,因此 asm 是必需的,无论是真实的还是内联的。
如果您习惯使用 .data 或期望 .bss 为零,则必须这样做,一些代码必须将 bss 归零并准备 .data。通常,您的系统(甚至您的台式机/笔记本电脑)将从闪存启动,如果您有 .data ,那么 .data 需要在闪存中,但需要读取/写入,因此您需要将该数据从闪存复制到它的家在 ram 中,你需要先启动并运行 ram(见下文)才能做到这一点。
不是在过去的美好时光,但绝对是今天,你不能只打开并开始使用内存,需要大量代码来启动和运行 dram。是的,这段代码是用 C 语言编写的,可能不是 asm 代码(尽管出于性能原因,asm 可用于利用您不一定让 C 编译器为您生成的特定指令)。
因此,您通常有不同的场景,不一定特定于 arm。我会列出一些但不是每一个细微差别
1)您的系统使用不需要初始化的 sram 或内部 ram,您没有使用 .data 并且您的代码不假定 .bss 已被归零。一般来说,最低限度是初始化堆栈指针并分支到您的 C 入口点(main,或任何您称之为的入口点)。
2)您的系统使用不需要初始化的 sram 或内部 ram,您正在使用您希望在 C 代码开始之前存在的 .data(对于 C 程序员来说非常典型)并且 .bss 之前为零您的 C 代码启动(也是典型的,但幸运的是 gcc 开始抱怨执行此操作的代码)。由于在这种情况下您的 C 代码期望在运行 C 代码之前准备好这些东西,因此 .bss 的归零和 .data 从闪存到 ram 的复制发生在 asm 中。这是你最常见的场景,去看看不同处理器的许多crt0.s例程,这是共同的主题,设置堆栈指针,零bss,复制.data分支到main。
3)您的系统有一些不需要初始化的内部 sram,但您希望使用的主内存是 dram。这是一个两步,您的第一个引导加载程序仍需要设置堆栈指针,根据您的喜好选择零 .bss 和复制 .data 然后分支到第一个引导加载程序的入口点。此引导加载程序将启动 DRAM 系统。这个引导加载程序现在可以选择复制 .data 和零 .bss(现在可以在 C 中),然后分支到主引导加载程序入口点/函数,它需要并使用更大的主内存。
4) 你有一个带有微编码的 x86 处理器,你需要在启动时修补微码,我个人对此不了解,但假设你应该使用的指令数量有限,因为你正在更改一些微编码,或者也许你复制到一些内存然后翻转一点,它神奇地切换到补丁,你执行更改,不知道,但我敢打赌需要一些组装。
请记住,许多 C 库调用都在汇编中。所以 C 是汇编,尤其是在手臂上。你避免所有的除法、乘法、模数、浮点数等吗?你从不使用任何字符串函数或复制函数。您是否使用 C 库调用?很可能有您正在使用但不知道的 asm。memcpy 经常在 asm 中手动调整,尤其是在 arm 上。如果您在代码中使用结构,编译器可以/将在 memcpys 中抛出,具体取决于您使用它们的内容和方式。除法和模绝对是asm。有时乘。浮点数,通常是 asm,即使有 fpu。当然,您自己没有编写此 asm,但其中可能有 asm,如果没有该 asm(如果您使用这些库),您的引导加载程序将不存在。
你的标题问题,暗示只有引导加载程序的汇编,是错误的,引导加载程序大多不是汇编。几乎总是需要一些组装。
cortex-m 是一种独特的野兽,因为它的设计使您不必使用特殊指令或 asm 包装中断(或让编译器为您执行此操作)。不典型。cortex-m 有一个很大到很大的向量表。很好奇您将如何在 C 中构建该表。我有一些想法如何做到这一点,但是使用 asm 会容易得多,即使 asm 实际上不是 asm 它是对汇编器的指令(.word this_handler,.word that_handler) .
传统的 arm 的 32 位 ARM7 类似指令 ARM 内核,您必须至少在 asm 中设置堆栈并分支到 C 代码,除非您玩编译器游戏,否则异常处理程序也需要一点 asm,只需几行代码。
我不得不怀疑这个问题的根源。引导加载程序与处理器和外围设备密切相关,编写引导加载程序的程序员必须熟悉硬件寄存器等。这意味着对该处理器的指令集有一定程度的熟悉。避免引导加载程序中的所有 asm 是一个问题。即使使用 cortex-m 只是因为您可以直接从向量表转到 C 代码,您仍然需要验证您使用的编译器是否符合硬件调用约定,而不仅仅是一些通用的 arm 调用约定,它特别具有确保保留一定范围的寄存器并在返回时使用正确的指令,这意味着在这个级别上对编译器生成的代码进行反汇编和手动/视觉检查,尽管只是阅读,
引导加载程序负责在设备启动时对其进行初始化。在这一点上,除了汇编程序之外别无他法。汇编程序部分通常保持尽可能小,并负责初始化系统,以便操作系统的部分和例如最小的 C 运行时可以加载到内存中并执行,在此之后可以使用例如完成其他初始化任务C。
一些可能有用的链接:
希望这会有所帮助。
我也不知道确切的答案。我只是提出一些我能想到的原因(减去内存和效率):
- 代码非常特定于设备,无需在其他地方编译和运行
- 访问特殊指令(?)
- 引导加载程序时的状态运行与普通程序不同(?)(堆栈,堆)
免责声明:此答案可能包含错误信息。在这里不要认真对待任何事情。