コンパイラ作成(64) printf
今回の目標
前回の続き。
// void*, size_t extern void *malloc(size_t size); int main() { char *buffer = malloc(256); printf("buffer = %016lx\n",buffer); }
何回も出てきたprintfだけど、このテストプログラムは上手くコンパイルできないよ。printfの処理はかなり前に作ったんだけど、そっちにはchar*型への対応が入ってないからね。で、この際その処理を削除して通常の関数として処理することにしたよ。その為にはまだちょっとだけ論理が足りないんで今回追加するよ。
reservedword
それでは修正行くよ。
=begin @reservedword = [ "return","goto","if","else","for","while","until","do","break", "printf" ] =end @reservedword = [ "return","goto","if","else","for","while","until","do","break" ]
printfを削除。これで特別扱いしてた関数は全部削除だよ。
codegen_func
ここもちょっと修正。
# 関数コールのコード生成 def codegen_func operand rettype = "int" f = @functions[operand[0].str] if @numuseregs != 0 then if @numuseregs % 2 == 1 then codegen " sub rsp, 8" end (0...@numuseregs).each do |i| codegen " push #{@regs64[i]}" end end if f != nil then if operand.size - 2 != f[1].size then perror "wrong number of parameters" end end (0...operand.size-2).each do |i| save = @numuseregs @numuseregs = i type = codegen_el operand[i+2] @numuseregs = save if f != nil then if f[1][i] == "size_t" then codegen " movsx rax, eax" type = f[1][i] elsif f[1][i] == "void*" && is_pointer_type?(type) then type = f[1][i] end if type != f[1][i] then perror "incompatible type parameter" end end if type == "int" codegen " mov #{@regs32[i]}, eax" elsif type == "size_t" codegen " mov #{@regs64[i]}, rax" =begin elsif type == "char*" codegen " mov #{@regs64[i]}, rax" elsif type == "void*" codegen " mov #{@regs64[i]}, rax" =end elsif is_pointer_type?(type) then codegen " mov #{@regs64[i]}, rax" else perror end end if f == nil then codegen " mov al, 0" end codegen " call " + operand[0].str if f != nil then rettype = f[0] end if @numuseregs != 0 then (0...@numuseregs).reverse_each do |i| codegen " pop #{@regs64[i]}" end if @numuseregs % 2 == 1 then codegen " add rsp, 8" end end return rettype end
関数宣言されてないときにmov al,0をコード生成するようにした。これはABIのコーリングシーケンスに合わせるため。
kogara324.hatenablog.com
statement
printfの処理を削除。
動作テスト
それじゃテスト。
~/myc$ myc o20.myc ~/myc$ ./o20 buffer = 00000000012e1260 ~/myc$
.intel_syntax noprefix .global main main: push rbp mov rbp, rsp sub rsp, 16 mov eax, 256 movsx rax, eax mov rdi, rax call malloc mov qword ptr [rbp - 8], rax lea rax, .L.str mov rdi, rax mov rax, qword ptr [rbp - 8] mov rsi, rax mov al, 0 call printf .RET_main: add rsp, 16 pop rbp ret .L.str: .asciz "buffer = %016lx\n"
ちゃんとポインタ変数が64bitで処理されてるし、alに0がセットされてる。本当はprintfのextern宣言まで行きたかったんだけど今日はここまで。