【问题标题】:nasm assembly for loop用于循环的 nasm 程序集
【发布时间】:2015-11-23 04:54:03
【问题描述】:

我正在尝试构建 for 循环,但它给了我无限循环:

SECTION .data

i: dd 0
message: db "The number is %d",10,0
SECTION .text

extern printf
global main

main:
    push ebp
    mov ebp, esp

    mov eax, DWORD [i]
    mov ecx, DWORD 10

    L1:
        add eax, DWORD 1
        push eax
        push message
        call printf
        add esp, 8
        loop L1
    mov esp, ebp
    pop ebp

nasm 给我无限的输出为The number is 18。但是如果我把printf 放在代码的末尾。它给了我正确的输出

L1:
    add eax, DWORD 1
    loop L1

push eax
push message
call printf
add esp, 8

mov esp, ebp
pop ebp

有人知道我哪里做错了吗?

【问题讨论】:

  • ECX (您的循环变量)需要在调用 printf 之前保留(保存)。 Linux 上 32 位代码的 C 调用约定是 EAXECXEDX 可能会被函数调用破坏。如果您需要这些寄存器中的任何一个成为调用之前的状态,则需要保存它,然后在之后恢复它。您对 EAX 有同样的问题

标签: assembly nasm


【解决方案1】:

ecx 是循环变量。它通常是 caller-saved - 也就是说,像 printf 这样的函数被允许覆盖它而不恢复旧值。因此,从printf 返回时,ecx 将是垃圾。

要解决此问题,您可以在推送参数之前添加push ecx,然后在add esp 之后添加pop ecx 删除函数参数。

【讨论】:

  • EAX 也被销毁了。他们似乎想打印从 1 到 10 的计数。EAX 正在被破坏。
  • @MichaelPetch 对于 32 位 [sans "fast call" 将前两个 args 放入寄存器],ABI 必须是相同的 linux/BSD/winX,因为如果推送命令是 printf 停止工作reversed 这只是一种语言可以提出的偏差(例如 IIRC,旧的 fortran 可能已经这样做或任何没有可变参数的语言 could
  • @SerenaQi:或者,更好的是,为循环计数器使用像ebx 这样的调用保留寄存器(使用dec/jnz 而不是慢速loop insn)。在main 的开始/结束处保存/恢复 ebx,而不是在循环内保存/恢复 ecx。 printf 必须保存/恢复 ebx 无论你是否使用它(如果它想使用它,它可能会这样做,因为它是一个复杂的功能)。查看stackoverflow.com/tags/x86/info x86 ABI 了解哪些寄存器是哪些(调用者保存或被调用者保存)的详细信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 2015-09-20
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多