Skip to content

Instantly share code, notes, and snippets.

@wbrown
Last active December 28, 2015 00:59
Show Gist options
  • Save wbrown/7417466 to your computer and use it in GitHub Desktop.
Save wbrown/7417466 to your computer and use it in GitHub Desktop.
This LLVM IR shows the logic that is used to store function pointers in a global heap, which is then retrieved and cast as a function to be executed. It crashes right when it tries to execute the pointer.
; constants to help with multiplatform stuff
%pntr = type i64*
%cell = type i64
; for ease of debugging, allows us to print a value to stdout
@valueString = internal constant [7 x i8] c"%llu\0D\0A\00"
declare i32 @printf(i8*, ... )
define void @printValue32(i32 %value) {
%string = getelementptr [7 x i8]* @valueString, i32 0, i32 0
%printf_ret = call i32 (i8*, ... )* @printf(i8* %string, i32 %value)
ret void
}
define void @printValue64(i64 %value) {
%string = getelementptr [7 x i8]* @valueString, i32 0, i32 0
%printf_ret = call i32 (i8*, ... )* @printf(i8* %string, %cell %value)
ret void
}
define void @printValueCell(%cell %value) {
%string = getelementptr [7 x i8]* @valueString, i32 0, i32 0
%printf_ret = call i32 (i8*, ... )* @printf(i8* %string, %cell %value)
ret void
}
; in the program, we use a global pointer
@heapPtr = weak global %pntr null
; given an index value, get a pointer to the heap value at that index
define %pntr @getHeap_ptr(%cell %index) {
; load our heap pointer, which is stored as a pointer
%heapPtr = load %pntr* @heapPtr
; retrieve and return our value pointer
%valuePtr = getelementptr %pntr %heapPtr, %cell %index
ret %pntr %valuePtr
}
; given an index and value, place the value at the heap
define void @putHeap(%cell %index, %cell %value) {
%valuePtr = call %pntr @getHeap_ptr(%cell %index)
store %cell %value, %pntr %valuePtr
ret void
}
; given an index and value, get the value from the index on the heap
define %cell @getHeap(%cell %index) {
%valuePtr = call %pntr @getHeap_ptr(%cell %index)
%value = load %pntr %valuePtr
ret %cell %value
}
; given a function and an index, insert the pointer cast
; as an int into the heap at the index
define void @insertFunction(%cell %index, void ()* %fn) {
%insPtr = call %pntr @getHeap_ptr(%cell %index)
%fnPtrInt32 = ptrtoint void ()* %fn to i32
%fnPtrInt64 = ptrtoint void ()* %fn to i64
%fnPtrIntCell = ptrtoint void ()* %fn to %cell
call void @putHeap(%cell %index, %cell %fnPtrIntCell)
; print our 32-bit pointer as integer
call void @printValue32(i32 %fnPtrInt32)
; print the 64-bit integer to see if it's a different
; value
call void @printValue64(i64 %fnPtrInt64)
ret void
}
; given an index, load the int stored at the heap,
; convert it to a pointer and execute it
define void @executeFunction(%cell %index) {
%functionPtrInt = call %cell @getHeap(%cell %index)
; print our retrieved pointer before we go on
call void @printValueCell(%cell %functionPtrInt)
; cast our int as a function pointer and then call it,
; this is where it crashes
%functionPtr = inttoptr %cell %functionPtrInt to void ()*
call void %functionPtr()
ret void
}
define void @testFn() {
call void @printValueCell(%cell 11111111111)
ret void
}
define %cell @main() {
; allocate our heap
%heapPtr = alloca %cell, %cell 1024
; store the pointer to our heap in a global value
store %pntr %heapPtr, %pntr* @heapPtr
; place our function onto the heap
call void @insertFunction(%cell 0, void ()* @testFn)
; call our function on the heapPtr
call void @executeFunction(%cell 0)
ret %cell 0
}
@wbrown
Copy link
Author

wbrown commented Nov 11, 2013

Looking at the assembly generated:

_executeFunction:                       ## @executeFunction
    .cfi_startproc
## BB#0:
    pushq   %rax
Ltmp17:
    .cfi_def_cfa_offset 16
    callq   _getHeap_i32
    movl    %eax, %eax
    callq   *%rax
    popq    %rax
    ret
    .cfi_endproc

    .globl  _testFn
    .align  4, 0x90

@wbrown
Copy link
Author

wbrown commented Nov 11, 2013

Second revision corrected this -- it was a 64bit vs 32bit issue with pointers.

@wbrown
Copy link
Author

wbrown commented Nov 11, 2013

Third revision abstracts out the type to %cell and %pointer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment