CPU 不会看到你的标签,它会逐条指令执行。
除非当前指令是某种跳转(call
and ret
也是某种跳转) - CPU 完成当前指令后,它将转到下一条指令。
当你这样做时call my_function
,它将执行函数内的所有指令,然后执行时ret
它将返回到下一条指令后call
.
下一条指令是第一条指令my_function
再次,第二次......击中后ret
第二次它实际上会迷路,谁知道在哪里(ret
将获取堆栈顶部的值并将其用作下一条指令的地址,因此第二次时堆栈中的内容ret
发生了,你的代码现在正在疯狂运行......)
汇编源不仅仅是一组指令,而且您还可以将它们定位在内存中,并通过将一条指令一个接一个地放置来控制代码流。 CPU 将按顺序逐行执行它们,就像您编写它们一样(除非您通过使用某种跳转来更改代码流,然后您可以跳过几行源代码)。
因此,如果您希望 CPU 在执行后停止main
是“完成”,并且您正在创建引导加载程序,即没有任何可返回的内容(没有操作系统或类似的东西),您将通过无限循环在 main 末尾创建死胡同,例如:
dead_end_loop:
pause ; give CPU hint this is idling loop
; so it will save power by switching off some circuitry
jmp dead_end_loop
而“主要结束”就在call my_function
。 “my_function”本身必须在“main”之外定义,例如在此无限循环停止程序之后。
也许你错过了什么jmp $
以及来源的目的是什么。这$
在这种情况下,符号对于汇编器来说意味着“当前指令/行的地址”,所以jmp $
可以翻译为“跳到同一行”,这意味着它是一个无限循环,CPU永远不会执行除此之外的任何其他事情jmp $
指令(除非它被设置为处理某些中断信号,否则任何此类外部信号都会导致 CPU 将执行切换到特定的中断处理程序代码,因为程序员/操作系统在进入无限循环之前对其进行了配置)。
还有一个想法:你可能想检查一下https://schweigi.github.io/assembler-simulator/并“单步”几次示例,看看 CPU 如何看不到源代码,而只看到机器代码字节(在右侧显示为“内存”),以及它如何从一条指令到下一条指令,如何IP
正在改变,等等...