Use LD_PRELOAD to load shared objects with the initfirst flag. Calling the getenv() function from a function with __attribute__((constructor)) returns NULL. I think this is probably because the function is being called before someone (libc?) initializes __environ.
// foo.c
#include <stdio.h>
#include <stdlib.h>
void setup(void) __attribute__((constructor));
void
setup(void)
{
fprintf(stderr, "FOO=\"%s\"\n", getenv("FOO"));
}
$ cc -o foo.so -fPIC -shared foo.c -Wl,-z,initfirst
$ LD_PRELOAD=./foo.so FOO=123 ./hello
FOO="(null)"
Removing the initfirst flag produced the expected result.
Questions:
- Is there a way to read environment variables under these conditions? (It's fine if it only works on Linux, amd64, gcc, and glibc)
- Who initializes
__environ? The loader, libc, crt0, or the kernel?
Environment: Ubuntu 24.04.1 LTS, amd64, gcc 13.3.0, glibc 2.39
__libc_start_maininitializes it (some interesting comments in github.com/bminor/glibc/blob/glibc-2.39/sysdeps/x86_64/start.S).int main(int argc, char *argv[], char *env[])?