在带有gcc的裸机ARM上的RAM和ROM部分之间的long_call

Eri*_*ell 10 c embedded linker gcc arm

我正在使用GCC 4.3开发一个ARM7TDMI项目,我有一些困难告诉编译器在某些情况下使用长调用而不是其他情况.

构建过程运行arm-eabi-gcc以为每个.c源文件(最相关的CFLAGS包括-Os -ffunction-sections -fdata-sections -mthumb -mthumb-interwork)生成可重定位的ELF目标文件,然后将它们全部链接到ELF可执行文件(最相关的LDFLAGS包括-Wl,--gc-sections -Wl,-static -Wl,-n -nostdlib,以及自定义链接描述文件).然后将该ELF文件转换为原始可执行文件arm-eabi-objcopy -O binary,并在启动时将自定义引导加载程序从ROM复制到RAM(具有代码和数据的单个SRAM).所以一切都从RAM执行,.rodata存在于RAM中,一切都快速进行,完全忽略ROM后启动.

我现在正在尝试更改它,以便某些选定的RO数据和选择函数的文本只能存在于ROM中,并在运行时根据需要进行访问.我已经修改了链接器脚本以了解两个新的部分,".flashdata"并且".flashtext"这两个部分都应该放在ROM中的固定地址.我也撒__attribute__((__section__(".flashdata")))__attribute__((__section__(".flashtext"),__long_call__))整个适当的C代码,我已经rejiggered构建过程使旧objcopy把现在增加了-R .flashdata -R .flashtext,和我做第二objcopy把-j为每个部分,再结合我的两个输出文件,以便引导加载程序可以做正确的事情,ROM部分出现在预期的内存映射位置.

这一切都很好 - 我可以打印标签到该.flashdata部分的字符串,我可以.flashtext从RAM中运行的代码调用一个函数(由于__long_call__属性旁边的__section__(".flashtext")属性,它知道使用长调用).基于ROM的功能可以很快地调用其他基于ROM的函数,并且它可以返回到基于RAM的调用者.

问题在于尝试从基于ROM的函数调用基于RAM的函数,这也必须是一个长调用.我不想在任何地方使用长呼叫,所以我不想在我的CFLAGS中使用-mlong_calls.如果我将ROM中的所有函数分组为单个rom.c,我可以构建一个文件-mlong-calls并且一切正常.但是,我强烈希望避免这种情况,并保持功能通常按目的分组,只需在适当的位置标记一些以便从ROM运行.

顺便说一句,这在gcc 3.4下是不够的.使用-mlong-calls让编译器思考正确的事情,但它无法完成,因为它只愿意用它的助手执行长跳转_call_via_rX...它们都存在于RAM中并且只能通过长时间调用来访问. 这是在gcc 4.0中的链接器中修复的,但没有向后移植到3.x树中的任何内容.

因为我使用gcc 4.3,所以我现在可以回调RAM了,真是太好了.如果我能以某种方式标记基于ROM的函数中的代码以强制它使用长调用,那将更好.有一个#pragma long_calls,但它只影响声明,所以我可以使用它而不是__attribute__((__long_call__)).遗憾的是,它并没有神奇地强制编译器对它生效时遇到的所有函数调用使用长调用.

在组织上,将所有运行缓慢的代码分组到单个文件中,脱离上下文并与其常规类别中的其他代码分开是不正确的.请告诉我有一个我尚未考虑过的选项.为什么不-ffunction截面或只是一个事实,即代码在不同的部分(.text.flashtext)自动修复我的问题?

顺便说一下,当链接器发现编译器使用了一个没有足够空间来管理重定位的短调用时,链接器的错误是:relocation truncated to fit: R_ARM_THM_CALL against symbolfoo'在objs/foo.o中的.text.foo节中定义CFLAGS中的(and the section.text.foo is used instead of.text because of-ffunction-sections`.

Eri*_*ell 3

看来这个问题可能在 gcc 4.3.3 及更高版本中得到解决,但我一直在使用 4.3.2。我创建了一个宠物示例,该示例不会执行,但演示了不同部分的使用以及由此产生的链接错误。它无法使用 Codesourcery 的arm-2008q3进行构建,但可以使用arm-2009q1及更高版本进行构建。我需要更多时间来更新整个项目以使用较新的 gcc 版本,所以我还不能明确地说这解决了我的问题,但我强烈怀疑它确实解决了。

顺便说一句,我有另一种解决方法,可以替代将所有基于 ROM 的函数分组到-mthumb-calls构建的 rom.c 中:通过函数指针调用所有内容。在这种解决方法的情况下,治疗方法比疾病本身更糟糕:

((void(*)(void*, void*, int))&memcpy+1)(&dest, &src, len);
Run Code Online (Sandbox Code Playgroud)

您需要这样+1优化器才不会比您更聪明,但这对我来说不是问题,因为bx-ing 到一个奇数地址表示拇指模式,而我的所有代码都是拇指模式。但是,我不相信有一种方法可以制作通用宏来包装所有此类函数调用,因为每个指针都需要显式转换以匹配返回类型和参数列表 - 您实际上最终会显式重新声明每个函数您想要调用,甚至是您不提供的库函数。