1

I have recently learned the LD_PRELOAD trick (What is the LD_PRELOAD trick?), which can be used to debug or patch the program.

I wanted to see if I could combine this trick and GCC destructor (https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html) to debug a variable, and created an extremely simple case to hone my understanding.

I have test.c as provided below:

#include <stdio.h>
int a = 1;
void __attribute__((destructor)) run_last() {
    printf("Destructor: %d\n", a);
}

and test_2.c as provided below:

#include <stdio.h>
#include "test.c"

int main()
{
    extern int a;
    printf("main: %d\n", a++);
}

I compile test.c using the command gcc -Wall -O3 -fPIC -shared test.c -o test.so to generate the shared object, and compile test_2.c using the command gcc test_2.c -o test_2

Now, what I'm hoping to see is an output of:

main: 1
Destructor: 2

The reason for this expectation is because I have post-incremented the variable a after I printed the statement, and as I am using extern int a, as far as I understand, I am incrementing the variable a that was declared in the test_2.c, which contains the destructor function run_last() that will use the most updated value of a.

However, instead, I get an output such as this: enter image description here

Why is there a Destructor: 1 here? From my understanding, shouldn't the destructor only be called once? My guess at the moment is that when I #include "test.c" in the test_2.c, there is a behavior that I don't understand at the moment.

Thank you for any suggestions or guidance,

Jay
  • 373
  • 1
  • 10
  • It's probably coming from some other program being invoked after your test program. Can you clarify exactly how you ran the test, whether you exported `LD_PRELOAD` explicitly or just by setting it at the beginning of the command? The screenshot is not clear, especially the odd bold-cyan `LD_PRELOAD` at the beginning of the line. – R.. GitHub STOP HELPING ICE Mar 16 '21 at 02:53
  • Thank you for your response @R..GitHubSTOPHELPINGICE Here is the exact step of how it has been done: 1. restart the computer 2. open the terminal 3. run `LD_PRELOAD=./test.so ./test_2` Sorry for the confusion with the bold-cyan `LD_PRELOAD`, that is my directory name which I am using zsh to keep me on track of what directory I'm currently in. So the above output can be understood as the same as `$ LD_PRELOAD=./test.so ./test_2` – Jay Mar 16 '21 at 15:19
  • 2
    You have two `a` variables, one of them got incremented, both got printed. One instance of the variable and function comes from `#include "test.c"`, the other one from the preload. –  Mar 16 '21 at 15:58
  • @dratenik Ah so as I thought, it was indeed because of the statement `#include "test.c"`. I suppose I need to do some reverse engineering to find something in more detail because I didn't know that doing #include "*.c" creates another instance of process. Thank you for your response – Jay Mar 16 '21 at 17:42
  • 2
    `#include` is a pure text operation, it will insert the contents of test.c at that location, the compiler will then compile them as if they were also part of test_2.c. –  Mar 16 '21 at 17:49
  • @dratenik Thank you very much! – Jay Mar 16 '21 at 18:45

0 Answers0