跳转到父标签时的程序集运行时错误?

时间:2013-03-28 17:41:05

标签: assembly x86 nasm

我在一段时间后涉足大会(NASM风味),我正试图再次学习它。 (我知道我可以先计算字符串长度,但这是一个练习)

无论如何,我编写了这段代码,使用stdout将空终止字符串打印到sys_write。 (我打算概括一下,我现在正在测试。)

似乎它会起作用,因为如果我在调用i之前递增sys_write,那么它会打印'e',但如果我之后递增它,那么它会打印'H' as预期。但是,只要遇到jne print_loop,就会产生运行时错误,错误代码为-1。我尝试了几个跳转指令,它们都崩溃了,但是一旦我删除了跳转,程序就会运行而没有任何错误。

Ideone

SECTION .data
    hello:
        db "Hello World!/n",0

SECTION .bss
    i: 
        resb 1

SECTION .text
    global _start

    _start:
        mov ecx, hello
        call print

        mov eax, 1
        mov ebx, 0
        int 80h

    print:
        mov eax, 4
        mov ebx, 1
        mov edx, 1

        print_loop:
            push eax
            mov eax, [i]
            lea ecx, [ecx+eax]
            pop eax

            int 80h
            inc dword [i]
            cmp ecx, 0  
            jne print_loop ; if I comment this out, it runs without error.

        ret

这是固定版本:

%macro print_ 1
    mov eax, 4
    mov ebx, 1
    mov ecx, %1

    call print
%endmacro

%macro exit_ 1
    mov eax, 1
    mov ebx, %1
    int 80h
%endmacro

SECTION .data
    hello:
        db "Hello World!/n",0

SECTION .bss
    i: 
        resb 1

SECTION .text
    global _start

    _start:
        print_ hello
        exit_ 0

    ;print code called by print_ macro
    print:
        push ecx
        count:
            inc ecx
            cmp byte [ecx], 0
            jne count

        mov edx, ecx
        pop ecx
        sub edx, ecx

        int 80h
    ret

2 个答案:

答案 0 :(得分:1)

代码有几个问题:

i: 
    resb 1

这里为一个字节保留空格,但在打印功能中,您将i视为双字。

int 80h

这会废弃eax的旧值,因为eax包含系统调用的返回值。因此,您需要在每次迭代时使用系统调用号(4)重新加载eax

lea ecx, [ecx+eax]

在这里,您使用&string[i]覆盖字符串的基址,这将导致后续迭代中的地址不正确,因为您不保留原始ecx值。

cmp ecx, 0

我不确定为什么你期望ecx为0.更有意义的是加载存储在[ecx]的字节并将 与零进行比较(之前)系统调用)。

答案 1 :(得分:0)

有几个问题。

首先:

  mov eax, [i]

i是一个字节变量,但该指令从其位置读取4个字节。

  inc dword [i]

i是一个字节变量,但该指令在其位置增加一个4字节的值。

第二(我认为):

在此指示之后ecx将会是什么

  lea ecx, [ecx+eax]

第二次执行?它仍然是指向hello的有效地址吗?

顺便说一下,学会使用调试器。现在是时候了。