在编译和链接程序时,您通常会为特定用途找到这样的特殊名称。
通常,类似于可执行文件_start的实际入口点,它将位于某个目标文件或库中(例如crt0.oC 运行时启动代码)——这通常会由链接器自动添加到您的可执行文件中,类似于添加 C 运行时库的方式(a)。
用于启动程序的操作系统代码将类似于(显然是伪代码,并且错误检查比它应该有的要少得多):
def spawnProg(progName):
id = newProcess() # make process address space
loadProgram(pid = id, file = progName) # load program into it
newThread(pid, initialPc = '_start') # make new thread to run it
Run Code Online (Sandbox Code Playgroud)
即使您自己main在用 C 编码时创建了一个,但这并不是真正开始发生的地方。有一个整体转换的需要是你的主要程序之前,甚至做的事情开始。因此,C 启动代码的内容将类似于(最简单的):
_start: ;; Weave magic here to set up C and libc.
call __setup_for_c ; set up C environment
call __libc_start_main ; set up standard library
call _main ; call your main
call __libc_stop_main ; tear down standard library
call __teardown_for_c ; tear down C environment
jmp __exit ; return to OS
Run Code Online (Sandbox Code Playgroud)
“魔法编织”是为 C 程序准备环境所需的一切。这可能包括以下内容:
argc并argv在堆栈上,甚至准备堆栈本身(有可能用于 C 的特定调用约定,并且很可能操作系统在调用时根本不需要设置堆栈,_start因为进程的需要是未知);只有当所有这些都完成后,才可以调用您的main函数。还有可能在您main退出后需要完成工作,例如:
atexit处理程序(您希望在退出时自动运行的东西,无论退出发生在哪里);(a)例如,如果您正在编写不使用标准 C 库的内容,或者您想为低级工作提供自己的例程,则可以告诉许多链接器不要这样做_start。