2012-10-17 9 views
8

次の問題が発生しました。以下のコードは、コードが単なる一例として提供され、あなたがそれを実行したときにセグメンテーションフォールトうMac OS X Lion(memcpyおよびSSE組み込み関数)のOpenMPでコンパイルが失敗する

#include <stdlib.h> 
#include <string.h> 
#include <emmintrin.h> 

int main(int argc, char *argv[]) 
{ 
    char *temp; 
#pragma omp parallel 
    { 
    __m128d v_a, v_ar; 
    memcpy(temp, argv[0], 10); 
    v_ar = _mm_shuffle_pd(v_a, v_a, _MM_SHUFFLE2 (0,1)); 
    } 
} 

私が試したすべてのXcodeの(4.4、4.5)でのMac OS X上でリンクしません。要点はコンパイルされないことです。コンパイルはないgcc-fopenmpフラグを使用している場合

/Applications/Xcode.app/Contents/Developer/usr/bin/gcc test.c -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -mmacosx-version-min=10.7 -fopenmp 

Undefined symbols for architecture x86_64: 
"___builtin_ia32_shufpd", referenced from: 
    _main.omp_fn.0 in ccJM7RAw.o 
"___builtin_object_size", referenced from: 
    _main.omp_fn.0 in ccJM7RAw.o 
ld: symbol(s) not found for architecture x86_64 
collect2: ld returned 1 exit status 

コードがうまくコンパイル次の行を使用して行われます。今、私は周りを見つけて、に接続された最初の問題の解決策を見つけました。これは​​または-D_FORTIFY_SOURCE=0からgccの引数リストを追加しています。私は第2の問題(sse intrinsic)を解決することはできませんでした。

誰でもこの問題を解決する手助けはできますか?質問:最も重要な

  • : "___builtin_ia32_shufpd" エラーを取り除くためにどのように
  • memcpyの問題の原因は何か、最終的には-D_FORTIFY_SOURCE=0のフラグは何ですか?
+0

は、-fopenmp -O1(またはそれ以上、-O0ではなく、 '___ gxx_personality_v0'が見つからないというリンカエラー)を使用すると、私にとってうまくコンパイルできます(OSX10.8.2、Xcode 4.5、macports gcc 4.7.1)。しかし、コードは実行時にsegfaultを生成します。 -fopenmpを指定せずにコンパイルすると、-Oはコンパイルされますが、segfaults(-O0:バスエラーは例外です)。 – Walter

+0

@Walterありがとうございます。 segfaultは問題ではなく、コードは単なる例に過ぎず、もちろん間違っています。あなたはgcc 4.7.1を使用していますので、Xcodeコンパイラではありません。私が与えたコマンドラインでコンパイルできますか?最適化レベルの変更はここでは役に立たなかった。 – angainor

+1

これは、Xcodeが提供する 'llvm-gcc'コンパイラのバグです。これはGCCフロントエンドを持つLLVMコンパイラです。 OpenMP段階では、バックエンドが認識できない組み込み関数が生成されています。 XcodeはGCCを 'clang'に完全に置き換えるように着実に進んでいるので、バグは決して解決されないでしょう。実際のGCCをソースか他の方法でインストールしてOpenMPコードをコンパイルするだけです。 –

答えて

15

これは、AppleのLLVM対応GCC(llvm-gcc)がOpenMP領域を変換し、その内部の組み込み関数への呼び出しを処理する方法のバグです。この問題は、中間ツリーダンプを調べることで診断できます(引数に-fdump-tree-all引数を渡すことで取得できます)。 OpenMPのがなければ、次の最終的なコードの表現は(test.c.016t.fapから)生成された有効:

main (argc, argv) 
{ 
    D.6544 = __builtin_object_size (temp, 0); 
    D.6545 = __builtin_object_size (temp, 0); 
    D.6547 = __builtin___memcpy_chk (temp, D.6546, 10, D.6545); 
    D.6550 = __builtin_ia32_shufpd (v_a, v_a, 1); 
} 

これは、コンパイラがすべての変換後、内部のコードを見ているかのCのような表現です。これがアセンブリ命令に変換されます。 のOpenMPで

は、並列領域は、自身の機能にmain.omp_fn.0抽出する有効(ビルトインを参照する行のみがここに示されている):再び

main.omp_fn.0 (.omp_data_i) 
{ 
    void * (*<T4f6>) (void *, const <unnamed type> *, long unsigned int, long unsigned int) __builtin___memcpy_chk.21; 
    long unsigned int (*<T4f5>) (const <unnamed type> *, int) __builtin_object_size.20; 
    vector double (*<T6b5>) (vector double, vector double, int) __builtin_ia32_shufpd.23; 
    long unsigned int (*<T4f5>) (const <unnamed type> *, int) __builtin_object_size.19; 

    __builtin_object_size.19 = __builtin_object_size; 
    D.6587 = __builtin_object_size.19 (D.6603, 0); 
    __builtin_ia32_shufpd.23 = __builtin_ia32_shufpd; 
    D.6593 = __builtin_ia32_shufpd.23 (v_a, v_a, 1); 
    __builtin_object_size.20 = __builtin_object_size; 
    D.6588 = __builtin_object_size.20 (D.6605, 0); 
    __builtin___memcpy_chk.21 = __builtin___memcpy_chk; 
    D.6590 = __builtin___memcpy_chk.21 (D.6609, D.6589, 10, D.6588); 
} 

私はコードのみを残していること組み込み関数を指します。明らかなことは(しかし、それはすぐにわかりません)というのは、OpenMPコードtrasnformerが実際には、がすべての組み込み関数を関数ポインタで呼び出すことを主張しているからです。これらのポインタasignments:

実際にはシンボルではなくむしろコンパイラによって特別な扱いを受ける名前のシンボルへの外部参照を生成します。リンカーは、それらを解決しようとしますが、コードがリンクされているオブジェクトファイルのいずれかにある__builtin_*の名前を見つけることはできません。と、1つの%xmm0%eax二XMM引数の整数と%xmm1:これは基本的に3つの引数を取る関数呼び出しがある

LBB2_1: 
    movapd -48(%rbp), %xmm0 
    movl $1, %eax 
    movaps %xmm0, -80(%rbp) 
    movaps -80(%rbp), %xmm1 
    movl %eax, %edi 
    callq ___builtin_ia32_shufpd 
    movapd %xmm0, -32(%rbp) 

:これはまた、一つ-Sgccに通過させることによって得ることができるアセンブリコードで観察されますその結果は%xmm0に返されます(SysV AMD64 ABI関数呼び出し規約に従って)。起こることになっているよう対照的に、-fopenmpせずに生成されたコードは、固有の命令レベルの展開は次のとおりです。

LBB1_3: 
    movapd -64(%rbp), %xmm0 
    shufpd $1, %xmm0, %xmm0 
    movapd %xmm0, -80(%rbp) 

何が-D_FORTIFY_SOURCE=0memcpyは「強化」、バージョンチェックに置き換えされていないということである渡すときに発生代わりにmemcpyへの通常の呼び出しが使用されます。これにより、object_sizeおよび__memcpy_chkへの参照は削除されますが、ia32_shufpdビルトインへのコールは削除できません。

これは明らかにコンパイラのバグです。

void func(char *temp, char *argv0) 
{ 
    __m128d v_a, v_ar; 
    memcpy(temp, argv0, 10); 
    v_ar = _mm_shuffle_pd(v_a, v_a, _MM_SHUFFLE2 (0,1)); 
} 

int main(int argc, char *argv[]) 
{ 
    char *temp; 
#pragma omp parallel 
    { 
    func(temp, argv[0]); 
    } 
} 

:あなたは本当に、本当に、本当にコードをコンパイルするために、AppleのGCCを使用しなければならない場合は、暫定的な解決策は、バグが明らかにのみparallelた領域から抽出された取得するコードに影響を与える外部関数に問題のコードを移動することです1つの追加の関数呼び出しのオーバーヘッドは、parallel領域への出入りのオーバーヘッドに比べて無視できません。 funcの中でOpenMPプラグマを使うことができます - parallel領域の動的スコープのために動作します。

将来的にAppleが固定コンパイラを提供するかもしれないが、GCCをClangに置き換えるコミットメントを考えれば、そうでないかもしれない。

+0

これはうまくいかないことを徹底的に説明していただきありがとうございます;)私は 'Xcode'をあきらめ、以前にWalterが述べたように、macports gcc 4.7をインストールしました。問題なく動作しました。唯一の厄介なのは、macportsを使うためには、Xcode **と**コマンドラインツールをインストールする必要があり、上に新しい一連のコンパイラがあることです。ちょうどうわー。 – angainor

関連する問題