如何确保全局符号的唯一性并限制其在C中的范围?

时间:2013-04-30 03:31:23

标签: c linux-kernel

以下是Linux内核中用于per-cpu贵重物品的技巧。 正如评论所说,它可以实现这两个目标:

1.强制范围。

2.确保独特性,即使是静态的。

以下是魔术的演奏方式(为简单起见,我认为是一些MACRO):

/*
 * __pcpu_scope_* dummy variable is used to enforce scope.  It
 * receives the static modifier when it's used in front of
 * DEFINE_PER_CPU() and will trigger build failure if
 * DECLARE_PER_CPU() is used for the same variable.
 *
 * __pcpu_unique_* dummy variable is used to enforce symbol uniqueness
 * such that hidden weak symbol collision, which will cause unrelated
 * variables to share the same address, can be detected during build.
 */
 #define DECLARE_PER_CPU_SECTION(type, name, sec)                        \
 extern __attribute__((section(".discard"), unused))                     \
               char __pcpu_scope_##name;                                 \
 extern __attribute__((section(sec))) __typeof__(type) name

 #define DEFINE_PER_CPU_SECTION(type, name, sec)                         \
 __attribute__((section(".discard"), unused)) char __pcpu_scope_##name;  \
 extern __attribute__((section(".discard"), unused))                     \
             char __pcpu_unique_##name;                                  \
 __attribute__((section(".discard"), unused)) char __pcpu_unique_##name; \
 __attribute__((section(sec)))  __attribute__((weak))                    \
              __typeof__(type) name

我的问题是

  1. 目标#1。它怎么能强制范围?它是这样的:

    相同的翻译单元中存在DECLARE *和DEFINE *时,它会变为 有问题的变量到内部链接,因此,任何额外的DECLARE * 相同的变量将触发构建失败(因为它们在链接上不一致)

    但如果这是真的,那么

    • 内部联动接收如何运作?从C99 6.9.2.2(外部对象定义),这仅适用于暂定定义,但这种情况似乎不是暂定定义
    • 这不会打破“One-definition-and-mutiple-declarations-are-OK”规则?
  2. 对于目标#2,两个__pcpu_unique _ ##名称decalation(确切地说,一个是声明,另一个是定义)似乎和__pcpu_scope _ ##名称一样播放trcik,那怎么样 有助于确保独特性?

  3. 仅供参考,有问题的代码可以在这里查看: http://lxr.linux.no/linux+v3.9/include/linux/percpu-defs.h#L61

1 个答案:

答案 0 :(得分:4)

我不认为这是由编译器强制执行的。请参阅ARM vmlinux.lds.Svmlinux.lds.hpercpu.h; 链接器文件已预处理为使用内核配置变量。 ".discard"部分是一堆符号,会导致多个定义的链接冲突;但是他们被扔掉了并且没有把它变成二进制文件。

请参阅 PER_CPU PER_CPU_FIRST PER_CPU_SHARED_ALIGNED 等。这些宏只占用输入名称

你的扩展不太正确。

 #define DECLARE_PER_CPU_SECTION(type, name, sec)                        \
 extern __attribute__((section(".discard"), unused))                     \
               char __pcpu_scope_##name;                                 \
 extern __attribute__((section(PER_CPU_BASE_SECTION sec))) __typeof__(type) name

sec 参数实际上是子部分;注意 PER_CPU_BASE_SECTION 和字符串连接。

据我了解,它收到静态修饰符...... 似乎有误导性。它会更好地表示为如果 它会收到...... 。所以这些情况不同,

static DEFINE_PER_CPU_PAGE_ALIGNED(... /* Cause error with DECLARE */
DEFINE_PER_CPU(unsigned int, irq_count) = -1; /* Fine with DECLARE */

在任何情况下,这都不是由编译器强制执行,而是由 GNU链接器(或至少两者)强制执行,因为这些值是高速缓存对齐并且在某些情况下是高速缓存很重要大小由 kbuild 基础架构配置。

注意与代码生成相关的前面评论也很重要,

 * s390 and alpha modules require percpu variables to be defined as
 * weak to force the compiler to generate GOT based external
 * references for them.  This is necessary because percpu sections
 * will be located outside of the usually addressable area.
 * This definition puts the following two extra restrictions when
 * defining percpu variables.
 *
 * 1. The symbol must be globally unique, even the static ones.
 * 2. Static percpu variables cannot be defined inside a function.
 *
 * Archs which need weak percpu definitions should define
 * ARCH_NEEDS_WEAK_PER_CPU in asm/percpu.h when necessary.

即,__attribute__((weak))不用于符号解析,而是用于代码生成副作用。有一个#else条件,weak并发症不会受到干扰。

现在简要回答一下你的问题,

  

目标#1。它怎么能强制范围?

我们拥有静态非静态声明结果,

DECLARE_PER_CPU_PAGE_ALIGNED(int,foobar);
static DEFINE_PER_CPU_PAGE_ALIGNED(int,foobar);
  

对于目标#2,... __pcpu_unique_##name,那么它如何帮助确保唯一性?

多个weak符号不会导致错误。 __pcpu_unique_##name不是weak因此用于强制执行唯一性,因为代码生成原因会使用weak

如果不了解弱的正常目的,请参阅Gcc's function attributes并搜索弱。