EABIとOABI


ARMで使われる二つのABI


ARM用のバイナリで使用されるABI(Application Binary Interface)には、OABIとEABIの二つがあります。'O'は'Old'を、'E'は'Embedded'を意味します。EABIは、ARM社のドキュメントでは"the ABI for the ARM Architecture"として記述されます。

DebianではOABIは"arm"、EABIは"armel"として記述します("armeb"というものもありますが、これはBig Endian ARMを表します)。Debian Etchまではarm(OABI)版しかありませんでしたが、Debian Lennyはarmel(EABI)版が提供されるなど徐々にEABIを採用する機会が増えてきています。

本ページでは、OABIとEABIの違いや使用する際の注意点を紹介します。

EABIのメリット

OABIと比較したとき、EABIには以下のようなメリットがあります。

  1. 浮動小数点演算がとても速くなる
  2. 効率的なシステムコール
  3. ソフトフロートとハードフロートのバイナリを混ぜることができる(OABIでは、混ぜることはできませんでした)
  4. OABIのユーザランドプログラムもEABIカーネル上で動作させることができる

参照: http://www.oesf.org/index.php?title=Q3:_What_are_OABI_and_EABI%3F

総じて処理速度が上がるというメリットがある一方で、可搬性は保たれています。いくつかあるEABIのメリットの中で、個人的には浮動小数点演算高速化がEABI採用の一番の理由だと思います。

OABIではデフォルトでハードフロートが使われることが一般的でした。ハードフロートでは、ターゲットのチップが浮動小数点演算ユニットを持っていて、かつ、それが有効になっていれば、高速に浮動小数点演算をおこなうことができます。対して、浮動小数点演算ユニットがないチップで浮動小数点演算をおこなうと、浮動小数点演算命令のたびにFPEによるコンテキストスイッチが行われるため、非常に効率が悪くなります。ARMは組み込み用途に使われることが多いため、浮動小数点演算ユニットを持っていないチップというのも多数存在します。また、チップによっては浮動小数点演算ユニットが載っていても、バグがあって使えないということもあったりします。そのため、OABIでは浮動小数点演算の速度が出ないことが問題になることがありました。

EABIでは浮動小数点演算を含むプログラムをコンパイルしたとき、浮動小数点演算命令をソフトウェアでエミュレーションするライブラリを使用します。そのため、コンテキストスイッチが発生せず、浮動小数点演算が高速におこなわれます。

OABIと比較した場合、EABIの方が10倍以上高速になるという結果も報告されています。

EABIを使用するには

EABIのバイナリを作成するには、EABI用のツールチェイン(gccは4.1以降)を使用してソースコードをコンパイルする必要があります。EABI用のツールチェインのインストール方法は、「ARMクロス開発環境構築」のページを参照してください。

また、EABIのバイナリを実行するには、カーネルがEABI対応していなければなりません。カーネルをEABI対応にするには、カーネルコンフィグレーションでCONFIG_AEBAIを有効にしてEABI対応のツールチェインでカーネルをコンパイルしなおす必要があります。OABIカーネルでEABIのユーザランドアプリケーションプログラムを実行することはできませんが、EABIカーネルでCONFIG_OABI_COMPATが有効になっている場合は、OABIのユーザランドアプリケーションプログラムを実行することができます。ただし、その場合、多少の効率性を犠牲にすることになります。

比較

同じコードをOABIとEABIでコンパイルしてみて、比較してみます。

サンプルコードは以下のものを使用します。逆アセンブルしたときに見やすいように、__attribute__((noinline))で関数がインライン展開されないようにしています。

サンプルコード

#include <stdio.h>

double __attribute__((noinline)) float_mult(double a, double b)
{
    return a * b;
}

int main(int argc, char *argv[])
{
    double d;

    d = float_mult(12.3, 98.7);

    printf("%lf\n", d);

    return 0;
}


OABIとEABIそれぞれでコンパイルします。デバッグ情報を残すために、-gオプションをつけています。

コンパイル(OABI)

$ arm-linux-gnu-gcc (Debian 4.3.2-1.1) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ arm-linux-gnu-gcc -Wall -g sample.c -o oabi


コンパイル(EABI)

$ arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Debian 4.3.2-1.1) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ arm-linux-gnueabi-gcc -Wall -g sample.c -o eabi

objdumpを使用して、逆アセンブルします。-Sオプションを使用して対応するソースコード行も表示するようにしています。

逆アセンブル結果(OABI)

$ arm-linux-gnu-objdump -S oabi
... (中略) ...
double __attribute__((noinline)) float_mult(double a, double b)
{
    84f4:       e1a0c00d        mov     ip, sp
    84f8:       e92dd810        push    {r4, fp, ip, lr, pc}
    84fc:       e24cb004        sub     fp, ip, #4      ; 0x4
    8500:       e24dd010        sub     sp, sp, #16     ; 0x10
    8504:       e50b0018        str     r0, [fp, #-24]
    8508:       e50b1014        str     r1, [fp, #-20]
    850c:       e50b2020        str     r2, [fp, #-32]
    8510:       e50b301c        str     r3, [fp, #-28]
        return a * b;
    8514:       ed1b9106        ldfd    f1, [fp, #-24]
    8518:       ed1b8108        ldfd    f0, [fp, #-32]
    851c:       ee110180        mufd    f0, f1, f0
    8520:       ed2d8102        stfd    f0, [sp, #-8]!
    8524:       e8bd0018        pop     {r3, r4}
}
    8528:       e92d0018        push    {r3, r4}
    852c:       ecbd8102        ldfd    f0, [sp], #8
    8530:       e24bd010        sub     sp, fp, #16     ; 0x10
    8534:       e89da810        ldm     sp, {r4, fp, sp, pc}
... (以下略) ...


OABIでは、float_mult()関数部分で浮動小数点演算(mufd)をおこなっています。

逆アセンブル結果(EABI)

$ arm-linux-gnueabi-objdump -S eabi
... (中略) ...
double __attribute__((noinline)) float_mult(double a, double b)
{
    8460:       e1a0c00d        mov     ip, sp
    8464:       e92dd810        push    {r4, fp, ip, lr, pc}
    8468:       e24cb004        sub     fp, ip, #4      ; 0x4
    846c:       e24dd014        sub     sp, sp, #20     ; 0x14
    8470:       e50b001c        str     r0, [fp, #-28]
    8474:       e50b1018        str     r1, [fp, #-24]
    8478:       e50b2024        str     r2, [fp, #-36]
    847c:       e50b3020        str     r3, [fp, #-32]
        return a * b;
    8480:       e24b001c        sub     r0, fp, #28     ; 0x1c
    8484:       e8900003        ldm     r0, {r0, r1}
    8488:       e24b2024        sub     r2, fp, #36     ; 0x24
    848c:       e892000c        ldm     r2, {r2, r3}
    8490:       eb000024        bl      8528 <__aeabi_dmul>
    8494:       e1a03000        mov     r3, r0
    8498:       e1a04001        mov     r4, r1
}
    849c:       e1a00003        mov     r0, r3
    84a0:       e1a01004        mov     r1, r4
    84a4:       e24bd010        sub     sp, fp, #16     ; 0x10
    84a8:       e89d6810        ldm     sp, {r4, fp, sp, lr}
    84ac:       e12fff1e        bx      lr
... (中略) ...
00008528 <__aeabi_dmul>:
    8528:       e92d4070        push    {r4, r5, r6, lr}
    852c:       e3a0c0ff        mov     ip, #255        ; 0xff
    8530:       e38ccc07        orr     ip, ip, #1792   ; 0x700
    8534:       e01c4a21        ands    r4, ip, r1, lsr #20
    8538:       101c5a23        andsne  r5, ip, r3, lsr #20
    853c:       1134000c        teqne   r4, ip
    8540:       1135000c        teqne   r5, ip
    8544:       0b000075        bleq    8720 <__aeabi_dmul+0x1f8>
    8548:       e0844005        add     r4, r4, r5
    854c:       e0216003        eor     r6, r1, r3
    8550:       e1c11a8c        bic     r1, r1, ip, lsl #21
    8554:       e1c33a8c        bic     r3, r3, ip, lsl #21
    8558:       e1905601        orrs    r5, r0, r1, lsl #12
... (以下略) ...



EABIでは、浮動小数点演算をおこなうのに__aeabi_dmulという関数を呼んでいます。そして、__aeabi_dmulはバイナリの中にスタティックリンクされています。浮動小数点演算ルーチンがユーザランドで実行されるバイナリに含まれたことで、浮動少数点演算ユニットがないチップでもFPE(Floating Point Emulation: カーネルで実行されるためコンテキストスイッチが発生し低速)を使用せずに、浮動少数点演算が行えます。
 
Comments