внимательно прочитайте документацию по execve(2) (а также Advanced Linux Programming, чтобы получить более широкий обзор). Прочтите о виртуальной памяти, пейджинг, MMU, процессы.
execve
системный вызов устанавливает новую новую виртуальное адресное пространство в вашем процесс (поэтому старое виртуальное адресное пространство программы, выполняющей execve
, успешно исчезает, перезаписываясь новым), поэтому вы не делитесь данными с предыдущим (и успешный execve
не возвращается, так как запускается новая программа). Ваша новая программа сможет позже изменить виртуальное адресное пространство, например. с mmap(2)...
Адреса argv
строк в новом виртуальном адресном пространстве не зависят от адресов аргументов execve
; содержимое строки такое же. Никакие данные не разделяются между старым виртуальным адресным пространством и новым, но аргументы новой программы (и программной среды) копируются. Читайте также об ASLR
Аргументы execve
копируются строки (с отправкой их копии) в новый свежий стек вызовов нового виртуального адресного пространства для его стартовой функции (_start
в crt0, который вызывает main
). Конечно, вы не должны free
выполнять какие-либо argv[
i]
- это будет неопределенное поведение.
Следовательно, int a; argv[1]=(char*)&a;
... execve
с argv
— это неопределенное поведение, потому что вы не можете гарантировать, что зона памяти по адресу a
является правильной строкой с завершающим нулем. Прочтите об порядке байтов и ABI.
Таким образом, execve
нужен NULL
завершенный массив argv
правильных строк (не произвольных указателей) и другой NULL
завершенный env
массив строк, и каждая строка должна заканчиваться нулевым байтом. Существует довольно небольшое ограничение ARG_MAX
(обычно 128 Кбайт) на общий объем памяти, скопированный из старого адресного пространства в новое через 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)./ вы можете выбрать несколько интересных проектов...) и участие в них должно быть полезным.
person
Basile Starynkevitch
schedule
20.12.2015
strace
- person Basile Starynkevitch   schedule 20.12.2015