How I can Replace main() in already-compiled application? - linux

I need additional initialization over existing in dynamic-linked application.

If you want to hook additional code before running main() in an already-compiled program, you can use a combination of the constructor attribute, and LD_PRELOAD like so:
#include <stdio.h>
void __attribute__((constructor)) init() {
printf("Hello, world!\n");
}
Compile and run:
$ gcc -shared demo_print.c -o demo_print.so -fPIC
$ LD_PRELOAD=$PWD/demo_print.so true
Hello, world!
If you don't want to run normal main() at all, just terminate (with exit() etc) before main() runs. Note that you won't be able to actually get the address of main() to call manually - just return from your constructor to continue normal startup.

If you're writing a shared library that needs specific startup initialisation, you can use the GCC "constructor" extension:
void foo() __attribute__ ((constructor))

Related

How to pass customized arguments from Makefile to Rust codes in Cargo?

Now I have a project managed by Makefile. That is, make run is the entry for the project. Rust codes, managed by Cargo, is a part of my project.
What I want to achieve is to pass some arguments from Makefile to Rust codes.
I know how to achieve this in C:
$ gcc --help | grep -- -D
-D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
So, I can just pass arguments from make run MYARGUMENT=xxx and in Makefile pass $(MYARGUMENT) to gcc.
How to achieve it if I want to pass MYARGUMENT to command cargo run?
Or, I kind of want a feature like this -- to disable some statements in Rust codes, which could be controlled from Makefile:
#ifdef XXX
printf("XXX is define!\n");
#endif
Using gcc, you can use -D to specify a predefined macro and then use preprofessor directives to compile some code conditionally as below:
int main(void)
{
#if defined(DEBUG_)
printf("Debug mode\n");
#endif
}
And pass -D to tell gcc a predefined macro: gcc -DDEBUG.
Using rustc, you can use cfg equivalently:
fn main() {
#[cfg(DEBUG)]
{
println!("Debug mode");
}
}
Then run rustc --cfg 'DEBUG' and you get the same result as gcc.
If you want to use cargo instead of use rustc directly, you can see this question: How do I use conditional compilation with cfg and Cargo?

Will libraries loaded with LD_PRELOAD be unload in the last

I am writing a memory leak tracker, and want to print the statistics messages in the tracked program at the time the library unloading.
This library will be used with the LD_PRELOAD trick, our programs have static variables that will be destroyed very late, so I want to be assured that the statistics messages will be printed after all the static variables in the program have been destroyed to avoid false alarm.
Will libraries loaded with LD_PRELOAD be unload in the last (Later than the hacked programs)?
Will libraries loaded with LD_PRELOAD be unload in the last
You are assuming that LD_PRELOADED library will be unloaded, but there is no guarantee that this will happen at all.
Here is a test case:
// main.c
#include <unistd.h>
int main(int argc, char *argv[]) {
if (argc > 1) _exit(0);
return 0;
}
// preload.c
#include <stdio.h>
__attribute__((constructor)) void init() { fprintf(stderr, "Init\n"); }
__attribute__((destructor)) void fini() { fprintf(stderr, "Fini\n"); }
Build them like so:
gcc main.c && gcc -fPIC -shared -o preload.so preload.c
Now observe the order of initialization and finalization:
LD_DEBUG=files LD_PRELOAD=./preload.so ./a.out |& grep 'calling .*ini'
18310: calling init: /lib/x86_64-linux-gnu/libc.so.6
18310: calling init: ./preload.so
18310: calling fini: ./a.out [0]
18310: calling fini: ./preload.so [0]
LD_DEBUG=files LD_PRELOAD=./preload.so ./a.out 1 |& grep 'calling .*ini'
18312: calling init: /lib/x86_64-linux-gnu/libc.so.6
18312: calling init: ./preload.so
Notice that in the case of _exit() the library is not finalized at all.
Also notice that any shared library will have a dependency on libc.so.6, and thus will be finalized before libc.so.6.
But absent signal or _exit() termination, yes: the libraries will be finalized in reverse order of their initialization (loading and unloading aren't really the right terms to use here), and that does mean that LD_PRELOADed libraries will be finalized last.

Why does dynamically loading of PIEs no longer work in glibc? [duplicate]

There is a large number of questions on SO about how to execute a library or dynamically load an executable. As far as I can tell, all the answers come down to: compile your executable as position-independent code and load it with dlopen. This worked great --- and still works great on macOS --- until a recent change in glibc, which explicitly disabled dlopening PIEs. This change is now in the current version of glibc (2.30) on ArchLinux, for example, and trying to dlopen a position-independent executable gives an error: "cannot dynamically load position-independent executable".
It's difficult to guess what prompted such a radical change that breaks so much code and useful use cases. (The explanations on Patchwork and Bugzilla don't make much sense to me.) But there is now a question: what to do if you want to create an executable that's also a dynamic library, or vice versa?
A solution was linked from one of the comments. Reproducing it here for posterity:
#include <stdio.h>
#include <unistd.h>
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux-x86-64.so.2";
extern "C" {
void lib_entry(void)
{
printf("Entry point of the service library\n");
_exit(0);
}
}
Compiling with g++ -shared test-no-pie.cpp -o test-no-pie -Wl,-e,lib_entry produces a shared object (dynamic library) that can also be executed on Linux.
I have two questions:
What if I want to pass command-line arguments? How to modify this solution so it accepts arc,argv?
Are there other alternatives?
It's difficult to guess what prompted such a radical change
Not really: it never worked correctly.
that breaks so much code
That code was broken already in subtle ways. Now you get a clear indication that it will not work.
Are there other alternatives?
Don't do that?
What problem does dlopening an executable solve?
If it's a real problem, open a GLIBC bugzilla feature request, explaining that problem and requesting a supported mechanism to achieve desired result.
Update:
at least say why "it never worked correctly". Is it some triviality like potentially clashing globals between the executables, or something real?
Thread-local variables is an example that doesn't work correctly. Whether you think they are "real" or not I have no idea.
Here is the code:
// foo.c
#include <stdio.h>
__thread int var;
__attribute__((constructor))
static void init()
{
var = 42;
printf("foo.c init: %d %p\n", var, &var);
}
int bar() {
printf("foo.c bar: %d %p\n", var, &var);
return var;
}
int main()
{
printf("foo.c main: %d %p bar()=%d\n", var, &var, bar());
return 0;
}
gcc -g foo.c -o foo -Wl,-E -fpie -pie && ./foo
foo.c init: 42 0x7fb5dfd7d4fc
foo.c bar: 42 0x7fb5dfd7d4fc
foo.c main: 42 0x7fb5dfd7d4fc bar()=42
// main.c
// Error checking omitted for brevity
#include <dlfcn.h>
#include <stdio.h>
int main()
{
void *h1 = dlopen("./foo", RTLD_LOCAL|RTLD_LAZY);
int (*bar)(void) = dlsym(h1, "bar");
printf("main.c: %d\n", bar());
return 0;
}
gcc -g main.c -ldl && ./a.out
foo.c init: 42 0x7fb7305da73c
foo.c bar: 0 0x7fb7305da73c <<< what?
main.c: 0 <<< what?
This is using GNU C Library (Debian GLIBC 2.28-10) stable release version 2.28.
Bottom line: this was never designed to work, and you just happened to not step on many of the land-mines, so you thought it is working, when in fact you were exercising undefined behavior.
Please see this answer:
https://stackoverflow.com/a/68339111/14760867
The argc, argv question is not answered there, but when I found I needed one, I hacked something together to parse /proc/self/cmdline at runtime for pam_cap.so use.

Loading executable or executing a library

There is a large number of questions on SO about how to execute a library or dynamically load an executable. As far as I can tell, all the answers come down to: compile your executable as position-independent code and load it with dlopen. This worked great --- and still works great on macOS --- until a recent change in glibc, which explicitly disabled dlopening PIEs. This change is now in the current version of glibc (2.30) on ArchLinux, for example, and trying to dlopen a position-independent executable gives an error: "cannot dynamically load position-independent executable".
It's difficult to guess what prompted such a radical change that breaks so much code and useful use cases. (The explanations on Patchwork and Bugzilla don't make much sense to me.) But there is now a question: what to do if you want to create an executable that's also a dynamic library, or vice versa?
A solution was linked from one of the comments. Reproducing it here for posterity:
#include <stdio.h>
#include <unistd.h>
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux-x86-64.so.2";
extern "C" {
void lib_entry(void)
{
printf("Entry point of the service library\n");
_exit(0);
}
}
Compiling with g++ -shared test-no-pie.cpp -o test-no-pie -Wl,-e,lib_entry produces a shared object (dynamic library) that can also be executed on Linux.
I have two questions:
What if I want to pass command-line arguments? How to modify this solution so it accepts arc,argv?
Are there other alternatives?
It's difficult to guess what prompted such a radical change
Not really: it never worked correctly.
that breaks so much code
That code was broken already in subtle ways. Now you get a clear indication that it will not work.
Are there other alternatives?
Don't do that?
What problem does dlopening an executable solve?
If it's a real problem, open a GLIBC bugzilla feature request, explaining that problem and requesting a supported mechanism to achieve desired result.
Update:
at least say why "it never worked correctly". Is it some triviality like potentially clashing globals between the executables, or something real?
Thread-local variables is an example that doesn't work correctly. Whether you think they are "real" or not I have no idea.
Here is the code:
// foo.c
#include <stdio.h>
__thread int var;
__attribute__((constructor))
static void init()
{
var = 42;
printf("foo.c init: %d %p\n", var, &var);
}
int bar() {
printf("foo.c bar: %d %p\n", var, &var);
return var;
}
int main()
{
printf("foo.c main: %d %p bar()=%d\n", var, &var, bar());
return 0;
}
gcc -g foo.c -o foo -Wl,-E -fpie -pie && ./foo
foo.c init: 42 0x7fb5dfd7d4fc
foo.c bar: 42 0x7fb5dfd7d4fc
foo.c main: 42 0x7fb5dfd7d4fc bar()=42
// main.c
// Error checking omitted for brevity
#include <dlfcn.h>
#include <stdio.h>
int main()
{
void *h1 = dlopen("./foo", RTLD_LOCAL|RTLD_LAZY);
int (*bar)(void) = dlsym(h1, "bar");
printf("main.c: %d\n", bar());
return 0;
}
gcc -g main.c -ldl && ./a.out
foo.c init: 42 0x7fb7305da73c
foo.c bar: 0 0x7fb7305da73c <<< what?
main.c: 0 <<< what?
This is using GNU C Library (Debian GLIBC 2.28-10) stable release version 2.28.
Bottom line: this was never designed to work, and you just happened to not step on many of the land-mines, so you thought it is working, when in fact you were exercising undefined behavior.
Please see this answer:
https://stackoverflow.com/a/68339111/14760867
The argc, argv question is not answered there, but when I found I needed one, I hacked something together to parse /proc/self/cmdline at runtime for pam_cap.so use.

playing around with LD_LIBRARY_PATH

I read this article recently, and I tried overriding the libc printf function with a doing the following for fun :-
Create an executable that uses printf to print this is a test(printer.c)
Create an c file with a custom puts to print muhahaha, this is a test(custom.c)
Create an object file gcc -fPIC -g -c -Wall custom.c
Create an so file gcc -shared -Wl,-soname,libmystuff.so.1 -o libmystuff.so.1.0.1 custom.o
I add the directory which contains the so file into the LD_PRELOAD environment variable. export LD_PRELOAD=$(pwd)
Try running printer
I'd imagine that muhahaha, this is a test would be printed out but it seems like im doing something wrong. Have I got some concept wrong? Or am I just doing something wrong?
[EDIT]
The code snippets involved are :-
// printer.c
int main() {
printf("this is a test");
return 0;
}
// custom.c
void printf(char *t) {
puts("muhahaha, this is a test");
}
You're supposed to name the library in the LD_PRELOAD environment variable, not the directory.
export LD_PRELOAD=/path/to/libmystuff.so.1.0.1

Resources