如何在C引导程序中使用fexecve替代system编译运行子C程序
修复方案
核心错误点
- 编译调用配置错误:
open("usr/bin/cc")路径拼写错误缺少开头/,且未传入./math.c -o math等必要编译参数,实际没有生成可执行的math文件 - 执行目标错误:调用
fexecve时传入的fd是math.c源码文件的描述符,并非编译生成的可执行文件math,源码本身不可执行自然调用失败 - 传参不规范:执行
math的argv数组末尾未加NULL作为终止符,不符合系统调用的传参要求 - 缺失错误排查逻辑:没有对系统调用返回值做校验,也没有打印错误信息,无法快速定位问题
修改后的完整代码
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/wait.h> // 新增wait相关头文件 int main(void){ printf("system_bootstrap pid:%d\n", getpid()); char *program = "#include <stdio.h>\n" "#include <stdlib.h>\n" "#include <unistd.h>\n" "int result;\n" "int main(int argc, char *argv[]){\n" "printf(\"main_add pid: %d\\n\", getpid());\n" "int a = 0;\n" "int b = 0;\n" "char* op;\n" "op = argv[1];\n" "a = atoi(argv[2]);\n" "b = atoi(argv[3]);\n" "int choice = 0;\n" "if(*op == '+')\n" "choice = 1;\n" "else if(*op == '-')\n" "choice = 2;\n" "else if(*op == '*')\n" "choice = 3;\n" "else if(*op == '/')\n" "choice = 4;\n" "switch(choice){\n" "case 1:\n" "result = a + b;\n" "printf(\"%d + %d = %d \\n\", a, b, result);\n" "break;\n" "case 2:\n" "result = a - b;\n" "printf(\"%d - %d = %d \\n\", a, b, result);\n" "break;\n" "case 3:\n" "result = a * b;\n" "printf(\"%d * %d = %d \\n\", a, b, result);\n" "break;\n" "case 4:\n" "result = a / b;\n" "printf(\"%d / %d = %d \\n\", a, b, result);\n" "break;\n" "default:\n" "printf(\"Invalid choice.\\n\");\n" "break;\n" }\n" "return 0;\n" "}\n"; int fd = creat("./math.c", S_IRUSR | S_IWUSR); printf("fd for math.c file:%d\n", fd); write(fd, program, strlen(program)); close(fd); // 写入完成后关闭math.c的文件描述符,释放资源 // 第一次fork:子进程执行编译 pid_t cc_pid = fork(); if (cc_pid == 0) { int cc_fd = open("/usr/bin/cc", O_RDONLY); if (cc_fd < 0) { perror("open cc failed"); exit(1); } // 传入完整编译参数,末尾以NULL结尾 char *cc_argv[] = {"cc", "./math.c", "-o", "math", NULL}; char *cc_env[] = {NULL}; fexecve(cc_fd, cc_argv, cc_env); // fexecve成功则不会走到这里,走到就是失败 perror("compile fexecve failed"); exit(1); } // 父进程等待编译完成 wait(NULL); // 第二次fork:子进程执行生成的math程序 printf("executing the math program ...\n"); pid_t math_pid = fork(); if (math_pid == 0) { int math_fd = open("./math", O_RDONLY); if (math_fd < 0) { perror("open math failed"); exit(1); } // 参数末尾加NULL终止符 char *math_argv[] = {"./math", "+", "6", "1", NULL}; char *math_env[] = {NULL}; fexecve(math_fd, math_argv, math_env); perror("run math fexecve failed"); exit(1); } // 父进程等待执行完成 wait(NULL); return 0; }
验证说明
修改后编译运行system_math_bs.c,会正常输出计算结果6 + 1 = 7,和原system实现的效果一致。如果需要修改计算参数,直接修改math_argv数组里的对应值即可。
内容的提问来源于stack exchange,提问作者cruella devil
相关产品推荐
相关产品推荐

