【问题标题】:Does adding a variable to a section provide staticness?向部分添加变量是否提供静态性?
【发布时间】:2018-02-23 21:12:11
【问题描述】:

基本上我是在问声明是否

unsigned char myBuffer[128] __attribute__((section (".some_section")));

相同
static unsigned char myBuffer[128] __attribute__((section (".some_section")));

即我想知道是否将变量声明为放入特定部分将提供不可覆盖的功能,就像 static 声明所做的那样。或者myBuffer 的内存是否分配在其代码范围内,可供其他人(范围外)覆盖?当我稍后回到myBuffer 的代码范围时,它可能根本不包含与以前相同的值?

测试起来并不简单,因为“未定义”行为通常(在简单的代码 sn-p 测试中)表现得非常明确。

编辑: 感谢您的回答和讨论。这里是对意图的澄清。

就我而言,在buf.c 中,我有一个结构ms 和一个uint32_t-array 成员(以及其他成员,但让我们把它们排除在外)。

buf.c

#include <stdio.h>  // and many other includes

typedef struct myStruct {
    uint32_t a[BUFSIZE];
} MyStruct_t;

MyStruct_t ms  __attribute__ ((__section__(".do_not_init_section")));

void startUpCode() {
    // Init all members of struct to some values...
}

void foo(uint32_t* buf, int bufsize) {
    // figure out the right position in array to write to, i.e. find posInStruct. And memcpy...
    memcpy(&ms.a[posInStruct], buf, bufsize)
}

main.cwhile 循环中,main.c 中的所有其他函数都可以在bar.c 中调用foo(...)

我当然希望ms.a 在程序的整个生命周期内只能由bar.c 修改,它就是这样。 (好的,它不受 extern 的保护,因为它不是静态的,但没关系,没有其他文件是 extern-ing ms in bar.c。) 但是我的问题是ms 是否真的受到保护。 ms 的内存是在整个生命周期中专用于 ms 还是只有 static 声明才能处理?

我希望在整个程序生命周期内“记住”所有修改,例如我在开头向数组ms.a[] 写入一些值,然后在bar.c 中退出foo(...)。下一次(在程序中的所有其他函数都完成了它们所做的事情之后),我在bar.c 中对foo(...) 进行了新调用,现在我希望ms.a[] 保持完整并包含与我上次离开它时相同的值.这与其他函数是否显式更改ms 的值无关,更多的是当ms 不在范围内时它们是否隐式碰巧写入ms 的内存,因为超出范围时内存不是专用的!?

如果它与globals 或sections 无关,我会通过声明结构static 来确定问题不会存在。但是我对section-ing 部分有点不确定,它是否真的在内存中保护并保持ms 的值完好无损。

我的天啊,我从来没有编辑过这么多的文字,我希望有人可以编辑并使它更紧凑和聪明。

【问题讨论】:

  • 请解释一下您的问题中不可覆盖的功能是什么意思。你在说什么功能?
  • @LuisColorado 我的意思是,对于static,变量的内存被分配并单独为该变量保留......没有其他人(即使在变量范围之外)可以意外覆盖该部分记忆
  • 带或不带静态,除了在 fortran 中,允许共享空间(公共)所有变量都单独保留一个空间(不能共享)但如果您的问题不是意外覆盖该变量,例如缓冲区溢出,在这种情况下你是不安全的。即使属于不同的部分,内存保护也不适用于此处。所有可写部分由链接器放在一起。那么,为什么不问你真正担心的是什么,而不是对static 关键字做出假设呢?这是 XY 问题的一个实例。
  • @LuisColorado 我认为您回答了问题中的“EDIT2”。我不知道你认为我对静态的假设有什么问题?想象一下这个问题不包括section,我会说我想在调用C文件之间记住我的变量的值,其中变量的作用域是全局的。你会告诉我声明变量为静态的,不是吗?

标签: c gcc arm


【解决方案1】:

section 属性仅用于with an initialized definition of a global variable。 IE。在任何情况下都有一个静态存储类。并且它不会添加 static 关键字所做的受限范围功能。所以不,它没有提供“静态”。

【讨论】:

  • 链接+1。我们谈论的是多么“全球化”。就我而言,该变量在整个文件中被初始化为“全局”,仅此而已。我的意思是,它没有在函数中声明。其次,我根本不明白“即在任何情况下都有一个静态存储类”。
  • C 术语中的全局变量是在任何函数(包括main)之外定义的变量。它们都具有 static 存储类,即具有整个程序运行的生命周期。与具有自动存储类型并且仅在函数执行时存在的函数局部变量(没有static 限定符)相反。您可能想对这些进行更多研究。
  • 我已经编辑了一些澄清......但无论如何......我没有收到警告,因为链接显示“GCC发出警告,否则会忽略未初始化变量声明中的部分属性”。 ..我不知道
  • 我的意思是,我理解它的方式..我的示例中的变量是全局的并且具有整个程序的生命周期...但与链接示例(和你的)不同,它无关与主。
  • 你的是全球性的,没关系。但未初始化。尝试显式启用 -Wignored-attributes 警告 (gcc.gnu.org/onlinedocs/gcc/Warning-Options.html)。还可以在 map 文件中查看此变量的实际运行位置。
【解决方案2】:

static 有两种含义,具体取决于使用的上下文。在块的自动作用域中,static 意味着使变量全局生命,同时保持块嵌套所指示的作用域。在全局文件范围上使用时,意味着不要将范围扩展到定义它的文件之外。无论如何,您指定的属性仅对全局变量有意义,因此在某种意义上它们是static,这意味着它们具有全局生命属性。全局范围(针对文件或编译单元范围)可以由编译器通过使变量全局可访问或不可访问来控制(这意味着变量名称是否进入符号表以进行链接)。如果你这样说:

int main()
{
    static int array[] __attribute__((__section__(".do_not_init_section")));
}

您可能无法从其他模块访问该变量(编译器不会在符号表中发布变量名称),因为编译器仅将本地范围声明为 main

无论如何,__attribute__ 关键字是 gcc 独有的功能(但我不能保证 CLANG 也实现了它)所以最好的方法是进行一些测试,直到你得到(并且满意)回应。

编辑

如果您认为可以通过将变量放在不同的部分来保护变量免受意外覆盖,那么您就错了。保护是在进程级别实现的,但是任何具有读/写访问权限的部分都可以被覆盖,而与您在代码中访问它的位置无关。代码通常属于一个部分,而它访问的代码通常位于不同的部分中,因此请考虑一下并尝试猜测保护如何区分您是有意还是无意访问变量。

【讨论】:

  • 我想我明白了。你说全局变量与非全局变量具有相同的生命属性,但static。当你声明一个全局变量static 时,你并没有添加到 life 属性,而只是将变量限制在范围内。对吗?
  • 不,我是说static 赋予变量永恒的生命,但变量的生命是完全独立的(编译器也是如此)可见性(通过包含或不是编译对象的符号表中的变量)在范围内不可见并不会阻止您意外地覆盖它,即使在变量属于另一个部分的情况下也是如此。内存保护未在节级别实现。
  • 好的,很好。因此,为了让我既保护变量(在整个程序生命周期内)并将其放在 .do_not_init 部分中,我必须在全局变量上使用 static
  • 不,使用const。然后它将被放入以文本段结尾的.rodata 部分......因此,它现在是可写的。但是你只能初始化它,你不能修改它的值。
  • 我必须能够在运行时修改...还有很多修改
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2010-10-02
  • 2012-05-18
  • 2016-09-10
  • 2023-04-07
  • 2011-01-24
相关资源
最近更新 更多