3

This may be a dumb question, as I feel like I must be overlooking something fairly obvious, but how do functions like getenv(3) access the environment when my program doesn't have any references to the environment?

  • I was about to tell you "system call", but then I looked it up and found this: stackoverflow.com/questions/46623018/… – Philip Couling Jan 26 at 22:55
  • @couling that stackoverflow answer is wrong; the 3rd argument to main(), (unlike the environ global sym) is non-standard – mosvy Jan 26 at 23:36
  • @mosvy careful with the phrase "non-standard". There are many standards, maybe specify which standards it's not defined in? – Philip Couling Jan 26 at 23:47
  • @couling POSIX (extra junk here for the stupid min length) – mosvy Jan 26 at 23:50
  • @mosvy now that I read your other comments and re-read the answer it's NOT wrong. Of course, main is just something invented by your compiler's runtime support libraries. As far as the OS is concerned, the interface is somewhat different. The same principle still stands, however. The environment is passed to the newly created program after execve on its stack. – Philip Couling Jan 27 at 1:05
10

Your program doesn't have a reference to the environment, but a whole copy of it.

The command line arguments and environment strings (as they were passed to the execve(2) system call) are all packed together and copied in the address space of the process [1].

In a typical implementation [2], two NULL-terminated lists of pointers to them (representing the argument lists and the environment) are made available on the stack to the entry point of the program (_start), where the startup code (run before main()) will point the char **environ global variable to the beginning of the latter.

The getenv(3) function is simply looking through that environ list and comparing each entry in turn.

When some new entry has to be added to the environment (as with setenv(3)), the environ list will be relocated elsewhere.

[1] On linux, the addresses of the argument list and environment variables are accessible as the 48th and 50th fields of /proc/PID/stat, see procfs(5).

[2] In glibc, _start will pop argc, point argv to the top of the stack, and __libc_start_main will set __environ (an alias for environ) to argv + argc + 1.

  • Could you be clearer with this on this point: by "known location" do you mean static memory address? If not, how does the OS tell the C library (or similar) what this address is? – Philip Couling Jan 26 at 23:51
  • On linux at least, they're put at the end of stack, so they're accessible via registers in the program's entry point (_start). You can get the actual addresses from 48th-51th fields (argv_start-env_end) from the /proc/PID/stat file, see procfs(5). – mosvy Jan 27 at 0:41
  • Could you edit your answer to include this. Putting a pointer on the stack prior to starting the program is substantially different to a "known location". – Philip Couling Jan 27 at 1:01
  • I'd appreciate you could consider unix.stackexchange.com/questions/498425/… – Tim Feb 3 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.