06 April 2012

拡張インラインアセンブラ、けっこう難しくてなかなか覚えられません。。

GCC Inline Assembler というサイトを見ながら、もう一回勉強してみた。

基本的に

asm( アセンブリテンプレート : 出力オペランド : 入力オペランド : 破壊レジスタ);

というフォーマットでいいのですが、「出力オペランド」と「入力オペランド」はわかるとして、 「破壊レジスタ」というのがいまいちピンときません。

そこで、「破壊レジスタ」を指定するのとしないのとで、どのような違いが出るのか、 ARM gcc の逆アセを見ながら勉強してみた。

まずは、普通に(拡張でない)インラインアセンブラを書いた場合

int hoge()
{
        register int a = 10, b = 20;
        asm("mov r4, #100");
        return a + b;
}

をコンパイルすると

<hoge>:
    push {r4, r5, fp}
    add fp, sp, #8
    mov r5, #10
    mov r4, #20
    mov r4, #100 ; 0x64
    add r3, r5, r4
    mov r0, r3
    sub sp, fp, #8
    pop {r4, r5, fp}
    bx lr

となった。

コンパイラは前後関係を考慮することなく、単に mov r4, #100 を挿入するだけなので、 30 ではなく、 110 を返すコードが生成された。 (変数 br4 に取られているためだが、これは事前に予測不能である。)

そこで拡張インラインアセンブラを使って、 r4 が破壊されることを指定する。

int hoge()
{
        register int a = 10, b = 20;
        asm("mov r4, #100" : : : "r4");
        return a + b;
}

<hoge>:
    push {r4, r5, r6, fp}
    add fp, sp, #12
    mov r6, #10
    mov r5, #20
    mov r4, #100 ; 0x64
    add r3, r6, r5
    mov r0, r3
    sub sp, fp, #12
    pop {r4, r5, r6, fp}
    bx lr

なるほど、 r4 を避けて、 変数 a, br6, r5 に割り当てています。 しかもちゃんと r4 をスタックに退避してくれています。

ではコンパイラを困らせてやれと思って、

int hoge()
{
        register int a = 10, b = 20;
        asm("mov r4, #100" : : : "r4", "r5", "r6", "r7", "r8", "r9", "r10");
        return a + b;
}

とすると、

<hoge>:
    push {r4, r5, r6, r7, r8, r9, sl, fp}
    add fp, sp, #28
    sub sp, sp, #8
    mov r1, #10
    str r1, [fp, #-32] ; 0xffffffe0
    mov r2, #20
    str r2, [fp, #-36] ; 0xffffffdc
    mov r4, #100 ; 0x64
    ldr r1, [fp, #-32] ; 0xffffffe0
    ldr r2, [fp, #-36] ; 0xffffffdc
    add r3, r1, r2
    mov r0, r3
    sub sp, fp, #28
    pop {r4, r5, r6, r7, r8, r9, sl, fp}
    bx lr

となった。

レジスタ変数をとれなくなって、変数 a, b はスタックに確保している。

ただし、破壊レジスタに r11 を指定すると

error: fp cannot be used in asm here

というエラーが出る。

一応、以下のようにほとんど破壊レジスタリストに指定しても、つじつまの合うように動くようです。

int hoge()
{
        register int a = 10, b = 20;
        asm("mov r13, #0x81000000" : : :
            "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
            "r8", "r9", "r10", "r12", "r13", "r14");

    return piyo(a, b);
}

をコンパイルすると、

<hoge>:
    push {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    add fp, sp, #32
    sub sp, sp, #12
    mov r3, #10
    str r3, [fp, #-40] ; 0xffffffd8
    mov r3, #20
    str r3, [fp, #-44] ; 0xffffffd4
    mov sp, #-2130706432 ; 0x81000000
    ldr r0, [fp, #-40] ; 0xffffffd8
    ldr r1, [fp, #-44] ; 0xffffffd4
    bl <piyo>
    mov r3, r0
    mov r0, r3
    sub sp, fp, #32
    pop {r4, r5, r6, r7, r8, r9, sl, fp, pc}


blog comments powered by Disqus