Upgrade to Pro — share decks privately, control downloads, hide ads and more …

コンパイラ作りの魅力を語る / Making compilers is fun

DQNEO
March 30, 2019

コンパイラ作りの魅力を語る / Making compilers is fun

PHPerKaigi 2019で、C/Goコンパイラを作る過程で学んだことについて話しました。

DQNEO

March 30, 2019
Tweet

More Decks by DQNEO

Other Decks in Programming

Transcript

  1. Cコンパイラ (8cc) int sum(int a, int b) { return a

    + b; } sum: push %rbp mov %rsp, %rbp push %rdi push %rsi mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret C言語 GNU assembler
  2. sum: push %rbp mov %rsp, %rbp push %rdi push %rsi

    mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret アセンブリ言語 ≒ マシン語 • 各行がCPUへの「命令」 • どの行も、ハードウェア に対して副作用を生じる (レジスタ(後述)またはメ モリ上のデータを変更す る)
  3. sum: push %rbp mov %rsp, %rbp push %rdi push %rsi

    mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret GNU Assembler CPUへの命令
  4. sum: push %rbp mov %rsp, %rbp push %rdi push %rsi

    mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret GNU assembler メモリ 読み書き
  5. sum: push %rbp mov %rsp, %rbp push %rdi push %rsi

    mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret GNU assembler レジスタ 読み書き
  6. Cコンパイラ (8cc) int sum(int a, int b) { return a

    + b; } sum: push %rbp mov %rsp, %rbp push %rdi push %rsi mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret C GNU Assembler 関数 → 関数 変数 → メモリ何番目
  7. 式を評価して値を得る x + y; mov -8(%rbp), %rax mov -16(%rbp), %rcx

    add %rcx, %rax 演算の結果をraxに書き込む
  8. 関数の戻り値 int sum(int x, int y) { return x +

    y; } sum: push %rbp mov %rsp, %rbp push %rdi push %rsi mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret raxに値を書き込ん で関数を抜ける。 これが戻り値。 受け取る側は、rax から値を読み出す。 int sum(int x, int y) { return x + y; }
  9. 関数の戻り値 int sum(int x, int y) { return x +

    y; } sum: push %rbp mov %rsp, %rbp push %rdi push %rsi mov -8(%rbp), %rax mov -16(%rbp), %rcx add %rcx, %rax leave ret int sum(int x, int y) { return x + y; } 「純粋な関数」 も、ハードウェア レベルでは副作 用がある
  10. 8cc 1コミット目 #include <stdio.h> #include <stdlib.h> int main(int argc, char

    **argv) { int val; if (scanf("%d", &val) == EOF) { perror("scanf"); exit(1); } printf("\t.text\n\t" ".global mymain\n" "mymain:\n\t" "mov $%d, %%eax\n\t" "ret\n", val); return 0; } #include <stdio.h> extern int mymain(void); int main(int argc, char **argv) { int val = mymain(); printf("%d\n", val); return 0; } https://github.com/rui314/8cc/commit/3764b2071b9601067b81976d80175a0851d0f209