Does .so file change any types? - c

I'm using pmemobj_create from https://pmem.io/pmdk/manpages/linux/v1.4/libpmemobj/pmemobj_open.3 in my own code foo.c. It takes arguments PMEMobjpool *pmemobj_create(const char *path, const char *layout, size_t poolsize, mode_t mode). When compile foo.c directly to foo.o, than link foo.o with test.o, everything works fine.
I used the following compilation commands.
gcc -c foo.c -o foo.o
gcc test.o foo.o -o test
But when I compile foo.c to libfoo.so first, using
gcc -c -fPIC foo.c -o foo.o
gcc -shared -o libfoo.so foo.o
Then link it with test.o,
the compilation succeeded, but at execution, the execution of the function pmemobj_create fails with an error indicates Invalid argument. My assumption is that the way I compile foo.c might be wrong, which causes the arguments I passed into pmemobj_create to be invalid. But how can I fix it? Thanks for any suggestions!

Does .so file change any types?
If you think of MIME types, no. Check with file(1). But in C++ code compiled by GCC, type information is encoded by name mangling (and some C-callable libraries are coded in C++). So use extern "C" (for public function names in plugins) as suggested in the C++ dlopen mini-howto.
A shared library (or *.so file) does not contain a lot of type information. Read about the ELF format. At link time, there is just a difference between data and code, and both named functions and data have a name, an alignment, a size (in bytes) an not much more type information (except being data, function and their segment). Check with readelf(1), objdump(1), nm(1).
On Linux: read how to write shared libraries then compile your plugin with gcc -Wall -Wextra -g -fPIC -O1 foo.c -shared -o libfoo.so.
Perhaps you should also append -lpmemobj to the above gcc command.
Learn to use the GDB debugger. Your main program needs to be compiled with gcc -Wall -Wextra -g then linked with -rdynamic -ldl passed to gcc
Use also not only gdb(1) but also strace(1), pmap(1), ltrace(1) to understand what is going on at runtime.
Read more about elf(5), ld.so(8), dlopen(3).

Related

Why do I get extra system calls when compiling code directly to an executable vs. compiling to an object file and then manually linking?

I want to compile this C code with the GNU C Compiler on Ubuntu without linking any standard libraries, having only the following code execute.
static void exit(long long code)
{asm inline
("movq $60,%%rax\n"
"movq %[code],%%rdi\n"
"syscall"
:
:[code]"rm"(code)
:"rax"
,"rdi");}
static void write(long long fd,char *msg,long long len)
{asm inline
("movq $0x1,%%rax\n"
"movq %[fd],%%rdi\n"
"movq %[msg],%%rsi\n"
"movq %[len],%%rdx\n"
"syscall"
:
:[fd]"rm"(fd)
,[msg]"rm"(msg)
,[len]"rm"(len)
:"rax"
,"rdi"
,"rsi"
,"rdx");}
#define PRINT(msg) write(1,msg,sizeof(msg))
void _start()
{PRINT("Hello World.\n");
exit(0);}
I compiled with cc example.c -ffreestanding -nostartfiles -O3 -o example.
When I called the output file I saw a lot of extra system calls with strace that should not have been there:
brk
arch_prctl
access
mmap
arch_prctl
mprotect
I then compiled like this: cc example.c -c -O3 -o example.o; ld example.o -o example and it did not do the extra syscalls. It even made the filesize somewhat smaller.
The objdump -d of it was exactly the same. In the objdump -D I found some extra symbols (_DYNAMIC,__GNU_EH_FRAME_HDR,.interp) in the first case compared to the second, but still no sign of any extra syscalls in the code.
Do you know why I get the extra system calls with cc example.c -ffreestanding -nostartfiles -O3 -o example and not with cc example.c -c -O3 -o example.o; ld example.o -o example?
I found out what is happening.
If I compile the code with cc example.c -ffreestanding -nostartfiles -O3 -o example the compiler makes a dynamically linked executable. Dynamically linked executables have an .interp section. That is what I was seeing in my objdump -D.
Dynamically linked executables are executing via the program interpreter and the dynamic linker. The additional system calls I saw, came from the dynamic linker. I still do not know why the executable wants to dynamically link anything in a program that does not link any libraries and wants to be freestanding.
If you do not want the extra system calls from the dynamic linker - you should give gcc the extra -static option. The compiler does not automatically do this if there is no dynamic linking happening.

ld would not link the static library because of it consider the library is not needed, but I need this library [duplicate]

I have a program and a static library:
// main.cpp
int main() {}
// mylib.cpp
#include <iostream>
struct S {
S() { std::cout << "Hello World\n";}
};
S s;
I want to link the static library (libmylib.a) to the program object (main.o), although the latter does not use any symbol of the former directly.
The following commands do not seem to the job with g++ 4.7. They will run without any errors or warnings, but apparently libmylib.a will not be linked:
g++ -o program main.o -Wl,--no-as-needed /path/to/libmylib.a
or
g++ -o program main.o -L/path/to/ -Wl,--no-as-needed -lmylib
Do you have any better ideas?
Use --whole-archive linker option.
Libraries that come after it in the command line will not have unreferenced symbols discarded. You can resume normal linking behaviour by adding --no-whole-archive after these libraries.
In your example, the command will be:
g++ -o program main.o -Wl,--whole-archive /path/to/libmylib.a
In general, it will be:
g++ -o program main.o \
-Wl,--whole-archive -lmylib \
-Wl,--no-whole-archive -llib1 -llib2
The original suggestion was "close":
How to force gcc to link unreferenced, static C++ objects from a library
Try this: -Wl,--whole-archive -lyourlib
I like the other answers better, but here is another "solution".
Use the ar command to extract all the .o files from the archive.
cd mylib ; ar x /path/to/libmylib.a
Then add all those .o files to the linker command
g++ -o program main.o mylib/*.o
If there is a specific function in the static library that is stripped by the linker as unused, but you really need it (one common example is JNI_OnLoad() function), you can force the linker to keep it (and naturally, all code that is called from this function). Add -u JNI_OnLoad to your link command.

GNU g++ -G option to create a shared library available on Solaris not on Linux

I am using GNU g++ 4.9.2 compiler both on Solaris and Linux.
On Solaris platform, to create a shared library from a source file (a.c), I use the following command:
g++ -G a.c -o a
a becomes a shared library
a.c contains the following code:
void libfn1()
{
}
If I try not to use -G option i.e. compile as:
g++ a.c -o a
It gets a linker error: Undefined Symbol main
But, on Linux, if I do the same thing: it says:
g++: error: unrecognized command line option -G
How to create a shared library on Linux? What is the g++ option for that?
The g++ documentation says this:
These additional options are available on System V Release 4 for
compatibility with other compilers on those systems:
-G Create a shared object. It is recommended that -symbolic or -shared be
used instead.
Normally you want to generate position independent code too, for a shared library, with the -fPIC flag.
So you'd want to run:
g++ -fPIC -shared a.c -o liba.so
The process to create a shared library on a Linux system is a bit different.
Shared libraries on Linux are .so (for "shared object") files, not .g.
You do it like this:
First, you need to generate position-independent code from your C++ source. That is so your library works from wherever it is called. To do that, you should use g++'s -fPIC flag.
So, for each source file you want to be included in your library, you should only compile it to position-independent code. We'll handle linking later.
For each source file:
g++ -c -fPIC file.cpp
(The -c flag tells g++ "compile, don't link").
for each file.cpp, g++ will generate file.o, an object file containing position-independent code.
To then build the object files into a shared library, you should use
g++ -o -shared myLibrary.so {all_object_files}
So if you have file1.o, file2.o and file3.o, the command would be:
g++ -shared -o myLibrary.so file1.o file2.o file3.o
Of course, if you have a lot of files this can get pretty tedious, so you should write a Makefile to automate this process for you! Here's an example:
myLibrary.so: file1.o file2.o file3.o
$(CXX) -shared $^ -o $#
file1.o file2.o file3.o : CXXFLAGS+=-fPIC

Custom C library: can functions in the same library refer to each other?

I've just started to create my own C libraries to keep my commonly used functions tidy. However, I've hit a new problem and I struggled to find information on the best route to take.
I generate my library of two functions using the following:
gcc -I. -c -fpic rand_site.c
gcc -I. -c -fpic rand_spin.c
gcc -shared -o libstatphys.so rand_site.o rand_spin.o
Each of these source files contained a single function. I was hoping to create a third function for my library that uses the two functions above but I'm not sure how to use functions from within the same library.
Am I going about this the right way? What is the best practice for doing this?
Yes, you can.
Create a header file rand_site.h and put the declaration of the function defined in rand_site.c in it.
Create a header file rand_spin.h and put the declaration of the function defined in rand_spin.c in it.
Use #include to include the two .h files in the third file, say foo.c.
Then compile foo.c and add it to the library using:
gcc -I. -c -fpic foo.c
gcc -shared -o libstatphys.so rand_site.o rand_spin.o foo.o
If you would like to create a second shared library that has foo.o, you can use:
gcc -I. -c -fpic foo.c
gcc -shared -o libfoo.so foo.o -lstatphys
If you would like to create an executable using foo.o, you can use:
gcc -I. -c foo.c
gcc foo.o -lstatphys

Custom header file implementation

I have a custom header file example.h which has prototypes for a few functions. There is a .C file example.c that I implemented which "includes" (#include "example.h") and has the implementations of the functions that has prototype in example.h.
Now, I have another function test.c that has to call the functions that are prototyped in example.h and are implemented in example.c. How Can I do it?
You need to link them all at the end (assuming you have already included the prototypes into your test.c). So if you're compiling, you can compile both of the .c files together into one executable. More commonly, however, is to compile these without linking (which produces object files). Then, at the end, link all of the object files together. To do this depends on your compiler, but an example would be:
gcc -c -o example.o example.c
gcc -c -o test.o test.c
gcc -o my_application test.o example.o
Or, for a small project, this works just as well
gcc -o my_application example.c test.c
Just #include "example.h" in test.c (and don't forget to link all of the object files!)

Resources