LoginSignup
1
0

More than 1 year has passed since last update.

x86_64で関数の引数とレジスタの対応を確認する (アセンブラ)

Last updated at Posted at 2021-08-29

はじめに

アセンブラについて勉強して気になったので、基礎事項の確認がてらメモ書き。

x86_64では、関数の引数をレジスタを使って受け渡している。
受け渡しに使われるレジスタは、呼出規約でRDI, RSI, RDX, RCX, R8, R9の6つの汎用レジスタが指定されている。(Linuxなどで使われるSystem V AMD64 ABIの場合1

簡単なC言語のコードを書き、実際にその通りにレジスタが使われているか確認する。

環境

OS: MacOS Catalina
GCC: gcc version 11.2.0
(Mac標準のApple Clangではなく、gccを使っている)

検証

int sum(int a, int b)
{
  return a + b;
}

引数2つの関数を書いたコードをコンパイルし、objdumpしてアセンブラを見る。

$ gcc -c test.c 
$ objdump -d test.o

test.o: file format Mach-O 64-bit x86-64


Disassembly of section __TEXT,__text:

0000000000000000 _sum:
       0: 55                            pushq   %rbp
       1: 48 89 e5                      movq    %rsp, %rbp
       4: 89 7d fc                      movl    %edi, -4(%rbp)
       7: 89 75 f8                      movl    %esi, -8(%rbp)
       a: 8b 55 fc                      movl    -4(%rbp), %edx
       d: 8b 45 f8                      movl    -8(%rbp), %eax
      10: 01 d0                         addl    %edx, %eax
      12: 5d                            popq    %rbp
      13: c3                            retq

1つ目のmovlで第一引数がediから取り出され、2つ目のmovlで第二引数がesiから取り出されている。

次に引数を6つに増やしてアセンブラを見る。

int sum(int a, int b, int c, int d, int e, int f)
{
  return a + b + c + d + e + f;
}
0000000000000000 _sum:
       0: 55                            pushq   %rbp
       1: 48 89 e5                      movq    %rsp, %rbp
       4: 89 7d fc                      movl    %edi, -4(%rbp)
       7: 89 75 f8                      movl    %esi, -8(%rbp)
       a: 89 55 f4                      movl    %edx, -12(%rbp)
       d: 89 4d f0                      movl    %ecx, -16(%rbp)
      10: 44 89 45 ec                   movl    %r8d, -20(%rbp)
      14: 44 89 4d e8                   movl    %r9d, -24(%rbp)
      18: 8b 55 fc                      movl    -4(%rbp), %edx
      1b: 8b 45 f8                      movl    -8(%rbp), %eax
      1e: 01 c2                         addl    %eax, %edx
      20: 8b 45 f4                      movl    -12(%rbp), %eax
      23: 01 c2                         addl    %eax, %edx
      25: 8b 45 f0                      movl    -16(%rbp), %eax
      28: 01 c2                         addl    %eax, %edx
      2a: 8b 45 ec                      movl    -20(%rbp), %eax
      2d: 01 c2                         addl    %eax, %edx
      2f: 8b 45 e8                      movl    -24(%rbp), %eax
      32: 01 d0                         addl    %edx, %eax
      34: 5d                            popq    %rbp
      35: c3                            retq

呼出規約の通り、edi ~ r9の6つのレジスタが使われている。

8つ以上に増やしてみる。

int sum(int a, int b, int c, int d, int e, int f, int g, int h)
{
  return a + b + c + d + e + f + g + h;
}
0000000000000000 _sum:
       0: 55                            pushq   %rbp
       1: 48 89 e5                      movq    %rsp, %rbp
       4: 89 7d fc                      movl    %edi, -4(%rbp)
       7: 89 75 f8                      movl    %esi, -8(%rbp)
       a: 89 55 f4                      movl    %edx, -12(%rbp)
       d: 89 4d f0                      movl    %ecx, -16(%rbp)
      10: 44 89 45 ec                   movl    %r8d, -20(%rbp)
      14: 44 89 4d e8                   movl    %r9d, -24(%rbp)
      18: 8b 55 fc                      movl    -4(%rbp), %edx
      1b: 8b 45 f8                      movl    -8(%rbp), %eax
      1e: 01 c2                         addl    %eax, %edx
      20: 8b 45 f4                      movl    -12(%rbp), %eax
      23: 01 c2                         addl    %eax, %edx
      25: 8b 45 f0                      movl    -16(%rbp), %eax
      28: 01 c2                         addl    %eax, %edx
      2a: 8b 45 ec                      movl    -20(%rbp), %eax
      2d: 01 c2                         addl    %eax, %edx
      2f: 8b 45 e8                      movl    -24(%rbp), %eax
      32: 01 c2                         addl    %eax, %edx
      34: 8b 45 10                      movl    16(%rbp), %eax
      37: 01 c2                         addl    %eax, %edx
      39: 8b 45 18                      movl    24(%rbp), %eax
      3c: 01 d0                         addl    %edx, %eax
      3e: 5d                            popq    %rbp
      3f: c3                            retq

7つ目の引数は16(%rbp)、8つ目の引数は24(%rbp)から取られている。
7つ目以降の引数は汎用レジスタではなく、スタックに積まれていることが分かる。

※ スタックには既に関数のリターンアドレスが積まれており、更に関数の冒頭でpushq %rbp movq %rsp, %rbpしているため、引数の格納部が16(%rbp)から始まっている。

おわりに

実際にアセンブラを読んで関数の引数とレジスタの対応を確認した。
今回はSystem V AMD64 ABIの呼出規約に沿っていることを確認したが、Windowsなどで使われているMicrosoft x64 calling conventionでは4つの汎用レジスタ(RCX, RDX, R8, R9)を使うことを定めている。


  1. Wikipediaに呼び出し規則をまとめた表がある。x86 calling conventions 

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0