Assembly 装配程序:泡沫游戏

Assembly 装配程序:泡沫游戏,assembly,x86,nasm,Assembly,X86,Nasm,这个汇编程序是一个泡沫游戏。它应该遵循儿童计数游戏“嘶嘶”的规则:它应该在1-100之间打印,当数字可以被5整除或包含数字5时,用“嘶嘶”一词替换数字 我目前对这个程序有意见。程序运行,但输出为: 数字=1 分段故障(堆芯转储) 如果有人能在这方面帮助我,我将不胜感激。谢谢 enter cextern printf section .data fmt: db "number = %d", 10, 0 ; printf format string fmt2: db " %s",10,0 f

这个汇编程序是一个泡沫游戏。它应该遵循儿童计数游戏“嘶嘶”的规则:它应该在1-100之间打印,当数字可以被5整除或包含数字5时,用“嘶嘶”一词替换数字

我目前对这个程序有意见。程序运行,但输出为: 数字=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
输入cextern printf
第二节数据
fmt:db“编号=%d”,10,0;printf格式字符串
fmt2:db“%s”,10,0
fmt3:db“%s”,10,0
第节.案文
全球主要
主要内容:
推ebx;EBX已被调用方保存,因此我们需要保存它,以便
; 当我们从主干道返回时,它可以恢复
异或ecx,ecx;ebx=0(计数器)
L1:
ecx公司
异或eax,eax
mov-eax,ecx
异或ebx,ebx
xor edx,edx
mov-ebx,5
idiv ebx
cmp-edx,0
jz嘶嘶作响
推动ecx;第二个参数是要打印的号码
推进fmt;第一个参数是格式字符串的地址
调用printf
;添加sp,8;我们在printf调用之前推送了8个字节,我们必须调整堆栈
; 通过有效地删除这些字节。
; 计数器+=1
cmp ecx,100

jle-L1;若计数器为,则程序将崩溃,因为在函数调用过程中,您没有考虑到
ECX
的更改,并且正在进行不平衡的推送/弹出操作。请注意:

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

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

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

也许是这个

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

你有没有试过在调试器中运行它,看看它在哪里崩溃?关于这个@micheal Petch,是的,它在0x080482中崩溃??(). 当我做信息寄存器时,它给我的是:eax 0x0 ecx 0x1 edx 0x1 ebx 0x5 esp 0xffffd810 0xffffd810 ebp 0x0 0x0 esi 0x1 edi 0xf7fb3000-134533120 eip 0xf7ff06c1 0xf7ff06c1 eflags 0x202[如果]cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99(gdb)ECX将被printf调用破坏,一旦
main
函数执行
ret
,您注释掉的add
esp,8
将无法正常结束。不确定对使用
fmt2
的printf的调用要做什么。EAX将被视为指针,但您已使用垃圾(0x7a7a)地址加载了它,因此printf可能无法达到预期效果(或崩溃)。为什么要在
EAX
ebx
中放置字符文本?只需在数据部分声明字符串
“Fizz”,10,0
,并使用它。好的,我已将其更改为您所说的字符串,当我运行它时,它正在打印数字1到4,然后给出一个分段错误(核心转储)。我能做些什么来解决这个问题呢?将相同的原则应用到代码中的其他非平衡推送/弹出组合。我注意到至少还有一个不平衡的设置。你能告诉我具体是哪一个吗?你能告诉我如何修复整个程序吗?谢谢。这显然是一个课堂作业。。。我已经给了你足够多的东西,可以让你在大部分的过程中达到目的,代码现在更加实用就是明证。看看你在推动三件事,而只弹出两件。