(See the history on this answer to get the more elaborate text, but I now think it's easier for the reader to see real command lines).
Common files shared by all below commands
$ cat a.cpp
extern int a;
int main() {
return a;
}
$ cat b.cpp
extern int b;
int a = b;
$ cat d.cpp
int b;
Linking to static libraries
$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o
$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order
The linker searches from left to right, and notes unresolved symbols as it goes. If a library resolves the symbol, it takes the object files of that library to resolve the symbol (b.o out of libb.a in this case).
Dependencies of static libraries against each other work the same - the library that needs symbols must be first, then the library that resolves the symbol.
If a static library depends on another library, but the other library again depends on the former library, there is a cycle. You can resolve this by enclosing the cyclically dependent libraries by -(
and -)
, such as -( -la -lb -)
(you may need to escape the parens, such as -\(
and -\)
). The linker then searches those enclosed lib multiple times to ensure cycling dependencies are resolved. Alternatively, you can specify the libraries multiple times, so each is before one another: -la -lb -la
.
Linking to dynamic libraries
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!
$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order
It's the same here - the libraries must follow the object files of the program. The difference here compared with static libraries is that you need not care about the dependencies of the libraries against each other, because dynamic libraries sort out their dependencies themselves.
Some recent distributions apparently default to using the --as-needed
linker flag, which enforces that the program's object files come before the dynamic libraries. If that flag is passed, the linker will not link to libraries that are not actually needed by the executable (and it detects this from left to right). My recent archlinux distribution doesn't use this flag by default, so it didn't give an error for not following the correct order.
It is not correct to omit the dependency of b.so
against d.so
when creating the former. You will be required to specify the library when linking a
then, but a
doesn't really need the integer b
itself, so it should not be made to care about b
's own dependencies.
Here is an example of the implications if you miss specifying the dependencies for libb.so
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)
$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"
If you now look into what dependencies the binary has, you note the binary itself depends also on libd
, not just libb
as it should. The binary will need to be relinked if libb
later depends on another library, if you do it this way. And if someone else loads libb
using dlopen
at runtime (think of loading plugins dynamically), the call will fail as well. So the "right"
really should be a wrong
as well.
gcc
and g++
are compiler-drivers of the GNU Compiler Collection (which was once upon a time just the GNU C Compiler).
Even though they automatically determine which backends (cc1
cc1plus
...) to call depending on the file-type, unless overridden with -x language
, they have some differences.
The probably most important difference in their defaults is which libraries they link against automatically.
According to GCC's online documentation link options and how g++ is invoked, g++
is equivalent to gcc -xc++ -lstdc++ -shared-libgcc
(the 1st is a compiler option, the 2nd two are linker options). This can be checked by running both with the -v
option (it displays the backend toolchain commands being run).
Best Answer
I believe the problem is that your array is on the stack, and that your compiler is too old to support over-aligned stack variables. GCC 4.6 and later fixed that bug.
C11/C++11
alignas(64) float a[4];
Just Works for any power of 2 alignment.So does the GNU C
__attribute__((aligned(x)))
as you were using it.(In C11,
#include <stdalign.h>
for the#define alignas _Alignas
: cppref).But in your case of a very large alignment, to a 4k page boundary, you may not want it on the stack.
Because the stack pointer could be anything when the function starts, there is no way to align the array without allocating a lot more than you need and adjusting it. (Compilers will
and rsp, -4096
or equivalent and not use any of the 0 to 4088 bytes that allocated; branching on whether that space is large enough or not would be possible but isn't done because huge alignments much larger than the size of the array or other locals are not the normal case.)If you move the array out of the function and into a global variable, it should work. The other thing you could do is keep it as a local variable (which is a very good thing), but make it
static
. This will prevent it from being stored on the stack. Beware that both of these ways are not thread-safe or recursion-safe, since there will be only one copy of the array.With this code:
I get this:
which is what is expected. With your original code, I just get random values like you did.