Assembly 装配程序:泡沫游戏
这个汇编程序是一个泡沫游戏。它应该遵循儿童计数游戏“嘶嘶”的规则:它应该在1-100之间打印,当数字可以被5整除或包含数字5时,用“嘶嘶”一词替换数字 我目前对这个程序有意见。程序运行,但输出为: 数字=1 分段故障(堆芯转储) 如果有人能在这方面帮助我,我将不胜感激。谢谢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
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
,您注释掉的addesp,8
将无法正常结束。不确定对使用fmt2
的printf的调用要做什么。EAX将被视为指针,但您已使用垃圾(0x7a7a)地址加载了它,因此printf可能无法达到预期效果(或崩溃)。为什么要在EAX
和ebx
中放置字符文本?只需在数据部分声明字符串“Fizz”,10,0
,并使用它。好的,我已将其更改为您所说的字符串,当我运行它时,它正在打印数字1到4,然后给出一个分段错误(核心转储)。我能做些什么来解决这个问题呢?将相同的原则应用到代码中的其他非平衡推送/弹出组合。我注意到至少还有一个不平衡的设置。你能告诉我具体是哪一个吗?你能告诉我如何修复整个程序吗?谢谢。这显然是一个课堂作业。。。我已经给了你足够多的东西,可以让你在大部分的过程中达到目的,代码现在更加实用就是明证。看看你在推动三件事,而只弹出两件。