我们通过调用jmp访问的代码的一部分仍然被认为是汇编中主函数的一部分吗?
示例:
main:
mov ebx,3
push ebx
jmp for_loop ; this part
rec:
;some function
for_loop:
;logic
je exit
call rec
;logic
jmp for_loop
exit:
pop ebx
mov eax,0
ret
不使用jmp并在for_loop
下编写main
会更好吗?
答案 0 :(得分:1)
嗯,看起来有点混乱。
装配中没有主要功能。您可以调用执行开始的入口点“main”,但实际上就是这样。它只是机器代码中不存在的虚构标签。函数可以是call
的任何函数,因为处理器的call
指令会在jmp
指向它时进行一些设置,但事实就是如此。
就个人而言,我会对此进行重组。
main:
xor ebx,ebx
add ebx,3 ; saves a byte
push ebx
forloop:
; I assume here you do a dec, or cmp, for the following:
je exit
; put the code for "rec" in here.
; No point wasting the bytes and time to jump.
jmp forloop
exit:
pop ebx
xor eax,eax
ret
好吧,所以这仍然是一团糟,但我对你想要达到的目标有了一些了解。
开头的je exit
可能连接到应该在此之前的“逻辑”。我个人宁愿试图解读这个,转过身来。这意味着,假设“逻辑”允许我这样做,我会把它变成jne forloop
并把它放在循环的末尾,所以我可以避免jmp到头。还可以再节省几个字节。
xor eax,eax
是一种将寄存器设置为零的更短,更快的方法。如果你真的需要 rec
是一个单独的函数,那么至少将它放在这个块之外,这样你就不必使用jmp for_loop
跳过它。您可以放心地将其放在ret
。
答案 1 :(得分:1)
整个部分:
rec:
; some function (ending with ret?!)
可以在代码的ret
部分中的exit:
之后移动,然后您将“main”放在一起,并且“rec”分开,如下所示:
main:
; some init
; some loop doing "call rec"
; something something
ret
rec:
; some "function" code
ret
然后,对于到CPU 根本不重要,它不知道你在源中的逻辑分组是什么,或者它是否在某个“函数”和“内部”有多深“。
CPU有cs:eip
地址指针,它将从中获取+执行下一条指令。这就是它在执行的特定时刻所知道的。
jmp
指令将eip
加载到其他地址,然后执行下一条指令。
“子程序”机制通过将返回地址存储到堆栈存储器中,然后通过eip
指令将其加载回ret
,但是如果通过其他方式调整堆栈内容以包含无效返回地址或不同的地址,ret
将崩溃或“跳转”到其他地址,CPU不知道它是“内部”某个子程序,也不需要“返回”它。所有这些都是由程序员编写的高级语义逻辑,程序员负责正确设计执行路径,形成“子程序调用”或“主循环”等逻辑模式。
CPU只有cs:eip
和其他寄存器和内存内容的内容,没有别的。无论状态在指令执行之前是什么状态,它都会确定性地强制接下来将执行什么指令以及它将对CPU寄存器和计算机存储器(以及其他连接芯片,通过I / O总线或使用某些内存部分作为“映射”I / O控制机制)。
所以换句话来说,编写你的源码以便人类轻松“阅读”,不要犹豫,花更多的时间来编写更简单/更精简的源代码,因为你将阅读比 WRITING 要多得多(调试,修改)。因此,在您的示例中,将“rec”部分代码移出,而不是交错“主代码”的主循环转换链更有意义。它应该在源级别上更好地阅读。
我们通过调用jmp访问的代码的一部分仍然被认为是汇编中主函数的一部分吗?
取决于来源的读者,她是否认为它是主要的一部分。机器不关心或理解这种指令分组的概念。