1.linux内核情景分析之execve的实现
2.通过do_execve源码分析程序的执行(上)(基于linux0.11)
3.å¦ä½ä½¿ç¨linux commands step by step
4.Linux 可执行文件程序载入和执行过程
linux内核情景分析之execve的实现
Linux内核中的execve函数实现涉及到用户态CPU寄存器在内核栈中的保存和系统调用的细节。首先,理解sys_execve源码中的do_execve函数至关重要。它涉及到一个名为linux_bin_fmt的结构,该结构存储了内核对各种可执行程序格式的支持信息,包括加载和执行函数,tensorflow彩票源码以及保存文件路径、参数和环境变量的linux_bin_prm结构。
do_execve的实现从读取可执行文件的头部字节开始,通过prepare_binprm函数,将文件头部数据放入bprm->buf缓存。内核通过search_binary_handler遍历formats队列,识别文件的正确格式并调用相应的处理函数,如load_aout_binary处理a.out格式。
在load_aout_binary中,muilib 源码如遇到/bin/echo,会调用flush_old_exec,涉及信号处理函数指针复制、内存空间处理(包括信号处理模式、用户空间的清理)和文件关闭等。其中,make_private_signal和exec_mmap函数分别处理信号处理和内存映射,根据close_on_exec位图关闭相关文件。
在载入新程序时,内核会复制可执行文件路径到内核空间,然后查找并打开文件,读取前字节初始化数据结构。接下来,通过formats队列的handvu 源码遍历,找到合适的代理加载器(如a.out的load_aout_binary)来执行后续的加载和初始化操作,如设置信号处理、用户空间和文件资源等。
最终,新进程会通过各个代理加载器的定制化空间申请和参数映射,调用start_thread启动进程。尽管描述了大致流程,但实际执行中涉及许多细节问题,如线程隔离、用户空间计数处理等,需要深入内核代码才能详细了解。
通过do_execve源码分析程序的执行(上)(基于linux0.)
execve函数是操作系统的关键功能,它允许程序转变为进程。本文通过剖析do_execve源码,realoa 源码揭示程序转变成进程的机制。do_execve被视为系统调用,其运行过程在前文已有详细解析,此处不再赘述。分析将从sys_execve函数开启。
在执行_do_execve前,先审视内核栈。接下来,我们将深入理解do_execve的实现。
在加载可执行文件时,存在两种情况:编译后的二进制文件与脚本文件。脚本文件需加载对应解释器,本文仅探讨编译后的二进制文件。解析流程如下:首先验证文件可执行性和当前进程权限,servicestack 源码通过后,仅加载头部数据,具体代码在真正运行时通过缺页中断加载。然后,申请物理内存并存储环境变量和参数,该步骤在copy_string函数中实现。
完成上述步骤后,内核栈结构发生变化。接着,执行代码释放原进程页目录和页表项信息,解除物理地址映射,这些信息通过fork继承。随后,调用change_ldt函数设置代码段、数据段基地址和限长,其中数据段限长为MB,代码段限长根据执行文件头部信息确定。完成物理地址映射后,内存布局随之调整。
紧接着,通过create_tables函数分配执行环境变量和参数的数组。执行完毕后,内存布局进一步调整。最后,设置栈、堆位置,以及eip为执行文件头部指定值,esp为当前栈位置,至此,可执行文件加载阶段完成。下文将探讨执行第一条指令后的后续步骤。
å¦ä½ä½¿ç¨linux commands step by step
æç§ä¹¦éçLinux代ç ä¾åé½å·²ä½å¤ï¼æ以çå°ç代ç ä¸è½å½çï¼é¢ä¼ææå°±è¡äº
æ¯å¦ä»¥åçinitè¿ç¨çå¯å¨ä»£ç
execve(init_filename,argv_init,envp_init);
ç°å¨æ¹ä¸º
static void run_init_process(char *init_filename)
{
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init);
}
好çï¼èªæ人就åç°ï¼linuxå æ ¸ä¸è°ç¨ç¨æ·ç©ºé´çç¨åºå¯ä»¥ä½¿ç¨initè¿æ ·çæ¹å¼ï¼è°ç¨ kernel_execve
ä¸è¿å æ ¸è¿æ¯æä¾äºæ´å¥½çè¾ å©æ¥å£call_usermodehelperï¼èªç¶æåä¹æ¯è°ç¨kernel_execve
è°ç¨ç¹å®çå æ ¸å½æ°ï¼ç³»ç»è°ç¨ï¼æ¯ GNU/Linux ä¸è½¯ä»¶å¼åçåæ¬å°±æçç»æé¨åãä½å¦ææ¹ååè¿æ¥å¢ï¼å æ ¸ç©ºé´è°ç¨ç¨æ·ç©ºé´ï¼ç¡®å®æä¸äºæè¿ç§ç¹æ§çåºç¨ç¨åºéè¦æ¯å¤©ä½¿ç¨ãä¾å¦ï¼å½å æ ¸æ¾å°ä¸ä¸ªè®¾å¤ï¼è¿æ¶éè¦å è½½æ个模åï¼è¿ç¨å¦ä½å¤çï¼å¨æ模åå è½½å¨å æ ¸éè¿ usermode-helper è¿ç¨è¿è¡ã
让æ们ä»æ¢ç´¢ usermode-helper åºç¨ç¨åºç¼ç¨æ¥å£ï¼APIï¼ä»¥åå¨å æ ¸ä¸ä½¿ç¨çä¾åå¼å§ã ç¶åï¼ä½¿ç¨ API æé ä¸ä¸ªç¤ºä¾åºç¨ç¨åºï¼ä»¥ä¾¿æ´å¥½å°çè§£å ¶å·¥ä½åçä¸å±éã
usermode-helper API
usermode-helper API æ¯ä¸ªå¾ç®åç APIï¼å ¶é项为ç¨æ·çç¥ãä¾å¦ï¼è¦å建ä¸ä¸ªç¨æ·ç©ºé´è¿ç¨ï¼é常åªè¦è®¾ç½®å称为 executableï¼é项é½ä¸º executableï¼ä»¥åä¸ç»ç¯å¢åéï¼æå execve 主页ï¼ãå建å æ ¸è¿ç¨ä¹æ¯ä¸æ ·ãä½ç±äºå建å æ ¸ç©ºé´è¿ç¨ï¼è¿éè¦è®¾ç½®ä¸äºé¢å¤é项ã
Linux 可执行文件程序载入和执行过程
在 Linux 系统中,可执行文件的加载和执行过程涉及到 ELF(Executable and Linking Format)格式。当你在终端输入命令执行一个可执行程序时,bash 程序首先通过 fork() 创建一个新的进程,然后新进程通过 execve() 系统调用来启动指定程序。
execve() 函数原型如下:它接收程序文件名、参数和环境变量作为输入。进入内核后,调用 sys_execve(),接着是 do_execve(),这里会根据 ELF 文件构建一个 linux_binprm 内核结构,存储文件信息,并根据文件类型决定执行方式。load_elf_binary 是关键接口,它主要负责初始化这个结构并处理加载过程。
结构中,`linux_binprm` 包含了文件路径、参数数组、文件属性等信息,其中参数是按栈方式存放的。在 load_elf_binary 中,首先验证 ELF 文件的标识,确认其类型和机器架构,接着读取程序头部信息,包括动态链接器路径。如果文件需要动态链接,会加载并处理解释器(动态链接器)。
然后,它会清除父进程相关代码,设置内存映射,如环境变量、堆栈地址等,并将执行入口设置为 ELF 文件的 e_entry。最后,调用 start_thread() 函数将 CPU 的 EIP(指令指针)和 ESP(堆栈指针)设置为新的地址,使得系统从内核态返回时,CPU会直接进入新程序的入口地址,完成程序的装载和执行。
阅读更多关于 Linux 系统调用、进程间通信、资源限制、性能诊断、系统工具等内容,可以在相关文章中找到详细说明。如果你对 Linux 进一步感兴趣,可以关注相关技术公众号获取更多深入内容。