【问题标题】:Why Does Printf Work Only When I Store and Load These Registers? aarch64为什么 Printf 只有在我存储和加载这些寄存器时才能工作? aarch64
【发布时间】:2021-11-03 00:23:38
【问题描述】:

我正在尝试打印数组中的所有双字。但是,执行“Segmentation fault”时出错。在尝试了这么多东西之后,我终于通过存储和加载寄存器 x8、x9 和 x10 使它工作(我测试了许多寄存器并不断消除寄存器,直到程序与这三个一起工作,我不能错过其中一个)。

我不知道为什么我什至需要存储和加载这些寄存器,printf 不应该这样做吗?为什么 printf 甚至会弄乱这些寄存器?我很困惑,因为参数和返回寄存器是 x0-x7。如果 printf 使用其他寄存器,它应该存储和加载。

这是我的代码。 (这是armv8 aarch64)

.text
    .equ ELEM, 10
    .extern printf
    .global _start
_start:
    .global selec_start
selec_start:
    ldr x0, =stack
    mov sp, x0
    sub sp, sp, #16

    ldr x8, =vec    // address of vec (first element)

    mov x9, #ELEM   // index of last element in vec
    sub x9, x9, #1

    mov x10, #0     // increment i
print:
    cmp x10, x9     // compare i with index of last element in vec
    bgt end         // branch to end if we hit end of loop

    lsl x11, x10, #3    // multiply i by 8
    add x12, x8, x11    // x12 = address of vec + i*8
    // x12 is address of index i in vec

    str x8, [sp, #-8]!
    str x9, [sp, #-8]!
    str x10, [sp, #-8]!

    ldr x0, =string
    ldr x1, [x12]
    bl printf

    ldr x10, [sp], #8
    ldr x9, [sp], #8
    ldr x8, [sp], #8

    add x10, x10, #1    // i++
    b print
end:
  mov w8, #93
  svc #0

    .data
string:
    .ascii "%d\n\0"
vec:
    .quad 1,2,3,4,5,6,7,8,9,10
    .bss
    .align 8
    .space 4096
stack:
    .space 16
.end

【问题讨论】:

    标签: assembly arm64 armv8


    【解决方案1】:

    x8、x9、x10都是AARCH64上的caller-save寄存器,所以如果你关心其中的值,你需要在任何函数调用(比如printf)周围保存和恢复它们,作为被调用函数可能会破坏他们。

    只有 x19-x29 和 x31 (sp) 是被调用者保存的,并且将(必须)被任何函数调用保存。

    【讨论】:

    • 谢谢!我改成 x19-x29 就成功了!
    • 术语注释:我发现"call-clobbered" vs. "call-preserved" 更清晰,更容易思考(从没有心理体操的任何一个角度来看,当我调用函数时regs 会发生什么,或者我必须对调用者的regs。)也没有错误地暗示每个寄存器实际上在某处保存/恢复。
    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    相关资源
    最近更新 更多