如何鼓励 'address-of' 访问链接器变量

How to encourage 'address-of' access to a linker variable

Access symbols defined in the linker script by application 中所述,“从源代码访问链接描述文件定义的变量并不直观”——本质上,访问它们的 通常不是您想要的想要(因为它们并没有真正分配内存块,作为真正的编译器变量),并且只能通过它们的 地址 访问。是否有可以在声明时应用于变量的属性,或者 PC-Lint/static-analysis property/rule 可以应用于变量?

/* Linker config (.icf) file */
define symbol __ICFEDIT_region_ROM_start__  = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__    = 0x080FFFFF;

define symbol __ICFEDIT_region_ROM_size__ = (__ICFEDIT_region_ROM_end__ - __ICFEDIT_region_ROM_start__) + 1;
export symbol __ICFEDIT_region_ROM_start__;
export symbol __ICFEDIT_region_ROM_size__;
/* main.c */
void OS_SetROM(uint32_t start, uint32_t size){} // empty for demonstration only
int main(void)
{
  extern unsigned int __ICFEDIT_region_ROM_start__;
  extern unsigned int __ICFEDIT_region_ROM_size__;

  // INCORRECT - both probably read as '0', depending on what's actually in those locations
  // Can I get a warning or error about this usage?
  OS_SetROM(__ICFEDIT_region_ROM_start__, __ICFEDIT_region_ROM_size__);
  // CORRECT - *addresses of* linker-defined variables read
  OS_SetROM((uint32_t)&__ICFEDIT_region_ROM_start__, (uint32_t)&__ICFEDIT_region_ROM_size__);

nice 将地址声明为指针(如下所示),即您可以使用指针变量的值来表示 address 和 'value-of' 语义更有意义(至少在逻辑上 - 更明显的是在这种情况下你不会取消引用),但这不是它们的工作方式 - 为此,链接器也必须分配一个内存位置并将地址 存储在那里 ,或者 compiler/linker 的一些特殊语义,这似乎是不可能的......

void void OS_SetROM(uint32_t * const start, uint32_t size){} // empty for demonstration only
int main(void)
{
  // would be nice, but not how it works
  extern unsigned int * const __ICFEDIT_region_ROM_start__;
  extern unsigned int const __ICFEDIT_region_ROM_size__;

  OS_SetROM(__ICFEDIT_region_ROM_start__, __ICFEDIT_region_ROM_size__);

某种妥协可能是用适当的类型重新定义这些变量,ala:

unsigned int * const p_rom_start = &__ICFEDIT_region_ROM_start__;
unsigned int const rom_size = (unsigned int)&__ICFEDIT_region_ROM_size__;

void OS_SetROM(unsigned int * const p_start, unsigned int size);

OS_SetROM(p_rom_start, rom_size);

这有助于将 'unintuitive' 访问收集到一个地方,然后进行类型安全的访问,但在这种情况下这是不可能的,因为 API 被预定义为需要 uint32_t的。

我意识到这可能并不常见(并且可能只在一个项目中使用过几次,如果有的话),我意识到这也取决于使用属性(例如在创建新项目时),但我'我很好奇是否有保护措施可以防止意外误用 - 或防止不正确的 'simplification' (例如,后来一些不理解其含义的维护者)...我也想不出另一种情况下强制执行 'address-only' 访问是有意义的,因此解决方案可能不存在...

你不应该把c++和c放在同一个问题里;它们是用于不同目的的不同语言。

至少在 C 中,将它们声明为:

extern char ROMStart[], ROMEnd[];  /* shortforms are less clumbsy */

给你很多你想要的:

OS_SetROM(ROMStart, ROMEnd, ROMEnd-ROMStart); /* not sure why the last one */

尽管如果您尝试将这些位置视为关于对齐的短或长,那么聪明的编译器可能会抱怨,因此为了安抚它们,您可能会:

extern long ROMStart[], ROMEnd[];
intptr_t size = (intptr_t)ROMEnd - (intptr_t)ROMStart;
OS_SetROM(ROMStart, ROMEnd, size);

在 C++ 中,您必须参考 语言标准每分钟

您可以为不完整类型的对象声明标识符,例如未给出定义的结构:

extern struct NeverDefined __ICFEDIT_region_ROM_start__;

然后你可以获取它的地址,但尝试使用或分配它会产生编译错误。