【问题标题】:Can I use a register as a loop counter?我可以使用寄存器作为循环计数器吗?
【发布时间】:2015-03-01 13:53:24
【问题描述】:

由于函数的调用约定规定了保留哪些寄存器,所以可以将寄存器用作循环计数器吗?

我一开始以为ecx寄存器是用来做循环计数器的,后来发现我用过的一个stdcall函数没有保留ecx的值,我又不以为然了。

是否有保证(至少通过最常用的调用约定)保留的寄存器?

注意:使用堆栈变量作为循环计数器没有问题,我只是想确保它是唯一的方法。

【问题讨论】:

  • 你可以将ecx压入堆栈并在ret之前恢复它,或者你可以使用另一个寄存器
  • push ecx 在调用之前调用stdcallpop ecx 在调用返回之后,每次都通过循环。

标签: windows assembly nasm calling-convention


【解决方案1】:

您可以使用任何通用寄存器,偶尔也可以使用其他寄存器作为循环计数器(当然不是堆栈指针 ☺)。

您要么使用一个手动循环,即替换...

loop label

…与…

dec ebp
jnz label

...反正速度更快(因为 AMD(以及后来的英特尔,当他们赶上时,在 MHz 方面)人为地减慢了 loop 指令,否则,Windows® 和一些 Turbo Pascal 编译的软件会崩溃)。

或者你只是在两者之间保存计数器:

label:
    push ecx
    call func
    pop ecx
    loop label

两者都是标准策略。

【讨论】:

    【解决方案2】:

    是否有保证(至少通过最常用的调用约定)保留的寄存器?

    如果您的循环代码不会调用任何外部实体,您可以在自己的代码中选择任何免费寄存器。

    如果您的循环代码将调用一个外部实体,其中唯一有保证的合同是 ABI 和调用约定,那么您必须保存/恢复您的寄存器并逐个选择寄存器。

    引用Agner Fog的优秀论文Calling conventions for different C++ compilers and operating systems

    6 注册使用

    寄存器的使用规则取决于操作系统,如表 4 所示。暂存寄存器是可以不受限制地用于临时存储的寄存器(也称为调用者保存或易失性寄存器)。被调用者保存寄存器是在使用前必须保存并在使用后恢复的寄存器(也称为非易失性寄存器)。您可以依赖这些寄存器在调用后与调用前具有相同的值...

    ...

    另见:

    【讨论】:

      猜你喜欢
      • 2014-04-08
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多