Why my example segfaults on movaps instruction?

78 Views Asked by At

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
}
0

There are 0 best solutions below