为什么所有ARM引导加载程序都有汇编代码?

时间:2012-05-24 05:26:00

标签: assembly arm bootloader

在汇编程序中编写可减少代码大小和执行时间。但是假设我有足够的记忆和足够的时间。我可以只使用C代码并启动设备吗?我的意思是,从开机,直接运行C代码。我对ARM处理器特别感兴趣。

4 个答案:

答案 0 :(得分:6)

实际上,你可以为ARM Cortex-M3 microcontrollers制作一个仅限C的固件。因为它的向量表包含堆栈指针的一个条目,所以它的值将由处理器初始化,你可以直接使用已编译的代码重置。您仍然需要设置外围设备并初始化C库环境,但您不必在汇编程序中执行此操作。 Cortex-M3还会自动在中断处理程序条目上保存易失性寄存器,因此它们也可以直接用C语言编写。

尽管如此,大多数编译器供应商仍然提供用汇编程序编写的启动程序,因为它提供了最多的控制权。

答案 1 :(得分:4)

如上所述,cortex-m3是特殊的,并允许这样的事情,除了一个例外,你还需要一些asm或其他魔法来构建向量表来调用C代码。

一般来说答案是否定的,需要一些装配。处理器是通用的,它们通常不知道你为程序,数据和堆栈设置了什么地址空间等,寄存器,特别是堆栈指针,通常被初始化为某些已知值,如零。通常已知处理器具有启动序列,或者是它开始执行的地址,或者是找到开始执行的地址的地址。这个地址表,一个用于复位,一个用于中断等,由引导代码的程序员放在那里,虽然可以在C中管理,不值得努力,更容易编写几行asm来构建该向量表。 (这是皮质m的情况)

所以至少你需要设置一个堆栈指针,然后转移到条目C代码,从那里你可以逃避运行C.现在,如果这是一个手臂,而不是皮质m,那么你有多个堆栈设置(如果你想使用中断,处理故障等),你必须使用特定的asm指令来执行该设置,因此asm是必需的,真实的或内联的。

如果您习惯使用.data或期望.bss为零,则必须执行某些操作,某些代码必须为零并准备.data。通常你的系统(甚至桌面/笔记本电脑)都会从闪存启动,如果你有.data,那么.data需要在flash中,但是想要读/写,所以你需要将这些数据从flash复制到它在ram中的家,你需要首先运行并运行(见下文)才能做到这一点。

不是在过去的好时光,但是今天肯定是因为你不能打开并开始使用内存,所以需要很多代码来启动和运行。是的,这段代码在C中,可能不是asm(虽然出于性能原因,asm可能用于利用特定的指令,你不能让C编译器为你生成)。

因此,您通常会有不同的情景,不一定特定于手臂。我会列出一些但不是每一个细微差别

1)你有一个使用sram或内部ram的系统,不需要初始化,你没有使用.data,你的代码并不认为.bss已经归零。通常最小的是初始化堆栈指针并分支到C入口点(主要或者你称之为的任何东西)。

2)你有一个使用sram或内部ram的系统,不需要初始化,你使用的是你希望在C代码启动之前存在的.data(非常典型的C程序员)和.bss在你的C代码开始之前为零(也很典型,但幸好gcc开始抱怨这样做的代码)。因为在这种情况下你的C代码期望在C代码运行之前准备好这些东西,然后将.bss的归零和.data从flash复制到ram发生在asm中。这是你最常见的场景,去看看不同处理器的许多crt0.s例程,这是常见的主题,设置堆栈指针,零bss,复制.data分支到main。

3)你有一个系统有一些内部sram,不需要初始化,但你期望使用的主内存是dram。这是两步,您的第一个引导加载程序仍然需要设置堆栈指针,可选择为.bss和copy .data,具体取决于您的首选项,然后分支到第一个引导加载程序的入口点。这个引导程序将启动dram系统。这个引导加载程序现在可以选择复制.data和零.bss(现在可以在C中),然后分支到主引导加载程序入口点/函数,它期望并使用更大的主内存。

4)你有一个带有微编码的x86处理器,你需要在启动时修补微码,我没有个人知识但是你会假设你应该使用有限数量的指令,因为你正在改变微码对于某些人,或者你可能复制到某个ram然后翻转一下它会神奇地切换补丁并执行更改,不知道,但我打赌需要一些程序集。

请记住,许多C库调用都在汇编中。所以C是装配,特别是在手臂上。你避免所有的分歧,乘法,模数,浮点等?你从不使用任何字符串函数或复制函数。你是否使用C库调用?很可能是因为你正在使用并且不知道它。 memcpy经常用asm手动调整,特别是在手臂上。如果您在代码中使用结构,编译器可以/将在memcpys中抛出,具体取决于您使用它们的方式和方式。明确划分和模数。有时会倍增。浮点,经常是asm,即使有一个fpu。你当然没有自己编写这个,但是有可能存在asm并且你的bootloader在没有asm的情况下就不会存在(如果你使用那些库)。

您的标题问题(仅表示引导加载程序的程序集)是错误的,引导加载程序通常不是程序集。几乎总是需要一些装配。

cortex-m是一个独特的野兽,因为它的设计使你不必用特殊指令或asm包装中断(或让编译器为你做这个)。不典型。但是,cortex-m有一个大到大的向量表。好奇你将如何在C中构建该表。我有一些想法如何做到这一点但是asm更容易,即使asm实际上不是asm它是汇编程序的指令(.word this_handler,.word that_handler)

传统的arm,32位ARM7类指令ARM内核,你必须至少设置堆栈并在asm中分支到C代码,除非你玩编译器游戏,异常处理程序也需要一点点asm,只是几行。

我不得不怀疑这个问题的根源。 Bootloader与处理器和外围设备密切相关,编写引导加载程序的程序员必须能够轻松使用硬件寄存器等。这意味着该处理器的指令集具有一定程度的舒适性。避免引导加载程序中的所有asm是一个问题。即使使用cortex-m只是因为你可以直接从向量表转到C代码,你仍然需要验证你使用的编译器是否符合硬件调用约定,而不仅仅是一些通用的arm调用约定,它特别具有为了确保保留一定范围的寄存器并在返回时使用正确的指令,这意味着编译器生成的代码的反汇编和手动/视觉检查,在这个级别,尽管只是读取,与写入asm相同。

答案 2 :(得分:1)

我也不知道确切的答案。我只提出一些我能想到的原因(减去记忆和效率):
- 代码非常特定于设备,无需编译并在别处运行 - 获得特殊指令(?)
- 运行引导加载程序时的状态与正常程序(?)(堆栈,堆)不同

免责声明:此回答可能包含错误信息。不要在这里认真对待任何事情。

答案 3 :(得分:1)

引导加载程序负责在设备启动时初始化设备。此时除了汇编程序之外别无其他。汇编程序部分通常保持尽可能小,并负责初始化系统,以便操作系统的各个部分,例如,可以将最小C运行时加载到存储器中并执行,并且在此之后,可以使用例如完成其他初始化任务。下进行。

某些可能有用的链接:

Wikipedia bootloader entry

U-boot design principles

希望这有用。