跳出全球主要还是被认为是主要功能的一部分,在组装中?

时间:2017-01-06 11:05:16

标签: assembly x86 nasm

我们通过调用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会更好吗?

2 个答案:

答案 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访问的代码的一部分仍然被认为是汇编中主函数的一部分吗?

取决于来源的读者,她是否认为它是主要的一部分。机器不关心或理解这种指令分组的概念。