Creating a shared library with main() [duplicate] - c

This question already has answers here:
How to make a linux shared object (library) runnable on its own?
(2 answers)
Closed 5 years ago.
In glibc (and also EGLIBC I believe), the libc.so library has a main() method:
$ /lib/i386-linux-gnu/libc.so.6
GNU C Library (Debian GLIBC 2.19-18+deb8u1) stable release version 2.19, by Roland McGrath et al.
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.4.
Compiled on a Linux 3.16.7 system on 2015-08-30.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.
Now I want to do the same with the following minimalistic example (i. e. I want my own SO to also have a main()):
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello, World!\n");
return 0;
}
Linking as a regular executable:
$ gcc -g -O0 -Wall -c test.c
$ gcc -o test test.o
$ ./test
Hello, World!
Now linking as a shared object:
$ gcc -g -O0 -Wall -c test.c
$ gcc -shared -o libtest.so test.o
$ ./libtest.so
Segmentation fault
nm shows that main symbol is present (000004f5 T main)
When debugging, gdb doesn't show any meaningful backtrace.
Adding -fpic or -fPIC to the gcc command line doesn't help.
What am I doing wrong?

the libc.so library has a main() method
No, the implementation of C library of gcc has an entry point not a main symbol.
You can find an example of how to do this here.

Related

Error compiling against libopcodes

I'm following some code from here which is as follows:
The OP says that you can link with -lbfd -lopcodes.
However, for OpenSuSE I've found that for libbfd I need -lbfd -liberty -lz -ldl
When trying to compile, here is my results:
make
gcc ./main.c -lbfd -liberty -lz -ldl -lopcodes -g -o bfd_se
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../lib64/libopcodes.a(arm-dis.o): In function `print_insn_neon':
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/arm-dis.c:2927: undefined reference to `floatformat_ieee_single_little'
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/arm-dis.c:2927: undefined reference to `floatformat_to_double'
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../lib64/libopcodes.a(m68k-dis.o): In function `print_insn_arg':
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/m68k-dis.c:1103: undefined reference to `floatformat_m68881_ext'
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/m68k-dis.c:1103: undefined reference to `floatformat_to_double'
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/m68k-dis.c:1099: undefined reference to `floatformat_ieee_double_big'
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/m68k-dis.c:1099: undefined reference to `floatformat_to_double'
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/m68k-dis.c:1095: undefined reference to `floatformat_ieee_single_big'
/home/abuild/rpmbuild/BUILD/binutils-2.24/build-dir/opcodes/../../opcodes/m68k-dis.c:1095: undefined reference to `floatformat_to_double'
collect2: error: ld returned 1 exit status
Makefile:4: recipe for target 'bfd_se' failed
make: *** [bfd_se] Error 1
What other flags do I need to add to have this program compile? I see the error is related to different architectures, but I'm not trying to cross compile.
Thanks!
useful information:
uname -a
Linux node 4.0.5-THS_on #1 SMP PREEMPT Thu Jun 18 16:37:06 CDT 2015 x86_64 x86_64 x86_64 GNU/Linux
gcc --version
gcc (SUSE Linux) 4.8.3 20140627 [gcc-4_8-branch revision 212064]
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
objdump --version (it uses libbfd and libopcodes)
GNU objdump (GNU Binutils; openSUSE 13.2) 2.24.0.20140403-6.1
Copyright 2013 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.
Most of the time libbfd and libopcodes does not come as shared libraries in standard distributions (because they are not meant to be linked to). You must either link to the static libraries (libbfd.a and libopcodes.a) or recompile your distribution package and include the shared libraries in it (.so files).
So, to make it clear, try:
gcc ./main.c -liberty -lz -ldl -g -o bfd_se /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../lib64/libopcodes.a /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../lib64/libbfd.a

Check glibc version for a particular gcc compiler

I have two gcc compilers installed on my system, one is gcc 4.1.2 (default) and the other is gcc 4.4.4. How can I check the libc version used by gcc 4.4.4, because /lib/libc.so.6 shows the glibc used by gcc 4.1.2, since it is the default compiler.
even easier
use ldd --version
This should return the glibc version being used i.e.
$ ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
...
which is the same result as running my libc library
$ /lib/libc.so.6
GNU C Library (GNU libc) stable release version 2.17, by Roland McGrath et al.
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
...
Write a test program (name it for example glibc-version.c):
#include <stdio.h>
#include <stdlib.h>
#include <gnu/libc-version.h>
int main(int argc, char *argv[]) {
printf("GNU libc version: %s\n", gnu_get_libc_version());
exit(EXIT_SUCCESS);
}
and compile it with the gcc-4.4 compiler:
gcc-4.4 glibc-version.c -o glibc-version
When you execute ./glibc-version the used glibc version is shown.
Use -print-file-name gcc option:
$ gcc -print-file-name=libc.so
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so
That gives the path. Let's examine the file:
$ file $(gcc -print-file-name=libc.so)
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so: ASCII text
$ cat $(gcc -print-file-name=libc.so)
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) )
The file is a linker script, which links the libraries in GROUP list.
On ELF platforms /lib/x86_64-linux-gnu/libc.so.6 is a position-independent executable with a dynamic symbol table (like that of a shared library):
$ file /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6: symbolic link to libc-2.31.so
$ file $(readlink -f /lib/x86_64-linux-gnu/libc.so.6)
/usr/lib/x86_64-linux-gnu/libc-2.31.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1878e6b475720c7c51969e69ab2d276fae6d1dee, for GNU/Linux 3.2.0, stripped
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9.9) stable release version 2.31.
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 9.4.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
gnu_get_libc_version identifies the runtime version of the GNU C Library.
If what you care about is the compile-time version (that is, the version that provided the headers in /usr/include), you should look at the macros __GLIBC__ and __GLIBC_MINOR__. These expand to positive integers, and will be defined as a side-effect of including any header file provided by the GNU C Library; this means you can include a standard header, and then use #ifdef __GLIBC__ to decide whether you can include a nonstandard header like gnu/libc-version.h.
Expanding the test program from the accepted answer:
#include <stdio.h>
#ifdef __GLIBC__
#include <gnu/libc-version.h>
#endif
int
main(void)
{
#ifdef __GLIBC__
printf("GNU libc compile-time version: %u.%u\n", __GLIBC__, __GLIBC_MINOR__);
printf("GNU libc runtime version: %s\n", gnu_get_libc_version());
return 0;
#else
puts("Not the GNU C Library");
return 1;
#endif
}
When I compile and run this program on the computer I'm typing this answer on (which is a Mac) it prints
Not the GNU C Library
but when compiled and run on a nearby Linux box it prints
GNU libc compile-time version: 2.24
GNU libc runtime version: 2.24
Under normal circumstances, the "runtime" version could be bigger than the "compile-time" version, but never smaller. The major version number is unlikely ever to change again (the last time it changed was the "libc6 transition" in 1997).
If you would prefer a shell 'one-liner' to dump these macros, use:
echo '#include <errno.h>' | gcc -xc - -E -dM |
grep -E '^#define __GLIBC(|_MINOR)__ ' | sort
The grep pattern is chosen to match only the two macros that are relevant, because there are dozens of internal macros named __GLIBC_somethingorother that you don't want to have to read through.
I doubt if you have more than one glibc installed in your system.But ldd -v <path/to/gcc-4.x> should give you the glibc used.
The easiest way is to use ldd which comes with glibc
Just run this command ldd --version :
dina#dina-X450LA:~$ ldd --version
ldd (Ubuntu GLIBC 2.23-0ubuntu9) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
Their is two additional ways to find out the glibc version:
Check the version of the installed glibc rpm package : this by runing this command
rpm -q glibc
Check the version of the used libc.so file. This way is a little bit more difficult. You can check it in this link: Linux: Check the glibc version
You can use strings command to check GLIBC version of compiler. Highest version is applicable.
ubuntu1604:extra$ strings ./arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-gcc | grep GLIBC
GLIBC_2.3
GLIBC_2.8
GLIBC_2.14
GLIBC_2.4
GLIBC_2.11
GLIBC_2.2.5
GLIBC_2.3.4
Also, check the higher versioning symbol of the libc:
readelf -V /lib64/libc.so.6

Can GDB reload executable with a statically linked library?

Normally when using gdb I can stop execution and rebuild the executable and restart without loosing my breakpoints. When I try this with an executable that has a statically linked library I get an error stating that I cannot open the executable file during the build.
A concrete example:
The library files:
libtest.h:
int square(int a);
libtest.c:
int square(int a) {
return a * a;
}
The library is compiled with:
gcc -g -c libfile.c
ar rcs libtest.a libfile.o
Main file a.c contains:
#include <stdio.h>
#include <stdlib.h>
#include "libfile.h"
int main() {
printf( "2 squared is %d\n", square(2) );
return 0;
}
The project is compiled and linked like this:
gcc -g -c a.c
gcc a.o -g --static -L. -ltest -o gdb_test
If I load the resulting file gdb_test into gdb it doesn't matter if it is running it not. As long is gdb is open a subsequent build will fail during the link step:
/usr/bin/ld: cannot open output file gdb_test: Permission denied
Is there a way around this? I would like to be able to work with gdb without having to restart it and loose my breakpoints.
It is probably a matter of versions of GDB or GCC; it works for me:
% gcc -g -c libtest.c
gcc -g -c libtest.c
% ar rcs libtest.a libtest.o
ar rcs libtest.a libtest.o
% gcc -g -c -Wall a.c
gcc -g -c -Wall a.c
% gcc -Wall -g a.o -L. -ltest -o gdb_test
gcc -Wall -g a.o -L. -ltest -o gdb_test
% ./gdb_test
2 squared is 4
% gdb ./gdb_test
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/basile/tmp/gdb_test...done.
(gdb) r
r
Starting program: /home/basile/tmp/gdb_test
2 squared is 4
[Inferior 1 (process 12271) exited normally]
(gdb) quit
quit
% gcc -v
gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc-4.6.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.2-9'
--with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr
--program-suffix=-4.6 --enable-shared --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc
--with-arch-32=i586
--with-tune=generic --enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.2 (Debian 4.6.2-9)
My system is Debian/Sid/amd64. GCC is (Debian 4.6.2-9); ld = binutils = ar is GNU gold (GNU Binutils for Debian 2.22); GDB is GNU gdb (GDB) 7.3.50.20111117-cvs-debian; Gnu Libc is (Debian EGLIBC 2.13-24). Kernel is Linux version 3.1.0-1-amd64 (Debian 3.1.5-1)
And I am able to recompile the program from inside gdb and to run it:
% gdb ./gdb_test
gdb ./gdb_test
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/basile/tmp/gdb_test...done.
(gdb) shell gcc -g -c -Wall a.c
shell gcc -g -c -Wall a.c
(gdb) r
r
Starting program: /home/basile/tmp/gdb_test
2 squared is 4
[Inferior 1 (process 12335) exited normally]
(gdb) shell gcc -Wall -g a.o -L. -ltest -o gdb_test
shell gcc -Wall -g a.o -L. -ltest -o gdb_test
(gdb)
(gdb) r
r
`/home/basile/tmp/gdb_test' has changed; re-reading symbols.
Starting program: /home/basile/tmp/gdb_test
2 squared is 4
[Inferior 1 (process 12346) exited normally]
(gdb) quit
quit
%
/usr/bin/ld: cannot open output file gdb_test: Permission denied
This is unlikely to be related to either GDB or ld (or their versions), and is most certainly not related to your use of archive library.
Much more likely this is happening because you are using some "strange" filesystem. Perhaps you are using NTFS or CIFS mount? What does df . say?

Creating static Mac OS X C build

How can i create a static build of a .c file on Mac OS X ? When i try:
gcc -o test Main.c -static
I get:
ld: library not found for -lcrt0.o
collect2: ld returned 1 exit status
It is not supported in Mac OS X's gcc:
http://discussions.apple.com/message.jspa?messageID=11053384
Perhaps that "-static" flag flat out won't work on MacOS X. Not all features of gcc are implemented on MacOS X. Apple won't even be using gcc in future versions of the OS.
I don't know how to link using "-static". I can't think of any reason to do so on MacOSX. If I knew why you wanted to use "-static" I might be more interested in the problem. Right now, I just don't get it. By asking for help, you are essentially asking for collaborators on the project - even if it is only for 10 minutes. You need to get me interested.
And http://developer.apple.com/library/mac/#qa/qa2001/qa1118.html
Static linking of user binaries is not supported on Mac OS X. Tying user binaries to the internal implementation of Mac OS X libraries and interfaces would limit our ability to update and enhance Mac OS X. Instead, dynamic linking is supported (linking against crt1.o automatically instead of looking for crt0.o, for example).
We strongly recommend that you consider the limitations of statically linking very carefully, and consider your customer and their needs, plus the long-term support you will need to provide.
Update: The prohibited is a static binary. But you still can compile some static library and use it with you another program. Program will be linked statically with your library, but other libraries like libc will be dynamic, so program will be a dynamic executable.
A binary that has no dynamic loaded libraries can not be built under OSX. I tried both apple llvm-gcc and macports gcc. However what no answer mentioned so far is that this is not needed. You can link the c/c++ library statically (and live with some dynamic part).
File hello.cpp:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!";
}
Compile as usual:
g++ hello.cpp -o hello
Check linkage:
otool -L hello
hello:
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
We can not get rid of the libSystem.B.dylib dependency but with macports gcc we can do this:
g++-mp-4.6 -static-libgcc -static-libstdc++ hello.cpp -o hello
otool -L hello
hello:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
Apparently just Apple does not support static linking:
llvm-g++ -static-libgcc -static-libstdc++ hello.cpp -o hello
otool -L hello
hello:
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
Imagine that you want to convert some functions into a library.
File: example.c
#include <stdio.h>
void aFunction( int a )
{
printf( "%d\n", a );
}
File: example.h
void aFunction( int a );
File: main.c
#include "example.h"
int main( )
{
aFunction( 3 );
return 0;
}
To create the library:
gcc -c example.c
ar -r libmylibrary.a example.o
To link the library:
gcc main.c -lmylibrary -L. -I.
And then the file example.c is a static build of the entire program.

a gcc sqrt function bug?

The following program cannot compile in gcc. But it compiles OK with g++ and MSC++ with .c extension.
#include <math.h>
#include <stdio.h>
int main()
{
double t = 10;
double t2 = 200;
printf("%lf\n", sqrt(t*t2));
return 0;
}
My system is CentOS, the version info.
> gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
The error info:
> gcc test.c
/tmp/ccyY3Hiw.o: In function `main':
test.c:(.text+0x55): undefined reference to `sqrt'
collect2: ld returned 1 exit status
Is this a bug?
Any one can do a test for me?
Have you linked the math library?
gcc -lm test.c -o test
Add the math library with flag -lm
> gcc test.c -lm
Try gcc -lm test.c -o test
For gcc, you need to tell it to link the math library in, by adding -lm
to your gcc call.
Everybody has been saying this, but I will too. You have to "tell" gcc to link to the math library. When you compile, instead of saying gcc test.c, you have to say gcc -lm test.c. I wish that I could just #include math.h and not have to do anything else.
The thing is, gcc -lm test.c -o test won't work because gcc will treat the -lm as a compiler and not a linker option. You need to put the -lm at the end of the command instead, i.e. gcc -o test test.c -lm

Resources