仔细阅读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;
... execve
with argv
, 是未定义的行为,因为您不能保证地址处的内存区域a
是正确的以空值结尾的字符串。阅读有关字节序和ABI的信息。
所以execve
想要一个NULL
终止argv
的正确字符串数组(不是任意指针)和另一个NULL
终止env
的字符串数组,并且每个字符串都应该以零字节终止。从旧地址空间通过&ARG_MAX
复制到新地址空间的总内存空间有一个相当小的限制(通常为 128 KB) 。argv
env
您可能会使用共享内存(请参阅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/你可以选择一些有趣的项目......)并为它们做出贡献应该是值得的。