Jar*_*der 16 c embedded assembly
背景:
我正在研究ARM目标,更具体地说是ST的Cortex-M4F微控制器.在这样的平台(一般的微控制器)上工作时,显然没有操作系统; 为了获得一个有效的C/C++"环境"(此外,在变量初始化方面符合标准),必须在重置时运行某种启动代码,在显式调用之前执行所需的最小设置main.正如我所暗示的,这样的启动代码必须初始化初始化的全局和静态变量(例如int foo = 42;在全局范围内)并将其他全局变量(例如全局范围)清零int bar;.然后,如果需要,调用全局"ctors".
在微控制器上,这只是意味着启动代码必须为每个初始化的全局(全部在".data"部分中)将数据从闪存复制到ram,并清除其他部分(全部在'.bss'中).因为我使用GCC,我必须提供这样的启动代码,我很高兴地分析了几个启动代码(及其相关的链接器脚本!),这些代码与我在互联网上找到的大量示例捆绑在一起,所有这些都使用我正在开发的相同演示板.
问:
正如所述,我已经看到了许多启动代码,它们以不同的方式初始化全局变量,在空间和时间方面比其他方式更有效.但他们都有一个共同点奇怪:他们没有使用memset也没有memcpy,而不是诉诸于手写的循环来完成这项工作.由于我觉得在可能的情况下使用标准函数(简单的"DRY原理")似乎很自然,我尝试了以下代替最初的手写循环:
/* Initialize .data section */
ldr r0, DATA_LOAD
ldr r1, DATA_START
ldr r2, DATA_SIZE
bl memcpy /* memcpy(DATA_LOAD, DATA_START, DATA_SIZE); */
/* Initialize .bss section */
ldr r0, BSS_START
mov r1, #0
ldr r2, BSS_SIZE
bl memset /* memset(BSS_START, 0, BSS_SIZE); */
Run Code Online (Sandbox Code Playgroud)
......它完美无缺.节省空间可以忽略不计,但现在显然已经很简单了.
所以,我想到了,在这种情况下,我认为没有理由做手写循环:
memcpy并且memset很可能无论如何都要链接在可执行文件中,因为程序员会直接使用它,或间接地通过另一个库使用它;知道为什么一个人不会依赖memcpy和memset启动代码?
R..*_*R.. 21
我怀疑启动代码不想对memcpylibc中的实现做出假设.例如,memcpy可以使用由libc初始化代码设置的全局变量来报告哪些cpu扩展可用,以便在支持此类操作的机器上提供优化的SIMD复制.在早期的"crt"启动代码运行时,这种全局的存储可能完全未初始化(包含随机垃圾),在这种情况下调用会很危险memcpy.即使打电话给你工作,也是实施的结果(或者甚至UB的不可预测的结果......)使它工作; 这可能不是crt代码想要依赖的东西.
Cli*_*ord 15
标准库是否完全链接是应用程序开发人员的决定(--nostdlib例如可能使用),但是启动代码是必需的,因此它不能做出任何假设.
此外,启动代码的目的是建立一个可以运行C代码的环境; 在完成之前,任何可能合理地假设完整运行时环境的库代码都无法正确运行.对于有问题的功能,这在许多情况下可能不是问题,但你不可能知道.
启动代码必须至少建立一个堆栈并初始化静态数据,在C++中它还会调用全局静态对象的构造函数.标准库可能合理地假设这些已经建立,因此在此之前使用标准库可能会导致错误的行为.
最后,您应该清楚C语言和C标准库是不同的实体.语言必须能够独立存在.
| 归档时间: |
|
| 查看次数: |
1736 次 |
| 最近记录: |