关于Linux下的system()调用

本文探讨了C语言中system()函数的使用及返回值问题。通过分析源码揭示了system()函数返回-1的原因,并指出其返回值并不代表命令的执行结果。此外,还提到了popen()作为替代方案的可能性。

程序里偶尔会用到system()函数,执行些脚本,不过把这个调用放在循环里调时,system()的返回结果经常为-1,

但它调的命令却是执行了。

有点奇怪,于是上网找了个system()的源码,贴下看看:

 

 

从上面这段代码,不难看出:

1. system()的返回值不是cmd的返回值

2. 当返回-1时,cmd不一定没有执行,有可能是folk出错,还有可能是在父进程里调waitpid()时出错。

 

好像很多人建议尽量用popen()代替system(),嗯,如果要是发现popen()有什么值得注意之处再来说说。

<think>我们正在讨论Linux系统中调用系统调用的方法。根据引用[1],系统调用通过执行“int $0x80”指令进入内核,然后由system_call例程处理。引用[2]展示了在应用程序中调用shell命令的方法,其中提到了system()函数。但是,注意system()是一个C库函数,不是直接的系统调用。引用[3]解释了系统调用表的结构,引用[4]则讨论了添加系统调用的步骤。 用户的问题是关于调用系统调用system的方法。注意,这里有一个可能的混淆:系统调用system call)和C标准库中的system()函数是两个不同的概念。用户可能指的是系统调用的通用方法,但也可能指的是system()函数的使用。 根据引用[1],系统调用的通用方法是: 1. 准备参数(例如,将系统调用号放入eax,参数放入ebx、ecx、edx等寄存器) 2. 执行软中断指令“int $0x80”(在x86架构上) 3. 系统调用例程system_call会处理中断,然后调用相应的系统调用服务例程。 但是,用户提到了“system”,这可能是指C库中的system()函数,用于执行shell命令。引用[2]展示了如何使用system()函数:在程序中包含stdlib.h,然后调用system("command")。 因此,我们需要区分两种情况: 1. 如何通过汇编直接调用系统调用(即使用int 0x80或sysenter指令)? 2. 如何使用C库中的system()函数来执行shell命令? 由于用户的问题中同时出现了“系统调用”和“system”,我们需要结合上下文。根据引用[4]提到了添加系统调用foo()的步骤,以及引用[2]中提到了system()函数,用户可能对这两种方式都感兴趣。 因此,回答应该涵盖: - 直接使用汇编指令进行系统调用的方法(以write系统调用为例) - 使用C库函数system()的方法 此外,用户之前的问题可能涉及系统调用的底层机制,因此重点放在直接系统调用上,但也要解释system()函数。 步骤: 1. 直接系统调用(汇编方式): - 将系统调用号放入eax寄存器。 - 将参数依次放入ebx, ecx, edx等寄存器(根据系统调用参数个数)。 - 执行int 0x80(或者根据架构使用sysenter)。 - 返回值在eax中。 2. 使用C库的system()函数: - 包含头文件#include <stdlib.h> - 调用system(const char *command),参数为要执行的shell命令字符串。 示例代码: - 汇编示例(使用int 0x80)调用write系统调用 - C语言示例调用system()函数 注意:用户要求使用中文回答,并且注意LaTeX格式。 最后,生成相关问题。 </think>### Linux系统调用方法详解 在Linux系统中调用系统调用主要有两种方式:**直接调用**(汇编层)和**库函数封装**(应用层)。以下分别说明: #### 1. 直接系统调用(汇编层) 这是最底层的调用方式,通过软中断指令触发内核服务流程[^1]: ```assembly movl $1, %eax ; 系统调用号(1=sys_exit) movl $0, %ebx ; 参数1(退出码) int $0x80 ; 触发中断 ``` **关键步骤**: - 将系统调用号存入$\text{eax}$寄存器(如$\text{sys_write}=4$) - 参数按顺序存入$\text{ebx, ecx, edx}$等寄存器[^4] - 执行$\text{int 0x80}$指令进入内核态 - 内核通过系统调用表$\text{sys_call_table}$跳转到对应例程[^3] > 💡 系统调用表本质是函数指针数组:$\text{void* sys_call_table[NR_syscalls]}$,下标对应系统调用号[^3] #### 2. 库函数封装调用(C应用层) 通过标准库函数间接调用,最常见方式: - **glibc封装函数**(如$\text{open()}$) ```c #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); ``` - **system()函数执行Shell命令** ```c #include <stdlib.h> int main() { system("ls -l"); // 执行Shell命令 } ``` `system()`内部通过$\text{fork() + execve()}$实现[^2] #### 3. 系统调用与库函数区别 | **特性** | 直接系统调用 | 库函数封装 | |----------------|--------------------------|-----------------------| | 执行方式 | 软中断($\text{int 0x80}$) | 函数调用 | | 性能开销 | 低(≈100ns) | 较高(含上下文切换) | | 可移植性 | 架构相关(x86/ARM不同) | 跨平台 | | 参数传递限制 | 最多6个参数(通过寄存器) | 无限制(通过栈传递) | | 典型应用场景 | 内核开发、性能敏感场景 | 常规应用开发 | #### 4. 执行流程示意图 ``` 用户空间 ├─ 直接调用:寄存器传参 → int 0x80 → 系统调用表[^3] └─ 库函数调用system() → fork() → execve() → 系统调用入口[^1] ↓ 内核空间 └─ system_call:参数验证 → 调用sys_xxx() → 返回结果[^1] ``` > ⚠️ 注意:现代CPU使用$\text{syscall/sysenter}$指令替代$\text{int 0x80}$,但原理类似。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值