関数コール
Macでの関数の呼び出しについて調べないと、関数が実装出来ません。
ということで、関数コールについて調べてみます。
void a(int a,int b, int c,int d, int e, int f, int g, int h,int i, int j) { printf("%d\n", a+b+c+d+e+f+g+h+i+j); } void ac() { a(1,2,3,4,5,6,7,8,9,10); }
この引数が大量にあるcプログラムをコンパイルしてアセンブラを出力します。
gcc -m64 tes.c -S
アセンブラのソースとして以下のような物が出力されます。以下のソースは整形してあります。
.cstring .ascii "%d\12\0" .text .globl _a _a: pushq %rbp movq %rsp, %rbp subq $32, %rsp movl %edi, -4(%rbp) movl %esi, -8(%rbp) movl %edx, -12(%rbp) movl %ecx, -16(%rbp) movl %r8d, -20(%rbp) movl %r9d, -24(%rbp) movl -8(%rbp), %eax addl -4(%rbp), %eax addl -12(%rbp), %eax addl -16(%rbp), %eax addl -20(%rbp), %eax addl -24(%rbp), %eax addl 16(%rbp), %eax addl 24(%rbp), %eax addl 32(%rbp), %eax movl %eax, %esi addl 40(%rbp), %esi leaq LC0(%rip), %rdi movl $0, %eax call _printf leave ret .globl _ac _ac: pushq %rbp movq %rsp, %rbp subq $32, %rsp movl $10, 24(%rsp) movl $9, 16(%rsp) movl $8, 8(%rsp) movl $7, (%rsp) movl $6, %r9d movl $5, %r8d movl $4, %ecx movl $3, %edx movl $2, %esi movl $1, %edi call _a leave ret
macのx86_64だと、引数は6つまではレジスタで渡すような仕様になっていて、6つ以上の場合は、スタックにとることがわかります。
それをうまく計算するプログラムが書ければ実装出来た!ってことになります。
とりあえず、引数名のリストを受け取って、格納先のリストと引数名から格納先のマップを作ってみました。
object tes { val regs = List("%edi", "%esi", "%edx","%ecx", "%r8d", "%r9d") def main(argv:Array[String]) { var args = List("a","b","c","d","e","f","g","h","i") println(h(args,regs)) println("m="+m) } var n = 0 var m = Map[String,String]() def h(as:List[String],rs:List[String]):List[String] = { (as,rs) match { case (List(),_) => List() case (as,List()) => h2(as) case (a::as,r::rs) => m = m + (a->r); r::h(as,rs) } } def h2(as:List[String]):List[String] = { as match { case List() => List() case a::as => val r = if(n == 0) "(%rsp)" else n+"(%rsp)" m = m + (a->r) n+=8 r::h2(as) } } }
作ってみたのだけど、欲しいコードとはなんか違います。
マップはいらないんじゃないかなとか、どうやって、スタックの領域を取るの?とか、
呼び出される側は、とにかく、メモリに保存してしまえばいいんだけど、出来てないとか。
とりあえず、そのへんをちゃんと考える必要がありますけど、進んではいるのでした。