Frage

I'm writing a compiler using LLVM as a backend, I've written the front-end (parser, etc.) and now I've come to a crossroads.

I have a structure (%Primitive) which contains a single field, an i8* value, a pointer to a character array.

%Primitive = type { i8* }

In the compiler, instances of Primitive are passed around on the stack. I'm trying to write this character array to standard output using the puts function, but it isn't working quite like I was hoping.

declare i32 @puts(i8*) ; Declare the libc function 'puts'

define void @WritePrimitive(%Primitive) {
entry:
  %1 = extractvalue %Primitive %0, 0 ; Extract the character array from the primitive.
  %2 = call i32 @puts(i8* %1) ; Write it
  ret void
}

When I try to run the code (either using an ExecutionEngine or the LLVM interpreter program lli), I get the same error; a segmentation fault.

The error lies in the fact that the address passed to puts is somehow the ASCII character code of the first character in the array. It seems the address passed, rather than being a pointer to an array of 8 bit chars, is instead an 8 bit wide pointer that equals the dereferenced string.

For example, if I call @WritePrimitive with a primitive where the i8* member points to the string "hello", puts is called with the string address being 0x68.

Any ideas?

Thanks

EDIT: You were right, I was initializing my Primitive incorrectly, my new initialization function is:

llvm::Value* PrimitiveHelper::getConstantPrimitive(const std::string& str, llvm::BasicBlock* bb)
{
    ConstantInt* int0 = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0);
    Constant* strConstant = ConstantDataArray::getString(getGlobalContext(), str, true);

    GlobalVariable* global = new GlobalVariable(module,
                                                strConstant->getType(),
                                                true, // Constant
                                                GlobalValue::ExternalLinkage,
                                                strConstant,
                                                "str");

    Value* allocated = new AllocaInst(m_primitiveType, "allocated", bb);

    LoadInst* onStack1 = new LoadInst(allocated, "onStack1", bb);

    GetElementPtrInst* ptr = GetElementPtrInst::Create(global, std::vector<Value*>(2,int0), "", bb);

    InsertValueInst* onStack2 = InsertValueInst::Create(onStack1, ptr, std::vector<unsigned>(1, 0), "", bb);

    return onStack2;
}

I missed that, Thank You!

War es hilfreich?

Lösung

There's nothing wrong with the code you pasted above; I just tried it myself and it worked fine. I'm guessing the issue is that you did not initialize the pointer properly, or did not set it properly into the struct.

The full code I used is:

@str = private unnamed_addr constant [13 x i8] c"hello world\0A\00"

; Your code
%Primitive = type { i8* }

declare i32 @puts(i8*) ; Declare the libc function 'puts'

define void @WritePrimitive(%Primitive) {
entry:
  %1 = extractvalue %Primitive %0, 0 ; Extract the character array from the primitive.
  %2 = call i32 @puts(i8* %1) ; Write it
  ret void
}

; /Your code

define void @main() {
  %allocated = alloca %Primitive
  %onstack1 = load %Primitive* %allocated
  %onstack2 = insertvalue %Primitive %onstack1, i8* getelementptr ([13 x i8]* @str, i64 0, i64 0), 0
  call void @WritePrimitive(%Primitive %onstack2)
  ret void
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top