LD_PRELOAD and weak references minimal example doesn't work - c

This is probably going to be embarrassing:
I am using library prelaoding in other projects, but I cannot get this minimal example to work:
weakref.h:
void f_weak() __attribute__((weak));
weakref.c:
#include <stdio.h>
#include "weakref.h"
void f_weak(){
printf("f_weak()\n");
fflush(stdout);
}
test_weakref.c:
#include <stdio.h>
#include "weakref.h"
int main(void)
{
if (f_weak) {
printf("main: f_weak()\n");
}
else {
printf("main: ---\n");
}
fflush(stdout);
return 0;
}
Here is what I do:
$ gcc weakref.c -shared -fPIC -o libweakref.so
$ nm libweakref.so | grep f_weak
0000000000000708 W f_weak
$ gcc test_weakref.c -o test_weakref
$ ./test_weakref
main: ---
$ LD_PRELOAD=./libweakref.so ./test_weakref
main: ---
The expected output of the last command is
main: f_weak()
What am I missing?

As far as I know, external functions are resolved only when you call them. So, your test if (f_weak) will always fail. If you do it the following way, you can see that it works:
weakref.c:
#include <stdio.h>
#include "weakref.h"
void f_weak(){
printf("original\n");
fflush(stdout);
}
weak2.c:
#include <stdio.h>
#include "weakref.h"
void f_weak(){
printf("overridden\n");
fflush(stdout);
}
test_weakref.c:
#include <stdio.h>
#include "weakref.h"
int main(void)
{
f_weak();
fflush(stdout);
return 0;
}
and then:
tmp> gcc weakref.c -shared -fPIC -o libweakref.so
tmp> gcc weak2.c -shared -fPIC -o libweak2.so
tmp> gcc -o test_weakref test_weakref.c ./libweakref.so
tmp> ./test_weakref
original
tmp> LD_PRELOAD=./libweak2.so !.
LD_PRELOAD=./libweak2.so ./test_weakref
overridden

I found the solution in an old Makefile: the program has also to be compiled with the -fPIC flag.
$ gcc weakref.c -shared -fPIC -o libweakref.so
$ nm libweakref.so | grep f_weak
0000000000000708 W f_weak
$ gcc test_weakref.c -o test_weakref -fPIC
$ ./test_weakref
main: ---
$ LD_PRELOAD=./libweakref.so ./test_weakref
main: f_weak()

Related

How to execute a certain part using makefile in C (LINUX)

I am developing a C program that calls 2 functions, func1() and func2().
Here is the code
void func1(void){/*...*/}
void func2(void){/*...*/}
int main(){
func1();
func2();
return 0;
}
Is there a way that when I compile the program using make and a certain flag, it just executes func1() and if I compile using another flag then it only executes func2()?
How to make such a makefile? Can anyone provide me with a makefile that does this job?
You can use the -D flag of the compiler:
cc -o demo demo.c -Dfunc=func1
then
#include <stdio.h>
void func1(void) { puts("1"); }
void func2(void) { puts("2"); }
int main(void)
{
func();
return 0;
}
Output:
1
You can also pass the function as an argument to make:
CC = gcc
CFLAGS = -std=c11 -Wpedantic -Wall
action: demo.c
$(CC) $(CFLAGS) demo.c -o demo -Dfunc=$(argument)
clean:
rm -f demo
call make using:
make action argument=func1
or
make action argument=func2
But if you really want to do that:
int main(){
func1();
func2();
call both functions inside main, you should use another approach (although this solution seems quite sticky to me):
#include <stdio.h>
void func0(void) { /* do nothing */ }
void func1(void) { puts("1"); }
void func2(void) { puts("2"); }
#ifdef delete_func1
#define func1 func0
#endif
#ifdef delete_func2
#define func2 func0
#endif
int main(void)
{
func1();
func2();
return 0;
}
compile using:
cc -o demo demo.c -Ddelete_func1
or
cc -o demo demo.c -Ddelete_func2
then the Makefile should look like:
CC = gcc
CFLAGS = -std=c11 -Wpedantic -Wall
func1: demo.c
$(CC) $(CFLAGS) demo.c -o demo -Ddelete_func2
func2: demo.c
$(CC) $(CFLAGS) demo.c -o demo -Ddelete_func1
clean:
rm -f demo
call it using:
make func1
or
make func2
you can delete both functions using -D twice:
cc -o demo demo.c -Ddelete_func1 -Ddelete_func2

Linking extern variables using multiple library in C

In my project, I have two libraries and one program.
Lib1.c and Lib1.h are two files of first library(Lib1.so).
Lib2.c and Lib2.h are two files of second library(Lib2.so).
prog.c is the main file of program(prog).
The program(prog) is linked only to the second library(Lib2.so) and the second library(Lib2.so) is linked to the first library(Lib1.so).
In Lib1.c, I have a declaration of global variable (int var = 0;) and in Lib1.h, I have a declaration (extern int var;).
In Lib2.h, I have a declaration (extern int var;) in order to use var variable in main program.
In main() function, I include the Lib2.h in prog.c file and I have a declaration (var = 5;)
Lib1.c :
#include <stdio.h>
#include "Lib1.h"
int var = 0;
int funct(void)
{
printf("hello world \n");
return 0;
}
Lib1.h :
extern int var;
int funct(void);
Lib2.c :
#include <stdio.h>
#include "Lib2.h"
int funct2(void)
{
printf("Library 2 \n");
funct();
return 0;
}
Lib2.h :
#include "Lib1.h"
extern int var;
int funct2(void);
prog.c :
#include <stdio.h>
#include "Lib2.h"
int main()
{
var = 5;
printf("===>var=%d\n", var);
funct2();
return 1;
}
Commands :
gcc -c -Wall -Werror -fpic Lib1.c
gcc -shared -o Lib1.so Lib1.o
gcc -c -Wall -Werror -fpic Lib2.c
gcc -shared -o Lib2.so Lib2.o -ldl /home/test/Lib1.so
gcc prog.c -o prog -ldl /home/test/Lib2.so
When I try to compile the program(prog.c), I get an error in the link step as below.
/usr/bin/ld: /tmp/ccKaq16a.o: undefined reference to symbol 'var'
/home/test/Lib1.so: error adding symbols: DSO missing from command line
Is there a way to use var variable in the main function when its defined in the first library?
You link your program against Lib2 but not Lib1. You need to add that as well. You also don't need to explicitly link Lib1 when you create Lib2
gcc -c -Wall -Werror -fpic Lib1.c
gcc -shared -o Lib1.so Lib1.o
gcc -c -Wall -Werror -fpic Lib2.c
gcc -shared -o Lib2.so Lib2.o
gcc prog.c -o prog /home/test/Lib2.so /home/test/Lib1.so

backtrace function only got the last frame

I want to call backtrace function to get the callchain, the following is my code, this code works good on x86, but can't work on mips
gcc -o hello-x86 hello.c -g -rdynamic -O0 -Wall
./hello-x86
size = 6
0x40095c : ./hello-x86(foo+0x1f) [0x40095c]
0x400a2d : ./hello-x86(b+0x9) [0x400a2d]
0x400a38 : ./hello-x86(a+0x9) [0x400a38]
0x400a4e : ./hello-x86(main+0x14) [0x400a4e]
0x7fee0d003f45 : /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fee0d003f45]
0x400879 : ./hello-x86() [0x400879]
but on mips, just only got the last frame, how to fix it ?
mips-linux-gnu-gcc -o hello hello.c -g -rdynamic -O0 -Wall -msoft-float -EL
./hello
size = 1
0x400a04 : ./hello(foo+0x24) [0x400a04]
can't get b and a and main. but i can got full callchain in gdb, why can't got it via backtrace function ?
my toolchain is codesourcery mips-2016.05, the libc version is 2.23
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <execinfo.h>
#define BACKTRACE_SIZ 100
int i = 0;
void foo(void)
{
void *array[BACKTRACE_SIZ];
size_t size, i;
char **strings;
size = backtrace(array, BACKTRACE_SIZ);
strings = backtrace_symbols(array, size);
printf("size = %ld\n", (long)size);
for (i = 0; i < size; ++i) {
printf("%p : %s\n", array[i], strings[i]);
}
free(strings);
while (1) {
i++;
}
}
void b(void)
{
foo();
}
void a(void)
{
b();
}
int main(int argc, char **argv)
{
a();
return 0;
}
i tried -fno-omit-frame-pointer and -fomit-frame-pointer, these two option all can't work.
mips-linux-gnu-gcc -o hello hello.c -g -rdynamic -O0 -Wall -msoft-float -EL -fomit-frame-pointer
mips-linux-gnu-gcc -o hello hello.c -g -rdynamic -O0 -Wall -msoft-float -EL -fno-omit-frame-pointer
and i tried on my arm board, it worse, the size is 0 on arm

Undefined reference to 'readline' - C

The error I'm getting:
undefined reference to `readline'
Here is my makefile:
all: stest stestdebug
stest: stest.o struct.o
gcc -g stest.o struct.o -lreadline -lncurses -o stest
stest.o: stest.c struct.h
gcc -g -c stest.c
stestdebug: stestdebug.o struct.o
gcc -g stestdebug.o struct.o -o stestdebug
stestdebug.o: stest.c struct.h
gcc -g -c stest.c -o stestdebug.o
struct.o: struct.c struct.h
gcc -g -c -DDEBUG struct.c
clean:
rm -f *.o stest stestdebug
docs:
doxygen
chmod a+r html/*
cp -p html/* ~/public_html/cs2303assig4
I've already imported all the necessary libraries for readline but am still getting this error.
Here is the code where I call it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "struct.h"
void requestInput() {
printf("Please fill out all prompts to create a new emplyoee.\n");
char *name = readline("Name:");
}
You are not linking to them in your main executable.
Put your libraries in a variable, and use them both in your test target and the normal target.
Have a look into LDFLAGS.

undefined reference to `test' when linking shared object

I'm studying a tutorial how to link shared objects in C
Here's my make file
test: glenn.c libhala.so
gcc glenn.c -L. -o test
libhala.so: hala.o
gcc -shared hala.o -o libhala.so
hala.o: hala.c hala.h
gcc -c -Wall -Werror -fpic hala.c
clean:
rm *.o
rm *.so
rm test
hala.h
#ifndef HALA
#define HALA
extern void test(char*);
#endif
hala.c
#include "hala.h"
#include <stdio.h>
extern void test(char* s)
{
printf("%s", s);
}
glenn.c
#include <stdio.h>
#include "hala.h"
int main()
{
test("Hello There!");
return 0;
}
This stocks me up. Help me please..
You should add -lhaha when you link glenn.c.
gcc glenn.c -L. -lhala -o test
Add -lhala while compiling glenn.c, so update makefile as
test: glenn.c libhala.so
gcc glenn.c -L. -lhala -o test

Resources