C 启动程序需要什么?

发布于 2024-10-10 10:47:51 字数 353 浏览 0 评论 0原文

引用一本unix编程书籍,

当 C 程序被执行时 kernelby,exec 函数之一 调用特殊的启动例程。这 函数在 main 之前调用 函数被调用。可执行文件 程序文件将该例程指定为 程序的起始地址; 这是由链接编辑器设置的 它由 C 编译器调用。这 启动例程取值 内核命令行参数和 环境并设置好 主函数被称为 之前已显示。

为什么我们需要一个中间人启动例程。 exec 函数可以直接调用 main 函数,并且内核可以直接将命令行参数和环境传递给 main 函数。为什么我们需要中间的启动例程?

Quoting from one of the unix programming books,

When a C program is executed by the
kernelby, one of the exec functions
calls special start-up routine. This
function is called before the main
function is called. The executable
program file specifies this routine as
the starting address for the program;
this is set up by the link editor when
it is invoked by the C compiler. This
start-up routine takes values from the
kernel the command-line arguments and
the environment and sets things up so
that the main function is called as
shown earlier.

Why do we a need a middle man start-up routine. The exec function could have straightway called the main function and the kernel could have directly passed the command line arguments and environment to the main function. Why do we need the start-up routine in between?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酒浓于脸红 2024-10-17 10:47:51

因为C没有“插件”的概念。因此,如果您想使用malloc(),就必须有人初始化必要的数据结构。 C 程序员很懒,不想一直编写这样的代码:

main() {
    initialize_malloc();
    initialize_stdio();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();

    ... oh wow, can we start already? ...
}

因此 C 编译器会找出需要做什么,生成必要的代码并设置一切,以便您可以从您的立即编写代码。

Because C has no concept of "plug in". So if you want to use, say, malloc() someone has to initialize the necessary data structures. The C programmers were lazy and didn't want to have to write code like this all the time:

main() {
    initialize_malloc();
    initialize_stdio();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();

    ... oh wow, can we start already? ...
}

So the C compiler figures out what needs to be done, generates the necessary code and sets up everything so you can start with your code right away.

ㄖ落Θ余辉 2024-10-17 10:47:51

启动例程初始化CRT(即创建CRT堆以便malloc/free工作,初始化标准I/O流等);对于 C++,它还调用全局的构造函数。可能还有其他特定于系统的设置,您应该检查运行时库的来源以获取更多详细信息。

The start-up routine initializes the CRT (i.e. creates the CRT heap so that malloc/free work, initializes standard I/O streams, etc.); in case of C++ it also calls the globals' constructors. There may be other system-specific setup, you should check the sources of your run-time library for more details.

慵挽 2024-10-17 10:47:51

调用 main() 是 C 的事情,而调用 _start() 是内核的事情,由二进制格式标头中的入口点指示。 (为了清楚起见:内核不想或不需要知道我们称之为 _start

如果您有一个非 C 二进制文件,则可能没有 main() function,你可能根本没有“函数”的概念。

所以实际的问题是:为什么编译器不给出 main() 的地址作为起点?这是因为典型的 libc 实现想要在真正启动程序之前进行一些初始化,请参阅其他答案。

例如,编辑,您可以像这样更改入口点:

$ cat entrypoint.c 
int blabla() { printf("Yes it works!\n"); exit(0); } 
int main() { printf("not called\n"); }

$ gcc entrypoint.c -e blabla

$ ./a.out 
Yes it works!

Calling main() is a C thing, while calling _start() is a kernel thing, indicated by the entry point in the binary format header. (for clarity: the kernel doesn't want or need to know that we call it _start)

If you would have a non-C binary, you might not have a main() function, you might not even have the concept of a "function" at all.

So the actual question would be: why doesn't a compiler give the address of main() as a starting point? That's because typical libc implementations want to do some initializations before really starting the program, see the other answers for that.

edit as an example, you can change the entry point like this:

$ cat entrypoint.c 
int blabla() { printf("Yes it works!\n"); exit(0); } 
int main() { printf("not called\n"); }

$ gcc entrypoint.c -e blabla

$ ./a.out 
Yes it works!
岁月染过的梦 2024-10-17 10:47:51

还需要了解的是,应用程序是在用户模式下执行的,任何系统都会调用、设置特权位并进入内核模式。这有助于防止用户访问内核级系统调用和许多其他复杂情况,从而提高操作系统的安全性。因此,对 printf 的调用将捕获、设置内核模式位、执行代码,然后重置为用户模式并返回到您的应用程序。

CRT 需要帮助您并允许您在 Windows 和 Linux 中使用您想要的语言。它提供了一些非常基本的操作系统引导,为您提供用于开发的功能集。

Important to know also is that an application program is executed in user mode, and any system calls out, set the privileged bit and go into kernel mode. This helps increase OS security by preventing the user from accessing kernel level system calls and a myriad of other complications. So a call to printf will trap, set kernel mode bit, execute code, then reset to user mode and return to your application.

The CRT is required to help you and allow you to use the languages you want in Windows and Linux. it provides some very fundamental bootstrapping into the OS to provide you with feature sets for development.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文