代码之家  ›  专栏  ›  技术社区  ›  dyukha

将被调用方保存的寄存器结果保存到分段错误[重复]

  •  1
  • dyukha  · 技术社区  · 6 年前

            .global main
            .text
    main:
            mov     $format, %rdi
            mov     $5, %rsi
            mov     $0, %rax
            call    printf
            ret
    format:
            .asciz  "%10d\n"
    

    这张照片按预期印了5张。

    但现在如果我做一个小的更改,并尝试打印一个浮点值:

            .global main
            .text
    main:
            mov     $format, %rdi
            movsd   x, %xmm0
            mov     $1, %rax
            call    printf
            ret
    format:
            .asciz  "%10.4f\n"
    x:
            .double 15.5
    

    此程序seg故障 不打印任何东西

    但是我可以通过推和跳来解决这个问题 %rbp

            .global main
            .text
    main:
            push    %rbp
            mov     $format, %rdi
            movsd   x, %xmm0
            mov     $1, %rax
            call    printf
            pop     %rbp
            ret
    format:
            .asciz  "%10.4f\n"
    x:
            .double 15.5
    

    现在它工作了,打印了15.5000张。

    我的问题是:为什么推搡 %苏格兰皇家银行 %苏格兰皇家银行 必须 保存,等等 printf 不能搞砸了。事实上, 打印 在第一个程序中工作,只有一个整数被传递给 打印

    0 回复  |  直到 12 年前
        1
  •  10
  •   Peter Cordes    7 年前

    我想这个问题和 %rbp ,但与堆栈对齐有关。引用ABI:

    参数区域(%rbp+16)必须是16的倍数。这个要求意味着框架 大小应填充为16字节的倍数。

    main() . 打电话 printf() 将返回地址推送到堆栈上,将堆栈指针移动8个字节。通过将另一个8字节推送到堆栈(碰巧是 %苏格兰皇家银行

    这是密码 gcc 生成(也 on the Godbolt compiler explorer

    .LC1:
            .ascii "%10.4f\12\0"
    main:
            leaq    .LC1(%rip), %rdi   # format string address
            subq    $8, %rsp           ### align the stack by 16 before a CALL
            movl    $1, %eax           ### 1 FP arg being passed in a register to a variadic function
            movsd   .LC0(%rip), %xmm0  # load the double itself
            call    printf
            xorl    %eax, %eax         # return 0 from main
            addq    $8, %rsp
            ret
    

    如您所见,它通过从 %rsp 开始的时候,最后再加回来。

    相反,你可以对你喜欢的寄存器做一个虚拟的推/弹出,而不是操纵 %rsp公司 直接; some compilers do use a dummy push to align the stack 因为 this can actually be cheaper