-1

I have two c files :

  1. myconstructor.c in which there is an implementation of __attribute__ ((constructor)) so that it can execute before main : in this file I have declared a variable a.

  2. main.c in which I try to access variable a : but I get ‘a’ undeclared (first use in this function)

I have created a shared library in which I have included my constructor using LD_PRELOAD.

__attribute__ ((constructor))
void myconstructor(){
    int a=5;
    printf("Hello from the constructor\n");

 int main(){
    printf("try to print a from  the main : %d\n",a);
    return 0;
}
Gerhardh
  • 11,688
  • 4
  • 17
  • 39
N.Omar
  • 29
  • 6
  • 4
    You are missing `extern int a;` in the main.c file? – P.W May 16 '19 at 10:37
  • 1
    It should be `int main(void)` and `void myconstructor(void)` – alx - recommends codidact May 16 '19 at 10:37
  • 1
    Relevant: https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files?rq=1 Others here might even consider your question a duplicate of that one. – Andrew Henle May 16 '19 at 10:38
  • 1
    You probably want a separate header file that defines `extern int a;` that both your source files include. – yyny May 16 '19 at 10:38
  • @AndrewHenle and P.W These questions do not handle variables defined within functions. – Gerhardh May 16 '19 at 10:46
  • I have tried using header file and extern but still the same problem, – N.Omar May 16 '19 at 10:47
  • @YoYoYonnY You mean declarations, not definitions. But this will also not work for variables defined locally. – Gerhardh May 16 '19 at 10:48
  • @N.Omar That's because your `a` variable is a local variable, and doesn't exist outside of the function - and even then, it only exists when the function is running. – Andrew Henle May 16 '19 at 10:48
  • @Gerhardh *These questions do not handle variables defined within functions.* Because there is no way to make a local variable visible. – Andrew Henle May 16 '19 at 10:49
  • My goal is to make the variable visible in main and declared in __attribute__constr. So If I must use header file I did : extern int a; And I have include the header file in both constructor and main but when I change the variable in constructor it does not appear in the main !!!! – N.Omar May 16 '19 at 10:51
  • If so how can do that ? is there any way ? – N.Omar May 16 '19 at 10:52

1 Answers1

2

You can't access local nonstatic variables of a function from another function. Especially not directly and especially if the function whose variables you want to access is finished.

Use a global. (Note that if you want to override a global defined in the main executable, you'll need to compile with -rdynamic).

Executable example:

#!/bin/sh -eu
cat > lib.c <<'EOF'
#include <stdio.h>
int a = 5;
__attribute__ ((constructor))
static void myconstructor(void)
{
    a = 53; //pointless
    //^if the init value is known, you can simply use 
    //static initialization, omitting the constructor

    printf("Hello from the constructor\n");
}
EOF

cat > main.c <<'EOF'
#include <stdio.h>
#if EXTERN
extern int a;
#else
int a = 0;
#endif

int main(void)
{
    printf("try to print a from  the main : %d\n",a);
    return 0;
}
EOF
gcc lib.c -fpic -shared -o liblib.so
gcc -rdynamic  main.c -o inbuilt_overridable #-rdynamic makes the global overridable
gcc -L$PWD -DEXTERN main.c -llib -o nonabsolute_dynamic_lib
gcc -DEXTERN main.c $PWD/liblib.so  -o absolute_dynamic_lib

set -x
echo INBUILT
./inbuilt_overridable
echo ===

echo NON-ABSOLUTE DYNAMIC LIB
#if the lib isn't in standard system locations, you need the LD_LIBRARY_PATH env variable
LD_LIBRARY_PATH=$PWD ./nonabsolute_dynamic_lib
echo ===

echo ABSOLUTE LIB
#I think Cygwin doesn't support this, but Linux definitely does
./absolute_dynamic_lib
echo ===

echo INBUILT OVERRIDDEN
LD_PRELOAD=$PWD/liblib.so ./inbuilt_overridable
echo ===
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • @CacahueteFrito OK – Petr Skocik May 16 '19 at 10:50
  • target.c is main.c . to compile : gcc -g target.c -o target gcc -g -c -Werror -fPIC myconstructor.c gcc -shared -o ourlibrary.so myconstructor.o LD_PRELOAD=$PWD/ourlibrary.so ./target ---- I did really what is suggested but I get this error : undefined reference to `a' collect2: error: ld returned 1 exit status – N.Omar May 16 '19 at 11:01
  • @N.Omar If you don't define a global `a` in the main executable, you'll need to link (at compile time, which isn't really linking, just a check that the lib provides the missing symbols) with `ourlibrary.so` (and then you don't need `LD_PRELOAD`). If you don't want to link with `ourlibrary.so` then your main executable or one of its linked libraries needs to provide a `a` symbol. If the `a` symbol isn't provided by a dynamic library, you'll need to compile with `-rdynamic` for it to be interposable. Example shown in my answer. – Petr Skocik May 16 '19 at 11:07
  • Yes I want to find out if I can do that without defining the variable in the main.c, you suggest by linking at compile time is that right ! So If i have understand I will not use LD_PRELOAD and I have just to compile my main.c with something like this : gcc -L/home/username/mylib -Wall -o test main.c -l(mylib) ? – N.Omar May 16 '19 at 11:13
  • @N.Omar Yes. I have now included that case in the executable example in my answer. Hope it's a little clearer now. (Dynamic linking is quite complex. Can't hope to cover all the edge cases in a SO answer.) – Petr Skocik May 16 '19 at 11:28