dlsym-like functionality for non-dynamically-loaded code? - c

I know how to use dlsym() to find symbols keyed by a string - when these symbols are exported by a shared library which I've dlopen()ed. But - what about other code? Just object code I've linked statically. Is it possible to somehow lookup symbols?
Notes:
If it helps, make any reasonable assumptions about the compilation and linking process (e.g. which compiler, presence of debug info, PIC code etc.)
I'm interested more in a non-OS-specific solution, but if it matters: Linux.
Solutions involving pre-registration of functions are not relevant. Or rather, maybe they are, but I would rather avoid that.

You can indeed just use dlsym() for that purpose.. You just have to export all symbols to the dynamic symbol table. Link the binary with gcc -rdynamic for that.
Example:
#include <stdio.h>
#include <dlfcn.h>
void foo (void) {
puts("foo");
}
int main (void) {
void (*foo)(void) = dlsym(NULL, "foo");
foo();
return 0;
}
Compile with: gcc -rdynamic -O2 dl.c -o dl -ldl
$ ./dl
foo
$

Related

Make a C static library that only exposes the API

I have an old static library that includes some functions produced by a C auto-coder (Mathworks/Simulink). I have just made a new static library (that does totally different things from the old library) that uses a newer version of the auto-coder. I need to make an executable that links both these libraries. Unfortunately many of the helper functions generated by the auto-coder have the same name in the old and new libraries but their functionality has changed. These functions are not part of the API. Obviously when I try to link I get complaints that the same symbols appear in both libraries.
The old library is untouchable, but I can mess with the new one.
The libraries are built with
gcc -c *.c
ar -crs libwhatever.a *.o
and linked with
gcc main.o -L. -lold -lnew
My current solution is to look at all the symbol clashes given by gcc and rename the symbols in the new library using
objcopy --redefine-sym sym=sym_new libnew.a
This seems to work. My program links and behaves as expected. But I'm wondering if it is the right/best thing to do.
Ideally I'd like to make a libnew.a that only exposes the API functions and nothing else. That way I guarantee no symbol clashes when I try to link. Is this possible I cannot figure out how.
Please note that I have little previous experience in these matters. Also, if it's relevant/not obvious, I'm using Linux.
Edit
Below is a rather contrived minimal working example.
old/printOld.c:
#include "printOld.h"
#include <stdio.h>
void printOld()
{
printStr();
}
void printStr()
{
printf("Old\n");
}
old/printOld.h:
void printStr();
old/buildOld:
gcc -c printOld.c
ar -crs libold.a printOld.o
new/printNew.c:
#include "printNew.h"
#include <stdio.h>
void printNew()
{
printStr();
}
void printStr()
{
printf("New\n");
}
new/printNew.h:
void printStr();
new/buildNew:
gcc -c printNew.c
ar -crs libnew.a printNew.o
#objcopy --redefine-sym printStr=printStrNew libnew.a
main/main.c:
void printOld();
void printNew();
int main()
{
printOld();
printNew();
return 0;
}
main/buildMain:
gcc main.c -L../old -L../new -lold -lnew
The linker error when I leave objcopy commented out is:
/usr/bin/ld: ../new/libnew.a(printNew.o): in function `printStr':
printNew.c:(.text+0x11): multiple definition of `printStr'; ../old/libold.a(printOld.o):printOld.c:(.text+0x11): first defined here
collect2: error: ld returned 1 exit status
The above example has the same kind of structure as the auto-generated code. I know that I can fix my problem by declaring the functions in the header files as static, but I'd rather not have to mess with the auto-generated code. It is very large and very unpleasant.

Rename a function without changing its references

I have an object file compiled using gcc with -ffunction-sections option. I have access to the source file but iam not allowed to modify it.
file.c
void foo(void)
{
bar();
}
void bar(void)
{
abc();
}
What iam trying to achieve is to make all the references to bar take an absolute address(which I'll assign in the linker script) whereas bar will be placed at some other address by the linker.
A possible solution is to rename bar to file_bar without changing the call to bar inside foo(). I tried using objcopy -redefine-syms but it seems to rename even the calls to bar.
Solution provided by busybee solves the problem unless the functions are in the same compilation unit.
foo1.c
#include <stdio.h>
extern void bar1();
void foo1(){
printf("foo1\n");
}
int main(){
printf("main\n");
foo1();
bar1();
}
bar1.c
#include <stdio.h>
void bar1(){
printf("bar1\n");
}
wrapper.c
#include <stdio.h>
void __wrap_foo1(){
printf("wrap_foo1\n");
}
void __wrap_bar1(){
printf("wrap_bar1\n");
}
Now,
$ gcc -c -ffunction-sections foo1.c bar1.c wrapper.c
$ gcc -Wl,--wrap=foo1 -Wl,--wrap=bar1 -o output foo1.o bar1.o wrapper.o
$ ./output
main
foo1
wrap_bar1
All functions to be redirected are in their own compilation unit
The linker has the option "--wrap" that replaces all references to the symbol "xxx" by "__wrap_xxx" and the symbol itself by "__real_xxx". It is used to put a wrapper function as an "interceptor" in between call and function.
But with this option you can do whatever you like with those symbols in your linker script. You just need to define "__wrap_xxx" with a symbol so that the references are resolvable.
Depending on your needs you can also write a dummy function named "__wrap_xxx()" that does not even call "__real_xxx()". Or you can place "__real_xxx" in a vector table, or... whatever you can think of.
All functions to be redirected are non-static ("global"), patching immediate values
I looked through the answers of the other question the OP posted in a comment. This gave me the idea to weaken the symbols in question and to override them with a value by the linker.
This example might give you some insight. I tested in on Linux which has address space layout randomization so all addresses are offsets from a random base. But for the OP's target system it should work as expected.
foo1.c
Because of arbitrary values for the redirected addresses the functions can't be called. But the program can print their addresses.
#include <stdio.h>
void foo1(void) {
}
extern void bar1(void);
int main(void) {
printf("%p\n", main);
printf("%p\n", foo1);
printf("%p\n", bar1);
return 0;
}
bar1.c
void bar1(void) {
}
wrapper.ld
This is the first alternative to give the linker the addresses to be used, an additional linker script. For the second one see below. The standard linker script will be augmented here, there is no need to copy and patch it. Because of the simple structure this is probably the most simple way to provide many redirected addresses which can be easily automated.
foo1 = 0x1000;
bar1 = 0x2000;
Note: This is not C! It is "linker script" syntax which happens to be quite similar.
How I built and tested
This command sequence can be automated and sorted for your liking. Especially the calls of objcopy could be done by some loop over a list.
gcc -c -ffunction-sections foo1.c
objcopy --weaken-symbol=foo1 foo1.o foo2.o
gcc -c -ffunction-sections bar1.c
objcopy --weaken-symbol=bar1 bar1.o bar2.o
gcc foo1.o bar1.o -o original
echo original
./original
gcc foo2.o bar2.o -o weakened
echo weakened
./weakened
gcc foo2.o bar2.o wrapper.ld -o redirected
echo redirected
./redirected
Instead of an additional linker script the symbol definitions can be given on the command line, too. This is the mentioned second alternative.
gcc foo2.o bar2.o -Wl,--defsym=foo1=0x1000 -Wl,--defsym=bar1=0x2000 -o redirected
BTW, the linker understands #file to read all arguments from the file file. So there's "no limit" on the size of the linker command.
All functions to be redirected are non-static ("global"), overwriting with new functions
Instead of providing immediate values you can of course just provide your alternative functions. This works like above but instead of the additional linker script or symbol definitions you write a source file.
wrapper.c
Yes, that's right, the names are equal to the names of the originals! Because we made the symbols of the original functions weak, we'll get no error message from the linker when it overwrites the references with the addresses of the new functions.
void foo1(void) {
}
void bar1(void) {
}
Build the redirected program like this (only new commands shown):
gcc -c -ffunction-sections wrapper.c
gcc foo2.o bar2.o wrapper.o -o redirected
A function to be redirected is static
Well, depending on your target architecture it will probably not be possible. This is because of the relocation entry of the reference. It will be some kind of relative, telling the linker to resolve by an offset into the section of the function instead to resolve by the symbol of the function.
I didn't investigate this further.

-rdynamic for select symbols only?

Scenario:
Executable loads shared object at run time via dlopen.
The shared object references some symbol (a function) that is actually compiled into the main executable.
This works fine if I add -rdynamic to gcc when linking the executable.
-rdynamic exports all non-static symbols of the executable. My shared object only needs a select few.
Question: Is there a way to achieve the effect of -rdynamic, but restricted the the few select symbols that I know are needed by my shared object?
Edit:
At least two people misunderstood the question, so I try to clarify:
This question is about exporting a symbol from the main executable.
This question is not about exporting a symbol from a dynamic library.
Here is a minimal example:
func.h, the common header file
#include <stdio.h>
void func(void);
main.c, the main executable code:
#include <dlfcn.h>
#include "func.h"
// this function is later called by plugin
void func(void) {
printf("func\n");
}
int main() {
void * plugin_lib = dlopen("./plugin.so", RTLD_NOW);
printf("dlopen -> %p, error: %s\n", plugin_lib, dlerror());
// find and call function "plugin" in plugin.so
void (*p)(void); // declares p as pointer to function
p = dlsym(plugin_lib, "plugin");
p();
return 0;
}
plugin.c, code for the plugin that is loaded at runtime:
#include "func.h"
void plugin()
{
printf("plugin\n");
func();
}
If I compile with
$ gcc -o main main.c -ldl
$ gcc -shared -fPIC -o plugin.so plugin.c
Then plugin.so cannot be loaded, because it references the symbol func, which cannot be resolved:
$ ./main
dlopen -> (nil), error: ./plugin.so: undefined symbol: func
Segmentation fault (core dumped)
I can convince the main executable to export all its global symbols by compiling with -rdynamic:
$ gcc -rdynamic -o main main.c -ldl
$ ./main
dlopen -> 0x75e030, error: (null)
plugin
func
But this fills the dynamic symbol table unnecessarily with all symbols.
(This dynamic symbol table can be inspected with nm -D main.)
The question is, how can I add only "func" to the dynamic symbol table of the main executable, and not everything.
Unfortunately it's harder to achieve this for executables. You need to generate a list of symbols that you want to export and then add -Wl,--dynamic-list=symfile.txt to LDFLAGS.
Here's example of how it's done in Clang (and here's the script they use to generate the symbols file).
You could do it with the visibility attribute of GCC.
Declare the function you need to export with __attribute__ ((visibility ("default"))) flag. Then compile your whole library passing -fvisibility=hidden argument to GCC.
For full explanation on this, refer to the following GCC documentation page.

Ubuntu C program loadable module and undefined symbols

Very new to linux in general and trying to build a loadable module for use in zabbix, which works, but trying to build a simple shell program for testing it. That means this module needs to be loaded dynamically.
Sharable module SNMPmath is built with this:
gcc -shared -o SNMPmath.so $(CFLAGS) -I../../../include -I/usr/include/libxml2 -fPIC SNMPmath.c
That works fine for zabbix.
The test program (TestSO.c) uses
lib_handle = dlopen("./SNMPmath.so", RTLD_NOW);
to load this image dynamically, and when it does, it is missing symbols including init_snmp which come from the net-snmp package which is referenced in the SNMPmath loadable module.
My question is both general and specific. What's the right approach -- is this library called by the loadable module supposed to be forced into the loadable module? Is it supposed to be forced into the test program (despite having no compile-time reference to it)? Or is it supposed to be dynamically loaded, itself, in the loadable module (which seems to contradict what I'm seeing in other examples)?
And in either case, how is the GCC command modified to include net-snmp? I've tried variations of whole-archive, no-as-needed, listing what I think is the library (/usr/lib/x86_64-linux-gnu/libsnmp.a) with various compiler options with no effect (or occasionally errors). Also tried linking to the .so version of that (no effect). So a hint as to the proper GCC command to include the library would be very helpful.
Here's one iteration of attempts at linking the main program:
gcc -rdynamic -o TestSO -I../../../include -I/usr/include/libxml2 TestSO.c -ldl -Wl,--no-as-needed /usr/lib/x86_64-linux-gnu/libsnmp.so
I've found numerous examples of loading modules, but they all load a simple routine that does not itself have undefined symbols that need satisfying.
Recap:
TestSO.c
==> Loads with dlopen SNMPmath.c
==> needs to refer to net-snmp routines like init_snmp
Pointers to examples or explanation welcome, I realize I'm missing something fairly obvious.
EDIT AFTER FIRST COMMENTS TO INCLUDE:
I have it sort of working now, but would appreciate a sanity check if this is correct. I pruned it down so as to show the whole code. Here is the code to produce the SO:
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <string.h>
int zbx_module_SNMPmath_avg(int i, int j)
{
init_snmp("snmpapp"); // initialize SNMP library
return 1;
}
Here is how it is compiled (note slight name change):
CFLAGS=-I. `net-snmp-config --cflags`
SNMPmath_small: SNMPmath_small.c
gcc -shared -o SNMPmath.so $(CFLAGS) -I../../../include -I/usr/include/libxml2 -fPIC SNMPmath_small.c -Wl,--no-as-needed,/usr/lib/x86_64-linux-gnu/libsnmp.so
Then here is the main program:
#include <stdio.h>
#include <dlfcn.h>
#include <dlfcn.h>
#include <string.h>
int main(int argc, char **argv)
{
void *lib_handle;
int(*fn)(int req, int ret);
int x;
char *error;
lib_handle = dlopen("./SNMPmath.so", RTLD_NOW);
if (!lib_handle)
{
fprintf(stderr, "Error on open - %s\n", dlerror());
exit(1);
}
else
fprintf(stderr,"Successfully loaded module\n");
fn = dlsym(lib_handle, "zbx_module_SNMPmath_avg");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "Error on dlsym %s\n", error);
exit(1);
}
else fprintf(stderr,"Successfully called dlsym\n");
// testing
int req, ret;
req=1;
ret=1;
x=(*fn)(req, ret);
printf("Valx=%i\n",x);
dlclose(lib_handle);
return 0;
}
And finally this is built with:
TestSO: TestSO.c
gcc -rdynamic -o TestSO -I../../../include -I/usr/include/libxml2 TestSO.c -ldl
This now will run as expected. I found that linking against the netsnmp library's so file when building my so seemed to work.
But is this the correct sequence? And/or the preferred sequence?
Ps. Off to read the paper in the first proposed answer.
Pointer to explanation: Drepper's paper: Howto write shared libraries
But we need more source code (and the commands used to compile it), and the real error messages (e.g. as given by dlerror() after dlopen call) to help more.
(See also this answer)
You might want to add some libraries like -lsomething (I don't know which, you probably do know!) to your command gcc -shared which is building SNMPmath.so .... You don't want to link a static library like libsnmp.a to it (you should link shared libraries to your SNMPmath.so shared object).

Undefined reference to sqrt (or other mathematical functions)

I have this simple code:
max = (int) sqrt (number);
and in the header I have:
#include <math.h>
But application still says undefined reference to sqrt. Do you see any problem here? It looks like everything should be okay.
You may find that you have to link with the math libraries on whatever system you're using, something like:
gcc -o myprog myprog.c -L/path/to/libs -lm
^^^ - this bit here.
Including headers lets a compiler know about function declarations but it does not necessarily automatically link to the code required to perform that function.
Failing that, you'll need to show us your code, your compile command and the platform you're running on (operating system, compiler, etc).
The following code compiles and links fine:
#include <math.h>
int main (void) {
int max = sqrt (9);
return 0;
}
Just be aware that some compilation systems depend on the order in which libraries are given on the command line. By that, I mean they may process the libraries in sequence and only use them to satisfy unresolved symbols at that point in the sequence.
So, for example, given the commands:
gcc -o plugh plugh.o -lxyzzy
gcc -o plugh -lxyzzy plugh.o
and plugh.o requires something from the xyzzy library, the second may not work as you expect. At the point where you list the library, there are no unresolved symbols to satisfy.
And when the unresolved symbols from plugh.o do appear, it's too late.
I suppose you have imported math.h with #include <math.h>
So the only other reason I can see is a missing linking information. You must link your code with the -lm option.
If you're simply trying to compile one file with gcc, just add -lm to your command line, otherwise, give some informations about your building process.
Just adding the #include <math.h> in c source file and -lm in Makefile at the end will work for me.
gcc -pthread -o p3 p3.c -lm
Here are my observation, firstly you need to include the header math.h as sqrt() function declared in math.h header file. For e.g
#include <math.h>
secondly, if you read manual page of sqrt you will notice this line Link with -lm.
#include <math.h> /* header file you need to include */
double sqrt(double x); /* prototype of sqrt() function */
Link with -lm. /* Library linking instruction */
But application still says undefined reference to sqrt. Do you see any
problem here?
Compiler error is correct as you haven't linked your program with library lm & linker is unable to find reference of sqrt(), you need to link it explicitly. For e.g
gcc -Wall -Wextra -Werror -pedantic test.c -lm
I had the same issue, but I simply solved it by adding -lm after the command that runs my code.
Example.
gcc code.c -lm

Resources