我将从最终的问题开始:在C中使用gcc,是否可以获得__func__(或等效地__FUNCTION__)存储在除.rodata(或其中任何-mrodata=点)或子部分之外的部分的值(?)?
完整的解释:
假设我有一个记录宏:
#define LOG(fmt, ...) log_internal(__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
(##当且仅当__VA_ARGS__列表为空时,在该一元上下文中使用的字符串连接运算符使用前面的逗号,从而允许使用带或不带参数的格式字符串.)
然后我可以正常使用宏:
void my_function(void) {
LOG("foo!");
LOG("bar: %p", &bar);
}
Run Code Online (Sandbox Code Playgroud)
可能打印(显然取决于实施log_internal):
foo.c:201(my_function) foo!
foo.c:202(my_function) bar: 0x12345678
Run Code Online (Sandbox Code Playgroud)
在这种情况下,格式字符串("foo"和"bar: %p")和预处理程序字符串("foo.c"和"my_function")是匿名只读数据,它们会.rodata自动放入该部分.
但是我说他希望他们去另一个地方(我在一个嵌入式平台上运行几乎所有来自RAM的速度,但内存限制正在推动将一些东西转移到ROM中).移动__FILE__和格式字符串"简单" :
#define ROM_STR(str) (__extension__({static const __attribute__((__section__(".rom_data"))) char __c[] = (str); (const char *)&__c;}))
#define LOG(fmt, ...) log_internal(ROM_STR(__FILE__), __LINE__, __func__, ROM_STR(fmt), ##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
你不能放一个__attribute__匿名字符串,所以 …
我正在使用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: …
我正在尝试执行一个理论上可行的内存优化,但我开始怀疑是arm-elf-gcc的能力.请告诉我,我错了.
我有一个嵌入式系统,主内存非常少,电池支持的nvram数量更少.我将校验和配置数据存储在nvram中,以便在启动时我可以验证校验和并继续前一次运行或在校验和无效时开始新的运行.在运行期间,我在此配置数据中更新各种大小的各种字段(并且可以使校验和无效,直到稍后重新计算).
所有这些都在物理地址空间中运行 - 正常的sram映射在一个位置,nvram映射到另一个位置.这是擦除 - 所有对nvram的访问必须以32位字进行; 不允许字节或半字访问(虽然它在主存中显然很好).
因此,我可以a)将所有配置数据的工作副本存储在主存储器中,并在重新计算校验和时将其存储到nvram中,或者b)直接在nvram中使用它,但不知何故说服编译器所有结构都是打包和所有访问不仅必须是32位对齐,还必须是32 位宽.
选项a)浪费宝贵的主内存,我宁愿通过选项b)进行运行时权衡以保存它(尽管不是代码大小最终浪费的东西比我节省的数据大).
我希望这__attribute__ ((packed, aligned(4)))或其中的一些变化可以帮到这里,但到目前为止我所做的所有阅读和实验都让我失望了.
这是我正在处理的配置数据的玩具示例:
#define __packed __attribute__ ((packed))
struct __packed Foo
{
uint64_t foo;
struct FooFoo foofoo;
}
struct __packed Bar
{
uint32_t something;
uint16_t somethingSmaller;
uint8_t evenSmaller;
}
struct __packed PersistentData
{
struct Foo;
struct Bar;
/* ... */
struct Baz;
uint_32 checksum;
}
Run Code Online (Sandbox Code Playgroud)
您可以想象不同的线程(每个线程执行Foo,Bar和Baz函数)根据需要更新自己的结构,并在某些时候进行同步以声明重新计算校验和并进入休眠状态的时间.