【问题标题】:NASM assembler infinite loop with cx register带有 cx 寄存器的 NASM 汇编程序无限循环
【发布时间】:2019-08-06 13:40:33
【问题描述】:
section .data:
         msg1: db "Hello 10 times!"
         msglen1: equ $-msg1
section .text:
        global _initial:
        global _start:
        global _end:
_initial:
        mov cx,10
_start:
        dec cx
        mov ecx,msg1
        mov edx,msglen1
        mov eax,4
        int 80h
        cmp cx,0 
        jz _end
        jmp _start
_end
        mov eax,1
        int 80h

上面的代码必须产生“Hello 10 times”10次。但是它进入了无限循环,我不明白为什么? 我认为 cx 寄存器不会减少或其他什么?

【问题讨论】:

  • 对不起,我听不懂,你是想说我应该把 cx 从 cx 改成 esi 吗?我刚才试过了,但死循环又出现了。可能是因为我是汇编初学者,但我不想学习。

标签: linux assembly x86 nasm system-calls


【解决方案1】:

你有很多问题。

  • Linux 程序的默认入口点是_start。您的程序首先在标签 _start 而不是 initial 处执行,因此您的循环计数器没有被初始化。

  • 部分名称的名称上没有:,global 的标签也没有1

  • 您缺少SYS_Write 系统调用的参数。 32 位系统调用是documented in a table:

    您需要将 EBX 设置为文件描述符。标准输入=0,标准输出=1,标准错误=2。您想写入控制台,因此您需要在调用 Int 80h

    之前将 EBX 设置为 1
  • 您正在破坏SYS_Write 系统调用的参数之一 (ECX)。 CX 和 ECX 是同一个寄存器的一部分。 CX 是 ECX 的低 16 位。改变 CX 改变 ECX。您需要为循环计数器使用其他一些寄存器。 ESI、EDI 和 EBP 目前在您的代码中未使用。将所有出现的 CX 更改为 32 位寄存器 ESI。

您的代码可能如下所示:

section .data
        msg1: db "Hello 10 times!", 10
                               ; Add 10 on the end of the string for Line Feed
                               ;     so each message prints on separate line
        msglen1 equ $-msg1

section .text
        global _initial
        global _start
        global _end

_start:
        mov esi, 10            ; Initialize loop counter
_msgloop:
        dec esi                ; Decrement loop counter
        mov ebx, 1             ; File Descriptor 1 = Write to Standard Output (STDOUT)
        mov ecx, msg1          ; Address of message to print
        mov edx, msglen1       ; Length of message to print
        mov eax, 4             ; SYS_Write system call = 4
        int 80h
        cmp esi, 0             ; Has the loop counter reached 0?
        jz _end                ; If it has then we are done
        jmp _msgloop           ; otherwise go back and print message again
_end:
        mov eax,1              ; SYS_Exit system call
        int 80h

你可以这样重写你的循环:

section .data
        msg1: db "Hello 10 times!", 10
                               ; Add 10 on the end of the string for Line Feed
                               ;     so each message prints on separate line
        msglen1 equ $-msg1

section .text
        global _start

_start:
        mov esi, 10            ; Initialize loop counter

.msgloop:
        mov ebx, 1             ; File Descriptor 1 = Write to Standard Output (STDOUT)
        mov ecx, msg1          ; Address of message to print
        mov edx, msglen1       ; Length of message to print
        mov eax, 4             ; SYS_Write system call = 4
        int 80h
        dec esi                ; Decrement loop counter
        jnz .msgloop           ; If loop counter hasn't reached zero then print again

        mov eax,1              ; SYS_Exit system call
        int 80h

脚注:

  • 1您不需要将initial 和end 设为全局,因为您没有链接到任何其他目标文件。可以删除那些 global 行。

【讨论】:

    【解决方案2】:

    您尝试使用cx 寄存器作为循环计数,同时需要使用ecx 作为输出参数。由于cx 是ecx 的低16 位,因此您会破坏循环计数。

    您需要为循环计数使用其他一些寄存器(在系统调用期间未使用),或者将计数存储在堆栈上的局部变量中。

    【讨论】:

    • 我已经使用过 ecx、edx 和 eax 寄存器,我不知道我可以使用哪个寄存器。我刚才尝试使用 ebx 寄存器,但这次没有输出。
    • @MichaelPetch İ 也尝试了您所说的,但此时输出中没有任何内容,没有错误,没有任何内容,终端光标正在等待。我在 x86 程序集中迷路了。
    • @ShooterLensAim:您需要ebx=1 作为write(1, msg, msglen) 的文件描述符。或者 EBX=0 也恰好可以工作。 ebx register doesn't work in NASM but ecx work 使用 ESI、EDI 或 EBP,并阅读有关 Linux 系统调用调用约定和您正在使用的系统调用的文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-08
    • 2012-01-02
    • 2019-06-25
    • 2012-06-24
    • 2019-12-26
    相关资源
    最近更新 更多