以任何方式访问 x0 时 opendir 导致崩溃 (ArmV8)

opendir causing crash when accessing x0 in any way (ArmV8)

所以我需要在 arm asm 中编写一个程序,它将打开一个目录并打印出每个条目的 ino_d、d_type 和 d_name 值。我正在使用函数 opendir 来执行此操作。但是,当我 运行 以下代码时(请注意,我不会一次 运行 所有测试,这些只是我尝试在几个单独的 运行 上用 x0 做的事情程序)

ldr x0, =dirname //dirname = ".[=10=]"
bl opendir

// and try this as a test (Bus error)
mov x0, xzr

// or try this as a test (__GI__readdir64)
ldr x0, =output // output = "%-20llu 0x%02x %s\n[=10=]"

// or try this (seg fault)
ldr w1, [x0]

总是有一些错误导致程序崩溃。比如分段错误,或“__GI__readdir64 (dirp=0x1)”错误,或总线错误。

有谁知道(或者可以告诉我去哪里解决这个问题)发生了什么事?

更新: 我要 运行 这个程序,我用 gcc 编译它,然后 运行 使用 qemu-system-aarch64 在 aarch64 虚拟机下 运行 安装它。

// command in terminal
gcc -g -o "main.s" "main.out"
./main.out

完整的代码,以防它可以帮助任何有更多上下文的人

    .global main
    .align 2
    .extern printf
    .extern strcpy
    .extern opendir
    .extern closedir
    .extern readdir
    .extern perror
    .extern __errno_location
    .text

    .equ _ino_d, 0
    .equ _off_d, 8
    .equ _d_reclen, 16
    .equ _d_type, 18
    .equ _d_name, 19

main:
    stp x29, x30, [sp, -16]!
    stp x20, x21, [sp, -16]!
    
    mov w20, w0
    mov x21, x1

    cmp w20, 1
    beq 2f

    // set dirname to passed in arg if any was given from the command line
    1:
        // I don't know how to do the equivelent of
        // dirname = argv[1]
        // so I'm copying argv[1] into dirname
       ldr x0, =dirname
       ldr x1, [x21, 8]
       bl strcpy

    // point to jump to if no args were passed in  
    2:

        // this is the part of the code the bug is originating in
        ldr x0, =dirname
        bl opendir
        ldr x0, =output
        // this is the part of the code the bug is originating in

        printLoop:
            // load de with proper dirent struct
            mov x0, x20
            bl readdir

            cbz x0, errCheck
            
            // loads the format text and d_ino member
            mov x7, x0
            ldr x0, =output
            ldr x1, [x7]

            // loads the d_typ member
            add x7, x7, _d_type
            ldrb w2, [x7]

            // loads the dname member
            add x7, x7, #1
            ldrb w3, [x7]

            bl printf

            b printLoop
        
        errCheck:
            // prints out an error message if something went wrong with reading the directory
            bl __errno_location
            ldr w1, [x0]

            cbz w1, closeDir
            ldr x0, =errmsg
            bl perror

        closeDir:
            mov x0, x20
            bl closedir

            // checks if errno was 0 or not. and stores 1 in retval if errno wasn't 0
            bl __errno_location
            ldr w1, [x0]

            cbz w1, retIsZero
            mov w1, #1

            str w1, [x0]
            b 5f
            retIsZero:
                str xzr, [x0]

        b 5f
    4:
        // prints error message if error occured
        ldr x0, =dirname
        bl perror

    5:
        // cleanup and return retval
        ldp x20, x21, [sp], 16
        ldp x29, x30, [sp], 16
        ldr x0, =ret_val
        ldr w0, [x0]
        ret

    .data

output:         .asciz "%-20llu 0x%02x %s\n"
test_output:    .asciz "%d\n"
dirname:        .asciz "."
errmsg:         .asciz "readdir() failed"
ret_val: .word 1

    .end

更新:当运行将代码置于gdb之外,并且只是打印出来以跟踪程序在导致错误之前的位置时,似乎下面的代码部分是问题

printLoop:
            // load de with proper dirent struct
            mov x0, x20
            bl readdir
            // seems I'm calling readdir wrongly or something 
            // involving readdir

update:看来我出现奇怪错误的原因是因为在调用 opendir 之后,null 存储在 x0 中。当我用 null 调用 readdir 时,它会导致崩溃

我发现我做错了什么。我没有从 opendir 保存目录数据(将指针放在 x0 中),然后我调用了 readdir(然后将 dirent 放在 x0 中)。由于我没有备份 DIR* 形式的 opendir,它导致了崩溃