_end symbol disappears when linking to libcurl - linux

On Linux, the D runtime library relies on the _end symbol in determining the GC root ranges (man 3 end), which is in fact very similar to what the Boehm GC does. However, when linking in libcurl, the symbol is no longer found by the linker:
$ cat test.c
#include <stdio.h>
extern char _end[];
int main() {
printf("%p\n", &_end);
return 0;
}
$ gcc test.c # works
$ gcc test.c -lcurl
/usr/bin/ld: /tmp/ccOPtbEv.o: undefined reference to symbol '_end'
/usr/bin/ld: note: '_end' is defined in DSO /usr/lib/libssl.so.1.0.0 so try adding it to the linker command line
/usr/lib/libssl.so.1.0.0: could not read symbols: Invalid operation
collect2: error: ld returned 1 exit status
From a quick search on the D forums, libpq, libdw and several other libraries seem to trigger the same problem. Any idea what could be happening here? test.c doesn't even depend on symbols from libcurl. (Arch Linux x86_64, GCC 4.7.2, ld 2.23)
Also, please note that »try linking in libssl« is not the answer I am looking for, I want to understand what is happening here. I'm trying to fix this problem in a compiler I'm working on, so you can assume basic familiarity with how the linking process works.
Edit: The reason why I'm not particularly satisfied with telling the users to just link in libssl, ..., explicitly is that pkg-config --libs curl, curl-config --libs, etc. don't contain this information; requiring it would thus break build systems. If anyone has a better idea for determining the bounds of the data (initialized and BSS) segments, I'd be keen to know.
Edit 2: With the toolchain mentioned above, end (without the underscore) also seems to be defined, and it doesn't trigger the problem. Still baffled as to why it occurs, though.

please note that »try linking in libssl« is not the answer I am looking for.
But most likely it actually is the answer you are looking for. Your command line is all wrong. Try this instead:
gcc test.c -lcurl
The order of libraries and sources,objects on command line matters.

_end symbol is provided by linker. It points past the last object in bss. However, it's just a convention, no standard requires this. Your toolchain's linker doesn't do that, apparently.

Related

How can I resolve this error when linking to zlib under Linux in a D application?

I've mainly worked on Windows, so I'm quite unfamiliar with less common issues under Linux.
Here's the error I'm getting when dub tries to link my application:
/usr/bin/ld: .dub/obj/pixelperfectengine_pixelperfecteditor.o: undefined reference to symbol 'inflateEnd'
//lib/x86_64-linux-gnu/libz.so.1: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
Error: /usr/bin/gcc failed with status: 1
/usr/bin/ldc2 failed with exit code 1.
I've an image handling library as a dependency, which is required for the application, and it (obviously) uses zlib for *.png compression/decompression. I've installed zlib1g-dev for Ubuntu, but did not fix my issues, and the same exact code compiles without any issues under Windows.
You need to link in zlib, as mentioned before.
I would recommend to do so via the "libs" array (see this page: https://dub.pm/package-format-json.html). The advantage of using libs over lflags is that libs will try to use pkg-config, which is a generic way to get linker / compile flags for C[++] libraries on POSIX. It works on Linux and Mac OSX. If pkg-config is not found, dub will just default to do what lflags would do in the first place.
Here's an example from my own project: https://github.com/Geod24/libsodiumd/blob/9b397645e2fc3ca502acb58e1b4631d3faf094e2/dub.json
/lib/x86_64-linux-gnu/libz.so.1: error adding symbols: DSO missing from command line
This error is telling you that you must add -lz to command line. I don't know what dub is, but somehow you must convince it to add -lz to the link command it constructs.
It's probably enough to add -lz to the lflags in your dub file.

Tell which version of symbols are available for linking against (in libc)?

Ok, so I want to link against a lower version of libc / glibc, for compatibility. I noticed this answer about how to do this, on a case-by-case basis:
How can I link to a specific glibc version?
https://stackoverflow.com/a/2858996/920545
However, when I tried to apply this myself, I ran into problems, because I can't figure out what lower-version-number I should use to link against. Using the example in the answer, if I use "nm" to inspect the symbols provided by my /lib/libc.so.6 (which, in my case, is a link to libc-2.17.so), I see that it seems to provide versions 2.0 and 2.3 of realpath:
> nm /lib/libc.so.6 | grep realpath#
4878d610 T realpath##GLIBC_2.3
48885c20 T realpath#GLIBC_2.0
However, if I try to link against realpath#GLIBC_2.0:
__asm__(".symver realpath,realpath#GLIBC_2.0");
...i get an error:
> gcc -o test_glibc test_glibc.c
/tmp/ccMfnLmS.o: In function `main':
test_glibc.c:(.text+0x25): undefined reference to `realpath#GLIBC_2.0'
collect2: error: ld returned 1 exit status
However, using realpath#GLIBC_2.3 works... and the code from the example, realpath#GLIBC_2.2.5 works - even though, according to nm, no such symbol exists. (FYI, if I compile without any __asm__ instruction, then inspect with nm, I see that it linked against realpath#GLIBC_2.3, which makes sense; and I confirmed that linking to realpath#GLIBC_2.2.5 works.)
So, my question is, how the heck to I know which version of the various functions I can link against? Or even which are available? Are there some other kwargs I should be feeding to nm? Am I inspecting the wrong library?
Thanks!
It seems to me that you have mixed up your libraries and binaries a bit...
/lib/libc.so.6 on most Linux distributions is a 32-bit shared object and should contain the *#GLIBC_2.0 symbols. If you are on an x86_64 platform, though, I would expect GCC to produce an 64-bit binary by default. 64-bit binaries are generally linked against /lib64/libc.so.6, which would not contain compatibility symbols for an old glibc version like 2.0 - the x86_64 architecture did not even exist back then...
Try compiling your *#GLIBC_2.0 program with the -m32 GCC flag to force linking against the 32-bit C library.

Change in gnu ld linker behavior

When I went from using GNU ld version 2.20 to 2.21 , I began seeing the following change in behavior. Not sure if it is broken behavior in 2.20 that was fixed in 2.21 or if something else is going on.
libfoo.so : provides symbols foo()
libfoobar.so : provides symbol bar() and specifies libfoo.so in its DT_NEEDED slot
main.cpp : uses symbols foo() as well as bar()
Previously, I could build main.cpp by just doing :
g++ main.cpp -lfoobar
The internal dependency of foobar.so on foo.so would ensure that foo() as well as bar() are found
Now, the above does not work and I have to explicitly link foo as well :
g++ main.cpp -lfoobar -lfoo
So my question is : What is the right behavior - If a .so has dependencies, then are they considered when searching for symbols used directly in the executable or are these dependencies available in a private namespace for the .so only?
Thanks.
So my question is : What is the right behavior
The new behavior is the right one.
If a .so has dependencies, then are they considered when searching for symbols used directly in the executable
No. Whatever dependencies libfoobar.so has is a private implementation detail, that can change tomorrow. You should not count on it. If you use symbols from libfoo.so, then you should specify -lfoo on command line.

undefined reference to `__errno_location'

I am compileing application for ndk, i am getting error "undefined reference to `__errno_location'".
The error comes from a line
sprintf( buff, "%s TIOCMGET failed: %s\n", buff, strerror(errno) );
If I comment this line, the linker does not complain about the same otherwise it does.
I am trying to build my own executable for android using Sourcery G++ Lite's arm-none-linux-gnueabi-gcc tool chain.
From what I can gather, your compiler is referencing a symbol __errno_location which cannot be found in any of the libraries which the linker is looking at.
This suggests that either:
You don't have the correct libraries; or
You do have the correct libraries but they're not being provided to the linker; or
You don't have the correct headers.
If the header doesn't match the library then symbols can have the wrong name and so you can get such link errors.
It appears that you're including the compilers' LibC headers and then linking against the android library which might not always work.

linux library problem

Everybody out there,
I'm writing a c code which have a strange problem when I compile it .
The source code is OK.
I compile it with following option:
$ gcc above_sample.c -I/home/hadoop/project/hadoop-0.20.2/src/c++/libhdfs -L/home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib -lhdfs -o above_sample.
But it show the out put like that:
/usr/bin/ld: warning: libjvm.so, needed by /home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib/libhdfs.so, not found (try using -rpath or -rpath-link) /home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib/libhdfs.so: undefined reference to `JNI_CreateJavaVM#SUNWprivate_1.1'
/home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib/libhdfs.so: undefined reference to `JNI_GetCreatedJavaVMs#SUNWprivate_1.1'
collect2: ld returned 1 exit status
I searched for libjvm.so i found It in my system in /usr/java/lib.
I made a symbolic link of it but did not work.
i copied the library in to several places like usr/lib check the LD_library_Path
but could not manage to compile the program it showing the same error again and again
Can any one tell me what I'm doing wrong ?
how to link .so file to gcc ?
or how .so files are linked in program?
Try adding:
-L/usr/java/lib
To your linker command, since that's the library your linker is not being able to find: I_GetCreatedJavaVMs#SUNWprivate_1.1.
A little piece of advice: it's not a good idea to mess with LD_LIBRARY_PATH. Just fix your linker command.
Linker gives a warning about not found reference to function JNI_CreateJavaVM#SUNWprivate_1.1
/usr/bin/ld: warning: libhdfs.so: undefined reference to
`JNI_CreateJavaVM#SUNWprivate_1.1'
This function name might be specific for library from Sun/Oracle HotSpot JVM. Other JVMs may have another name. For example, mine OpenJDK had only shorter name such as JNI_CreateJavaVM and linker gave me the same warning.
You may get list of the functions from your libjvm.so by running command:
readelf -s libjvm.so | grep JNI_CreateJavaVM # given that you are in catalog containing libjvm.so
If output does not contain required function, then you might want to install another JDK.
That's what worked for me:
CDH=/opt/cloudera/parcels/CDH
OS_ARCH=amd64
gcc hdfs_example.c -I$CDH/include -L$CDH/lib64 \
-L/usr/java/default/jre/lib/${OS_ARCH}/server \
-ljvm -lhdfs -o hdfs_write_test

Resources