関数コール

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

macx86_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)
    }
  }
}

作ってみたのだけど、欲しいコードとはなんか違います。
マップはいらないんじゃないかなとか、どうやって、スタックの領域を取るの?とか、
呼び出される側は、とにかく、メモリに保存してしまえばいいんだけど、出来てないとか。
とりあえず、そのへんをちゃんと考える必要がありますけど、進んではいるのでした。