尝试在 Linux 上的 NASM 中编写 for 循环时出现分段错误

发布于 2024-10-25 05:37:00 字数 533 浏览 5 评论 0原文

我正在尝试编写一个简单的 NASM 程序来娱乐,但我似乎不知道如何在其中编写 for 循环。使用以下代码,我得到了分段错误。以下代码应该打印出“Hello world!”接下来是从 1 到 100 的所有数字。

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message

section .text
    global _start

_start:
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0
    jmp loop

    mov eax, 1
    mov ebx, 0
    int 80h

loop:
    mov eax, 4
    mov ebx, 1
    mov edx, 1
    int 80h

    add ecx, 1
    cmp ecx, 100
    jl loop

I'm trying to write a simple NASM program for fun, but I can't seem to figure out how to write a for loop in it. With the following code, I get a segmentation fault. The following code is supposed to print out "Hello world!" followed by all of the numbers from one to 100.

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message

section .text
    global _start

_start:
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0
    jmp loop

    mov eax, 1
    mov ebx, 0
    int 80h

loop:
    mov eax, 4
    mov ebx, 1
    mov edx, 1
    int 80h

    add ecx, 1
    cmp ecx, 100
    jl loop

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

°如果伤别离去 2024-11-01 05:37:00

在跳到循环之前,您将 0 分配给 ECX...

这意味着您的程序将尝试打印位于内存地址 0 处的字符串,该字符串不属于您,因此会出现分段错误...

记住您正在工作与内存地址。
将 10 分配给寄存器值实际上不会打印 ASCII 中的 10...这只是意味着您正在获取内存地址 10...

Before you jump to the loop, you are assigning 0 to ECX...

It means your program will try to print a string located at memory address 0, which you don't own, hence the segmentation fault...

Remember you are working with memory addresses.
Assigning 10 to a register value wont actually print 10, in ASCII... It just means you are getting memory address 10...

老子叫无熙 2024-11-01 05:37:00

您有两个问题:首先,对 exit() 的系统调用出现在循环之前,而不是之后;其次,您将整数而不是内存指针传递给 write() 系统调用。

试试这个:

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message

    digits: db '0123456789'

section .text
    global _start

_start:
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0
    jmp loop

loop:
    push ecx
    mov eax, digits
    add ecx, eax
    mov eax, 4
    mov ebx, 1
    mov edx, 1
    int 80h
    pop ecx

    add ecx, 1
    cmp ecx, 10
    jl loop

这是一个格式化数字并打印循环计数器的版本:

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message

    number: db '000'
            db 10

section .text
    global _start

_start:
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0
    jmp loop

loop:
    call _format_number
    push ecx
    mov ecx, number
    mov eax, 4
    mov ebx, 1
    mov edx, 4
    int 80h
    pop ecx

    add ecx, 1
    cmp ecx, 10
    jl loop

    mov eax, 1
    mov ebx, 0
    int 80h

_format_number:
    push ecx
    xor edx, edx
    mov eax, ecx
    mov ecx, 10
    idiv ecx
    add edx, '0'
    mov ebx, number
    mov [ebx+2], dl
    xor edx, edx
    idiv ecx
    add edx, '0'
    mov [ebx+1], dl
    xor edx, edx
    idiv ecx
    add edx, '0'
    mov [ebx+0], dl
    pop ecx
    ret

You had two problems: first, your syscall to exit() came before the loop, instead of after; second you are passing an integer instead of a memory pointer to the write() syscall.

Try this instead:

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message

    digits: db '0123456789'

section .text
    global _start

_start:
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0
    jmp loop

loop:
    push ecx
    mov eax, digits
    add ecx, eax
    mov eax, 4
    mov ebx, 1
    mov edx, 1
    int 80h
    pop ecx

    add ecx, 1
    cmp ecx, 10
    jl loop

And here is a version that formats numbers and prints the loop counter:

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message

    number: db '000'
            db 10

section .text
    global _start

_start:
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0
    jmp loop

loop:
    call _format_number
    push ecx
    mov ecx, number
    mov eax, 4
    mov ebx, 1
    mov edx, 4
    int 80h
    pop ecx

    add ecx, 1
    cmp ecx, 10
    jl loop

    mov eax, 1
    mov ebx, 0
    int 80h

_format_number:
    push ecx
    xor edx, edx
    mov eax, ecx
    mov ecx, 10
    idiv ecx
    add edx, '0'
    mov ebx, number
    mov [ebx+2], dl
    xor edx, edx
    idiv ecx
    add edx, '0'
    mov [ebx+1], dl
    xor edx, edx
    idiv ecx
    add edx, '0'
    mov [ebx+0], dl
    pop ecx
    ret
瀟灑尐姊 2024-11-01 05:37:00

您的代码的问题是您尝试将整数打印为双字。
我宁愿像这样使用 printf :

extern printf ;make sure we can use printf

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message
    decFormat   db '%d',10 ;format string to use in printf

section .text
    global main

main:
    ;print hello world the usual way
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0

loop:
    push ecx ;add counter
    push decFormat ;add format string
    call printf ;execute printf, which will use the stack values as arguments

    pop ecx ;clean the stack
    pop ecx

    inc ecx ;if you just want to add 1 to the value, you should use inc not add
    cmp ecx, 100
    jl loop

mov eax,1
mov ebx,0
int 80h

The problem with your code is that you try to print a integer as a dword.
I would rather use printf like this:

extern printf ;make sure we can use printf

section .data
    message: db 'Hello world!', 10
    messageLength: equ $-message
    decFormat   db '%d',10 ;format string to use in printf

section .text
    global main

main:
    ;print hello world the usual way
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, messageLength
    int 80h

    mov ecx, 0

loop:
    push ecx ;add counter
    push decFormat ;add format string
    call printf ;execute printf, which will use the stack values as arguments

    pop ecx ;clean the stack
    pop ecx

    inc ecx ;if you just want to add 1 to the value, you should use inc not add
    cmp ecx, 100
    jl loop

mov eax,1
mov ebx,0
int 80h
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文