Linuxにおける環境変数
dive into the environment
drumatoと飯食ってる時に「環境変数ってどうなってんだ?」となったので、調べた。
とりあえずプロセスに付随する情報なので、task_struct
を読んでみるもそれっぽい情報はなし。
environment variables
でgrepしてみると、mm_struct
の方に
unsigned long arg_start, arg_end, env_start, env_end;
とあるのを見つけた。確かにGDBで見るとスタックにあるし、main
の引数もargc, argv, envp
だな。
それを裏付けるように、fs/proc/base.c
のenviron_read
static ssize_t environ_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
char *page;
unsigned long src = *ppos;
int ret = 0;
struct mm_struct *mm = file->private_data;
unsigned long env_start, env_end;
/* Ensure the process spawned far enough to have an environment. */
if (!mm || !mm->env_end)
return 0;
page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
ret = 0;
if (!mmget_not_zero(mm))
goto free;
spin_lock(&mm->arg_lock);
env_start = mm->env_start;
env_end = mm->env_end;
spin_unlock(&mm->arg_lock);
while (count > 0) {
size_t this_len, max_len;
int retval;
if (src >= (env_end - env_start))
break;
this_len = env_end - (env_start + src);
max_len = min_t(size_t, PAGE_SIZE, count);
this_len = min(max_len, this_len);
retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON);
if (retval <= 0) {
ret = retval;
break;
}
if (copy_to_user(buf, page, retval)) {
ret = -EFAULT;
break;
}
ret += retval;
src += retval;
buf += retval;
count -= retval;
}
*ppos = src;
mmput(mm);
free:
free_page((unsigned long) page);
return ret;
}
って感じでmm_struct
のenv_start
とenv_end
を使っている。
という訳で環境変数はユーザ空間にあることがわかった。
getenv
の実装も気になったので読んでみると
char *
getenv (const char *name)
{
size_t len = strlen (name);
char **ep;
uint16_t name_start;
if (__environ == NULL || name[0] == '\0')
return NULL;
...
みたいな感じで__environ
を参照している。その__environ
は
/* This file just defines the `__environ' variable (and alias `environ'). */
#include <unistd.h>
#include <stddef.h>
/* This must be initialized; we cannot have a weak alias into bss. */
char **__environ = NULL;
てな感じで定義されており、じゃあどこで初期化されるのか?というと__libc_start_main
の中にある
STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char **argv,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
ElfW(auxv_t) *auxvec,
#endif
__typeof (main) init,
void (*fini) (void),
void (*rtld_fini) (void), void *stack_end)
{
/* Result of the 'main' function. */
int result;
__libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
#ifndef SHARED
_dl_relocate_static_pie ();
char **ev = &argv[argc + 1];
__environ = ev;
よく考えたらexecve
の引数もconst char *filename, char *const argv[], char *const envp[]
だもんな
なるほどね〜
Comments