Linux execve函数详解

2024-03-13 12:20
文章标签 linux 函数 详解 execve

本文主要是介绍Linux execve函数详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1 基本介绍
    • 2 execve实例
      • 2.1 自定义argv和envp
      • 2.2 fork后再通过子进程执行execve

1 基本介绍

#include <unistd.h>
int execve(const char *pathname, char *const argv[], char *const envp[]);
  • 描述

    execve()执行由pathname引用的程序。这会导致当前由调用进程运行的程序被一个新程序替换,该新程序具有新初始化的堆栈、堆和(已初始化和未初始化)数据段。

    pathname必须是二进制可执行文件或以形式为#!interpreter [optional-arg]开头的脚本。

    argv是传递给新程序作为其命令行参数的字符串指针数组。按照惯例,这些字符串中第一个(即argv[0])应包含与正在执行文件相关联的文件名。argv数组必须以NULL指针结尾。(因此,在新程序中,argv[argc]将为NULL)。

    envp是传递给新程序环境变量的字符串指针数组。该数组包含了环境变量。每个环境变量都是一个 char* 指针,格式为 “name=value”。envp数组同样必须以NULL指针结尾。

    char *envp[] = {"PATH=/bin","HOME=/home/user","USER=user",NULL // 终止环境变量数组
    };
    

    argvenvp可以从新程序的主函数访问。例如我们编写的C程序,实际上是由操作系统通过execve()系统调用执行(这里是操作系统先执行fork系统调用,创建一个新的子进程,然后在新的子进程中,操作系统执行execve()系统调用),它会传递这些参数给新程序的主函数,即 main 函数。这些参数定义了新程序执行时的环境和命令行参数,在程序启动时由操作系统设置,并在整个程序执行期间保持不变。这使得程序能够根据传递给它的参数和环境变量来执行不同的任务或调整其行为。

  • 返回值

    成功时,execve() 不返回任何值,当 execve 成功替换当前进程的映像并开始执行新的程序时,原来的进程(即调用 execve 的进程)已经不再存在,因此无法返回任何值。

    在出错时返回 -1,并设置适当的 errno

  • 重点

    1. execve实际上就是将当前运行的状态机重置成另一个程序的初始状态
    2. 允许对新状态机设置参数 argv (v) 和环境变量 envp (e)
    3. 在程序启动时,操作系统首先执行 fork 系统调用,创建一个新的子进程。然后,操作系统在子进程中执行 execve 系统调用,以替换子进程的程序映像并开始执行新的程序。原来的父进程继续执行 fork 之后的代码。
    4. 在调用 execve 之前,确保释放所有不再需要的资源,如打开的文件描述符、锁等。
    5. 在调用 execve 之前,确保子进程已经处理了所有待处理的信号,除非你希望信号处理程序在新程序中执行。
    6. 如果 execve 失败,子进程通常应该终止。
    7. 在父进程中,通常会在 fork 之后立即调用 wait 或 waitpid 来等待子进程结束,以确保父进程不会过早退出,从而导致子进程的僵尸进程。

2 execve实例

2.1 自定义argv和envp

#include <unistd.h>
#include <stdio.h>int main() {char * const argv[] = {"/bin/bash", "-c", "env", NULL,};char * const envp[] = {"HELLO=WORLD", NULL,};execve(argv[0], argv, envp);printf("Hello, World!\n");return 0;
}

在这段代码中,我们显式的设置了argvenvp,其中参数 "/bin/bash", "-c", "env", NULL,这里的参数实际上是在告诉 bash 执行一个命令(由 -c 后面的字符串指定),在这个例子中是 env,它打印当前的环境变量。

我们运行代码,得到如下输出:

image-20240313091345219

如果我们不传 -c 参数和随后的命令,即只传入 "/bin/bash", NULL 作为参数,bash 会默认进入交互式模式。在这种模式下,它不会执行任何命令并立即退出,而是会等待用户输入,表现为进入了 shell 环境。

我们发现,打印的当前环境变量除了自定的envp,还有一些其他的输出。这是因为除了我们设定的环境变量外,还有一些系统或者 shell 默认的环境变量会被添加到新进程中,例如 PWD 表示当前工作目录,SHLVL 表示 shell 层级,_ 是上一个执行的命令。这就是为什么我们会看到额外的环境变量出现在输出中。

2.2 fork后再通过子进程执行execve

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程char * const argv[] = {"/bin/echo", "Hello, World!", NULL};char * const envp[] = {NULL};execve("/bin/echo", argv, envp);} else if (pid > 0) {// 父进程wait(NULL); // 等待子进程结束printf("Child process finished.\n");} else {// fork失败perror("fork");return 1;}return 0;
}

这段代码演示了如何使用 fork() 系统调用创建一个新的子进程,然后在子进程中执行 execve() 系统调用。这是在 Unix-like 系统中常见的操作模式,因为 execve() 系统调用有一些关键的限制:

  • 一次机会:execve() 系统调用只能用于替换当前进程的映像一次。如果一个进程已经调用了 execve(),它就不能再调用 fork() 或再次执行 execve()
  • 无返回值:execve() 成功执行时,原来的进程映像被新程序映像替换,原来的进程不再存在,因此无法返回任何值。如果在 execve() 执行之前有任何返回值,那么这个返回值是在 fork() 调用之后,由父进程获得的。

因此,在实际应用中,我们通常会先使用 fork() 创建一个子进程,然后在子进程中调用 execve() 执行新的程序。父进程在 fork() 之后会继续执行,并通过调用 wait(NULL) 来等待子进程结束。这样,父进程可以知道子进程已经成功执行了 execve(),并且可以继续执行其他任务或退出。

在多线程程序中,如果一个线程执行了 fork() 并尝试在子进程中执行 execve(),那么其他线程将继续执行,不受 fork()execve() 的影响。只有调用 fork() 的线程会进入子进程,而其他线程则继续在父进程中运行。

得到的运行结果:

image-20240313102827423

这篇关于Linux execve函数详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/804861

相关文章

VScode连接远程Linux服务器环境配置图文教程

《VScode连接远程Linux服务器环境配置图文教程》:本文主要介绍如何安装和配置VSCode,包括安装步骤、环境配置(如汉化包、远程SSH连接)、语言包安装(如C/C++插件)等,文中给出了详... 目录一、安装vscode二、环境配置1.中文汉化包2.安装remote-ssh,用于远程连接2.1安装2

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

详解如何在React中执行条件渲染

《详解如何在React中执行条件渲染》在现代Web开发中,React作为一种流行的JavaScript库,为开发者提供了一种高效构建用户界面的方式,条件渲染是React中的一个关键概念,本文将深入探讨... 目录引言什么是条件渲染?基础示例使用逻辑与运算符(&&)使用条件语句列表中的条件渲染总结引言在现代

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

SQL注入漏洞扫描之sqlmap详解

《SQL注入漏洞扫描之sqlmap详解》SQLMap是一款自动执行SQL注入的审计工具,支持多种SQL注入技术,包括布尔型盲注、时间型盲注、报错型注入、联合查询注入和堆叠查询注入... 目录what支持类型how---less-1为例1.检测网站是否存在sql注入漏洞的注入点2.列举可用数据库3.列举数据库

Linux之软件包管理器yum详解

《Linux之软件包管理器yum详解》文章介绍了现代类Unix操作系统中软件包管理和包存储库的工作原理,以及如何使用包管理器如yum来安装、更新和卸载软件,文章还介绍了如何配置yum源,更新系统软件包... 目录软件包yumyum语法yum常用命令yum源配置文件介绍更新yum源查看已经安装软件的方法总结软