Rustc/LLVM generates faulty code for aarch64 with

2020-04-07 19:07发布

问题:

I have two files which are assembled/compiled/linked into minimalistic kernel.

start.s:

    .set CPACR_EL1_FPEN, 0b11 << 20

    .set BOOT_STACK_SIZE, 8 * 1024

    .global __boot_stack
    .global __start
    .global __halt

    .bss
    .align 16
__boot_stack:
    .fill BOOT_STACK_SIZE

    .text
__start:
    /* disable FP and SIMD traps */
    mov x0, #CPACR_EL1_FPEN
    msr cpacr_el1, x0

    /* set stack */
    adr x0, __boot_stack
    add sp, x0, #BOOT_STACK_SIZE

    /* call the Rust entry point */
    bl __boot

__halt:
    /* halt CPU */
    wfi
    b __halt

boot.rs:

#[no_mangle]
pub extern fn __boot() {
    unsafe {
        let ptr = 0x9000000 as *mut u8;
        *ptr = '!' as u8;
   }
}

For opt-level=3 the resulting code outputs single '!' to a serial port (as was intended). For opt-level=0 I have a strange infinite loop (e.g. '!!!!!!!!!....'). Here is the disassembled dump of the problematic code:

0000000000000000 <__kernel_begin>:
   0:   d2a00600    mov x0, #0x300000               // #3145728
   4:   d5181040    msr cpacr_el1, x0
   8:   100007c0    adr x0, 100 <__boot_stack>
   c:   9140081f    add sp, x0, #0x2, lsl #12
  10:   94000003    bl  1c <__boot>

0000000000000014 <__halt>:
  14:   d503207f    wfi
  18:   17ffffff    b   14 <__halt>

000000000000001c <__boot>:
  1c:   a9bf7bfd    stp x29, x30, [sp,#-16]!
  20:   910003fd    mov x29, sp
  24:   94000003    bl  30 <aarch64::boot::__boot::__rust_abi>
  28:   a8c17bfd    ldp x29, x30, [sp],#16
  2c:   d65f03c0    ret

0000000000000030 <aarch64::boot::__boot::__rust_abi>:
  30:   d10043ff    sub sp, sp, #0x10
  34:   52a12008    mov w8, #0x9000000              // #150994944
  38:   2a0803e9    mov w9, w8
  3c:   f90007e9    str x9, [sp,#8]
  40:   52800428    mov w8, #0x21                   // #33
  44:   39000128    strb    w8, [x9]
  48:   910043ff    add sp, sp, #0x10
  4c:   d65f03c0    ret

The code is tested using qemu-system-aarch64. I don't see serious problems with it (except redundancy). Can you suggest a possible cause of such abnormal behaviour?

P.S. This is the optimised version which works properly:

0000000000000000 <__kernel_begin>:
   0:   d2a00600    mov x0, #0x300000               // #3145728
   4:   d5181040    msr cpacr_el1, x0
   8:   1007ffc0    adr x0, 10000 <__boot_stack>
   c:   9140081f    add sp, x0, #0x2, lsl #12
  10:   94000003    bl  1c <__boot>

0000000000000014 <__halt>:
  14:   d503207f    wfi
  18:   17ffffff    b   14 <__halt>

000000000000001c <__boot>:
  1c:   52a12008    mov w8, #0x9000000              // #150994944
  20:   52800429    mov w9, #0x21                   // #33
  24:   39000109    strb    w9, [x8]
  28:   d65f03c0    ret

回答1:

I've succeeded to run the non-optimised code without abnormalities. Thanks to Notlikethat for the idea. My stack was just mapped into readonly memory.

So I've just added the offset statement into my linker script (". = 1024M;") in order to make all the symbols to start from 1GiB (where RAM begins). After this modification the code started to work properly.