【问题标题】:Assembly Program: Game of Fizz组装程序:嘶嘶声游戏
【发布时间】:2016-03-21 07:13:01
【问题描述】:

这个汇编程序是一个 Fizz 游戏。它应该遵循儿童计数游戏 Fizz 的规则:它应该从 1 到 100 打印,并且每当数字可以被 5 整除或包含数字 5 时,将数字替换为单词“Fizz”。

我目前遇到了这个程序的问题。程序运行,但输出为: 数字 = 1 分段错误(核心转储) 如果有人可以帮助我,我将不胜感激。谢谢

    enter cextern printf
section .data
fmt: db "number = %d", 10, 0 ; printf format string
fmt2: db " %s",10,0
fmt3: db " %s ", 10, 0
section .text
global main
main:
    push ebx      ; EBX is callee saved so we need to save it so that it
                  ; it can be restored when we RETurn from main
    xor ecx,ecx  ; ebx = 0 (counter)
L1:
    inc ecx
    xor eax,eax
    mov eax,ecx
    xor ebx,ebx
    xor edx,edx
    mov ebx,5
    idiv ebx
    cmp edx,0
    jz Fizz
    push ecx      ; 2nd parameter is our number to print
    push fmt      ; 1st parameter is the address of the format string
    call printf

    ;add sp, 8     ; We pushed 8 bytes prior to printf call, we must adjust the stack
                  ; by effectively removing those bytes.
           ; counter += 1
    cmp ecx,100
    jle L1        ; If counter is <= 100 go back and print again
    jmp end
Fizz:
    mov ebx,0x4669
    mov eax, 0x7A7A
    push ebx
    push eax
    push fmt2
    call printf
    pop eax
    pop ebx

    jmp L1
end:
    pop ebx       ; Restore EBX before exiting main per calling convention
    ret           ; RETurn from main will cause program to gracefully exit
                  ;     because we are linked to the C runtime code and main was
                  ;     called by that C runtime code when our program started.ode here

【问题讨论】:

  • 你试过在调试器中运行它并查看它崩溃的地方吗?
  • 关于这个looks familiar
  • @micheal Petch,是的,它在 0x080482 处崩溃?? ()。当我完成信息寄存器时,这就是它给我的东西:eax 0x0 0 ECX 0x1 1 EDX 0x1 1 EBX 0x5 5 ESP 0xFFFFD810 0xFFFFD810 EBP 0x0 0x0 ESI 0x1 1 EDI 0xF7FB3000 -134533120 EIP 0xF7FF06C1 0xF7FF06C1 <_dl_runtime_resolve> EFLAGS 0x202 [如果] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb)
  • ECX 将被 printf 调用丢弃,您注释掉的添加 esp, 8 将不会在您的 main 结束后顺利结束函数执行ret。不确定您要对使用 fmt2 的 printf 的调用做什么。 EAX 将被视为一个指针,但您已使用垃圾 (0x7a7a) 地址加载它,因此 printf 可能会失败(或崩溃)
  • 为什么要在eaxebx 中放置字符文字?只需在数据部分声明字符串"Fizz",10,0 并使用它。

标签: assembly x86 nasm


【解决方案1】:

您的程序正在崩溃,因为您没有考虑到函数调用期间ECX 的更改,并且您正在进行不平衡的推送/弹出操作。注意这里:

push ecx
push fmt
call printf

但您永远不会 pop 这两个值退出堆栈。由于ECX 未保留在调用中,并且您在函数返回后不执行任何其他操作,因此您依赖于在函数调用之后发生的任何ECX

如果您查看calling conventions,您会发现ecx 并未保留在函数调用中。你可能会发现它没有改变,但你不能依赖它。你必须保存它。

这导致代码立即跳转到end 并尝试跳转到ret。这将立即崩溃,因为您现在正试图返回格式字符串的地址,因为这是堆栈中的下一个地址。

也许是这个?

push ecx
push fmt
call printf
pop ecx  ; fmt
pop ecx  ; ECX
cmp ecx, 100
jle end

【讨论】:

  • 好的,我已经把它改成了你说的那个,当我运行它时打印数字 1 到 4 然后给出一个分段错误(核心转储)。我能做些什么来解决这个问题?
  • 将相同的原则应用于代码中的其他不平衡推送/弹出组合。我注意到至少还有一个不平衡的集合。
  • 能具体说一下是哪一个吗?
  • 您能告诉我如何修复整个程序吗?谢谢
  • 没有。这显然是一个课堂作业......我已经给了你足够多的东西来让你大部分时间到达那里,现在代码功能更强大就证明了这一点。看看你在哪里推三件东西,只弹出两件。
猜你喜欢
  • 1970-01-01
  • 2011-04-26
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
相关资源
最近更新 更多