Here https://github.com/vivekvpandya/vivek is my completed code. I am trying run a program with no_std on bare matel x86.
Can someone please explain why following code fails?
#[cfg(not(feature = "std"))]
#[panic_handler]
#[no_mangle]
fn panic_fault(panic_info: &PanicInfo) -> ! {
// This line works as some how it avoids memcpy and hence also avoids `movaps` instruction.
// let msg = alloc::fmt::format(format_args!("{}", panic_info));
// Using following line to get msg causes SEGFAULT due to `movaps` having unaligned memory
// address as operand.
let msg = alloc::format!("{}", panic_info);
unsafe {
libc::write(1, msg.as_ptr() as *const libc::c_void, msg.len());
libc::exit(255);
}
}
}
Based on diff between failing and passing assembly and llvm IR it seems that failing version have movaps instruction (potentially coming from memcpy) and its operand is not 16 byte aligned and hence SEGFAULTs.
but what causes this alignment to go wrong?
Working ASM:
.section .text.rust_begin_unwind,"ax",@progbits
.globl rust_begin_unwind
.p2align 4, 0x90
.type rust_begin_unwind,@function
rust_begin_unwind:
.Lfunc_begin40:
.loc 20 80 0
.cfi_startproc
subq $184, %rsp
.cfi_def_cfa_offset 192
movq %rdi, 32(%rsp)
leaq 32(%rsp), %rcx
movq %rcx, 128(%rsp)
movq %rcx, 152(%rsp)
movq _ZN44_$LT$$RF$T$u20$as$u20$core..fmt..Display$GT$3fmt17h23c9a56a7359af60E@GOTPCREL(%rip), %rax
movq %rax, 160(%rsp)
.Ltmp122:
.file 21 "/home/vivek/.rustup/toolchains/nightly-2023-11-05-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt" "rt.rs"
.loc 21 92 18 prologue_end
movq %rcx, 136(%rsp)
movq %rax, 144(%rsp)
.loc 21 93 6
movq 136(%rsp), %rcx
movq 144(%rsp), %rax
.Ltmp123:
.loc 20 91 43
movq %rcx, 112(%rsp)
movq %rax, 120(%rsp)
leaq .L__unnamed_20(%rip), %rsi
leaq 64(%rsp), %rdi
movq %rdi, 8(%rsp)
leaq 112(%rsp), %rcx
movl $1, %r8d
movq %r8, %rdx
callq _ZN4core3fmt9Arguments6new_v117h02a3f57b21fc54aeE
movq 8(%rsp), %rsi
leaq 40(%rsp), %rdi
movq %rdi, 16(%rsp)
.loc 20 91 19 is_stmt 0
callq _ZN5alloc3fmt6format17h38db669e2255f9dcE
movq 16(%rsp), %rdi
.Ltmp124:
.loc 20 94 24 is_stmt 1
callq _ZN65_$LT$alloc..string..String$u20$as$u20$core..ops..deref..Deref$GT$5deref17hefb84f18c4879aa5E
movq 16(%rsp), %rdi
movq %rax, 24(%rsp)
movq %rax, 168(%rsp)
movq %rdx, 176(%rsp)
.loc 20 94 61 is_stmt 0
callq _ZN5alloc6string6String3len17h149182d849355ba5E
movq 24(%rsp), %rsi
movq %rax, %rdx
.loc 20 94 9
movq write@GOTPCREL(%rip), %rax
movl $1, %edi
callq *%rax
.loc 20 95 9 is_stmt 1
movq exit@GOTPCREL(%rip), %rax
movl $255, %edi
callq *%rax
ud2
.Ltmp125:
.Lfunc_end40:
.size rust_begin_unwind, .Lfunc_end40-rust_begin_unwind
.cfi_endproc
Failing ASM:
.section .text.rust_begin_unwind,"ax",@progbits
.globl rust_begin_unwind
.p2align 4, 0x90
.type rust_begin_unwind,@function
rust_begin_unwind:
.Lfunc_begin40:
.loc 20 80 0
.cfi_startproc
subq $200, %rsp
.cfi_def_cfa_offset 208
movq %rdi, 24(%rsp)
leaq 24(%rsp), %rcx
movq %rcx, 144(%rsp)
movq %rcx, 168(%rsp)
movq _ZN44_$LT$$RF$T$u20$as$u20$core..fmt..Display$GT$3fmt17h23c9a56a7359af60E@GOTPCREL(%rip), %rax
movq %rax, 176(%rsp)
.Ltmp122:
.file 21 "/home/vivek/.rustup/toolchains/nightly-2023-11-05-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt" "rt.rs"
.loc 21 92 18 prologue_end
movq %rcx, 152(%rsp)
movq %rax, 160(%rsp)
.loc 21 93 6
movq 152(%rsp), %rcx
movq 160(%rsp), %rax
.Ltmp123:
.loc 20 92 19
movq %rcx, 128(%rsp)
movq %rax, 136(%rsp)
leaq .L__unnamed_20(%rip), %rsi
leaq 80(%rsp), %rdi
movq %rdi, (%rsp)
leaq 128(%rsp), %rcx
movl $1, %r8d
movq %r8, %rdx
callq _ZN4core3fmt9Arguments6new_v117h02a3f57b21fc54aeE
movq (%rsp), %rsi
leaq 56(%rsp), %rdi
callq _ZN5alloc3fmt6format17h38db669e2255f9dcE
.Ltmp124:
.loc 20 92 19 is_stmt 0
movq 72(%rsp), %rax
movq %rax, 48(%rsp)
movups 56(%rsp), %xmm0
movaps %xmm0, 32(%rsp)
leaq 32(%rsp), %rdi
movq %rdi, 8(%rsp)
.Ltmp125:
.loc 20 94 24 is_stmt 1
callq _ZN65_$LT$alloc..string..String$u20$as$u20$core..ops..deref..Deref$GT$5deref17hefb84f18c4879aa5E
movq 8(%rsp), %rdi
movq %rax, 16(%rsp)
movq %rax, 184(%rsp)
movq %rdx, 192(%rsp)
.loc 20 94 61 is_stmt 0
callq _ZN5alloc6string6String3len17h149182d849355ba5E
movq 16(%rsp), %rsi
movq %rax, %rdx
.loc 20 94 9
movq write@GOTPCREL(%rip), %rax
movl $1, %edi
callq *%rax
.loc 20 95 9 is_stmt 1
movq exit@GOTPCREL(%rip), %rax
movl $255, %edi
callq *%rax
ud2
.Ltmp126:
.Lfunc_end40:
.size rust_begin_unwind, .Lfunc_end40-rust_begin_unwind
.cfi_endproc
Working LLVM IR dump
; Function Attrs: noreturn nounwind nonlazybind
define void @rust_begin_unwind(ptr align 8 %0) unnamed_addr #3 !dbg !1047 {
start:
%self.dbg.spill.i = alloca { ptr, i64 }, align 8
%f.dbg.spill.i = alloca ptr, align 8
%x.dbg.spill.i1 = alloca ptr, align 8
%_0.i = alloca { ptr, ptr }, align 8
%x.dbg.spill.i = alloca ptr, align 8
%_7 = alloca [1 x { ptr, ptr }], align 8
%_3 = alloca %"core::fmt::Arguments<'_>", align 8
%msg = alloca %"alloc::string::String", align 8
%panic_info = alloca ptr, align 8
store ptr %0, ptr %panic_info, align 8
call void @llvm.dbg.declare(metadata ptr %panic_info, metadata !1052, metadata !DIExpression()), !dbg !1055
call void @llvm.dbg.declare(metadata ptr %msg, metadata !1053, metadata !DIExpression()), !dbg !1056
store ptr %panic_info, ptr %x.dbg.spill.i, align 8
call void @llvm.dbg.declare(metadata ptr %x.dbg.spill.i, metadata !1057, metadata !DIExpression()), !dbg !1066
store ptr %panic_info, ptr %x.dbg.spill.i1, align 8
call void @llvm.dbg.declare(metadata ptr %x.dbg.spill.i1, metadata !1068, metadata !DIExpression()), !dbg !1076
store ptr @"_ZN44_$LT$$RF$T$u20$as$u20$core..fmt..Display$GT$3fmt17h23c9a56a7359af60E", ptr %f.dbg.spill.i, align 8
call void @llvm.dbg.declare(metadata ptr %f.dbg.spill.i, metadata !1075, metadata !DIExpression()), !dbg !1078
store ptr %panic_info, ptr %_0.i, align 8, !dbg !1079
%1 = getelementptr inbounds { ptr, ptr }, ptr %_0.i, i32 0, i32 1, !dbg !1079
store ptr @"_ZN44_$LT$$RF$T$u20$as$u20$core..fmt..Display$GT$3fmt17h23c9a56a7359af60E", ptr %1, align 8, !dbg !1079
%2 = load ptr, ptr %_0.i, align 8, !dbg !1080, !nonnull !20, !align !361, !noundef !20
%3 = getelementptr inbounds { ptr, ptr }, ptr %_0.i, i32 0, i32 1, !dbg !1080
%4 = load ptr, ptr %3, align 8, !dbg !1080, !nonnull !20, !noundef !20
%5 = insertvalue { ptr, ptr } poison, ptr %2, 0, !dbg !1080
%6 = insertvalue { ptr, ptr } %5, ptr %4, 1, !dbg !1080
%_0.0.i = extractvalue { ptr, ptr } %6, 0, !dbg !1081
%_0.1.i = extractvalue { ptr, ptr } %6, 1, !dbg !1081
%_8.0 = extractvalue { ptr, ptr } %6, 0, !dbg !1082
%_8.1 = extractvalue { ptr, ptr } %6, 1, !dbg !1082
%7 = getelementptr inbounds [1 x { ptr, ptr }], ptr %_7, i64 0, i64 0, !dbg !1082
%8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0, !dbg !1082
store ptr %_8.0, ptr %8, align 8, !dbg !1082
%9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1, !dbg !1082
store ptr %_8.1, ptr %9, align 8, !dbg !1082
; call core::fmt::Arguments::new_v1
call void @_ZN4core3fmt9Arguments6new_v117h02a3f57b21fc54aeE(ptr sret(%"core::fmt::Arguments<'_>") align 8 %_3, ptr align 8 @alloc_ffa3cdb3ae88e54a1cc225f31dd07672, i64 1, ptr align 8 %_7, i64 1) #10, !dbg !1082
; call alloc::fmt::format
call void @_ZN5alloc3fmt6format17h38db669e2255f9dcE(ptr sret(%"alloc::string::String") align 8 %msg, ptr align 8 %_3) #10, !dbg !1083
; call <alloc::string::String as core::ops::deref::Deref>::deref
%10 = call { ptr, i64 } @"_ZN65_$LT$alloc..string..String$u20$as$u20$core..ops..deref..Deref$GT$5deref17hefb84f18c4879aa5E"(ptr align 8 %msg) #10, !dbg !1084
%_13.0 = extractvalue { ptr, i64 } %10, 0, !dbg !1084
%_13.1 = extractvalue { ptr, i64 } %10, 1, !dbg !1084
store ptr %_13.0, ptr %self.dbg.spill.i, align 8
%11 = getelementptr inbounds { ptr, i64 }, ptr %self.dbg.spill.i, i32 0, i32 1
store i64 %_13.1, ptr %11, align 8
call void @llvm.dbg.declare(metadata ptr %self.dbg.spill.i, metadata !1085, metadata !DIExpression()), !dbg !1090
; call alloc::string::String::len
%_15 = call i64 @_ZN5alloc6string6String3len17h149182d849355ba5E(ptr align 8 %msg) #10, !dbg !1092
%_10 = call i64 @write(i32 1, ptr %_13.0, i64 %_15) #10, !dbg !1093
call void @exit(i32 255) #11, !dbg !1094
unreachable, !dbg !1094
Failing LLVM IR dump
; Function Attrs: noreturn nounwind nonlazybind
define void @rust_begin_unwind(ptr align 8 %panic_info) unnamed_addr #3 !dbg !1004 {
start:
%self.dbg.spill.i = alloca { ptr, i64 }, align 8
%panic_info.dbg.spill = alloca ptr, align 8
%_8 = alloca [0 x { ptr, ptr }], align 8
%_4 = alloca %"core::fmt::Arguments<'_>", align 8
%res = alloca %"alloc::string::String", align 8
%msg = alloca %"alloc::string::String", align 8
store ptr %panic_info, ptr %panic_info.dbg.spill, align 8
call void @llvm.dbg.declare(metadata ptr %panic_info.dbg.spill, metadata !1037, metadata !DIExpression()), !dbg !1044
call void @llvm.dbg.declare(metadata ptr %msg, metadata !1038, metadata !DIExpression()), !dbg !1045
call void @llvm.dbg.declare(metadata ptr %res, metadata !1040, metadata !DIExpression()), !dbg !1046
; call core::fmt::Arguments::new_v1
call void @_ZN4core3fmt9Arguments6new_v117h02a3f57b21fc54aeE(ptr sret(%"core::fmt::Arguments<'_>") align 8 %_4, ptr align 8 @alloc_9bf36e7b09a407a5241fc0624ebc2da7, i64 1, ptr align 8 %_8, i64 0) #10, !dbg !1047
; call alloc::fmt::format
call void @_ZN5alloc3fmt6format17h38db669e2255f9dcE(ptr sret(%"alloc::string::String") align 8 %res, ptr align 8 %_4) #10, !dbg !1047
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %msg, ptr align 8 %res, i64 24, i1 false), !dbg !1046
; call <alloc::string::String as core::ops::deref::Deref>::deref
%0 = call { ptr, i64 } @"_ZN65_$LT$alloc..string..String$u20$as$u20$core..ops..deref..Deref$GT$5deref17hefb84f18c4879aa5E"(ptr align 8 %msg) #10, !dbg !1048
%_12.0 = extractvalue { ptr, i64 } %0, 0, !dbg !1048
%_12.1 = extractvalue { ptr, i64 } %0, 1, !dbg !1048
store ptr %_12.0, ptr %self.dbg.spill.i, align 8
%1 = getelementptr inbounds { ptr, i64 }, ptr %self.dbg.spill.i, i32 0, i32 1
store i64 %_12.1, ptr %1, align 8
call void @llvm.dbg.declare(metadata ptr %self.dbg.spill.i, metadata !1049, metadata !DIExpression()), !dbg !1054
; call alloc::string::String::len
%_14 = call i64 @_ZN5alloc6string6String3len17h149182d849355ba5E(ptr align 8 %msg) #10, !dbg !1056
%_9 = call i64 @write(i32 1, ptr %_12.0, i64 %_14) #10, !dbg !1057
call void @exit(i32 255) #11, !dbg !1058
unreachable, !dbg !1058
}