質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

インライン展開される関数内でインラインアセンブラを使う方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,023

下記のような、最適化によってインライン展開されるような関数内で、ラベルを含むインラインアセンブラを使うと、コンパイル時にラベル重複でエラーとなってしまいます。

#include <stdio.h>

static int func(){
    __asm__("xxx:");
    return 0;
}

int main(){
    printf("%d\n", func());
    printf("%d\n", func());
    return 0;
}
$ gcc -O1 hoge.c -o hoge   # 少しでも最適化するとエラーになる
hoge.c: Assembler messages:
hoge.c:4: Error: symbol `xxx' is already defined
$ gcc -O0 hoge.c -o hoge   # -O0だとコンパイルできる
$


最適化を-O0にしたり、関数func()を別の翻訳単位に移動してリンクしたりする以外に、これを回避する方法ってあるのでしょうか?
x64のLinuxと、GCC 4.9, 5.2で試しています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+6

こんにちは。

noinlineアトリビュートを付けるとインライン展開されなくなるようです。

#include <stdio.h>

__attribute__((noinline))
static int func(){
    __asm__("xxx:");
    return 0;
}

int main(){
    printf("%d\n", func());
    printf("%d\n", func());
    return 0;
}

【追記】
インラインのまま通すためには、ラベルをユニークにする方法があれば良さそうですね。
そこで、「インラインアセンブラ ラベル」でググったら、ここがでました。
なんでも、ラベル名の後ろに"%="を付けると連番が追加されるとか。でも、ダメでした。

上記の回答者がリンクしているここをよく見ると、'%='と書かれてます!!
で、下記でうまくいくようです。

static int func(){
    __asm__("xxx'%=':");
    return 0;
}

アセンブラ出力をみると、両方ともxxx'%=':と出力されていますが、ビルドに通るのでアセンブルされる段階で連番に置き換わるのではないかと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/17 17:54

    コンパイル通りました~
    ありがとうございます。

    ただ、もしインライン展開するけど、エラーを出さない方法とかあれば興味がありますので、引き続きご回答を募集いたします。

    キャンセル

  • 2016/02/17 21:23

    なるほど。ちょっと思い立ったのでググッてみたらできました。
    回答に追記します。

    キャンセル

+2

使われているアセンブラがどれかわからないのですが、
気の利いたアセンブラなら、テンポラリラベルとか、特殊ローカルラベルがあったりするのですが
見当たりませんか?

例えば gas 系だと 0: ~ 9: がローカルラベルになってたりすることが多いんですけど・・・

ex)
1:        jra 1f ; フォワード方向にある1:
2:        jra 1b ; バック方向にある1:
1:        jra 2f ; フォワード方向にある2:
2:        jra 1b ; バック方向にある1:

こんな感じのありませんでしたか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/17 20:35 編集

    この場合は、ラベルそのものをインラインアセンブラとして定義しているので、__asm__("xxx:");を変更するのはまずいかと・・・数字だけのラベル(e.g. 123:)はOKですね。

    キャンセル

  • 2016/02/18 12:35

    ありがとうございます。
    数字だけラベルだと確かにコンパイル通りました。
    セマンティクス的に若干気持ち悪いですが、インラインアセンブラはどうしても特定の命令を局所的に使うため以外には使う気は無いので、なんとかなりそうです。

    キャンセル

+1

面白かったのでアセンブラソースを出してみましたd^^

~/test/ctst >cat *.s
        .file   "tst02.c"
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%d\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB2:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
#APP
# 4 "tst02.c" 1
        xxx:
# 0 "" 2
#NO_APP
        movl    $0, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
#APP
# 4 "tst02.c" 1
        xxx:
# 0 "" 2
#NO_APP
        movl    $0, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        addq    $8, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE2:
        .size   main, .-main
        .ident  "GCC: (FreeBSD Ports Collection) 4.9.4 20160203 (prerelease)"
        .section        .note.GNU-stack,"",@progbits
~/test/ctst >


・・・2回呼ぶ事で同じラベルが出来てしまうようです。

#include <stdio.h>

static int func(){
    __asm__("xxx:");
    return 0;
}

int main(){
    printf("%d\n", func());
/*    printf("%d\n", func());*/                                                                 
    return 0;
}


これなら通りますv^^

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る