I'm wondering if the compiler/linker will remove global variables that have been extern'd in a public header? For example:
// public.h
struct func_ptrs {
void (*foo)(void);
void (*bar)(int);
};
extern const struct func_ptrs DEFAULT_FUNCS;
and:
// private.c
#include "public.h"
void def_foo(void) { ... }
void def_bar(int a) { ... }
const struct func_ptrs DEFAULT_FUNCS = { .foo = def_foo, .bar = def_bar };
Are there any specific linker flags that will allow for this variable (and the two functions) to be stripped from the resulting binary?
Assume GCC and MSVC as the two target compilers.
DEFAULT_FUNCS:
Since the symbol DEFAULT_FUNCS - due to its scope and modifiers - is subject to being exported to the symbol table of the binary for (dynamic) linking, it cannot be stripped. In other words: The linker (ld) cannot determine if the symbols will be used or not.
Functions def_foo & def_bar
Furthermore, there are no functions at all which could be stripped, since you only declared them. Indeed, linking of this binary would fail, since def_foo and def_bar are undefined symbols.
One more thing: Correct would be:
const struct func_ptrs DEFAULT_FUNCS = ...
without the asterisk, since you initialize a struct, not a pointer.
Related
I'm trying to declare a global function accessible through different *.c files.
I have declared it in param.hxx, defined it in param.cxx and I would like to access it in compute_grid.c.
Unfortunately, during the compilation I have the following error :
compute_grid.c:(.text+0x5) : undefined reference to « grid_create »
I'm not very familiar with such functions declarations in C. Actually I'm building a module part of a big program, I've copied those declaration from another file of the code witch seems to work ?!
Unfortunately, the program is hugely confidential, I don't have access to all the sources but I will do my best to give you expurged parts...
param.hxx :
typedef struct grid_t
{
int *test;
} grid_t;
void
grid_create(void);
extern grid_t *grid;
param.cxx :
#include <malloc.h>
#include "param.hxx"
grid_t *grid;
void grid_create(void)
{
grid = (grid_t*)malloc(sizeof(grid_t));
grid->test = (int*)malloc(sizeof(int));
*grid->test = 123;
}
compute_grid.c :
#include "param.hxx"
void
compute_grid()
{
grid_create();
return;
}
Thank you for your help !
.cxx is one of the extensions used for C++ files. Your compiler may be using the extension of the file to compile the source as C++. When the C file is compiled, it generates an unresolved reference to the C symbol grid_create, but the compiled C++ file defines grid_create as a C++ symbol. Thus, the linker will leave the C symbol reference to grid_create unresolved, since there is only a C++ symbol associated with void grid_create(void).
You can try to guard the header file so that the C++ compiler will generate a C symbol rather than a C++ one.
#ifdef __cplusplus
extern "C" {
#endif
void
grid_create(void);
#ifdef __cplusplus
}
#endif
In my application I have a build config for pseudo unit testing (this is more a kind of manual debugging a dedicated function).
In those unit tests I'd like to access functions declared as static in their translation unit.
Is there an option of GCC that would allow me to call static functions from anywhere?
I'd like to avoid:
#if UNIT_TEST_MODE
void myfunction(void)
#else
static void myfunction(void)
#end
{
// body
}
Everywhere!
Thanks for your help :).
There is not need to be verbose. Use a prefix define for every static function:
#if UNIT_TEST_MODE
#define UNIT_TEST_STATIC
#else
#define UNIT_TEST_STATIC static
#end
UNIT_TEST_STATIC void myfunction(void)
{
// body
}
Another option is to move all static function from that .c file to a separate header. That header is included only in that .c file, but it can be included in the unit test .c file if needed. The functions will remain invisible in other files, unless the header is manually included.
(They will have to be defined as static inline. )
As applied to a function or file-scope variable, the static keyword means that the declared function or object has internal linkage. That means such a function or object can be directly referenced only from within the same translation unit. GCC has no option to alter this core provision of the C language, nor should it have.
Your alternatives, then, are either
to give the functions in question external linkage instead of internal linkage, perhaps conditionally, or
to make them available to the test code via an indirect mechanism, such as function pointers initialized and provided to the test code by some facility (another function, a global variable) inside the translation unit.
The first alternative is simpler, but using it means that the code under test is not wholly equivalent to code built for ordinary use. Additionally, this option is not viable if the names of any of the erstwhile-static functions collide with the names of other global objects. This option has been adequately demonstrated in other answers, so I won't go into further detail here.
The pros and cons of the second alternative are more or less the mirror image of those of the first. It is more complicated, but the functions can be tested in the same form that they have in the production build, and you can avoid name collisions by this route. There are many possible variations on this approach; here's one:
test_header.h
#ifndef TEST_HEADER_H
#define TEST_HEADER_H
struct test_pointers {
int (*function_to_test)(const char *);
};
void initialize_test_pointers(struct test_pointers *pointers);
#endif
module_under_test.c
static int function_to_test(const char *);
#ifdef ENABLE_TESTING
#include "test_header.h"
extern void initialize_test_pointers(struct test_pointers *pointers) {
pointers->function_to_test = function_to_test;
}
#endif
static int function_to_test(const char *s) {
// ... whatever
}
the_test.c
#include "test_header.h"
int test_it(void) {
struct test_pointers pointers;
char test_input[] = "test THIS!";
const int expected_result = 42;
int result;
initialize_test_pointers(&pointers);
result = pointers.function_to_test(test_input);
return result == expected_result;
}
No, it can not. This keyword specifies visibility of a function to be translation-unit only, as defined by launguage standard. Ignoring it by a compiler would render it non-conformant.
UPD. To solve your problem, you can indeed do the preprocessor directive trick, as mentioned in comments to your question.
This does not answer your question about GCC, but as a solution to your unit testing problem, you could conditionally compile a wrapper function in the same module,
static void myfunction(void)
{
// body
}
#if UNIT_TEST_MODE
void myfunction_test(void)
{
myfunction();
}
#endif
Or, you could #include the module from a unit test wrapper file,
// unit_test.c
#include "myfunction.c"
void unit_test()
{
myfunction();
}
Scoping in C is confusing as hell. I have a variable: "int qwe". This var should be visible in one or more files - f1.c in this case, but not the another f2.c .
Say i have: main.c, f1.c, f2.c, header.h
main:
call f1();
call f2();
header:
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
int qwe = 1;
void f1();
void f2();
#endif // HEADER_INCLUDED
f1.c:
#include <stdio.h>
extern int qwe;
void f1(){
printf("In f1: %d\n", qwe);
}
f2.c:
#include <stdio.h>
static int qwe = 2;
void f2(){
printf("In f2: %d\n", qwe);
}
Now this gets confusing. There is definition and declaration. I have defined qwe in the header, declared it in f1.c. Is that correct? Should definition happen in header and declaration in f1.c instead? I tried the latter case, but got an error - "multiple definition of qwe". When i removed the #include directive from f1.c, it worked... It also works when i remove the extern keyword. Is extern redundant?
f2.c i guess it's ok and behaves as expected, or is it? But if i put an #include with header, it breaks. Why is that?
When should i use #include in source files? If i don't include it f1.c or f2.c it works...
Also, if i define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data. And next time that same function gets called, will have access to it, right? But the var won't be reinitialized to 0, i.e. the line where is defines won't execute. Correct?
Life stomps me :(
In the header, declare the variable. In e.g f1.c, define the variable, e.g. int qwe = 1; // at global scope.
In all files that want to see/change qwe, include the header that declares the variable. Easy-peasy.
You need to declare the variable in the header, and define it in one and only one C file.
In C, you cannot have a variable that doesn't "belong" to a given translation unit (source file). So it must be defined by exactly one translation unit in the whole program.
When you declare a variable as extern, you're telling the compiler the symbol is (possibly) external to your translation unit (c file).
It's probably also worth noting that when you try to declare a variable without extern, the variable is also defined, e.g.:
/* Declares, but does not defines external symbol 'foo' */
extern int foo;
/* Both declares AND defines bar */
int bar;
This is also different from how functions work to where the "default" syntax for declaration does NOT define a function:
/* Declare, but don't define spam */
void spam(void);
/* Declare, but don't define eggs */
extern void eggs(void);
/* Declare & define 'cheese' */
void cheese(void){ return; }
So your example should look more like this:
qwe.h:
#ifndef QWE_H
#define QWE_H
/* Declare qwe here */
extern int qwe;
#endif
f1.c:
/* DEFINE qwe here */
int qwe = 1;
f2.c:
#include "qwe.h" /*header includes the `extern int qwe` declaration */
void my_function(void)
{
/* use external symbol here! */
qwe = 10;
}
The scoping system isn't that confusing. The rule is this:
if you define something in a .c file EVERY other .c file in your program can access it (it is put in the global namespace).
if you specify static in front of its definition then only things in the SAME file can see it. This should be your default position for all functions and variables you don't want other .c files to be able to access.
It is very important to remember that extern only tells the compiler that the variable/function in question is not defined in the current file. This prevents the compiler for otherwise issuing an error because it can't find the symbol, but it has nothing to do with scoping - your .c file sees everything in the global namespace and if you have not followed the second part of the rule you will quickly find out about this at link time.
Header files similarly have nothing to do with scoping. They are just convenient places to put a bunch of extern statements and macros.
In C, you should use the header file in general to declare the data but not define the data. You don't want to define global data in a header because it will then be redundantly defined in multiple modules. The header indicates to multiple modules the existence of some data or function somewhere and what its type is, as well as common constants and macros (#defines). Outside of that, things in C are very simple. Just about anything is, technically, global unless you declare it static, keeping it scoped to the module it's defined in. The extern declarations for data in the headers and the function prototypes help the compiler know that these items are being accessed by a particular module and what the data types are for access so that the correct code can be generated.
You have:
Two functions f1 and f2 that are defined in separate modules but used in main. So these need to be declared in a header file.
A global data item qwe being used in more than one module.
A static qwe used in one module.
Assuming you want this done with one header file (you might need separate ones for f1, f2, and global data - see below), you could set up
your header as:
#ifndef MY_HEADER_H
#define MY_HEADER_H
extern int qwe;
void f1(void);
void f2(void);
#endif // MY_HEADER_H
Then in your main.c:
...
#include "my_header.h"
int qwe; // This is global and can be accessed from other modules
void main(...)
{
// call f1
// call f2
...
I just defined the global variable, qwe, in main.c arbitrarily. If you have a few globals, you can define them in their own glob_data.c module, for example, and have it's own header, glob_data.h, to declare them. Any other module that needs to access them would include the glob_data.h header so that compilation can properly be done on that module to access that data. Keeping the global data in separate headers helps with cases like you have where you have a static instance of the data versus the global, which are in conflict. You can avoid including the data header file for that global item when you want to compile with the static item.
Then in your C file, f1.c:
...system headers included...
#include "my_header.h"
void f1() {
printf("In f1: %d\n", qwe);
}
And in f2.c:
...system headers included...
#include "my_header.h" // Only if it doesn't contain `extern int qwe;`
static int qwe = 2; // This hides the global qwe and is known only
// to f2.c
void f2(){
printf("In f2: %d\n", qwe);
}
As I mentioned above, you might want to separate your function prototypes and your global data declaration in separate headers. That way, you can include only what's needed in each module and avoid conflicts, such as when you have a static int qwe; versus the global int qwe;.
I have defined qwe in the header, declared it in f1.c. Is that correct?
No, it should be the other way around. You are supposed to have a definition of a global variable in a single translation unit (that's geek speak for a .C file) but you may declare it in as many translation units as you wish. Since headers potentially get included from many translation units, declarations go in the headers.
When should i use #include in source files?
You do it when the header has anything that is needed for your translation unit to compile, with very few exceptions. Note that in some situations it may be necessary or desirable to make a forward declaration manually without including the header.
Also, if I define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data.
That is correct, the static variable inside the function will be assigned the initial value only once, and retain the value that you assign to it for as long as your program continues to run.
I want to statically initialise a struct that will be visible from all files which include some header.
The actual intention is to run lists of functions specified at compile time, which is why I want to initialise statically. I'd like to put the lists where they belong, in the file in which they are declared or defined.
Contrived example:
general.h:
struct Widget { int (*a)(); };
foo.h:
int oof1(void);
int oof2(void);
foo.c:
#include "foo.h"
int oof1(void) { return 1; }
int oof2(void) { return 2; }
struct Widget foo_widgets[] = { {oof1}, {oof2} };
bar.c:
#include "foo.h"
#include "baz.h"
struct Widget *foo_widgets;
struct Widget *baz_widgets;
struct WidgetsContainer {
struct Widget *widget_list;
} wlists[] =
{
{ foo_widgets },
{ baz_widgets }
};
void usage(void) { ... ; process (wlists[i].widget_list); ... }
This obviously doesn't work because "the initialiser element is not constant" - This is because when the compiler is translating bar.c, it thinks it doesn't know the location of foo_widgets (or bar_widgets).
But since bar.c #includes foo.h anyway, it's always compiled alongside foo.c:
gcc foo.c baz.c bar.c
So I'm hoping there's a way of reflecting this in the source code.
I can't declare foo_widgets in foo.h, because then I wouldn't be able to initialise it without defining it multiple times (as foo.h is included in more than one file).
Inelegant workaround
foo.h:
...
Widget *get_foos(void) { return foo_widgets; }
bar.c:
...
struct Widget_lists {
struct Widget (*widget_list)();
} wlist[] =
{
{ get_foos },
{ get_bazes }
};
void usage(void) { ...; process(wlist[i].widget_list()); ... }
Is there a better way?
You want to have a global variable that you can reach anywhere ... To do so you have to declare it as an external variable in the appropriate header.
Here, it should be done as follows :
In foo.h :
/* ... */
int oof1(void);
int oof2(void);
extern int (*foo_widget)(void)[2];
In foo.c :
int (*foo_widget)(void)[2] = {{oof1}, {oof2}};
By doing so, when including "foo.h", the foo_widget variable will be known (and expected to be defined somewhere else - in foo.c here - ).
To be more precise ... Any piece of code that needs to make use of foo_widget must have the line extern int (*foo_widget)(void)[2]; somewhere, be it in an included header (the smarter way) or just a line at the beginning of the .c file.
Of course, if you cannot know in advance the number of widgets you can have, you are likely to need a dynamic data structure such as a linked list or a tree (ordered and balanced if possible ;) ) to store them. The extern variable is likely to be a regular pointer dynamically allocated when needed. But the definition line is still needed, so in this case you might have something like struct my_struct *pointer = NULL; in the appropriate source file.
Note : I took the freedom to replace your struct Widget with a common function pointer to get the initialization simpler.
from here
48 struct snd_card *snd_cards[SNDRV_CARDS];
49 EXPORT_SYMBOL(snd_cards);
I am not getting whats the meaning of it and why that is used. I tried to search about it but not understanding the meaning of that.
It makes a symbol accessible to dynamically loaded modules (provided that said modules add an extern declaration).
Not long ago, someone asked how to use it.
Here is a good explanation.
https://www.quora.com/What-is-the-difference-between-extern-and-EXPORT_SYMBOL-in-Linux-kernel-codes
Extern is a C storage class keyword. In the kernel, as in any other C
code, it tells the compiler that the definition of the variable or
function it qualifies is implemented in another “file”, or rather,
more accurately Translation unit (programming) - Wikipedia. The
translation unit that does define it should not use the static
qualifier. Therefore, the symbol table has an entry corresponding to
it. At link time, the symbol is resolved as normal. There is nothing
kernel specific about “extern”.
EXPORT_SYMBOL() is a macro the Linux kernel headers define. It has not
much in common with extern. It tells the kbuild mechanism that the
symbol referred to should be part of the global list of kernel
symbols. That, in turn allows kernel modules to access them. Code that
is built into the kernel itself (as opposed to a module) can, of
course, access any non-static symbol via an extern declaration, in
accordance with regular C. The EXPORT_SYMBOL() mechanism allows us to
export a symbol for use by loadable modules as well. An interesting
thing is that a symbol thus exported by one module becomes accessible
to another module that may depend on it!
To summarise, extern is not kernel specific. It is used to qualify a
declaration to a non-static symbol from another translation unit.
EXPORT_SYMBOL() is specific to the Linux kernel. It is used in the
translation unit of the definition to make the symbol available to
loadable modules.
So EXPORT_SYMBOL is just a mechanism like extern, but it's for reference between loadable modules not file.
To move forwards, we can guess it's achived by the extern because extern is form C which is the foundation.
Here is a clue.
https://elixir.bootlin.com/linux/v4.6.7/source/include/linux/export.h#L56
#define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "")
/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec) \
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] __attribute__((section("__ksymtab_strings"), aligned(1))) = VMLINUX_SYMBOL_STR(sym); \
extern const struct kernel_symbol __ksymtab_##sym; \
__visible const struct kernel_symbol __ksymtab_##sym __used __attribute__((section("___ksymtab" sec "+" #sym), unused)) = { (unsigned long)&sym, __kstrtab_##sym }
First declare a extern sym.
Then a string __kstrtab_##sym = = VMLINUX_SYMBOL_STR(sym).
Last a extern struct kernel_symbol __ksymtab_##sym = { (unsigned long)&sym, __kstrtab_##sym }. &sym record the real address of the sym such as a function or variable, _kstrtab##sym record the name string.
Not an answer per se but a demonstration, as promised from my comment, that exported symbols are not required to be non-static. The below 2 modules demonstrate this:
/* mod1.c */
#include <linux/module.h>
static int mod1_exp_func(int i)
{
pr_info("%s:%d the value passed in is %d\n",
__func__, __LINE__, i);
return i;
}
EXPORT_SYMBOL(mod1_exp_func); /* export static symbol */
static int __init mod1_init(void)
{
pr_info("Initializing simple mod\n");
return 0;
}
static void __exit mod1_exit(void)
{
pr_info("This module is exiting\n");
}
module_init(mod1_init);
module_exit(mod1_exit);
MODULE_LICENSE("GPL v2");
And the second module
/* mod2.c */
#include <linux/module.h>
extern int mod1_exp_func(int);
static int __init mod2_init(void)
{
pr_info("Initializing mod2\n");
pr_info("Calling exported function in mod1\n");
mod1_exp_func(3);
return 0;
}
static void __exit mod2_exit(void)
{
pr_info("mod2 exiting\n");
}
module_init(mod2_init);
module_exit(mod2_exit);
MODULE_LICENSE("GPL v2");
These were tested on CentOS 6 & CentOS 7: kernels 2.6.32 and 3.10 (respectively). Loading mod1.ko and then mod2.ko will result in the value passed to mod1_exp_func() being printed to the kernel log buffers.