【问题标题】:Assembly- preserving register values?汇编保留寄存器值?
【发布时间】:2013-02-22 22:59:31
【问题描述】:

在我在汇编中创建的函数中使用 printf 时,我遇到了一些麻烦。我做的功能是:

printnstars:
    movl $0, %edi
    movl 4(%esp), %ebx

starloop:
    cmpl %ebx, %edi
    je exitloop
    incl %edi
    pushl $star
    call printf
    addl $4, %esp
    jmp starloop

exitloop:
    ret

该函数接受一个数字作为参数,我将其移至 %ebx,并使用以下方法打印该数量的“*”:

star:
    .asciz "*"

这个函数做了它应该做的事情,但是当我尝试做这样的事情时遇到了问题:

    pushl (%ecx)
    call printnstars
    pushl (%ecx)
    call printnstars

其中 (%ecx) 是 2。如果我只调用一次,它的行为与预期一样并打印 2 颗星,但当我再次调用它时,它会打印出无限颗星。很明显 %ecx 一定是在 printf 内部弄乱了,因为我没有在我创建的任何东西中使用该寄存器。我该怎么做才能确保 (%ecx) 通过多次调用 printnstars 保持不变?

还需要注意的是,这是在一个函数内部使用的,该函数正在打印一个直方图,每行上都有星号,表示一个数字出现的次数。我的所有频率值都基于 %ecx,这就是我使用 (%ecx) 的原因。

【问题讨论】:

  • 杰克,请停止污蔑你的问题。我不会删除它,因为这是一个很好的问题,也有很好的答案。

标签: assembly x86 printf


【解决方案1】:

如何确保 (%ecx) 通过多次调用 printnstars 保持不变?

您将寄存器值保存在堆栈上的局部变量中。

另外,请记住printf() 接受可变数量的参数,并且由于它事先不知道有多少参数以及它们的类型,因此它不会删除堆栈上的参数并将它们从堆栈(通过调整esp)成为调用者的职责。

【讨论】:

  • 好吧,我是否在第一次调用之前添加 pushl %ecx,然后在第二次调用之前添加 popl %ecx?在 printf 调用之后我也确实做了 addl $4, %esp 所以我没有正确地做到这一点......?
  • 您可以将其推送两次,然后再调用该函数两次。那个怎么样?并注意 printf 的堆栈参数。
  • 难道 addl $4 %esp 不会解决这个问题吗?
  • 啊,我错过了。可能会。
  • 好吧,我做了两次推送,然后调用了两次,这似乎有效:) 谢谢。
猜你喜欢
  • 1970-01-01
  • 2021-03-25
  • 2015-03-27
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-11
相关资源
最近更新 更多