linux - 如何在 x86 程序集中循环打印一个数字后的新行?

标签 linux assembly x86 nasm

我有一个汇编程序,可以像这样在一行中打印出 1 - 9 的数字:123456789。我想要的是将这些值分别打印在一行上;每行一个数字。

我尝试实现新行,但在我的代码中抛出错误 Segmentation fault (core dumped)。我对组装还很陌生,所以我真的不知道如何找出为什么这不起作用。它只打印第一个数字 (1),然后抛出该错误。

我尝试换行的代码:

mov dl, 13
mov ah, 02h
int 21h
mov dl, 10
mov ah, 02h
int 21h

我的代码:

_start:
    mov ecx, 10
    mov eax, '1'

L1:
    mov [num], eax
    mov eax, 4
    mov ebx, 1
    push ecx

    mov ecx, num
    mov edx, 1
    int 0x80

    mov eax, [num]
    sub eax, '0'
    inc eax
    add eax, '0'
    pop ecx
    loop L1

    mov eax, 1
    int 0x80

section .bss
    num resb 1

最佳答案

您应该使用与打印数字相同的系统调用来打印换行符。

此外,Linux 中的换行符只是 LF(字符 10,)而不是 CR(字符 13)后跟 LF,就像 Windows/DOS 使用的那样。

如何在 Linux 上以 x86 汇编打印到标准输出

This answer描述每个参数对 Linux 打印系统调用的作用,这就是您通过引发 int 0x80 调用的内容。

系统调用使用寄存器来传递参数。从链接的答案中,eax 是系统调用号(4 = 打印),ebx 是目标流(1 = stdout),ecx是指向要打印的数据的指针,edx是要打印的数据的长度。

因此,在您的循环中实际执行打印的代码是:

mov [num], eax  ; Moves the character in eax to the buffer pointed to by num.
mov eax, 4      ; Moves 4 into eax, i.e. selects the print system call.
mov ebx, 1      ; Moves 1 into ebx, i.e. selects stdout as the destination.
mov ecx, num    ; Moves the address where your text is stored into ecx.
mov edx, 1      ; Moves the number of bytes to characters (1) into edx.
int 0x80        ; Executes a Linux system call using the above parameters.

要打印换行符,您只需要在 eax 中在此代码之前添加换行符(十进制字符 10),而不是数字字符。因此,例如,在此代码之前添加 mov eax, 10 将打印换行而不是数字。

如何使它与您现有的循环一起工作

“我的代码”部分中的

num 是您存储要打印的数据的缓冲区。但是,此代码也使用此内存来跟踪它打印的最后一个数字。因此,有两种方法可以避免在循环之间丢失该信息:

选项 1:只需将缓冲区的大小从 1 个字节增加到 2 个字节,然后将换行符放在第二个字节中。然后你可以将 2 移动到 edx 而不是 1 来告诉 Linux 你想要打印 2 个字符,从而打印两个数字以及每次循环迭代时的换行符。

选项 2:分配另一个单字节缓冲区来存储换行符。将换行符移到那里,然后在系统调用之后进行第二个系统调用,该系统调用会在循环中打印数字以打印换行符。例如,如果您的新缓冲区被称为“lfbuffer”,那么您将在现有循环中的 int 0x80 行之后添加此代码:

mov byte [lfbuffer], 10  ; Moves the a line feed to the buffer pointed to by lfbuffer.
mov eax, 4           ; Moves 4 into eax, i.e. selects the print system call.
mov ebx, 1           ; Moves 1 into ebx, i.e. selects stdout as the destination.
mov ecx, lfbuffer    ; Moves the address where your line feed is stored into ecx.
mov edx, 1           ; Moves the number of bytes to characters (1) into edx.
int 0x80             ; Executes a Linux system call using the above parameters.

关于linux - 如何在 x86 程序集中循环打印一个数字后的新行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58427656/

相关文章:

c++ - std::atomic::fetch_add 是 x86-64 上的序列化操作吗?

c - 在不更改 x87 寄存器的情况下进行十进制除法

assembly - ARM/AArch64 上的 DIVQ 对应项(使用双宽度除数缩小除法)?

c++ - 使用 Visual Studio 10 编译 x64 EMMS

assembly - 在我的程序启动之前堆栈上有什么?

python - 在 Linux 到 Windows (Flask) 中将模式管道传输到 sqlite 的对应物是什么

Python过滤和保存

与 Shell 交互时的 PHP 行为

mysql - 从 mysql 执行时找不到 Linux Bash 自定义函数

assembly - MIPS 汇编中的 .word 指令