Продолжаем публикацию книги о программирование на языке ассемблера (GAS) в операционной системе Linux (x86-64). Сегодня говорим о запуске процесса и функции execve.
Параграф 7.1
Запуск процесса в Linux, системная функция execve
При загрузке приложения в память операционная система создает объект под названием процесс. В него входят всевозможные атрибуты и структуры, хранящиеся в ядре, а также виртуальное адресное пространство, куда загружается код программы. Кроме этого объект – процесс хранит еще и окружение, передаваемое при запуске. Можно сказать, процесс это запущенный экземпляр приложения.
Процесс, однако, это статический объект. Для хранения данных о выполнении кода система создает также еще один объект, называемый потоком. Один поток создается всегда автоматически после создания процесса, он называется главным или первичным потоком. Первичный поток может создавать еще потоки, которые в свою очередь создавать потоки еще. Все потоки существуют в одном виртуальном адресном пространстве, т.е. разделяют одну память – могут пользоваться одними и теми же данными.
Сегодня разберем создание процесса путем программного запуска исполняемого модуля. Для запуска исполняемого модуля используется системный вызов с номером 59 (execve). Особенность запуска программы таким образом заключается в том, что запущенная программа полностью замещает процесс, который запускает данную программу. Это важный момент, который будем учитывать в дальнейшем. Чтобы управлять запускаемым процессом, нужен механизм, позволяющий запускать параллельный процессы, но это будем обсуждать в следующем параграфе.
Ниже представлена программа, которая запускает указанный исполняемый модуль с возможностью указания параметров, используемых данной программой. Программа состоит из двух модулей. В модулей из листинга 61 представлены вспомогательные функции: getpar - получить параметр командной строки, _exit — закончить работу программы. Этот код нами уже неоднократно использовался и я не буду его комментировать. Заметим только что, функция getpar имеет два входных параметра: номер получаемого параметра и адрес буфера, куда параметр должен быть помещен. Если параметра с данным номером нет, то функция возвращает 0.
В листинге 62 основная часть программы запуска исполняемого модуля. Прежде чем разбирать эту программу, обратимся к описанию системной функции execve.
Системная функция execve имеет три параметра:
1. Полное имя запускаемого файла, например /bin/ls, ./prog1 и т.д. Это может быть двоичный исполняемый файл или скрипт, в первой строке которого указано как этот скрипт должен запускаться. Структура первой строки такого файла следующая: #!запускающая программа [возможный параметр].
2. Массив, состоящий из указателей на строки. Последний элемент массива должен быть нулем. По умолчанию первая строка — имя запускаемой программы. Дальше могут идти другие параметры. Но это не обязательно, т.е. первая строка может содержать и другую информацию. Если параметров нет, первая строка должна обязательно присутствовать.
3. Массив, состоящий из указателей на строки окружения. Каждая такая строка имеет структуру переменная=значение. Если третий параметр равен нулю (NULL), то это означает, что запускаемая программа имеет то же окружение, что и запускающая. Чаще всего выбирается именно этот вариант.
Программа, представленная в листинге 62, запускает исполняемые модули имена и параметры которых указаны в командной строке как параметры.
Пояснение к программе из листинга 62.
1. В программе принята следующая структура данных. nm— указывает на первый параметр execve. Далее идут метки nm1-nm4, где будут размещены параметры для массива, который идет вторым параметром данной системной функции. nn1-nn5— указатели на строки, т.е. массив указателей, который и будет передавать в системную функцию. nn5— всегда будет содержать 0. Таким образом количество элементов в массиве не может превышать 5, а количество строк не более 4.
2. Далее идет блок получения параметров. Здесь следует отметить, что в отсутствие первого параметра в командной строке приводит сразу к окончанию работы программы, так запуск ей не чего. В случае одного параметра в командной строке, второй элемент массива будет показывать на полное имя программы. Т.е. два первых элемента массива показывают на одну и ту же строку. Для всех остальных параметров командной строки используется принцип: если параметра нет, то соответствующий элемент массива будет равен нулю (см. листинг 62).
3. При запуске execve ее параметры, таким образом равны: значение nm (адрес полного имени запускаемой программы, nn1— начала массива указателей на строки, 0— последний параметр.
Для трансляции программы выполняется последовательность команд
as --64l68.s -ol68.o
as --64l69.s -ol69.o
ldl69.o l68.o -ol69
Примеры запуска программы
./l70 /bin/ls -al /etc
./l70 /bin/ls ls --help
./l70 /bin/ps ps -A
и т.д.
Рассмотренная нами функция execve замещает запускающее приложение новым процессом. При этом старое приложение просто теряется. Конечно, хотелось бы иметь механизм, позволяющий не только запускать другие приложения, но сохранять и старые, более того, иметь возможность управлять запущенными приложениями. Такие механизмы будут изложены в следующих параграфах.
На сегодня все. Подписываемся на мой канал Old Programmer и ставьте "лайки". А я продолжаю заниматься книгой Ассемблер для Linux 64.
<--Глава 6. Параграф 6.7 -->Глава 7. Параграф 7.2
#программирование #программисты #assembler #ассемблер #языки программирования