golang cgo check if C function exists - c

I'm linking a library via CGO, and not all implementations or versions have a feature which I'd like to utilize if possible — namely the presence of a function int feature(void). Is there a way I can check if this symbol is defined before attempting a call?
Any attempted use of C.feature() unsurprisingly results in a build failure on systems with a version of the library that doesn't support the feature.
In case it isn't clear, I want to build against many platforms, which may or may not have the feature. I imagine I'd either need to be able to check if a function exists at runtime (more ideal) or use go:generate to do a check and change the code depending on what it finds (less ideal). Either way, I'm not too sure how exactly to proceed.

Most libraries come with a #define that describes its version.
For example, in version 1.0:
// simple.h
#define LIB_SIMPLE_VERSION 0x00010000
void hello();
In version 1.1:
// simple.h
#define LIB_SIMPLE_VERSION 0x00010001
void hello();
void bye();
You have many choices:
Provide an IsByeAvailable() function to check the existence
Modify the signature of bye() in Go such that it returns an error, or a bool for ok
Panic if the implementation doesn't exist
Code for Choice 1
// simple.go
// #include <simple.h>
import "C"
func IsByeAvailable() bool {
return C.LIB_SIMPLE_VERSION >= 0x00010001
}
func Hello() {
C.hello()
}
func Bye() {
C.bye()
}
// version_support.c
#include <simple.h>
#if LIB_SIMPLE_VERSION < 0x00010001
void bye() { /* Empty */ }
#endif

There are several ways to do that when building your program, but that will leave you with a need to always make two builds and maintain two versions of your program, which is not convenient. In runtime you're very limited because C itself is not reflective and Go runtime features don't (actually can't) give you any benefits.
Still, there are two non-portable (but most probably good enough) hacks you can do. And as the problem is more of a C problem, the hacks are also more of C hacks. One is direct dynamic linker interface, namely dlopen()/dlsym() and the other one is usage of weak symbols in dynamic linker.
Let's first create some setup to test things out:
$ tree
.
├── lib
│   ├── lib1.c
│   ├── lib1.h
│   └── lib2.c
└── some.go
$ cat lib/lib1.h
int feature(void);
int fun(int a);
$ cat lib/lib1.c
int feature(void)
{
return 5;
}
int fun(int a)
{
return a*a;
}
$ cat lib/lib2.c
int fun(int a)
{
return a*a;
}
That's a very simple library that declares two functions and has two implementations, one has both, the other just one. Building them is easy:
$ gcc -shared -o lib/lib1.so.featured lib/lib1.c
$ gcc -shared -o lib/lib1.so.featureless lib/lib2.c
And a symlink to easily switch between two versions:
$ ln -s lib1.so.featured lib/lib1.so
So, for the dlopen()/dlsym() you create a wrapper and use dynamic linker interface to get the feature() pointer like this (yes, you can do that without calling dlsym() on every call, but let's use the very minimum code):
package main;
// #cgo LDFLAGS: -Llib -Wl,-rpath lib -l1 -ldl
// #include "lib/lib1.h"
// #include <stddef.h>
// #include <dlfcn.h>
//
// int feature_wrap(void)
// {
// static void* dlhandle;
// static int (*featurep)(void);
//
// if (!dlhandle)
// dlhandle = dlopen(NULL, RTLD_NOW);
// if (!dlhandle) // error
// return 0;
// featurep = dlsym(dlhandle, "feature");
// if (featurep)
// return featurep();
// else
// return 3;
//}
import "C"
import "fmt"
func main() {
r := C.feature_wrap()
fmt.Println(r)
}
Testing:
$ go build some.go
$ ln -sf lib1.so.featured lib/lib1.so
$ ./some
5
$ ln -sf lib1.so.featureless lib/lib1.so
$ ./some
3
For the weak symbol approach (that is preferrable IMO as it is simpler) you need to redefine you feature() function as weak and also create a wrapper for it that will provide runtime switch between two implementations:
package main;
// #cgo LDFLAGS: -Llib -Wl,-rpath lib -l1
// #include "lib/lib1.h"
// int feature(void) __attribute__((weak));
// int feature_wrap(void)
// {
// if (feature)
// return feature();
// else
// return 3;
//}
import "C"
import "fmt"
func main() {
r := C.feature_wrap()
fmt.Println(r)
}
Testing is the same.
Obviously, once you have proper if, you can do whatever you need to substitute missing feature() including callbacks to Go code.

Related

In gcc is there any way to dynamically add a function call to the start of main()?

I'm dynamically overriding malloc() with a fast_malloc() implementation of mine in a glibc benchmark malloc speed test (glibc/benchtests/bench-malloc-thread.c), by writing these functions in my fast_malloc.c file:
// Override malloc() and free(); see: https://stackoverflow.com/a/262481/4561887
inline void* malloc(size_t num_bytes)
{
static bool first_call = true;
if (first_call)
{
first_call = false;
fast_malloc_error_t error = fast_malloc_init();
assert(error == FAST_MALLOC_ERROR_OK);
}
return fast_malloc(num_bytes);
}
inline void free(void* ptr)
{
fast_free(ptr);
}
Notice that I have this inefficient addition to my malloc() wrapper to ensure fast_malloc_init() gets called first on just the first call, to initialize some memory pools. I'd like to get rid of that and dynamically insert that init call into the start of main(), without modifying the glibc code, if possible. Is this possible?
The downside of how I've written my malloc() wrapper so far is it skews my benchtest results making it look like my fast_malloc() is slower than it really is, because the init func gets timed by glibc/benchtests/bench-malloc-thread.c, and I have this extraneous if (first_call) which gets checked every malloc call.
Currently I dynamically override malloc() and free(), while calling the bench-malloc-thread executable, like this:
LD_PRELOAD='/home/gabriel/GS/dev/fast_malloc/build/libfast_malloc.so' \
glibc-build/benchtests/bench-malloc-thread 1
Plot I will be adding my fast_malloc() speed tests to (using this repo):
LinkedIn post I made about this: https://www.linkedin.com/posts/gabriel-staples_software-engineering-tradeoffs-activity-6815412255325339648-_c8L.
Related:
[my repo fork] https://github.com/ElectricRCAircraftGuy/malloc-benchmarks
[how I learned how to generate *.so dynamic libraries in gcc] https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
Create a wrapper function for malloc and free in C
Is this possible?
Yes. You are building and LD_PRELOADing a shared library, and shared libraries can have special initializer and finalizer functions, which are called by the dynamic loader when the library is loaded and unloaded respectively.
As kaylum commented, to create such a constructor, you would use __attribute__((constructor)), like so:
__attribute__((constructor))
void fast_malloc_init_ctor()
{
fast_malloc_error_t error = fast_malloc_init();
assert(error == FAST_MALLOC_ERROR_OK);
}
// ... the rest of implementation here.
P.S.
it skews my benchtest results making it look like my fast_malloc() is slower than it really is, because the init func gets timed
You are comparing with multi-threaded benchmarks. Note that your static bool fist_call is not thread-safe. In practice this will not matter, because malloc is normally called long before any threads (other than the main thread) exist.
I doubt that this single comparison actually makes your fast_malloc() slower. It probably is slower even after you remove the comparison -- writing a fast heap allocator takes a lot of effort, and smart people have spent many man-years optimizing GLIBC malloc, TCMalloc and jemalloc.
How to dynamically inject function calls before and after another executable's main() function.
Here is a full, runnable example for anyone wanting to test this on their own. Tested on Linux Ubuntu 20.04.
This code is all part of my eRCaGuy_hello_world repo.
hello_world_basic.c:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("This is the start of `main()`.\n");
printf(" Hello world.\n");
printf("This is the end of `main()`.\n");
return 0;
}
dynamic_func_call_before_and_after_main.c:
#include <assert.h>
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
#include <stdlib.h> // For `atexit()`
/// 3. This function gets attached as a post-main() callback (a sort of program "destructor")
/// via the C <stdlib.h> `atexit()` call below
void also_called_after_main()
{
printf("`atexit()`-registered callback functions are also called AFTER `main()`.\n");
}
/// 1. Functions with gcc function attribute, `constructor`, get automatically called **before**
/// `main()`; see:
/// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
__attribute__((__constructor__))
void called_before_main()
{
printf("gcc constructors are called BEFORE `main()`.\n");
// 3. Optional way to register a function call for AFTER main(), although
// I prefer the simpler gcc `destructor` attribute technique below, instead.
int retcode = atexit(also_called_after_main);
assert(retcode == 0); // ensure the `atexit()` call to register the callback function succeeds
}
/// 2. Functions with gcc function attribute, `destructor`, get automatically called **after**
/// `main()`; see:
/// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
__attribute__((__destructor__))
void called_after_main()
{
printf("gcc destructors are called AFTER `main()`.\n");
}
How to build and run the dynamic lib*.so shared-object library and dynamically load it with LD_PRELOAD as you run another program (see "dynamic_func_call_before_and_after_main__build_and_run.sh from my eRCaGuy_hello_world repo"):
# 1. Build the other program (hello_world_basic.c) that has `main()` in it which we want to use
mkdir -p bin && gcc -Wall -Wextra -Werror -O3 -std=c11 -save-temps=obj hello_world_basic.c \
-o bin/hello_world_basic
# 2. Create a .o object file of this program, compiling with Position Independent Code (PIC); see
# here: https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
gcc -Wall -Wextra -Werror -O3 -std=c11 -fpic -c dynamic_func_call_before_and_after_main.c \
-o bin/dynamic_func_call_before_and_after_main.o
# 3. Link the above PIC object file into a dynamic shared library (`lib*.so` file); link above shows
# we must use `-shared`
gcc -shared bin/dynamic_func_call_before_and_after_main.o -o \
bin/libdynamic_func_call_before_and_after_main.so
# 4. Call the other program with `main()` in it, dynamically injecting this code into that other
# program via this code's .so shared object file, and via Linux's `LD_PRELOAD` trick
LD_PRELOAD='bin/libdynamic_func_call_before_and_after_main.so' bin/hello_world_basic
Sample output. Notice that we have injected some special function calls both before AND after the main() function found in "hello_world_basic.c":
gcc constructors are called BEFORE `main()`.
This is the start of `main()`.
Hello world.
This is the end of `main()`.
gcc destructors are called AFTER `main()`.
`atexit()`-registered callback functions are also called AFTER `main()`.
References:
How to build dynamic lib*.so libraries in Linux: https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
#kaylum's comment
#Employed Russian's answer
#Lundin's comment
gcc constructor and destructor function attributes!:
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
c atexit() func to register functions to be called AFTER main() returns or exits!:
https://en.cppreference.com/w/c/program/atexit

Is it possible to remove dead code from a static library?

I would like to remove dead code from a static library by specifying an entry point.
For instance:
lib1.c
int foo() { return 0; }
int bar() { return 0; }
lib2.c
#include "lib1.h"
int entry() {
return foo();
}
new.a (lib1.a + lib2.a)
libtool -static -o new.a lib1.a lib2.a
I would like new.a to not contain int bar() because it is unused in the entry point of lib1.a, and I don't plan on using lib2.a directly.
Is this possible?
If you compile with -ffunction-sections (and possibly -fdata-sections) and link with -Wl,--gc-sections, the unreferenced functions will be removed. This is subtly different from them not being present to begin with (for example, if bar contained references to other functions or data, it could cause the files containing them to be pulled in for consideration, possibly resulting in new global ctors or overriding weak definitions) but close enough for most purposes.
The right way, on the other hand, is not to define functions that can be used independently in the same translation unit (source file). Split them into separate files and this just works automatically with no special options.

Disable Stack protection for go compiled program

I want to disable the stack protection for my Go program. I'm trying to simulate a vulnerable C library and want to pivot into the Go code from there. However, I can't seem to find the right flags to disable the stack smashing detection.
Here is my go code:
package main
import "os"
import "fmt"
/*
#include "test.h"
*/
import "C"
func main() {
if (len(os.Args) >= 2){
argsWithoutProg := os.Args[1:]
if (argsWithoutProg[0] == "admin") {
secret();
}
} else {
regular()
}
}
func regular() {
fmt.Println("Go: BORING")
C.hackme()
}
func secret() {
fmt.Println("Go: SECRET FUNC")
}
and here is my c library code:
// #cgo CFLAGS: -g -O3 -fno-stack-protector
#include <stdint.h>
#include <stdio.h>
void hackme();
// this function is vulnerable and is used as an entrypoint to the go part
void hackme() {
char buf[3];
int r;
r = read(0, buf, 300);
printf("C: %d bytes read. Content: %s!\n", r, buf);
return;
}
I compile with go build -a poc.go.
As you can see, I already added some CFLAGS instructions at the beginning of my C library, but they don't seem to help. Previously I tried adding them via the -gcflags switch in my compilation command, but that was fruitless as well. Everytime I try to attack my program with a 300*A string, it is being detected:
Go: BORING
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
C: 300 bytes read. Content: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
*** stack smashing detected ***: <unknown> terminated
SIGABRT: abort
PC=0x7fd263dcee97 m=0 sigcode=18446744073709551610
goroutine 0 [idle]:
runtime: unknown pc 0x7fd263dcee97
stack: frame={sp:0x7ffda3507600, fp:0x0} stack=[0x7ffda2d08ad0,0x7ffda3507b00)
00007ffda3507500: 00007fd200000008 00007fd200000000
00007ffda3507510: 00007ffda3507610 0000000000000003
[...]
Checking the file with GDB also tells me the option is still active..
Could you please point me to some hints as to what I'm doing wrong or what flags I should use to disable this feature?
Thanks so much!
Start with the Go cgo command documentation.
Command cgo
Using cgo with the go command
To use cgo write normal Go code that imports a pseudo-package "C". The
Go code can then refer to types such as C.size_t, variables such as
C.stdout, or functions such as C.putchar.
If the import of "C" is immediately preceded by a comment, that
comment, called the preamble, is used as a header when compiling the C
parts of the package. For example:
// #include <stdio.h>
// #include <errno.h>
import "C"
The preamble may contain any C code, including function and variable
declarations and definitions. These may then be referred to from Go
code as though they were defined in the package "C". All names
declared in the preamble may be used, even if they start with a
lower-case letter. Exception: static variables in the preamble may not
be referenced from Go code; static functions are permitted.
See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
"C? Go? Cgo!" for an introduction to using cgo:
https://golang.org/doc/articles/c_go_cgo.html.
CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with
pseudo #cgo directives within these comments to tweak the behavior of
the C, C++ or Fortran compiler. Values defined in multiple directives
are concatenated together. The directive can include a list of build
constraints limiting its effect to systems satisfying one of the
constraints (see
https://golang.org/pkg/go/build/#hdr-Build_Constraints for details
about the constraint syntax). For example:
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
In particular:
To use cgo write normal Go code that imports a pseudo-package "C".
If the import of "C" is immediately preceded by a comment, that
comment, called the preamble, is used as a header when compiling the C
parts of the package.
CFLAGS may be defined with
pseudo #cgo directives within these comments to tweak the behavior of
the C compiler.
For your example:
/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"
Output (no stack smashing detected):
$ go build -a poc.go && ./poc
Go: BORING
AAAAAAAAAAAAAAA
C: 16 bytes read. Content: AAAAAAAAAAAAAAA
!
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0xa41414141 pc=0xa41414141]
runtime stack:
runtime.throw(0x4bb802, 0x2a)
/home/peter/go/src/runtime/panic.go:608 +0x72
runtime.sigpanic()
/home/peter/go/src/runtime/signal_unix.go:374 +0x2ec
goroutine 1 [syscall]:
runtime.cgocall(0x484e90, 0xc000052f38, 0x0)
/home/peter/go/src/runtime/cgocall.go:128 +0x5b fp=0xc000052f08 sp=0xc000052ed0 pc=0x403deb
main._Cfunc_hackme()
_cgo_gotypes.go:41 +0x41 fp=0xc000052f38 sp=0xc000052f08 pc=0x484c51
main.regular()
/home/peter/gopath/src/poc/poc.go:25 +0x62 fp=0xc000052f88 sp=0xc000052f38 pc=0x484d52
main.main()
/home/peter/gopath/src/poc/poc.go:19 +0x65 fp=0xc000052f98 sp=0xc000052f88 pc=0x484cd5
runtime.main()
/home/peter/go/src/runtime/proc.go:201 +0x1ec fp=0xc000052fe0 sp=0xc000052f98 pc=0x42928c
runtime.goexit()
/home/peter/go/src/runtime/asm_amd64.s:1340 +0x1 fp=0xc000052fe8 sp=0xc000052fe0 pc=0x450cd1
$
poc.go:
package main
import "os"
import "fmt"
/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"
func main() {
if (len(os.Args) >= 2){
argsWithoutProg := os.Args[1:]
if (argsWithoutProg[0] == "admin") {
secret();
}
} else {
regular()
}
}
func regular() {
fmt.Println("Go: BORING")
C.hackme()
}
func secret() {
fmt.Println("Go: SECRET FUNC")
}
test.h:
#include <stdint.h>
#include <stdio.h>
void hackme();
// this function is vulnerable and is used as an entrypoint to the go part
void hackme() {
char buf[3];
int r;
r = read(0, buf, 300);
printf("C: %d bytes read. Content: %s!\n", r, buf);
return;
}
Without -fno-stack-protector:
/*
#cgo CFLAGS: -g -O3
#include "test.h"
*/
import "C"
Output (stack smashing detected):
$ go build -a poc.go && ./poc
Go: BORING
AAAAAAAAAAAAAAA
C: 16 bytes read. Content: AAAAAAAAAAAAAAA
!
*** stack smashing detected ***: <unknown> terminated
SIGABRT: abort
PC=0x7f1c5323ee97 m=0 sigcode=18446744073709551610
$

How can a shared library (.so) call a function that is implemented in its loader code?

I have a shared library that I implemented and want the .so to call a function that's implemented in the main program which loads the library.
Let's say I have main.c (executable) which contains:
void inmain_function(void*);
dlopen("libmy.so");
In the my.c (the code for the libmy.so) I want to call inmain_function:
inmain_function(NULL);
How can the shared library call inmain_function regardless the fact inmain_function is defined in the main program.
Note: I want to call a symbol in main.c from my.c not vice versa which is the common usage.
You have two options, from which you can choose:
Option 1: export all symbols from your executable.
This is simple option, just when building executable, add a flag -Wl,--export-dynamic. This would make all functions available to library calls.
Option 2: create an export symbol file with list of functions, and use -Wl,--dynamic-list=exported.txt. This requires some maintenance, but more accurate.
To demonstrate: simple executable and dynamically loaded library.
#include <stdio.h>
#include <dlfcn.h>
void exported_callback() /*< Function we want to export */
{
printf("Hello from callback!\n");
}
void unexported_callback() /*< Function we don't want to export */
{
printf("Hello from unexported callback!\n");
}
typedef void (*lib_func)();
int call_library()
{
void *handle = NULL;
lib_func func = NULL;
handle = dlopen("./libprog.so", RTLD_NOW | RTLD_GLOBAL);
if (handle == NULL)
{
fprintf(stderr, "Unable to open lib: %s\n", dlerror());
return -1;
}
func = dlsym(handle, "library_function");
if (func == NULL) {
fprintf(stderr, "Unable to get symbol\n");
return -1;
}
func();
return 0;
}
int main(int argc, const char *argv[])
{
printf("Hello from main!\n");
call_library();
return 0;
}
Library code (lib.c):
#include <stdio.h>
int exported_callback();
int library_function()
{
printf("Hello from library!\n");
exported_callback();
/* unexported_callback(); */ /*< This one will not be exported in the second case */
return 0;
}
So, first build the library (this step doesn't differ):
gcc -shared -fPIC lib.c -o libprog.so
Now build executable with all symbols exported:
gcc -Wl,--export-dynamic main.c -o prog.exe -ldl
Run example:
$ ./prog.exe
Hello from main!
Hello from library!
Hello from callback!
Symbols exported:
$ objdump -e prog.exe -T | grep callback
00000000004009f4 g DF .text 0000000000000015 Base exported_callback
0000000000400a09 g DF .text 0000000000000015 Base unexported_callback
Now with the exported list (exported.txt):
{
extern "C"
{
exported_callback;
};
};
Build & check visible symbols:
$ gcc -Wl,--dynamic-list=./exported.txt main.c -o prog.exe -ldl
$ objdump -e prog.exe -T | grep callback
0000000000400774 g DF .text 0000000000000015 Base exported_callback
You'll need make a register function in your .so so that the executable can give a function pointer to your .so for it's later used.
Like this:
void in_main_func () {
// this is the function that need to be called from a .so
}
void (*register_function)(void(*)());
void *handle = dlopen("libmylib.so");
register_function = dlsym(handle, "register_function");
register_function(in_main_func);
the register_function needs to store the function pointer in a variable in the .so where the other function in the .so can find it.
Your mylib.c would the need to look something like this:
void (*callback)() = NULL;
void register_function( void (*in_main_func)())
{
callback = in_main_func;
}
void function_needing_callback()
{
callback();
}
Put your main function's prototype in a .h file and include it in both your main and dynamic library code.
With GCC, simply compile your main program with the -rdynamic flag.
Once loaded, your library will be able to call the function from the main program.
A little further explanation is that once compiled, your dynamic library will have an undefined symbol in it for the function that is in the main code. Upon having your main app load the library, the symbol will be resolved by the main program's symbol table. I've used the above pattern numerous times and it works like a charm.
The following can be used to load a dynamic library and call it from the loading call (in case somebody came here after looking for how to load and call a function in an .so library):
void* func_handle = dlopen ("my.so", RTLD_LAZY); /* open a handle to your library */
void (*ptr)() = dlsym (func_handle, "my_function"); /* get the address of the function you want to call */
ptr(); /* call it */
dlclose (func_handle); /* close the handle */
Don't forget to put #include <dlfcn.h> and link with the –ldl option.
You might also want to add some logic that checks if NULL is returned. If it is the case you can call dlerror and it should give you some meaningful messages describing the problem.
Other posters have however provided more suitable answers for your problem.

Linking against older symbol version in a .so file

Using gcc and ld on x86_64 linux I need to link against a newer version of a library (glibc 2.14) but the executable needs to run on a system with an older version (2.5). Since the only incompatible symbol is memcpy (needing memcpy#GLIBC_2.2.5 but the library providing memcpy#GLIBC_2.14), I would like to tell the linker that instead of taking the default version for memcpy, it should take an old version I specify.
I found a quite arkward way to do it: simply specify a copy of the old .so file at the linker command line. This works fine, but I don't like the idea of having multiple .so files (I could only make it work by specifying all old libraries I link to that also have references to memcpy) checked into the svn and needed by my build system.
So I am searching for a way to tell the linker to take the old versioned symbol.
Alternatives that don't work (well) for me are:
Using asm .symver (as seen on Web Archive of Trevor Pounds' Blog) since this would require me to make sure the symver is before all the code that is using memcpy, which would be very hard (complex codebase with 3rd party code)
Maintaining a build environment with the old libraries; simply because I want to develop on my desktop system and it would be a pita to sync stuff around in our network.
When thinking about all the jobs a linker does, it doesn't seem like a hard thing to imlpement, after all it has some code to figure out the default version of a symbol too.
Any other ideas that are on the same complexity level as a simple linker command line (like creating a simple linker script etc.) are welcome too, as long as they are not weird hacks like editing the resulting binary...
edit:
To conserve this for the future readers, additionally to the below ideas I found the option --wrap to the linker, which might be useful sometimes too.
I found the following working solution. First create file memcpy.c:
#include <string.h>
/* some systems do not have newest memcpy##GLIBC_2.14 - stay with old good one */
asm (".symver memcpy, memcpy#GLIBC_2.2.5");
void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
return memcpy(dest, src, n);
}
No additional CFLAGS needed to compile this file. Then link your program with -Wl,--wrap=memcpy.
Just link memcpy statically - pull memcpy.o out of libc.a ar x /path/to/libc.a memcpy.o (whatever version - memcpy is pretty much a standalone function) and include it in your final link. Note that static linking may complicate licensing issues if your project is distributed to the public and not open-source.
Alternatively, you could simply implement memcpy yourself, though the hand-tuned assembly version in glibc is likely to be more efficient
Note that memcpy#GLIBC_2.2.5 is mapped to memmove (old versions of memcpy consistently copied in a predictable direction, which led to it sometimes being misused when memmove should have been used), and this is the only reason for the version bump - you could simply replace memcpy with memmove in your code for this specific case.
Or you could go to static linking, or you could ensure that all systems on your network have the same or better version than your build machine.
I had a similar issue. A third party library we use needs the old memcpy#GLIBC_2.2.5. My solution is an extended approach #anight posted.
I also warp the memcpy command, but i had to use a slightly different approach, since the solution #anight posted did not work for me.
memcpy_wrap.c:
#include <stddef.h>
#include <string.h>
asm (".symver wrap_memcpy, memcpy#GLIBC_2.2.5");
void *wrap_memcpy(void *dest, const void *src, size_t n) {
return memcpy(dest, src, n);
}
memcpy_wrap.map:
GLIBC_2.2.5 {
memcpy;
};
Build the wrapper:
gcc -c memcpy_wrap.c -o memcpy_wrap.o
Now finally when linking the program add
-Wl,--version-script memcpy_wrap.map
memcpy_wrap.o
so that you will end up with something like:
g++ <some flags> -Wl,--version-script memcpy_wrap.map <some .o files> memcpy_wrap.o <some libs>
I had a similar problem. Trying to install some oracle components on RHEL 7.1, I got this:
$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ...
/some/oracle/lib/libfoo.so: undefined reference to `memcpy#GLIBC_2.14'
It seems that (my) RHEL's glibc only defines memcpy#GLIBC_2.2.5:
$ readelf -Ws /usr/lib/x86_64-redhat-linux6E/lib64/libc_real.so | fgrep memcpy#
367: 000000000001bfe0 16 FUNC GLOBAL DEFAULT 8 memcpy##GLIBC_2.2.5
1166: 0000000000019250 16 FUNC WEAK DEFAULT 8 wmemcpy##GLIBC_2.2.5
So, I managed to get around this, by first creating a memcpy.c file without wrapping, as follows:
#include <string.h>
asm (".symver old_memcpy, memcpy#GLIBC_2.2.5"); // hook old_memcpy as memcpy#2.2.5
void *old_memcpy(void *, const void *, size_t );
void *memcpy(void *dest, const void *src, size_t n) // then export memcpy
{
return old_memcpy(dest, src, n);
}
and a memcpy.map file that exports our memcpy as memcpy#GLIBC_2.14:
GLIBC_2.14 {
memcpy;
};
I then compiled my own memcpy.c into a shared lib like this:
$ gcc -shared -fPIC -c memcpy.c
$ gcc -shared -fPIC -Wl,--version-script memcpy.map -o libmemcpy-2.14.so memcpy.o -lc
, moved libmemcpy-2.14.so into /some/oracle/lib (pointed to by -L arguments in my linking), and linked again by
$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... /some/oracle/lib/libmemcpy-2.14.so -lfoo ...
(which compiled without errors) and verified it by:
$ ldd /some/oracle/bin/foo
linux-vdso.so.1 => (0x00007fff9f3fe000)
/some/oracle/lib/libmemcpy-2.14.so (0x00007f963a63e000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f963a428000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f963a20c000)
librt.so.1 => /lib64/librt.so.1 (0x00007f963a003000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9639c42000)
/lib64/ld-linux-x86-64.so.2 (0x00007f963aa5b000)
This worked for me. I hope it does it for you, too.
I'm clearly a little late responding to this but I recently upgraded (more reasons to never upgrade) my Linux OS to XUbuntu 14.04 which came with the new libc. I compile a shared library on my machine which is used by clients who, for whatever legitimate reasons, have not upgraded their environment from 10.04. The shared library I compiled no longer loaded in their environment because gcc put a dependency on memcpy glibc v. 2.14 (or higher). Let's leave aside the insanity of this. The workaround across my whole project was three fold:
added to my gcc cflags: -include glibc_version_nightmare.h
created the glibc_version_nightmare.h
created a perl script to verify the symbols in the .so
glibc_version_nightmare.h:
#if defined(__GNUC__) && defined(__LP64__) /* only under 64 bit gcc */
#include <features.h> /* for glibc version */
#if defined(__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 14)
/* force mempcy to be from earlier compatible system */
__asm__(".symver memcpy,memcpy#GLIBC_2.2.5");
#endif
#undef _FEATURES_H /* so gets reloaded if necessary */
#endif
perl script fragment:
...
open SYMS, "nm $flags $libname |";
my $status = 0;
sub complain {
my ($symbol, $verstr) = #_;
print STDERR "ERROR: $libname $symbol requires $verstr\n";
$status = 1;
}
while (<SYMS>) {
next unless /\#\#GLIBC/;
chomp;
my ($symbol, $verstr) = (m/^\s+.\s(.*)\#\#GLIBC_(.*)/);
die "unable to parse version from $libname in $_\n"
unless $verstr;
my #ver = split(/\./, $verstr);
complain $symbol, $verstr
if ($ver[0] > 2 || $ver[1] > 10);
}
close SYMS;
exit $status;
Minimal runnable self contained example
GitHub upstream.
main.c
#include <assert.h>
#include <stdlib.h>
#include "a.h"
#if defined(V1)
__asm__(".symver a,a#LIBA_1");
#elif defined(V2)
__asm__(".symver a,a#LIBA_2");
#endif
int main(void) {
#if defined(V1)
assert(a() == 1);
#else
assert(a() == 2);
#endif
return EXIT_SUCCESS;
}
a.c
#include "a.h"
__asm__(".symver a1,a#LIBA_1");
int a1(void) {
return 1;
}
/* ## means "default version". */
__asm__(".symver a2,a##LIBA_2");
int a2(void) {
return 2;
}
a.h
#ifndef A_H
#define A_H
int a(void);
#endif
a.map
LIBA_1{
global:
a;
local:
*;
};
LIBA_2{
global:
a;
local:
*;
};
Makefile
CC := gcc -pedantic-errors -std=c89 -Wall -Wextra
.PHONY: all clean run
all: main.out main1.out main2.out
run: all
LD_LIBRARY_PATH=. ./main.out
LD_LIBRARY_PATH=. ./main1.out
LD_LIBRARY_PATH=. ./main2.out
main.out: main.c libcirosantilli_a.so
$(CC) -L'.' main.c -o '$#' -lcirosantilli_a
main1.out: main.c libcirosantilli_a.so
$(CC) -DV1 -L'.' main.c -o '$#' -lcirosantilli_a
main2.out: main.c libcirosantilli_a.so
$(CC) -DV2 -L'.' main.c -o '$#' -lcirosantilli_a
a.o: a.c
$(CC) -fPIC -c '$<' -o '$#'
libcirosantilli_a.so: a.o
$(CC) -Wl,--version-script,a.map -L'.' -shared a.o -o '$#'
libcirosantilli_a.o: a.c
$(CC) -fPIC -c '$<' -o '$#'
clean:
rm -rf *.o *.a *.so *.out
Tested on Ubuntu 16.04.
This workaround seem not compatible with -flto compile option.
My solution is calling memmove. memove does exactly the same jobs than memcpy.
The only difference is when src and dest zone overlap, memmove is safe and memcpy is unpredictable. So we can safely always call memmove instead memcpy
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
return memmove(dest, src, n);
}
#ifdef __cplusplus
}
#endif
For nim-lang, I elaborated on a solution I found using the C compiler --include= flag as follows:
Create a file symver.h with:
__asm__(".symver fcntl,fcntl#GLIBC_2.4");
Build your program with nim c ---passC:--include=symver.h
As for me I'm cross compiling too. I compile with nim c --cpu:arm --os:linux --passC:--include=symver.h ... and I can get symbol versions using arm-linux-gnueabihf-objdump -T ../arm-libc.so.6 | grep fcntl
I had to remove ~/.cache/nim at some point. And it seems to work.
I think you can get away with making a simple C file containing the symver statement and perhaps a dummy function calling memcpy. Then you just have to ensure that the resulting object file is the first file given to linker.
I suggest you either link memcpy() statically; or find the source of memcpy( ) and compile it as your own library.
It may caused by old ld (gnu link) version.
For following simple problem:
#include <string.h>
#include <stdio.h>
int main(int argc,char **argv)
{
char buf[5];
memset(buf,0,sizeof(buf));
printf("ok\n");
return 0;
}
When I use ld 2.19.1, memset is relocated to: memset##GLIBC_2.0, and cause crash.
After upgraded to 2.25, it is: memset#plt, and crash solved.
We had a similar issue, but instead of one older GLIBC symbol, we have to provide in our .so libs a mix of newer ones with necessary functionality and older ones our libs may be referencing but are not available. This situation occurs because we are shipping to customers high performance codec libs with vectorized math functions and we cannot impose requirements on what version of OS distro, gcc, or glibc they use. As long as their machine has appropriate SSE and AVX extensions, the libs should work. Here is what we did:
Include glibc 2.35 libmvec.so.1 and libm.so.6 files in a separate subfolder. These contain the necessary vectorized math functions. In a "hello codec" application example, we reference these in the link target depending on what distro, gcc, and glibc versions are found by the Makefile. More or less, for anything with glibc v2.35 or higher the high performance libs are referenced, otherwise slower libs are referenced.
To deal with missing symbols -- the subject of this thread -- we used a modification of Ortwin Anermeier's solution, in turn based on anight's solution, but without using the -Wl,--wrap=xxx option.
The .map file looks like:
GLIBC_2.35 {
hypot;
:
: (more function symbols as needed)
};
GLIBC_2.32 {
exp10;
:
: (more function symbols as needed)
};
:
: (more version nodes as needed)
and in a "stublib" .so we have:
#define _GNU_SOURCE
#include <math.h>
asm(".symver hypot_235, hypot#GLIBC_2.35");
asm(".symver exp10_232, exp10f#GLIBC_2.32");
/* ... more as needed */
double hypot_235(double x, double y) { return hypot(x, y); }
double exp10_232(double x) { return exp10(x); }
/* ... more as needed */
-lstublib.so is then included in the app build as the last link item, even after -lm.
This answer and this one also offer clues, but they not handling the general case of a .so flexible enough to be used on a wide variety of systems.

Resources