x64 asm,溢出到系统v呼叫转移的堆栈

时间:2018-03-25 15:09:08

标签: assembly x86 x86-64

我对调用函数时如何将内容传递给堆栈感到有些困惑,我有以下程序集:

.data
str:
    .asciz "%d %d %d %d %d %d %d %d %d %d\n"

.text
__entry:
    pushq %rbp
    movq %rsp, %rbp
    leaq str(%rip), %rdi
    movq $1, %rsi
    movq $2, %rdx
    movq $3, %rcx
    movq $4, %r8
    movq $5, %r9
    movq $6, -4(%rbp)
    movq $8, -8(%rbp)
    movq $9, -12(%rbp)
    movq $10, -16(%rbp)
    call _printf
    popq %rbp
    ret

.global _main
_main:
    pushq %rbp
    movq %rsp, %rbp
    call __entry
    popq %rbp
    ret

但是当我运行程序时,我得到了大量的垃圾值。寄存器中传递的值很好,但堆栈中传递的值不是。我检查了调用约定,它说"其他参数在堆栈上传递。",它们应该"对齐到16字节边界"。

两个问题:

  • 我在这里做错了什么,而不是将我的值传递给堆栈?

  • "与16字节边界对齐"是什么意思?

1 个答案:

答案 0 :(得分:1)

您的核心问题是,在加载堆栈上的所有参数之前,通过减少堆栈指针忽略了在堆栈上分配空间。当然,printf会立即删除堆栈指针下方区域中的任何内容,从而导致垃圾打印输出。

您还需要修复堆栈偏移:movq一次移动8个字节,因此每个插槽大8个字节。

您的固定代码如下所示:

    pushq %rbp
    movq %rsp, %rbp
    sub $32,%rsp           # new
    leaq str(%rip), %rdi
    movq $1, %rsi
    movq $2, %rdx
    movq $3, %rcx
    movq $4, %r8
    movq $5, %r9
    movq $6, -8(%rbp)      # fixed: offsets are multiples of 8, not 4
    movq $8, -16(%rbp)     # fixed
    movq $9, -24(%rbp)     # fixed
    movq $10, -32(%rbp)    # fixed
    xor  %eax,%eax         # new: %al=0 FP register args
    call _printf
    add $32,%rsp           # new
    popq %rbp
    ret

一切都应该再次奏效。通常,您使用push通过堆栈加载参数。例如,您的函数调用如下所示:

    pushq %rbp
    movq %rsp, %rbp
    leaq str(%rip), %rdi
    movq $1, %rsi
    movq $2, %rdx
    movq $3, %rcx
    movq $4, %r8
    movq $5, %r9
    push $6                # push rightmost argument
    push $8                # push second-to-last argument
    push $9                # ...
    push $10
    xor  %eax,%eax         # tell printf to expect 0 floating point args
    call _printf
    add $32,%rsp           # pop arguments off the stack
    popq %rbp
    ret