NASM 带有 cx 寄存器的汇编程序无限循环

NASM assembler infinite loop with cx register

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 times.But 它进入了无限循环,我不明白为什么? 我认为 cx 寄存器不会减少或其他什么?

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

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

你有很多问题。

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

  • 部分名称没有 :global1[=25 的标签也没有=]

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

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

  • 之前将 EBX 设置为 1
  • 您正在破坏 SYS_Write 系统调用的参数之一 (ECX)。 CXECX 是同一寄存器的一部分。 CXECX的低16位。更改 CX 会更改 ECX。您需要为循环计数器使用其他一些寄存器。 ESIEDIEBP 当前未在您的代码中使用。将所有出现的 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您不需要将 initialend 设为全局,因为您没有链接到任何其他目标文件。那些 global 行可以删除。