"No symbol version section for versioned symbol" - c

I'm attempting to cross-compile my own shared library (libmystuff.so) against another shared library (libtheirstuff.so) that makes use of the libcurl shared library and am getting the following error:
libmystuff.so: No symbol version section for versioned symbol
'curl_global_init##CURL_OPENSSL_3'
Which is then followed by:
final link failed: Nonrepresentable section on output.
Going through the code that creates libtheirstuff, I can see that curl_global_init is the first reference to curl.
Doing ldd libtheirstuff.so on the target platform (arm5) shows that it can find all of the references.
What's going on here?
Edit: Here are the calls to gcc
arm-none-linux-gnueabi-gcc -fPIC -c mystuff_impl.c -o mystuff_impl.o -I/home/me/arm/include
arm-none-linux-gnueabi-gcc -shared -Wl,soname=libmystuff.so -o libmystuff.so.0.1 mystuff_impl.o -L/home/me/arm/lib -ltheirstuff

Linker was grabbing the wrong version.

This problem (No symbol version section for versioned symbol
'curl_global_init##CURL_OPENSSL_3') also appears when you are trying to compile a binary that will work on multiple Linux distributions. You can check for the problem like this:
$ objdump -x mybinary | grep curl_global_init
0... F *UND* 0... curl_global_init##CURL_OPENSSL_3
The solution in this case is to build on a machine where libcurl has been compiled with ./configure --disable-versioned-symbols. Binaries compiled this way will work elsewhere (including on systems which use versioned symbols). A portable binary should produce output like this (without any # signs):
$ objdump -x mybinary | grep curl_global_init
0... F *UND* 0... curl_global_init

Related

Unable to link openssl libraries to CLion C program on windows with cygwin

I'm new to C programming, and I wanted to start a project for learning purposes.
I am trying to open an ssl socket in C with clion on windows using cygwin.
For the code I've been using this tutorial:
https://aticleworld.com/ssl-server-client-using-openssl-in-c/
I've installed cygwin with those libs: make, gdb, gcc-g++, libssl-dev
I don't see any compliation errors in the editor, but I can't run thr project.
When I try to run it I get many errors of undefined during the linking phase:
undefined reference to `OPENSSL_init_crypto'
undefined reference to `OPENSSL_init_ssl'
undefined reference to `SSL_CTX_new'
and many more like it.
So I updated m cmake file to look like this:
cmake_minimum_required(VERSION 3.21)
project(ssl_example C)
set(CMAKE_C_STANDARD 99)
include_directories(/usr/include/openssl/)
link_libraries(openssl)
add_executable(ssl_example main.c)
and now I get this error-
FAILED: ssl_example.exe
: && /usr/bin/gcc.exe -g -Wl,--enable-auto-import CMakeFiles/ssl_example.dir/main.c.o -o ssl_example.exe -Wl,--out-implib,libssl_example.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lopenssl -lcrypto && :
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lopenssl
collect2: error: ld returned 1 exit status
EDIT:
this is how my cmake file looks like:
cmake_minimum_required(VERSION 3.21)
project(ssl_example C)
set(CMAKE_C_STANDARD 99)
include_directories(/usr/include/openssl/)
link_libraries(ssl)
link_libraries(crypto)
link_libraries(openssl)
add_executable(ssl_example main.c)
I still get the same error cannot find -lopenssl
OPENSSL_init_crypto belongs to libcrypto
$ cd /usr/lib
$ grep OPENSSL_init_crypto *.dll.a
grep: libcrypto.dll.a: binary file matches
$ nm libcrypto.dll.a |grep " T " |grep OPENSSL_init
0000000000000000 T OPENSSL_init_crypto
0000000000000000 T OPENSSL_init
while the other two to libssl
$ grep OPENSSL_init_ssl *.dll.a
grep: libssl.dll.a: binary file matches
$ nm libssl.dll.a |grep " T " |grep OPENSSL_init_ssl
0000000000000000 T OPENSSL_init_ssl
$ grep SSL_CTX_new *.dll.a
grep: libQtNetwork.dll.a: binary file matches
grep: libssl.dll.a: binary file matches
nm libssl.dll.a |grep " T " |grep SSL_CTX_new
0000000000000000 T SSL_CTX_new
so you need to link versus both libssl and libcrypto
The library you must link to is called "libssl" not "openssl". In the linking must appear as '-lssl', not '-lopenssl'

Find all symbols in a directory

I am looking to figure out which C library to include when compiling a program that includes it as a header, in this case #include <pcre2.h>. The only way I've been able to figure out where the file is I need is to check for a specific symbol that I know needs to be exported. For example:
$ ls
CMakeCache.txt Makefile install_manifest.txt libpcre2-posix.pc pcre2_grep_test.sh
CMakeFiles a.out libpcre2-8.a pcre2-config pcre2_test.sh
CTestCustom.ctest cmake_install.cmake libpcre2-8.pc pcre2.h pcre2grep
CTestTestfile.cmake config.h libpcre2-posix.a pcre2_chartables.c pcre2test
$ objdump -t libpcre2-8.a|grep pcre2_compile
pcre2_compile.c.o: file format elf64-x86-64
0000000000000000 l df *ABS* 0000000000000000 pcre2_compile.c
00000000000100bc g F .text 00000000000019dd pcre2_compile_8
0000000000000172 g F .text 00000000000000e3 pcre2_compile_context_create_8
0000000000000426 g F .text 0000000000000055 pcre2_compile_context_copy_8
0000000000000557 g F .text 0000000000000032 pcre2_compile_context_free_8
And because the symbol pcre2_compile_8 exists in that file (after trying every other file...) I know that the library I need to include is pcre2-8, that is, I compile my code with:
$ gcc myfile.c -lpcre2-8 -o myfile; ./myfile
Two questions related to this:
Is there a simpler way to find a symbols in a batch of files (some of which are not elf files)? For example, something like objdump -t *? Or what's the closest thing to doing that?
Is there a better way to find out what the library value of -l<library> is? Or, what's the common way when someone downloads a new C program that they know what to add to their command-line so that the program works? (For me, I've just spent the last hour figuring out that it's -lpcre2-8 and not -lpcre or -lpcre2.
Usually, the function you call from the library will be a symbol defined by that library. But in PCRE2, due to different code unit sizes, the function you call (e.g. pcre2_compile) actually becomes a different symbol through preprocessor macros (e.g. pcre2_compile_8). You can find the symbol you need from the library by compiling your program and checking the undefined symbols:
$ cat test.c
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
int main() {
pcre2_compile("",0,0,NULL,NULL,NULL);
}
$ gcc -c test.c
$ nm -u test.o
U _GLOBAL_OFFSET_TABLE_
U pcre2_compile_8
Is there a simpler way to find a symbols in a batch of files?
You can search a directory (/usr/lib/ below) for the library files (.a or .so extension below), running nm for each and search for the undefined symbol (adapted from this question):
$ for lib in $(find /usr/lib/ -name \*.a -o -name \*.so)
> do
> nm -A --defined-only $lib 2>/dev/null| grep pcre2_compile_8
> done
/usr/lib/x86_64-linux-gnu/libpcre2-8.a:libpcre2_8_la-pcre2_compile.o:0000000000007f40 T pcre2_compile_8
Is there a better way to find out what the library value of -l is?
It is usually conveyed through the library documentation. For PCRE2, the second page of the documentation talks about the pcre-config tool that gives the appropriate flags:
pcre2-config returns the configuration of the installed PCRE2 libraries and the options required to compile a program to use them. Some of the options apply only to the 8-bit, or 16-bit, or 32-bit libraries, respectively, and are not available for libraries that have not been built.
[...]
--libs8 Writes to the standard output the command line options required to link with the 8-bit PCRE2 library (-lpcre2-8 on many systems).
[...]
--cflags Writes to the standard output the command line options required to compile files that use PCRE2 (this may include some -I options, but is blank on many systems).
So for this particular library, the recommended way to build and link is:
gcc -c $(pcre2-config --cflags) test.c -o test.o
gcc test.o -o test $(pcre2-config --libs8)

dietlibc, lowfat, opentracker - compiling against alternative libc

I'm attempting to build opentracker. My system has the following:
| package | library | headers |
| lowfat | /usr/lib/libowfat.a | /usr/include/libowfat |
| dietlibc | /opt/diet/lib-x86_64/*.a | /usr/diet/include |
| glibc | /usr/lib/*.{a,so} | /usr/include |
Looking at the Makefile for opentracker, I see (essentially) the following:
PREFIX?=..
LIBOWFAT_HEADERS=$(PREFIX)/libowfat
LIBOWFAT_LIBRARY=$(PREFIX)/libowfat
CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra
LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lpthread -lz
opentrackers: $(OBJECTS) $(HEADERS)
cc -o $# $(OBJECTS) $(LDFLAGS)
I've not compiled against an alternative libc before, so I'm including this information in case I've done this part wrong. When I invoke make, I need to point it at where my system has dietlibc and lowfat live. I'm doing it like this:
$ LDFLAGS=-L/opt/diet/lib-x86_64 make PREFIX=/opt/diet LIBOWFAT_HEADERS=/usr/include/libowfat LIBOWFAT_LIBRARY=/usr/lib
...
...
cc -o opentracker opentracker.o trackerlogic.o scan_urlencoded_query.o ot_mutex.o ot_stats.o ot_vector.o ot_clean.o ot_udp.o ot_iovec.o ot_fullscrape.o ot_accesslist.o ot_http.o ot_livesync.o ot_rijndael.o -L/opt/diet/lib-x86_64 -L/usr/lib -lowfat -pthread -lpthread -lz
/usr/bin/ld: /usr/lib/libowfat.a(io_fd.o):(.bss+0xb0): multiple definition of `first_deferred'; /usr/lib/libowfat.a(io_close.o):(.data+0x0): first defined here
...
... lots of warnings ...
/usr/bin/ld: opentracker.o: undefined reference to symbol '__ctype_b_loc##GLIBC_2.3'
/usr/bin/ld: /usr/lib/libc.so.6: error adding symbols: DSO missing from command line
Looks like there's two issues going on in there.
Multiple definitions of first_deferred
I see references to first_deferred in both io_close and io_fd, but they are in different sections.
$ objdump -t /usr/lib/libowfat.a | egrep '^[^:]+.o:|first_deferred' | grep -B1 first_deferred
io_close.o: file format elf64-x86-64
0000000000000000 g O .data 0000000000000008 first_deferred
--
io_fd.o: file format elf64-x86-64
00000000000000b0 g O .bss 0000000000000008 first_deferred
--
io_waituntil2.o: file format elf64-x86-64
0000000000000000 *UND* 0000000000000000 first_deferred
In io/io_fd.c, there's an #include io_internal.h and in that header there's an extern long first_deferred;. In io/io_close.c it's defined as long first_deferred=-1. So it doesn't look like it's double defined in the libowfat code itself. Did I compile lowfat wrong?
DSO missing from command line / symbol '__ctype_b_loc##GLIBC_2.3'
Since the Makefile is trying to compile against dietlibc, I'm a bit surprised that there's a reference to glibc (but, to be honest, also not surprised at all).
Here's the recipe for opentracker.o:
cc -c -o opentracker.o -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -I/usr/include/libowfat -Wall -pipe -Wextra -O3 -DWANT_FULLSCRAPE opentracker.c
This doesn't appear to have the -L/opt/diet/lib-x86_64 argument from LDFLAGS that is used for the main executable. Should it? I don't think so as that's a linker argument so it would not make sense to add it to the compile command. I don't see any references to glibc in the object file:
$ objdump -t ./src/opentracker/opentracker.o | grep -c 'glib'
0
DSO missing from command line / symbol '__ctype_b_loc##GLIBC_2.3'
I found two permutations to solve this issue. Option one is to make sure the very first -L argument is the location of dietlibc's lib directory, so that all symbols are resolved from there first.
The other permutation was to invoke make via the /opt/diet/bin/diet wrapper program. From the dietlibc FAQ
Q: How do I install it? make install?
A: Yep. It will then install itself to /opt/diet, with the wrapper in
/opt/diet/bin/diet. Or you don't install it at all.
The diet libc comes with a wrapper called "diet", which can be found
in bin-$(ARCH)/diet, i.e. bin-i386/diet for most of us. Copy this
wrapper somewhere in your path (for example ~/bin) and then just
compile stuff by prepending diet to the command line, e.g. "diet gcc
-pipe -g -o t t.c".
Q: How do I compile programs using autoconf with the diet libc?
A: Set CC in the environment properly. For Bourne Shells:
$ CC="diet gcc -nostdinc" ./configure --disable-nls
That should be enough, but you might also want to set
--disable-shared and --enable-static for packages using libtool.
It's not explained anywhere on the website, as far as I can tell, what the wrapper program does. The code is annoying to read due to all the architecture specific #ifdefs, but the file comment indicates it just modifies the gcc command line in an architecture specific way. A quick scan suggests relevant args modifications include: -I/opt/diet/include when compiling, -nostdlib when linking, and possibly -Os.
Multiple definitions of first_deferred
I'm not happy with my workaround here. The symbol is defined in io_internal.h:
#ifndef my_extern
#define my_extern extern
#endif
my_extern long first_deferred;
Why is there a funny redefinition of the extern keyword? Read on. The initialization of this variable is in io_close.c:
#include "io_internal.h"
long first_deferred=-1;
And here's the interesting bit. In io_fd.c:
#define my_extern
#include "io_internal.h"
#undef my_extern
Why? Who knows. The author believes they are clever I guess and saved themselves some keystrokes? The effect of this is that my_extern is defined as an empty string, so when my_extern long first_deferred; is transcluded from the header, it appears as long first_deferred;. This is what leads there to be two locations for the symbol in the archive, as there are two files that reserve space for that symbol.
I'm not happy with my "solution", which was to remove the static initialization from io_close.c. Technically, that means the variable starts with random heap memory. A quick look at how it gets used suggests this is maybe not safe, but is probably safe enough. The variable is used as an index into an array. Thankfully iarray_get does a bounds check, so it's very likely that if(e) will be false and the variable will get set to -1 as it should be.
if (first_deferred!=-1) {
while (first_deferred!=-1) {
io_entry* e=iarray_get(&io_fds,first_deferred);
if (e) {
if (e->closed) {
e->closed=0;
close(first_deferred);
}
first_deferred=e->next_defer;
} else
first_deferred=-1; // can't happen
}
}
I can't provide a good explanation for those errors, but your post helped me to get it to compile so I figured I'd mention what I did.
The "first_deferred" error seems to come from using a newer version of libowfat, I got past that by using 0.31 instead.
I didn't come across the second error, but I was getting "__you_tried_to_link_a_dietlibc_object_against_glibc" errors which I got past by uninstalling dietlibc and compiling libowfat with glibc instead.
I compiled them the same way as the AUR packages:
https://aur.archlinux.org/packages/opentracker/
https://aur.archlinux.org/packages/libowfat/
Although, instead of installing libowfat, I just put it in the src directory and skipped fetching libowfat from CVS.

Unsatisfied symbol in file libssl.a on HPUX64 [duplicate]

I am building a shared library (we'll call it "foo") that makes use of another library (we'll call it "bar"). "bar" makes use of some functions from OpenSSL.
Here's where the problem surfaces.
"bar" was compiled as a static library and it would appear that OpenSSL was too. So when I link the library ("foo"), I include the:
object files for "foo"
static library libbar.a
OpenSSL static libraries libcrypto.a and libssl.a
The build command looks something like this:
g++ -Wl,-soname,libfoo.so -shared file1.o file2.o libbar.a \
libcrypto.a libssl.a -o libfoo.so
However, I get a ton of errors:
ld: ./obj/libbar.a(file1.c.o): in function initialize_openssl:
ssl.c:117: error: undefined reference to 'SSL_library_init'
Running the following command:
nm libssl.a | grep SSL_library_init
Produces the following output:
00000000 T SSL_library_init
So obviously there is nothing wrong with the OpenSSL libraries. What could have possibly caused something like this? Here are the three commands used to build OpenSSL:
export cross=arm-linux-androideabi-
./Configure android --prefix=~/openssl-arm
make CC="${cross}gcc" AR="${cross}ar r" RANLIB="${cross}ranlib"
The compilation process completed without any errors, so I'm utterly baffled.
Why am I getting linker errors that refer to a bunch of OpenSSL symbols that clearly exist?
The problem was caused by the order of the libraries in the link command. Switching the order of libcrypto.a and libssl.a resolved all of the symbols.
GCC uses LD by default, and its a single pass linker. When you have two libraries, like libssl and libcrypto linked in a particular order, it means libssl depends on symbols from libcrypto. Therefore, libssl must precede libcrypto (or libcrypto must follow libssl). It should be no surprise libssl relies upon libcrypto since libcrypto provides the crypto used by libssl.

In Linux stubs are used for standard libraries. Why are stubs required?

In Linux, why are stubs required for standard libraries?
stubs are required to ensure proper linking of an executable across various linux releases without building the object files.
For example:
Let a be the executable we are building:
gcc -o a test.o test1.o test2.o -lz
In the above case executable a has a dependency on the libz.so (-lz is to link with libz.so). The linker resolves libz.so using the LD_LIBRARY_PATH.
Now let us see the problem:
In RHEL4(Linux Zseries):
objdump -T /usr/lib64/libz.so.1 | grep stack_chk
In RHEL5(Linux ZSeries);
objdump -T /usr/lib64/libz.so.1 | grep stack_chk
0000000000000000 DF UND 0000000000000031 GLIBC_2.4 __stack_chk_fail
In RHEL5, we see an undefined symbol in the libz.so.
Unless we pass libc to the linker after lz in the above command, this cannot be resolved.
Stubs:
If we generate the stub for libz.so, packing all the symbols of libz.so in to a stub library and link with the stub library instead of the real library, we don't see any errors:
Modified link line:
gcc -o a test.o test1.o test2.o -L/home/lib/stubs/ -lz
In the /home/lib/stubs directory, we have a stub library for libz.so by name libzstub.so.
Linker gives higher priority to the path given in the link command than LD_LIBRARY_PATH.
Now even if we link in the RHEL5 release, the linker resolves the symbols for the libz.so from the /home/lib/stubs directory.
Here the configuration details of the boxes i have used.
Loader takes care of loading the coresponding function at runtime.
RHEL5:
libcmpiutil-0.4-2.el5
glibc-utils-2.5-42
libc-client-2004g-2.2.1
libcap-1.10-26
libcap-1.10-26
libchewing-devel-0.3.0-8.el5
libchewing-0.3.0-8.el5
libcxgb3-1.2.3-1.el5
libcap-devel-1.10-26
glibc-common-2.5-42
libcxgb3-static-1.2.3-1.el5
libcroco-devel-0.6.1-2.1
compat-glibc-headers-2.3.4-2.26
libcroco-0.6.1-2.1
compat-libcom_err-1.0-7
libcmpiutil-devel-0.4-2.el5
compat-glibc-2.3.4-2.26
glibc-headers-2.5-42
glibc-devel-2.5-42
libcap-devel-1.10-26
libc-client-2004g-2.2.1
libcmpiutil-0.4-2.el5
libcroco-0.6.1-2.1
libc-client-devel-2004g-2.2.1
glibc-2.5-42
libchewing-devel-0.3.0-8.el5
libcroco-devel-0.6.1-2.1
compat-libcom_err-1.0-7
libc-client-devel-2004g-2.2.1
libchewing-0.3.0-8.el5
libcxgb3-1.2.3-1.el5
libcmpiutil-devel-0.4-2.el5
glibc-2.5-42
glibc-devel-2.5-42
compat-glibc-2.3.4-2.26
RHEL4:
rpm -qa | grep libc
glibc-2.3.4-2.41
libcxgb3-1.1.4-1.el4
libc-client-2002e-14
libcroco-0.6.0-4
libcap-devel-1.10-20
glibc-kernheaders-2.4-9.1.103.EL
compat-libcom_err-1.0-5
glibc-devel-2.3.4-2.41
compat-glibc-2.3.2-95.30
compat-libcom_err-1.0-5
glibc-common-2.3.4-2.41
libcroco-devel-0.6.0-4
libcxgb3-1.1.4-1.el4
libc-client-2002e-14
glibc-utils-2.3.4-2.41
libcap-1.10-20
glibc-headers-2.3.4-2.41
glibc-profile-2.3.4-2.41
libcxgb3-static-1.1.4-1.el4
glibc-devel-2.3.4-2.41
compat-glibc-2.3.2-95.30

Resources