Listing external variables in cpp file - c++

External variables are not listed by "nm" command because they have been declared as extern so memory for them will not be allocated in this program. Is there any other way to list extern variables? Where stored information about external variables declaration?
os windows 7
compiler mingw or vs2010

They will be there, marked U for undefined.
extern int foo;
int bar() {
return foo++;
}
Gives:
g++ -c test.cc
nm test.o
00000000 T _Z3barv
U foo
Note that bar is needed for this example to work. If the variable is unused no reference will be generated in the output.

Related

C++ assign function in order to re-export it as extern "C"

Is it possible to export a C++ function with a C-compatible type (in this case (int, int) -> int) as a C symbol just by assigning it? Are there any hidden gotchas you have to watch out for?
The following code compiles without warnings and the resulting file has two symbols exposed.
I was surprised that it compiles at all, since I'm not sure what it means to copy a function.
namespace simplemath {
int add(int x, int y) {
return x + y;
}
}
extern "C" auto add = simplemath::add;
$ clang++ -Wall -Werror -pedantic --std=c++11 -c example.cc
$ nm example.o
0000000000000000 T __ZN10simplemath3addEii
0000000000000018 D _add
Is the code above equivalent to the following (up to whether or not simplemath::add is inlined)?
extern "C" int add(int x, int y) {
return simplemath::add(x, y);
}
namespace simplemath {
int add(int x, int y) {
return x + y;
}
}
You get
$ clang++ -Wall -Werror -pedantic -c example.cc
$ nm example.o
0000000000000020 T __ZN10simplemath3addEii
0000000000000000 T _add
No, this won't, in general, work. Functions with C linkage and functions with C++ linkage have different types, even if they take the same argument types and return the same type. So that function-pointer assignment is not legal. Most compilers don't enforce this, however, so you might get away with it. Of course, as soon as you upgrade to a compiler that enforces the correct semantics here your code will break.
Many people misunderstand the difference between C and C++ linkage, and think that it's just a matter of name mangling. But it's more than that. For example, the compiler can use different calling conventions for the two different linkages, and in that case, there's no way you could use a pointer to a C++ function in C code. extern "C" tells the compiler to compile the function so that it can be called from C.
The first version doesn't really copy a function (you can't do that), but rather creates a pointer to the function.
That might perhaps work if the compiler uses the same calling conventions for C and C++ functions. It might fail to compile otherwise, I don't know.
Anyway, I would use the second version as that is the intended way to create wrapper functions, and will be more portable. By "repacking" the parameters in the extern "C" function we know that they are passed correctly.

gcc linking externs incorrectly?

I'm relatively new to gcc and I'm using 'gcc (tdm-1) 5.1.0'. I've come across a very peculiar circumstance by mistake. I've shrunk my concern down to a very small reproducible example...
main.cpp
extern int g;
int main(){
return g;
}
someOtherFile.cpp
#include<windows.h>
RECT g;
this I compile with
gcc -c someOtherFile.cpp
gcc main.cpp someOtherFile.o
and this will link without error.
Am I missing something here as to why this is allowed to link?
3.5/10:
After all adjustments of types (during which typedefs (7.1.3) are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound (8.3.4). A violation of this rule on type identity does not require a diagnostic.
That last sentence means the compiler and linker are not required to give you an error message. It's your job to get it straight.
In C++ it won't link as the types of g are non-matching between main.cpp and someOtherFile.cpp. You have to have int g in someOtherFile.cpp or opposite, extern RECT g; in main.cpp.
In C this will compile and link, but on in c++.
Com compile and link as c++:
g++ -c someOtherFile.cpp
g++ -c main.cpp
g++ main.o someOtherFile.o -o test
Alternatively, you may use functions for this:
main.cpp
int g();
int main{
return g();
}
someOtherFile.cpp
#include<windows.h>
RECT r;
int g()
{
return (int)r;
}
Obviously not recommended (as there isn't much point to cast RECT to int), but that would be similar in effect to what you were trying to do.
Variable g inside someOtherFile.cpp isn't related to the other extern int g declared in main.cpp. In effect, the int g simply isn't defined anywhere and linker will fail at the end for this reason.
Apparently, this will actually compile and link by g++, while microsoft linker will error on this type of mistake.

Am I guaranteed to not be bitten by this ODR violation?

I have a header file that declares a template with a static variable and also defines it:
/* my_header.hpp */
#ifndef MY_HEADER_HPP_
#define MY_HEADER_HPP_
#include <cstdio>
template<int n>
struct foo {
static int bar;
static void dump() { printf("%d\n", bar); }
};
template<int n>
int foo<n>::bar;
#endif // MY_HEADER_HPP_
This header is included both by main.cpp and a shared library mylib. In particular, mylib_baz.hpp just includes this template and declares a function that modifies a specialization of the template.
/* mylib_baz.hpp */
#ifndef MYLIB_BAZ_HPP_
#define MYLIB_BAZ_HPP_
#include "my_header.hpp"
typedef foo<123> mylib_foo;
void init_mylib_foo();
#endif // MYLIB_BAZ_HPP_
and
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
When I make mylib.so (containing mylib_baz.o), the symbol for foo<123>::bar is present and declared weak. However, the symbol for foo<123>::bar is declared weak also in my main.o:
/* main.cpp */
#include "my_header.hpp"
#include "mylib_baz.hpp"
int main() {
foo<123>::bar = 456;
foo<123>::dump(); /* outputs 456 */
init_mylib_foo(); /* outputs 123 */
foo<123>::dump(); /* outputs 123 -- is this guaranteed? */
}
It appears that I am violating one definition rule (foo<123>::bar defined both in my_header.cpp and main.cpp). However, both with g++ and clang the symbols are declared weak (or unique), so I am not getting bitten by this -- all accesses to foo<123>::bar modify the same object.
Question 1: Is this a coincidence (maybe ODR works differently for static members of templates?) or am I in fact guaranteed this behavior by the standard?
Question 2: How could I have predicted the behavior I'm observing? That is, what exactly makes the compiler declare symbol weak?
There is no ODR violation. You have one definition of bar. It is here:
template<int n>
int foo<n>::bar; // <==
As bar is static, that indicates that there is one definition across all translation units. Even though bar will show up once in all of your object files (they need a symbol for it, after all), the linker will merge them together to be the one true definition of bar. You can see that:
$ g++ -std=c++11 -c mylib_baz.cpp -o mylib_baz.o
$ g++ -std=c++11 -c main.cpp -o main.o
$ g++ main.o mylib_baz.o -o a.out
Produces:
$ nm mylib_baz.o | c++filt | grep bar
0000000000000000 u foo<123>::bar
$ nm main.o | c++filt | grep bar
0000000000000000 u foo<123>::bar
$ nm a.out | c++filt | grep bar
0000000000601038 u foo<123>::bar
Where u indicates:
"u"
The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use.

What's the usecase of gcc's used attribute?

#include <stdio.h>
// xyz will be emitted with -flto (or if it is static) even when
// the function is unused
__attribute__((__used__))
void xyz() {
printf("Hello World!\n");
}
int main() {
return 0;
}
What do I need this for?
Is there any way I could still reach xyz somehow besides directly calling the function, like some dlsym() like magic?
Attribute used is helpful in situation when you want to force compiler to emit symbol, when normally it may be omitted. As GCC's documentation says (emphasis mine):
This attribute, attached to a function, means that code must be
emitted for the function even if it appears that the function is not
referenced. This is useful, for example, when the function is
referenced only in inline assembly.
For instance, if you have code as follows:
#include <iostream>
static int foo(int a, int b)
{
return a + b;
}
int main()
{
int result = 0;
// some inline assembly that calls foo and updates result
std::cout << result << std::endl;
}
you might notice, that no symbol foo is present with -O flag (optimization level -O1):
g++ -O -pedantic -Wall check.cpp -c
check.cpp:3: warning: ‘int foo(int, int)’ defined but not used
nm check.o | c++filt | grep foo
As a result you cannot reference foo within this (imaginary) inline assembly.
By adding:
__attribute__((__used__))
it turns into:
g++ -O -pedantic -Wall check.cpp -c
nm check.o | c++filt | grep foo
00000000 t foo(int, int)
thus now foo can be referenced within it.
You may also have spotted that gcc's warning is now gone, as you have tell you compiler that you are sure that foo is actually used "behind the scene".
A particular usecase is for interrupt service routines in a static library.
For example, a timer overflow interrupt:
void __attribute__((interrupt(TIMERA_VECTOR),used)) timera_isr(void)
This timera_isr is never called by any function in the user code, but it might form an essential part of a library.
To ensure it is linked and there isn't a interrupt vector pointing to an empty section the keyword ensures the linker doesn't optimise it out.
If you declare a global variable or function that is unused, gcc will optimized it out (with warning), but if you declared the global variable or the function with '__attribute__((used))', gcc will include it in object file (and linked executable).
https://gcc.gnu.org/legacy-ml/gcc-help/2013-09/msg00108.html
Another use case is to generate proper coverage information for header files. Functions declared in header files are usually removed by the compiler when unreferenced. Therefore, you will get 100% coverage in your coverage reports even if you forgot to call some functions that are located in the header file. To prevent this, you may mark your function with __attribute__((used)) in your coverage builds.

Section type conflict for identically defined variables

This question arose in the context of this question: Find unexecuted lines of c++ code
When searching for this problem most people tried to add code and variables into the same section - but this is definitely not the problem here. Here is a minimal working example:
unsigned cover() { return 0; }
#define COV() do { static unsigned cov[2] __attribute__((section("cov"))) = { __LINE__, cover() }; } while(0)
inline void foo() {
COV();
}
int main(int argc, char* argv[])
{
COV();
if (argc > 1)
COV();
if (argc > 2)
foo();
return 0;
}
which results with g++ -std=c++11 test.cpp (g++ (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)) in the following error:
test.cpp:6:23: error: cov causes a section type conflict with cov
COV();
^
test.cpp:11:30: note: ‘cov’ was declared here
COV();
^
The error is not very helpful though, as it does not state why this is supposed to be a conflict. Both the .ii and .s temporary files give no hint as to what might be the problem. In fact there is only one section definition in the .s file
.section cov,"aw",#progbits
and I don't see why the next definition should conflict with this ("aw",#progbits is correct...).
Is there any way to get more information on this? See what the precise
conflict is? Or is this just a bug...?
The message is indeed very bad, but it isn't a bug.
The problem here occurs with inline function foo()
and occurs because Inline functions must be defined in each translation context where they used. In this link we can read about section attribute:
"..uninitialized variables tentatively go in the common (or bss) section and can be multiply ‘defined’. Using the section attribute changes what section the variable goes into and
may cause the linker to issue an error if an uninitialized variable has multiple definitions...".
Thus, when the foo function needs to be 'defined' in function main, the linker finds cov variable previously defined in inline function foo and issues the error.
Let’s make the pre-processor's work and expand COV() define to help to clarify the problem:
inline void foo()
{
do { static unsigned cov[2] __attribute__((section("cov"))) = { 40, cover() }; } while(0);
}
int main(int argc, char *argv[]) {
do { static unsigned cov[2] __attribute__((section("cov"))) = { 44, cover() }; } while(0);
if (argc > 1)
do { static unsigned cov[2] __attribute__((section("cov"))) = { 47, cover() }; } while(0);
if (argc > 2)
foo();
To facilitate reasoning, let’s alter the section attribute of definition in foo inline function to cov.2 just to compile the code. Now we haven’t the error, so we can examine the object (.o) with objdump:
objdump -C -t -j cov ./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o
./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l d cov 0000000000000000 cov
0000000000000000 l O cov 0000000000000008 main::cov
0000000000000008 l O cov 0000000000000008 main::cov
objdump -C -t -j cov.2 ./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o
./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l d cov.2 0000000000000000 cov.2
0000000000000000 u O cov.2 0000000000000008 foo()::cov
We can see that compiler makes foo::cov, in section cov.2 GLOBAL (signed by ‘u’ letter).
When we use the same section name (cov), the compiler, trying to ‘define’ foo in main block encounters a previous globally defined cov and the issues the error.
If you make inline foo static (inline static void foo() . . .), which avoids compiler to emit code for inline function and just copies it at expansion time, you’ll see the error disappears, because there isn't a global foo::cov.