测试汇编中的程序是否正常工作
Testing if a program in assembly is working correctly
我是汇编的新手,我正在尝试为 x86 构建一个非常简单的程序,将值放入 EAX:
(Nothing?) if EBX can be divided by 2^n with n>3
1 if EBX can be divided by 2^3 -> 8
2 if EBX can be divided by 2^2 -> 4
3 if EBX can be divided by 2^1 -> 2
0 if EBX is an odd number
所以我构建了这个程序并对其进行了测试,一切运行良好,但我不知道如何查看它是否真的按照我想要的方式执行。我找不到任何方法来输出注册表的当前值,并且互联网的丰富知识只能为我提供部分答案,这些答案并没有让我走得太远。
我主要担心的是我不确定 ret 语句 returns 到 _main 函数,还是只是 "breaks" 执行。后者是我想要的。那么有没有办法让我检查我的程序是否正常工作?
section .text
global _main
_main:
MOV EAX, EBX
MOV ECX, 16
DIV ECX
CMP DX, 0 ;Op=word (1,0,0,0,0), AX := DX:AX/Op, DX -> rest
JE end0 ;If number%16 == 0
MOV EAX, EBX
MOV ECX, 8
DIV ECX
CMP DX, 0 ;Op=word (1,0,0,0), AX := DX:AX/Op, DX -> rest
JE end8 ;If number%8 == 0
MOV EAX, EBX
MOV ECX, 4
DIV ECX
CMP DX, 0 ;Op=word (1,0,0), AX := DX:AX/Op, DX -> rest
JE end4 ;If number%4 == 0
MOV EAX, EBX
MOV ECX, 2
DIV ECX
CMP DX, 0 ;Op=word (1,0), AX := DX:AX/Op, DX -> rest
JE end2 ;If number%2 == 0
JMP end1 ;
end8:
MOV EAX, 3
ret
end4:
MOV EAX, 2
ret
end2:
MOV EAX, 1
ret
end1:
MOV EAX, 0
ret
end0:
ret
您可以使用调试器单步执行代码并在每一步检查寄存器和内存。
关于你关于ret
的问题:它是call
的对立面,粗略地说它会在最近的call
之后继续。 (这是一个简化的视图。)请注意,您使用简单的条件跳转,例如 je end0
,因此 end0
中的 ret
不会 return 到该位置。相反,它将退出您的 _main
并继续调用它的人,这大概是 C 启动代码。实际上它退出了你的_main
。据我所知,这正是您想要的。
PS:您使用的 DIV
是错误的,它只是偶然起作用。它隐含地使用 EDX
作为被除数的高 32 字,因此对于 32 位无符号除法,您应该始终将其归零。甚至您的评论也这么说,尽管那描述了 16 位版本的操作。
另请注意,要检查 2 的幂的整除性,通常使用按位运算,而不是除法。
我是汇编的新手,我正在尝试为 x86 构建一个非常简单的程序,将值放入 EAX:
(Nothing?) if EBX can be divided by 2^n with n>3
1 if EBX can be divided by 2^3 -> 8
2 if EBX can be divided by 2^2 -> 4
3 if EBX can be divided by 2^1 -> 2
0 if EBX is an odd number
所以我构建了这个程序并对其进行了测试,一切运行良好,但我不知道如何查看它是否真的按照我想要的方式执行。我找不到任何方法来输出注册表的当前值,并且互联网的丰富知识只能为我提供部分答案,这些答案并没有让我走得太远。
我主要担心的是我不确定 ret 语句 returns 到 _main 函数,还是只是 "breaks" 执行。后者是我想要的。那么有没有办法让我检查我的程序是否正常工作?
section .text
global _main
_main:
MOV EAX, EBX
MOV ECX, 16
DIV ECX
CMP DX, 0 ;Op=word (1,0,0,0,0), AX := DX:AX/Op, DX -> rest
JE end0 ;If number%16 == 0
MOV EAX, EBX
MOV ECX, 8
DIV ECX
CMP DX, 0 ;Op=word (1,0,0,0), AX := DX:AX/Op, DX -> rest
JE end8 ;If number%8 == 0
MOV EAX, EBX
MOV ECX, 4
DIV ECX
CMP DX, 0 ;Op=word (1,0,0), AX := DX:AX/Op, DX -> rest
JE end4 ;If number%4 == 0
MOV EAX, EBX
MOV ECX, 2
DIV ECX
CMP DX, 0 ;Op=word (1,0), AX := DX:AX/Op, DX -> rest
JE end2 ;If number%2 == 0
JMP end1 ;
end8:
MOV EAX, 3
ret
end4:
MOV EAX, 2
ret
end2:
MOV EAX, 1
ret
end1:
MOV EAX, 0
ret
end0:
ret
您可以使用调试器单步执行代码并在每一步检查寄存器和内存。
关于你关于ret
的问题:它是call
的对立面,粗略地说它会在最近的call
之后继续。 (这是一个简化的视图。)请注意,您使用简单的条件跳转,例如 je end0
,因此 end0
中的 ret
不会 return 到该位置。相反,它将退出您的 _main
并继续调用它的人,这大概是 C 启动代码。实际上它退出了你的_main
。据我所知,这正是您想要的。
PS:您使用的 DIV
是错误的,它只是偶然起作用。它隐含地使用 EDX
作为被除数的高 32 字,因此对于 32 位无符号除法,您应该始终将其归零。甚至您的评论也这么说,尽管那描述了 16 位版本的操作。
另请注意,要检查 2 的幂的整除性,通常使用按位运算,而不是除法。