【コンピューティング】OS上でのコマンド実行時の処理について

#### はじめに

こんにちは、インフラエンジニアです。

最近私はふと思いました。

「OSのコマンドや開発言語の関数一つとっても、コンピューターにとっては複数の処理命令を一塊にしたタスクの集合体なわけだよな」と。

普段の作業でコマンドを叩いたり、コードを実行したりしていても、コンピュータ上でどんな処理が行われているのか、細かく意識をすることは少ないし、淡々と作業を進めてしまう場面って多いのではないでしょうか。
※アーキテクチャのコンセプトがそうだからっていうのもある

インフラエンジニアってシステムが動いている一番身近(物理的に)で仕事してるのに、そういう感覚ってなんだか忘れがちですよね。

そんな感じのきっかけで、Linuxのcatコマンドを例にとってコンピュータの処理をまとめてみました。

#### catコマンドの模倣

C言語でcatコマンドの動作を模倣したコードを作成。
処理としては以下のような感じ
![スクリーンショット 2024-11-28 001540.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953197/4a89f833-354f-951f-6b07-999196c27d31.png)

以下コード
```c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
    FILE* fp;
    int c;

    // 引数が適切に指定されているか確認
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
        return 1;
    }

    // ファイルパスを引数から取得
    char* inputPath = argv[1];

    // ファイルを開く
    fp = fopen(inputPath, "r");
    if (fp == NULL) {
        fprintf(stderr, "Error: ファイルが存在しないか、開けませんでした。\n");
        return 1;
    }

    printf("ファイル内容:\n");

    // ファイル内容を1文字ずつ読み取って出力
    while ((c = fgetc(fp)) != EOF) {
        putchar(c); // 標準出力に表示
    }

    // ファイルを閉じる
    if (fclose(fp) != 0) {
        fprintf(stderr, "Error: ファイルを閉じることができませんでした。\n");
        return 1;
    }

    printf("\nファイルを正常に閉じました。\n");

    return 0;
}

```

#### ソースコードの動作確認
cat.cというファイルを作成し、Rocky Linux 上でコンパイル。
![スクリーンショット 2024-11-27 225130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953197/5df3a01a-f55e-75f2-8e0d-45d7c121021c.png)

"catSim"という実行ファイルに変換しました。
![スクリーンショット 2024-11-27 225137.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953197/f18769b0-21f4-ef62-a311-91638205c53e.png)

引数に閲覧したいファイルを取ると、ちゃんと動きますね。
![スクリーンショット 2024-12-09 215849.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953197/ec8f1d73-7143-7463-88f9-1f5ffdb0af9a.png)

#### アセンブリに変換

処理の流れがより細かく見えるように、以下のサイトでコードをアセンブリに変換します。
https://gcc.godbolt.org/

以下main処理の出力結果
```asm

main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 48
        mov     DWORD PTR [rbp-36], edi
        mov     QWORD PTR [rbp-48], rsi
        cmp     DWORD PTR [rbp-36], 2
        je      .L2
        mov     rax, QWORD PTR [rbp-48]
        mov     rdx, QWORD PTR [rax]
        mov     rax, QWORD PTR stderr[rip]
        mov     esi, OFFSET FLAT:.LC0
        mov     rdi, rax
        mov     eax, 0
        call    fprintf
        mov     eax, 1
        jmp     .L3
.L2:
        mov     rax, QWORD PTR [rbp-48]
        mov     rax, QWORD PTR [rax+8]
        mov     QWORD PTR [rbp-8], rax
        mov     rax, QWORD PTR [rbp-8]
        mov     esi, OFFSET FLAT:.LC1
        mov     rdi, rax
        call    fopen
        mov     QWORD PTR [rbp-16], rax
        cmp     QWORD PTR [rbp-16], 0
        jne     .L4
        mov     rax, QWORD PTR stderr[rip]
        mov     rcx, rax
        mov     edx, 71
        mov     esi, 1
        mov     edi, OFFSET FLAT:.LC2
        call    fwrite
        mov     eax, 1
        jmp     .L3
.L4:
        mov     edi, OFFSET FLAT:.LC3
        call    puts
        jmp     .L5
.L6:
        mov     eax, DWORD PTR [rbp-20]
        mov     edi, eax
        call    putchar
.L5:
        mov     rax, QWORD PTR [rbp-16]
        mov     rdi, rax
        call    fgetc
        mov     DWORD PTR [rbp-20], eax
        cmp     DWORD PTR [rbp-20], -1
        jne     .L6
        mov     rax, QWORD PTR [rbp-16]
        mov     rdi, rax
        call    fclose
        test    eax, eax
        je      .L7
        mov     rax, QWORD PTR stderr[rip]
        mov     rcx, rax
        mov     edx, 68
        mov     esi, 1
        mov     edi, OFFSET FLAT:.LC4
        call    fwrite
        mov     eax, 1
        jmp     .L3
.L7:
        mov     edi, OFFSET FLAT:.LC5
        call    puts
        mov     eax, 0
.L3:
        leave
        ret

```

アセンブリは1行につきコンピュータに命令する処理が1つ、という感じで書かれるのでコンピューティングの過程が分かりやすいですね。

そんなこんなで以下のような処理が行われていることが確認できます。
![スクリーンショット 2024-12-11 010008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953197/6d0497b0-6cac-203b-24f8-1985026bf4c0.png)


#### 結論

普段なんにも考えずに白目向きながら使っているコマンドも、中身ではどのような処理をコンピュータにさせようとしているのか、分解してみるとおもしろいですね。

正直分解された処理の流れが見えるようになったからって何なんだっていう話なのですが、コンピュータがどのように世界を捉えていて、どのようにプログラムを動かそうとしているのか、さらにはそれらに加えてハードウェアやファイルシステムなどの要素も含めた横断的な視点もつことで、スムーズなシェルコードの作り込みや、障害時の被疑箇所の絞り込みなどに役立てられるのかなと感じました。

以上、ありがとうございました!
初めての投稿なもので、変なところがあったらコメント等で教えて頂けるとありがたいです!

#### PS
lsコマンドの動作を模倣したコードを作っている方のブログを見つけました。
すごい。
https://www.mm2d.net/main/prog/linux/ls-01.html