execve()関数

実行ファイルは、
– コードを含むデータ領域のファイル上のオフセット、サイズ、メモリマップ開始アドレス
– 最初に実行する命令のメモリアドレス(エントリポイント)
を持っている。

100 オフセット(基準点)
100 サイズ
300 メモリマップ開始アドレス
200 データオフセット
200 データサイズ
400 メモリマップ開始アドレス
400 エントリポイント(エントリポイントからプログラム開始)

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>

static void child(){
    char *args[] = {"/bin/echo", "hello", NULL};
    printf("I'm child! my pid is %d.\n", getpid());
    fflush(stdout);
    execve("/bin/echo", args, NULL);
    err(EXIT_FAILURE, "exec() failed");
}

static void parent(pid_t pid_c) {
    printf("I'm parent! my pid is %d and the pid of my child is %d.\n", getpid(), pid_c);
    exit(EXIT_SUCCESS);
}

int main(void) {
    pid_t ret;
    ret = fork();
    if (ret == -1)
        err(EXIT_FAILURE, "fork() failed");
    if (ret == 0) {
        child();
    } else {
        parent(ret);
    }
    err(EXIT_FAILURE, "shouldn't reach here");
}

$ ./fork
I’m parent! my pid is 314918 and the pid of my child is 314919.
I’m child! my pid is 314919.
hello

スタックマシンの場合はpushとpupだが、この場合はオフセット、サイズ、エントリポイント、メモリ(レジスタ)の番地を指定している。逆に言えば、スタックの場合は順番に気をつけなければならないが、オフセットなどを指定できる場合はより柔軟に対応できるということか。