Wyobraź sobie, że chcesz uruchomić inny program z poziomu swojego procesu — na przykład uruchomić skrypt, program lub powłokę. W systemie Linux, aby to zrobić na najniższym poziomie, korzystamy z wywołania systemowego execve
.
W tym artykule dowiesz się, czym jest syscall execve
, jak działa i zobaczysz praktyczne przykłady jego użycia — zarówno z poziomu języka C, jak i asemblera.
Co to jest execve
?
execve
(ang. execute program) to wywołanie systemowe w Linuxie służące do uruchomienia nowego programu, zastępując obecny obraz procesu nowym programem.
- Nie tworzy nowego procesu — zamienia kod, dane i stos bieżącego procesu.
- Przyjmuje ścieżkę do programu, argumenty oraz zmienne środowiskowe.
- Po wywołaniu
execve
obecny program przestaje istnieć — zastępuje go nowy.
Jak działa execve
?
Wywołanie execve
ma następującą sygnaturę:
int execve(const char *pathname, char *const argv[], char *const envp[]);
pathname
— ścieżka do wykonywalnego pliku.argv
— tablica wskaźników do argumentów przekazywanych do programu.envp
— tablica wskaźników do zmiennych środowiskowych.
Jeśli wywołanie powiedzie się, nie wraca do programu wywołującego — proces jest zastąpiony nowym programem. Jeśli zwróci błąd, execve
zwróci -1
.
execve
w asemblerze x86-64
Wywołania systemowe w Linux x86-64 wykonuje się instrukcją syscall
. Numer execve
to 59 (decimal).
Argumenty przekazujemy do rejestrów:
Rejestr | Argument |
---|---|
rax | numer syscall (59) |
rdi | pathname |
rsi | argv |
rdx | envp |
Przykład minimalnego kodu w NASM, który uruchamia /bin/ls
:
section .data
path db '/bin/ls', 0
argv dq path, 0
envp dq 0
section .text
global _start
_start:
mov rax, 59 ; execve syscall number
mov rdi, path ; ścieżka programu
mov rsi, argv ; argumenty
mov rdx, envp ; środowisko
syscall
; jeśli execve zawiedzie - zakończ program
mov rax, 60 ; exit syscall
xor rdi, rdi
syscall
Kompilacja powyższego kodu na Linux
$ nasm -f elf64 -o run_ls_asm.o run_ls_asm.asm
$ ld -o run_ls_asm run_ls_asm.o
$ ./run_ls_asm
run_ls_asm run_ls_asm.asm run_ls_asm.o
Praktyczne zastosowania execve
1. Implementacja własnego exec
w shellu
execve
to fundament działania wielu powłok (shelli). Po wpisaniu polecenia:
ls -l /home
shell wykorzystuje fork()
do utworzenia procesu potomnego, a w nim execve
do uruchomienia /bin/ls
z argumentami.
2. Uruchamianie skryptów lub programów z własnej aplikacji
Czasem aplikacja musi uruchomić zewnętrzny program, np. narzędzie do konwersji plików. execve
pozwala na zastąpienie procesu tym programem, albo (częściej) wykorzystuje się fork()
+ execve()
, by nie zamknąć aplikacji macierzystej.
3. Zastąpienie bieżącego procesu nowym programem
Jeśli w procesie chcesz całkowicie zmienić jego kod i dane (np. po zalogowaniu się użytkownika), wywołujesz execve
, co zastępuje proces nowym obrazem.
execve
vs system()
Funkcja system()
w C uruchamia powłokę /bin/sh
i wykonuje komendę. Jest wygodna, ale mniej elastyczna i bezpieczna niż bezpośrednie użycie execve
.
Uwaga na błędy
- Jeśli ścieżka jest błędna lub program nie ma uprawnień —
execve
zwróci błąd. - Pamiętaj o przekazaniu poprawnych tablic argumentów i środowiska.
execve
nigdy nie wraca jeśli jest sukcesem!
Podsumowanie
execve
to najniższy poziom uruchamiania programów w Linuxie.- Zastępuje obecny proces nowym obrazem programu.
- Jest fundamentem działania powłok i procesów potomnych.
- Można go używać bezpośrednio z asemblera, lub przez standardowe funkcje w C.