仔细阅读execve(2)的文档(以及Advanced Linux Programming以获得更广阔的视野)。阅读有关虚拟内存、分页、MMU、进程的信息。
execve 系统调用正在您的进程中安装一个新的虚拟地址空间(因此成功执行的程序的旧虚拟地址空间execve 消失了,被新的虚拟地址空间覆盖),因此您不会与前一个共享任何数据(并且asuccessexecve不会返回,因为新程序已启动)。您的新程序稍后将能够更改虚拟地址空间,例如使用mmap(2) ...
新虚拟地址空间中字符串的地址与;argv的参数地址无关 execve字符串内容相同。旧的虚拟地址空间和新的虚拟地址空间之间没有数据共享,但新程序(和程序环境)的参数被复制。另请阅读关于ASLR
的参数execve是在新虚拟地址空间的新调用堆栈上复制的字符串_start(其副本被推送),用于其起始函数( 在crt0中调用main)。当然,您不应该free有任何argv[i-]那将是未定义的行为。
因此int a; argv[1]=(char*)&a;... execvewith argv, 是未定义的行为,因为您不能保证地址处的内存区域a是正确的以空值结尾的字符串。阅读有关字节序和ABI的信息。
所以execve 想要一个NULL终止argv的正确字符串数组(不是任意指针)和另一个NULL 终止env的字符串数组,并且每个字符串都应该以零字节终止。从旧地址空间通过&ARG_MAX复制到新地址空间的总内存空间有一个相当小的限制(通常为 128 KB) 。argvenv
您可能会使用共享内存(请参阅shm_overview(7))在各个进程之间共享内存(并且您将与信号量同步,请参阅sem_overview(7) ...);但您通常更喜欢其他进程间通信技术(例如pipe(7) -s、fifo(7) -s、socket(7) -s 等...)。
顺便说一句,还可以使用strace(1)来了解您的程序涉及哪些系统调用,并使用proc(5),特别是通过运行cat /proc/$$/maps和了解更多关于虚拟地址空间的信息。cat /proc/$pidofyourprogram/maps
你甚至可以把你的两个main函数都放进去(execve在第一个之前,return 0;在第二个之前),比如
char cmd[64];
snprintf(cmd, sizeof(cmd), "/bin/cat /proc/%d/maps", (int)getpid());
printf("before running %s\n", cmd);
fflush(NULL);
int err = system(cmd);
if (err) fprintf(stderr, "system failed err=%d\n", err);
else printf("system %s done\n", cmd);
这将向您显示虚拟地址空间的视图。当然,更严肃的程序应该fopen是一个/proc/1234/maps文件并循环fgets读取每一行,直到EOF那时fclose。
请耐心等待,阅读此处的所有参考资料,并花时间了解有关 POSIX 编程的更多信息。学习一些自由软件源代码(例如在http://github.com/你可以选择一些有趣的项目......)并为它们做出贡献应该是值得的。