【问题标题】:Factorial Assembly x86阶乘组装 x86
【发布时间】:2015-11-21 19:22:27
【问题描述】:

我有这个汇编代码(Linux 32Bit 用 gcc -m32 编译),我真的不明白为什么我的程序不工作。

.data

    .bla:
            .ascii "%d\n\0"

    .globl main

    .text

    main:           pushl $4
                    call factorial
                    movl $1, %eax
                    ret
    factorial:
                    push %ebp
                    movl %esp, %ebp
                    movl 8(%ebp), %ecx
                    cmpl $1, %ecx
                    jg .rek
                    movl $1, %eax
                    movl %ebp, %esp
                    pop %ebp
                    ret

    .rek:
                    decl %ecx
                    pushl %ecx
                    call factorial
                    addl $4, %esp
                    movl 8(%ebp), %ecx
                    imull %ecx, %eax
                    pushl %eax
                    pushl $.bla
                    call printf
                    addl $8, %esp
                    movl %ebp, %esp
                    pop %ebp
                    ret

不幸的是,每次确实发生分段错误 + 大于 4 的参数都不起作用。

当我用“3”运行程序时,这应该是我的堆栈:

3
ret add
ebp
2
ret add
ebp
1
ret add
ebp

当我到达递归的底部时,我将保存在 eax 中的返回值与 8(%ebp) 相乘,这应该是下一个值。

非常感谢您提供的任何帮助。

【问题讨论】:

  • 考虑到尝试调用名为 maine 的不存在例程,我看不出上面的代码是如何构建的。
  • 谢谢,发在这里之前忘记改了。但问题仍然存在。
  • @Noahnder 看到我的回答。

标签: linux assembly x86


【解决方案1】:

我看到了三个问题。

1) 你的call maine(我假设这是一个错字,你的意思是main)应该是call factorial

2) 在您的 main 程序中,您不会恢复您的堆栈指针。

3) 您的printf 调用会修改%eax 并在返回之前覆盖您的factorial 的结果。

修复程序:

.data

.bla:
        .ascii "%d\n\0"

.globl main

.text

main:   pushl $5
        call factorial
        addl $4, %esp         # ADDED THIS
        movl $1, %eax
        ret
factorial:
        push %ebp
        movl %esp, %ebp
        movl 8(%ebp), %ecx
        cmpl $1, %ecx
        jg .rek
        movl $1, %eax
        movl %ebp, %esp
        pop %ebp
        ret
.rek:
        decl %ecx
        pushl %ecx
        call factorial   # FIXED THIS
        addl $4, %esp
        movl 8(%ebp), %ecx
        imull %ecx, %eax
        pushl %eax            # ADDED THIS - SAVE RETURN VALUE
        pushl %eax
        pushl $.bla
        call printf
        addl $8, %esp         # MODIFIED THIS
        pop %eax              # ADDED THIS (restore eax result)
        movl %ebp, %esp
        pop %ebp
        ret

【讨论】:

  • 我很确定 printf() 被允许修改堆栈上的参数。 pop %eax 不一定会从调用printf() 之前恢复%eax 的值。
  • @EOF 不,printf 不应修改堆栈参数。为什么会这样做?你能举一个发生这种情况的例子吗?你在这个基础上否决了我的回答?这似乎违反了 C 调用序列的原则。另外,我正确地指出了 OP 代码的所有问题。因此,仅在此基础上,我认为投反对票是不恰当的。
  • 绝对允许函数修改其参数。如果函数的参数在寄存器中传递,您不会期望它们保持不变,为什么在堆栈上传递的参数会有所不同?
  • @EOF,请举例说明这发生在标准 C 调用序列中。当然,我可以在任何地方编写一个修改堆栈的汇编程序。但是 C lib 函数不会这样做。再次,请举例证实您的主张。作为寄存器传递是一个完全不同的场景。是的,我希望它会有所不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-24
  • 1970-01-01
  • 2018-08-17
  • 2015-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多