How do I prevent namespace collisions in a library? Let's say I have a internal library function called foo(), that is not included in a public header, so the user doesn't know about this function. But foo() is used across multiple files and can't be declared static.
The Problem is, if the user now creates a function called foo(), there is an error. How do I prevent namespace collision (as the library author), without forcing the user to not use specific function names?
example.c
#include <stdio.h>
void foo() {
printf("my foo called");
}
int main() {
foo();
}
lib.c
#include <stdio.h>
void foo() {
printf("library foo() called\n");
}
output:
$ gcc -Wall -Wextra -Werror example.c example-lib.c
/usr/bin/ld: /tmp/cci3Dd3J.o: in function `foo':
example-lib.c:(.text+0x0): multiple definition of `foo'; /tmp/ccneOJjI.o:example.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
Edit
I now tried the following (with the same files):
$ gcc -Wall -Wextra -Werror example-lib.c -fpic -shared -o example-lib.so
$ gcc -Wall -Wextra -Werror example.c example-lib.so
And for some reason it works. Can anyone explain why?
Related
Why is my following code not throwing duplicate symbol conflict?
I referred to name mangling, but that seems only when there is difference in parameters. But, here there is not difference in parameters. But, still it does not throw conflict. Why?
good.c
#include <stdio.h>
void printGood() {
printf("I am good");
}
perfect.c
#include <stdio.h>
void printGood() {
printf("I am perfect");
}
A.c
extern void printGood();
void bringGood() {
printGood();
}
B.c
extern void printGood();
void bringPerfect() {
printGood();
}
orchestrator.c
#include <stdio.h>
void bringGood();
void bringPerfect();
int main() {
printf("bringing good");
bringGood();
printf("bringing perfect");
bringPerfect();
return 1;
}
compile line:
gcc -g -c good.c
gcc -g -c perfect.c
gcc -g -c A.c
gcc -g -c B.c
gcc -g -c orchestrator.c
ar rcs libA.a perfect.o A.o
ar rcs libB.a good.o B.o
gcc -o orchestrator orchestrator.o -L. -lA -lB
Why is my following code not throwing duplicate symbol conflict?
The linker looks for undefined symbols in the libraries in the order in which they are specified in the linker line. When it finds a symbol in a library, it uses that definition and stops. It does not check whether that symbol is defined in any of the other libraries specified in the linker line.
In your case, if the linker finds a symbol in A.lib, it stops there. It does not look for the symbol in B.lib.
With your commands, the linker will find function printGood() in object perfect.o in library A. It will not use the function of the same name in good.o from library B. So you effectively link orchestrator.o, A.o, B.o and perfect.o. That's why the executable program prints I am perfect twice and not I am good.
Multiple definition errors are reported only when the object files used in the linker line contain multiple definitions.
You will see the error if you use:
gcc -o orchestrator orchestrator.o a.o b.o perfect.o good.o
I am having trouble with multiple definitions of functions. All other solutions here on stack overflow have not worked out for me.
This is my main.c:
#include "lib.h"
int main(){
test();
}
This is the lib.c file:
#include "lib.h"
int var;
void test(){
//code here
}
And this is the lib.h file:
#ifndef _HTTPLIB_H_
#define _HTTPLIB_H_
#include <stdio.h>
extern int var;
extern void test();
#endif
I have checked and there are no definitions of any function twice and I am never including a .c source file.
I am compiling with
gcc lib.c main.c -Wall -g -o main
main: In function 'test': (.text+0xfdd): multiple definition of 'test' /tmp/ccb8byZi.o:lib.c:(.text+0xef9): first defined here'
real code:
main file: http://pastebin.com/xr3DF0TE
lib.c and lib.h file: http://pastebin.com/KemhKX3f
This is the compilation code
gcc -lpthread -D_REENTRANT httplib.c http.c -o -g http
real error message:
http: In function `sigusr1':(.text+0xfdd): multiple definition of `sigusr1'/tmp/ccb8byZi.o:httplib.c:(.text+0xef9): first defined here
gcc -lpthread -D_REENTRANT httplib.c http.c -o -g http
Here's your problem: You're telling gcc to compile 3 files (httplib.c, http.c, http) into an executable called -g. This is because the argument after -o is taken to be the output filename.
The errors are caused by you apparently having an http executable lying around, which already contains the (compiled) functions defined in httplib.c.
Fix:
gcc -lpthread -D_REENTRANT httplib.c http.c -g -o http
I'm in a situation that's quite similar to the following. There's libA.so that depending on some compile time flags exhibits slightly different behaviour (it's an external lib, and I can't modify the source). Then, I have libB.so that depends on libA.so (compiled with say -DVALUE=1), and in my executable I depend both on libB.so, as well as on libA.so, but compiled with -DVALUE=0. However, once I launch it, ld resolves all symbols with one of libA.so versions, so both my executable and libB.so are using the same functions.
Is there any way to specify that I want to load resolve undefined symbols of libB.so only using its dependencies? I've tried using -Wl,-Bgroup flag when building libB.so, but it didn't change anything. I know there's dlmopen that can load the library in a new namespace, but I'd like to have it loaded automatically at startup.
I'm attaching a set of files that reproduce the behaviour:
libA.so:
#include <stdio.h>
#define _STR(x) #x
#define STR(x) _STR(x)
#ifndef VALUE
#define VALUE default
#endif
void func2() {
printf(STR(VALUE) "\n");
}
void func() {
func2();
}
libB.so:
#include <stdio.h>
extern void func(void);
void b_func() {
func();
}
executable:
#include <stdio.h>
extern void b_func(void);
extern void func(void);
int main() {
func(); // should print "default"
b_func(); // should print "other"
}
build commands:
gcc -fPIC -shared A.c -o libA.so
gcc -fPIC -shared -DVALUE=other A.c -o libA2.so
gcc -fPIC -shared B.c -L. -lA2 -o libB.so
gcc main.c -L. -lA -lB -o main
Curiously, it all works fine on OS X.
I am building a shared library in C that is dynamically loaded by a program that I do not have source access to. The target platform is a 64-bit Linux platform and we're using gcc to build. I was able to build a reproduction of the issue in ~100 lines, but it's still a bit to read. Hopefully it's illustrative.
The core issue is I have two non-static functions (bar and baz) defined in my shared library. Both need to be non-static as we expect the caller to be able to dlsym them. Additionally, baz calls bar. The program that is using my library also has a function named bar, which wouldn't normally be an issue, but the calling program is compiled with -rdynamic, as it has a function foo that needs to be called in my shared library. The result is my shared library ends up linked to the calling program's version of bar at runtime, producing unintuitive results.
In an ideal world I would be able to include some command line switch when compiling my shared library that would prevent this from happening.
The current solution I have is to rename my non-static functions as funname_local and declare them static. I then define a new function:
funname() { return funname_local(); }, and change any references to funname in my shared library to funname_local. This works, but it feels cumbersome, and I'd much prefer to just tell the linker to prefer symbols defined in the local compilation unit.
internal.c
#include <stdio.h>
#include "internal.h"
void
bar(void)
{
printf("I should only be callable from the main program\n");
}
internal.h
#if !defined(__INTERNAL__)
#define __INTERNAL__
void
bar(void);
#endif /* defined(__INTERNAL__) */
main.c
#include <dlfcn.h>
#include <stdio.h>
#include "internal.h"
void
foo(void)
{
printf("It's important that I am callable from both main and from any .so "
"that we dlopen, that's why we compile with -rdynamic\n");
}
int
main()
{
void *handle;
void (*fun1)(void);
void (*fun2)(void);
char *error;
if(NULL == (handle = dlopen("./shared.so", RTLD_NOW))) { /* Open library */
fprintf(stderr, "dlopen: %s\n", dlerror());
return 1;
}
dlerror(); /* Clear any existing error */
*(void **)(&fun1) = dlsym(handle, "baz"); /* Get function pointer */
if(NULL != (error = dlerror())) {
fprintf(stderr, "dlsym: %s\n", error);
dlclose(handle);
return 1;
}
*(void **)(&fun2) = dlsym(handle, "bar"); /* Get function pointer */
if(NULL != (error = dlerror())) {
fprintf(stderr, "dlsym: %s\n", error);
dlclose(handle);
return 1;
}
printf("main:\n");
foo();
bar();
fun1();
fun2();
dlclose(handle);
return 0;
}
main.h
#if !defined(__MAIN__)
#define __MAIN__
extern void
foo(void);
#endif /* defined(__MAIN__) */
shared.c
#include <stdio.h>
#include "main.h"
void
bar(void)
{
printf("bar:\n");
printf("It's important that I'm callable from a program that loads shared.so"
" as well as from other functions in shared.so\n");
}
void
baz(void)
{
printf("baz:\n");
foo();
bar();
return;
}
compile:
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -o main main.c internal.c -l dl -rdynamic
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -o shared.so shared.c
run:
$ ./main
main:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
baz:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
Have you tried -Bsymbolic linker option (or -Bsymbolic-functions)? Quoting from ld man:
-Bsymbolic
When creating a shared library, bind references to global symbols to the definition within the shared library, if any. Normally, it is possible for a program linked against a shared library to override the definition within the shared library. This option can also be used with the --export-dynamic option, when creating a position independent executable, to bind references to global symbols to the definition within the executable. This option is only meaningful on ELF platforms which support shared libraries and position independent executables.
It seems to solve the problem:
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -o shared.so shared.c
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -o main main.c internal.c -l dl -rdynamic
$ ./main
main:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
baz:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -Wl,-Bsymbolic -o shared.so shared.c
$ ./main
main:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
baz:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
A common solution for this problem is to not actually depend on a global symbol not being overriden. Instead do the following:
Call the function bar from your library mylib_bar or something like that
Hide mylib_bar with __attribute__((visibility("hidden"))) or similar
Make bar a weak symbol, referring to mylib_bar like this:
#pragma weak bar = mylib_bar
Make your library call mylib_bar everywhere instead of bar
Now everything works as expected:
When your library calls mylib_bar, this always refers to the definition in the library as the visibility is hidden.
When other code calls bar, this calls mylib_bar by default.
If someone defines his own bar, this overrides bar but not mylib_bar, leaving your library untouched.
I have a C file named first.c in which I define an array and call a function which is defined in a C file named second.c. This is how first.c looks:
int main(void)
{
int array[100];
myFunc(*array);
}
second.c on the other hand looks like this:
void myFunc(int array)
{
...
}
But anytime I try to compile these, second.c gives me errors as if it had no idea about the array I passed to its function as an argument. I guess the function doesn't know that at the linking stage. I compile these like this:
gcc -O2 -std=c99 -Wall -pedantic -lm second.c -c
gcc -O2 -std=c99 -Wall -pedantic first.c -c
gcc second.o first.o -o finished
But that's just what I came up with and of course it doesn't work. I guess a Makefile would be in place, but I'm not sure how to implement it.
Your issue may lie in that the received value is not a pointer- so change void myFunc(int array) to void myFunc(int* array).