Below is the trick used in Linux Kernel for per-cpu valuables. As the comment says, it could acheive these two goals:
1.enforce scope.
2.ensure uniqueness, even the static ones.
Here is how the magic plays(For simplicity, I subsititude some MACRO's) :
/*
* __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
My questions are
For Goal #1. How could it enforce scope? Does it work like this:
When DECLARE* and DEFINE* exist in the same traslation unit, it turns the variable in question to internal linkage, and thus, any extra DECLARE* for the same variable will trigger build failure(cause they disagree on linkage)
But if this is true, then
For Goal #2, the two __pcpu_unique_##name decalation(exactly, one is declaration, the other one is definition) seems play the same trcik as the __pcpu_scope_##name, then how it help to ensure the uniqueness ?
FYI, the code in question could be viewed here: http://lxr.linux.no/linux+v3.9/include/linux/percpu-defs.h#L61
I don't think this is enforced by the compiler. See the ARM vmlinux.lds.S, vmlinux.lds.h and percpu.h; the linker file is pre-processed to use kernel configuration variables. The ".discard"
sections are a bunch of symbols that will cause a link conflict on multiple definitions; but they are thrown away and do not make it into a binary.
See the macros PER_CPU, PER_CPU_FIRST, PER_CPU_SHARED_ALIGNED, etc. These macros only take a type and name.
Your macro expansion is not quite correct.
#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
The sec parameters is actually a sub-section; note PER_CPU_BASE_SECTION and the string concatenation.
As I understand it, It receives the static modifier... seems misleading. It would be better expressed as If it receives.... So these cases are different,
static DEFINE_PER_CPU_PAGE_ALIGNED(... /* Cause error with DECLARE */
DEFINE_PER_CPU(unsigned int, irq_count) = -1; /* Fine with DECLARE */
In any case, this is not being enforced by the compilers, but by the GNU linker (or at least both) as it is important that these values are cache aligned and in some cases the cache size is configured by the kbuild infrastructure.
It is also important to note a preceding comment related to code generation,
* 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.
Ie, the __attribute__((weak))
is being used not for symbol resolution but for code generation side effects. There is an #else
condition where the weak
complication is not bothered with.
Now to answer your questions briefly,
For Goal #1. How could it enforce scope?
Both a static and non-static declaration result when we have,
DECLARE_PER_CPU_PAGE_ALIGNED(int,foobar);
static DEFINE_PER_CPU_PAGE_ALIGNED(int,foobar);
For Goal #2, ...
__pcpu_unique_##name
, then how it help to ensure the uniqueness ?
Multiple weak
symbols do not cause errors. The __pcpu_unique_##name
is not weak
so it is being used to enforce uniqueness as weak
is being used for code generation reasons.
See Gcc's function attributes and search for weak, in case the normal purpose of weak is not understood.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With