Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
嵌入式:大多数CRT启动代码未使用memcpy/memset―;为什么?_C_Assembly_Embedded - Fatal编程技术网

嵌入式:大多数CRT启动代码未使用memcpy/memset―;为什么?

嵌入式:大多数CRT启动代码未使用memcpy/memset―;为什么?,c,assembly,embedded,C,Assembly,Embedded,上下文: 我正在研究一个ARM目标,更具体地说是一个来自ST的Cortex-M4F微控制器。在这样的平台上工作时(一般是微控制器),显然没有操作系统;为了获得一个工作的C/C++“环境”(此外,在变量初始化方面符合标准),必须在重置时运行某种启动代码,在显式调用main之前执行所需的最低设置。正如我所暗示的,这样的启动代码必须初始化初始化的全局变量和静态变量(例如全局范围内的intfoo=42;),并将其他全局变量(例如全局范围内的intbar;)归零。然后,如有必要,调用全局“系数” 在微控制

上下文:
我正在研究一个ARM目标,更具体地说是一个来自ST的Cortex-M4F微控制器。在这样的平台上工作时(一般是微控制器),显然没有操作系统;为了获得一个工作的C/C++“环境”(此外,在变量初始化方面符合标准),必须在重置时运行某种启动代码,在显式调用
main
之前执行所需的最低设置。正如我所暗示的,这样的启动代码必须初始化初始化的全局变量和静态变量(例如全局范围内的
intfoo=42;
),并将其他全局变量(例如全局范围内的
intbar;
)归零。然后,如有必要,调用全局“系数”

在微控制器上,这仅仅意味着启动代码必须将每个初始化全局(全部在“.data”部分)的数据从闪存复制到ram,并清除其他(全部在“.bss”部分)。因为我使用GCC,所以我必须提供这样一个启动代码,我很高兴地分析了几个启动代码(及其关联的链接器脚本!),这些代码与我在互联网上找到的许多示例捆绑在一起,所有这些都使用我正在开发的同一个演示板

问题:
如前所述,我见过许多启动代码,它们以不同的方式初始化全局变量,有些在空间和时间方面比其他的更有效。但他们都有一些奇怪的共同点:他们没有使用
memset
memcpy
,而是使用手写循环来完成这项工作。由于在可能的情况下使用标准函数(简单的“干燥原理”)对我来说是很自然的,我尝试了以下方法来代替最初的手写循环:

/* 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); */
。。。它工作得很好。节省的空间可以忽略不计,但现在显然非常简单

所以,我想了想,我认为没有理由在这种情况下进行手写循环:

  • memcpy
    memset
    很可能在可执行文件中链接,因为程序员会直接使用它,或者通过另一个库间接使用它
  • 它较小
  • 速度不是启动代码的一个非常重要的因素,但它可能更快
  • 几乎不可能弄错

你知道为什么启动代码不依赖
memcpy
memset
吗?

我怀疑启动代码不想对libc中的
memcpy
等的实现进行假设。例如,
memcpy
的实现可能会使用libc初始化代码设置的全局变量来报告哪些cpu扩展可用,以便在支持此类操作的机器上提供优化的SIMD复制。在运行早期“crt”启动代码时,这样一个全局文件的存储可能完全未初始化(包含随机垃圾),在这种情况下,调用
memcpy
是危险的。即使打电话对你有效,这也是实现的结果(甚至可能是UB的不可预测的结果…)使其有效;这可能不是crt代码想要依赖的东西。

是否链接标准库是应用程序开发人员的决定(
--nostlib
可能会被使用),但是启动代码是必需的,因此它不能做出任何假设

此外,启动代码的目的是建立C代码可以运行的环境;在这一过程完成之前,任何可能合理假设完整运行时环境将正确运行的库代码都是不确定的。对于所讨论的函数,在许多情况下这可能不是问题,但您无法知道这一点

<>启动代码至少需要建立一个堆栈并初始化静态数据,在C++中它另外调用全局静态对象的构造函数。标准库可能会合理地假设这些都已建立,因此在此之前使用标准库可能会导致错误行为


最后,您应该清楚C语言和C标准库是不同的实体。该语言必须能够独立使用。

我认为这与“关于memcy/memset内部状态的假设”无关,它们不太可能使用任何全局资源(尽管我认为在它们使用的地方存在一些奇怪的情况)

微控制器上的所有启动代码通常都是以这种方式编写的“内联汇编程序”,这仅仅是因为它在代码的早期阶段运行,此时可能尚未出现堆栈,也可能尚未执行MMU设置。因此,Init代码不想冒险将任何东西放在堆栈上,就这么简单。函数调用将东西放在堆栈上


因此,虽然这恰好是静态存储拷贝down的初始化代码,但在其他此类init代码中也可能会找到相同的内联汇编程序。例如,您可能会在复制之前的某个地方找到汇编程序中编写的一些基本寄存器设置代码,您也会在汇编程序中的某个地方找到MMU设置。

也许启动代码“很可能链接到”还不够好?dwelch:请解释您自己。你没有解释为什么我的假设都是假的。也许你可以添加一些更有意义的见解?@dwelch:很抱歉挂了国旗。我不知道你为什么要删除你的帖子。如果我能联系你,我会解释我自己。也许我的问题不是很好,你的问题的答案很简单。这是一个鸡和蛋的问题,您试图使用C代码来引导C代码。您不能假设您正在使用的C代码不需要引导。假设不是事实,只是观点,如果你没有自己编写或亲自验证C代码(或者更好的是只编写一个