I've stumbled onto an interesting phenomenon while exploring shared library constructors. If I have a program which links against multiple shared libraries, and each library has its own constructor, if all the constructors have the same function name, only one library's constructor will be called multiple times, rather than each library's constructor being called once.
Here's a minimal example:
foo.h
#pragma once
void foo();
foo.c
#include <stdio.h>
#include "foo.h"
void foo() {};
void __attribute__((constructor)) init()
{
printf("foo init\n");
}
bar.h
#pragma once
void bar();
bar.c
#include <stdio.h>
#include "bar.h"
void bar() {};
void __attribute__((constructor)) init()
{
printf("bar init\n");
}
main.c
#include <stdio.h>
#include "foo.h"
#include "bar.h"
int main()
{
foo();
bar();
return 0;
}
Compile:
gcc -o libfoo.so foo.c -fPIC -shared
gcc -o libbar.so bar.c -fPIC -shared
gcc -o main main.c -lfoo -lbar -L.
Now if I run main
I get:
foo init
foo init
I expect to see one foo init
and one bar init
as each library's constructor is being called, but instead foo
's constructor is called twice. What's also interesting is that if I reverse the order of the libraries in the last compile step to
gcc -o main main.c -lbar -lfoo -L.
The output I get is
bar init
bar init
I can fix this by changing one of the constructor function names to make them unique. I should also note this happens regardless of the function name, as long as they're named the same in both libraries.
My question is: why does this happen in the first place? I assume this is because there is a name conflict but I don't understand exactly what's happening.
I tested using gcc 4.8.4 on Ubuntu 14.04.5 LTS, as well as gcc 7.4.0 on Ubuntu 18.04.2 LTS in WSL.