2

私は LLVM を初めて使用し、プロファイリングに LLVM を使用する方法を学んでいます。配列を外部メソッドに渡し、メソッドへの呼び出し命令をコードに挿入する必要があります。現在、次のコードを使用していますが、実行時にセグメンテーション違反が発生します。

std::vector<Value*> Args(1);

//Vector with array values
SmallVector<Constant*, 2> counts;

counts.push_back(ConstantInt::get(Type::getInt32Ty(BB->getContext()),32, false));
                        counts.push_back(ConstantInt::get(Type::getInt32Ty(BB->getContext()),12, false));

//Array with 2 integers
Args[0]= ConstantArray::get(llvm::ArrayType::get(llvm::Type::getInt32Ty(BI->getContext()),2), counts);

ここで、外部関数「hook」は次のように定義されます。M.getOrInsertFunction("hook", Type::getVoidTy(M.getContext()), llvm::ArrayType::get(llvm::Type::getInt32Ty(BI->getContext()),2) (Type*)0);

いくつかのソース ファイルを読んだ後、GetElementPtrInst を使用して配列を渡そうとしました。

std::vector<Value*> ids(1);
ids.push_back(ConstantInt::get(Type::getInt32Ty(BB->getContext()),0));
Constant* array = ConstantArray::get(llvm::ArrayType::get(llvm::Type::getInt32Ty(BI->getContext()),2), counts);
Args[0] = ConstantExpr::getGetElementPtr(&(*array), ids, false);

しかし、それは失敗します

7  opt 0x00000000006c59f5 bool llvm::isa<llvm::Constant, llvm::Value*>(llvm::Value* const&) + 24

8  opt 0x00000000006c5a0f llvm::cast_retty<llvm::Constant, llvm::Value*>::ret_type llvm::cast<llvm::Constant, llvm::Value*>(llvm::Value* const&) + 24

9  opt 0x0000000000b2b22f

10 opt 0x0000000000b2a4fe llvm::ConstantFoldGetElementPtr(llvm::Constant*, bool, llvm::ArrayRef<llvm::Value*>) + 55

11 opt 0x0000000000b33df2 llvm::ConstantExpr::getGetElementPtr(llvm::Constant*, llvm::ArrayRef<llvm::Value*>, bool) + 82

また、この場合、「フック」は次のように定義されます。 M.getOrInsertFunction("hook", Type::getVoidTy(M.getContext()), PointerType::get(Type::getInt32PtrTy(M.getContext()),0), //when using GEP (Type*)0);

配列を外部関数に渡す方法について、誰かが親切に私にいくつかの指針を教えてくれませんか(署名付きで言ってvoid hook(int abc[])ください)。私はおそらくずっと間違っているので、助けていただければ幸いです。

4

2 に答える 2

5

「LLVM IR でこの C のようなことを行うにはどうすればよいか」という質問から始めるのに適した場所は、最初に C でやりたいことを書き、次にClangを介して LLVM IR にコンパイルし、結果を確認することです。

特定のインスタンスでは、ファイル:

void f(int a[2]);

void g() {
    int x[2];
    x[0] = 1;
    x[1] = 3;
    f(x);
}

次のようにコンパイルされます。

define void @g() nounwind {
  %x = alloca [2 x i32], align 4
  %1 = getelementptr inbounds [2 x i32]* %x, i32 0, i32 0
  store i32 1, i32* %1, align 4
  %2 = getelementptr inbounds [2 x i32]* %x, i32 0, i32 1
  store i32 3, i32* %2, align 4
  %3 = getelementptr inbounds [2 x i32]* %x, i32 0, i32 0
  call void @f(i32* %3)
  ret void
}

declare void @f(i32*)

したがって、clang が配列ではなくgreceiveにコンパイルされていることがわかります。i32*つまり、配列自体から配列の最初の要素へのアドレスを取得する方法が必要であり、getelementptr 命令はそれを行う簡単な方法です。

ただし、たとえば を介して GEP (getelementptr 命令) を生成する必要があることに注意してくださいGetElementPtrInst::create。ここで生成しようとしているgep定数式は別のものであり、コンパイル時の定数でのみ機能します。

于 2013-01-29T16:55:05.147 に答える
0

Clang を使用してコンパイルする必要があります。次に、配列の境界を確認し、すべての要素が定義されているかどうかを確認します。

于 2013-01-29T18:35:21.520 に答える