標準偏差さんとsksatのツイートから学ぶABI(Application Binary Interface)
セキュリティキャンプ24の探査機自作ゼミ参加者である標準偏差さんと、同ゼミの講師であるsksatのTwitter上でのやり取りが、ABIという概念について理解・説明するものとして大変良かったので、本人たちの許可を得た上でブログ記事としてまとめる。
ていうか、call命令でスタックだけ使って引数やりとりするのはCISCアーキテクチャ特有だったりする…? https://t.co/UJhG6ifH9m
— 標準偏差 (@HomeKijitora) October 22, 2024
一連のやり取りは、標準偏差さんが「call命令でスタックメモリのみを使って引数を渡すのはCISCアーキテクチャ特有なのか?」という疑問をツイートし、sksatが「それはアーキテクチャがRISCであるかCISCであるかとは関係ない」と回答したことから始まった。
以下は主に、sksatの一連のツイートの内容をまとめたものである。
ABIという概念
そもそも、「関数」というものはソフトウェア(というか各言語)の概念であり、CPUアーキテクチャの側の概念ではない。
したがって、「関数の引数」という概念をどのように表現するのかというのも、CPUアーキテクチャ側の関心事ではなく、もっと上のレイヤのソフトウェアの関心事である。たとえば、関数の引数を特定のレジスタに入れるのか、スタックメモリに入れるのか、というのはCPUアーキテクチャの側からすればどうでも良い。
もしも自分でコンパイラを自作するなら、関数の引数をどのように表現するのかを自分で決めることもできる。たとえば、第1引数をレジスタに、第2引数をスタックに入れるみたいな変なことをしても問題はない。
しかし、呼び出し側と呼び出される側が同じ約束を守っている必要がある。つまり、関数を呼び出す側が、第1引数をレジスタAに、第2引数をスタックに入れるなら、呼び出される関数側は、第1引数をレジスタAから、第2引数をスタックから取り出す必要がある。
こういう約束のことをABI(Application Binary Interface)という。
関数を呼び出す側と呼び出される側でABIが異なっている場合、意図したとおりには動かない。たとえば、呼び出す側が第1引数をレジスタAに、第2引数をスタックに入れて関数を呼び出したとして、もし呼び出される関数側が第1引数をスタックから、第2引数をレジスタAから取り出した場合、意図したとおりには動かない(第1引数と第2引数を取り違えてしまう)。
なので、多くの人々が守ってくれる約束(ABI)が広く共有されていると、色々なバイナリをくっつけることができるようになる。たとえば、異なる言語のコンパイラが同じABIに従っていれば、別の言語の関数を呼び出すことができる。
そして、人類は長いことC言語というプログラミング言語を使って様々な資産を作り上げてきた。今でも、普通にアプリケーションを書いたらほぼ必ずlibcに依存することになる。つまり、Cの関数を呼んだり、Cの関数から呼ばれたり、ということは今でも当たり前にありうる。
そのためABIは、言語やコンパイラに依らず統一されていてほしい。
OSとABI
このように、みんなが同じABIを守っていると、異なる言語(コンパイラ)の間での関数呼び出しができて便利である。しかし、一般的に異なるOS間での関数呼び出しが行われることはあまりないため、OSごとにABIが違っていても困らないケースが多い。
したがって、CPUアーキテクチャとABIの組み合わせは一つだけというわけではない。たとえば、CPUアーキテクチャはx86-64であってもABIはMicrosoft x64 ABIであったりSystem V ABIであったりすることがある。
関数の引数をどのように表現するのか
ここで、関数の引数を表すのにレジスタとスタックをどのように使うのか、という話題に戻る。
以前はいくつかの観点で今とは状況が異なっていた。たとえば、コンパイラ最適化が十分ではなかった、今ほどCPUやメモリが高速ではなかった、汎用レジスタの数が今よりも少なかった、など。このような状況のもとでは、すべての引数をスタックに入れる方が実装がシンプルで良い、というときもあった。
しかし、CPUのレジスタに対する操作というのは高速で、メモリに対するアクセスは(相対的に)とても遅い。さらに、ほとんどの関数は引数の数が少ないという経験則がある。そこで、最初のいくつかの引数をレジスタに、それを超過したらスタックに入れるようになっていった。
おわりに
この記事では、標準偏差さんとsksatによる一連のツイートの内容をまとめた。内容は彼らのツイートに基づいているが、この記事の文責はすべて筆者( Sosuke Suzuki )にある。