I'm working on a small programming language compiled using cranelift. Now, my generated code segfaults whenever I call malloc
or even puts
. I'll focus on a small example with malloc
:
The code I'm trying to compile is roughly equivalent to the following pseudo-C program:
void _start(){
malloc(8);
exit(0);
return;
}
Note that I'm not actually compiling C and therefore using the _start
entrypoint, like you would in assembler, instead of Cs main
.
The generated Cranelift IR:
function u0:0() system_v {
sig0 = (i64) -> i64 system_v # malloc
sig1 = (i32) system_v # exit
fn0 = u0:0 sig0
# fn1 is not defined for some reason?
block0:
v0 = iconst.i64 8
v1 = call fn0(v0) ; v0 = 8
v2 = iconst.i32 0
call fn1(v2) ; v2 = 0
return
}
Which is compiled to an object file which I link using
ld -pie -O2 --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -o test -lc test.o
I tried omitting the -pie
and -O2
with no effect. The default link interpreter is /lib/ld64
for some reason which does not produce a valid executable on my system.
This Cranelift IR is equvalent to the following assembly:
Dissassembled using objdump -d test.o
:
<other functions omitted>
00000000000010f0 <_start>:
10f0: 55 push %rbp
10f1: 48 89 e5 mov %rsp,%rbp
10f4: bf 08 00 00 00 mov $0x8,%edi
10f9: 48 8b 15 f0 1e 00 00 mov 0x1ef0(%rip),%rdx # 2ff0 <malloc@GLIBC_2.2.5>
1100: ff d2 call *%rdx
1102: 31 ff xor %edi,%edi
1104: 48 8b 15 ed 1e 00 00 mov 0x1eed(%rip),%rdx # 2ff8 <exit@GLIBC_2.2.5>
110b: ff d2 call *%rdx
110d: 48 89 ec mov %rbp,%rsp
1110: 5d pop %rbp
1111: c3 ret
Dissassembled using Cranelift itself:
pushq %rbp
unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
movq %rsp, %rbp
unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
block0:
movl $8, %edi
load_ext_name userextname0+0, %rdx
call *%rdx
xorl %edi, %edi, %edi
load_ext_name userextname1+0, %rdx
call *%rdx
movq %rbp, %rsp
popq %rbp
ret
A GDB-Stacktrace of the segfault:
(gdb) backtrace
#0 0x00007ffff7ca4540 in _int_malloc (av=av@entry=0x7ffff7e19c80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4375
#1 0x00007ffff7ca4a49 in tcache_init () at ./malloc/malloc.c:3245
#2 0x00007ffff7ca525e in tcache_init () at ./malloc/malloc.c:3241
#3 __GI___libc_malloc (bytes=8) at ./malloc/malloc.c:3306
#4 0x0000555555555102 in _start ()
Used Cranelift Options:
use_colocated_libcalls: "false"
is_pic: "true"
opt_level: "speed"
regalloc_checker: "true"
enable_alias_analysis: "true"
enable_verifier: "true"
enable_probestack: "false"
I can update the question with strace
and valgrind
output if needed. I'm on Ubuntu 22.04 x64 using Cranelift 0.93.1
(using cranelift-object
for emitting the obj-file).