有和没有操作系统的两个空主{}程序有什么区别?

时间:2012-12-30 13:49:56

标签: c++ c compiler-construction operating-system runtime

使用c / c ++编译器为OS(比如linux)和没有OS(比如嵌入式DSP目标)编译时,两个空程序main {}有什么区别?我特别想知道当存在操作系统时编译器的作用会有所不同。两种情况下编译器/语言运行时有何不同?

4 个答案:

答案 0 :(得分:12)

实际上,链接器在打包程序以在操作系统上运行时执行不同的工作,而不是构建仅在裸硬件上运行的程序。编译器只生成包含针对主机体系结构的指令的目标文件,这些块稍后由链接器组合和打包。

要在操作系统上运行的程序必须具有某种二进制结构 - 这是可执行格式发挥作用的地方。例如,这种格式可能要求程序在开头应该有几个标题部分,然后代码应该跟随。操作系统加载程序的工作是解释此结构,然后向CPU提供代码部分包含的指令流。

相比之下,一个打算在裸硬件上运行的程序通常没有特殊的结构,可以直接送到CPU。

答案 1 :(得分:6)

  

实际上,链接器在打包时执行不同的工作   程序在操作系统上运行而不是构建程序   仅在裸硬件上运行。编译器只生成对象   包含针对主机架构的指令的文件,   这些块稍后由链接器组合和打包。

     

要在操作系统上运行的程序必须具有   某种二进制结构 - 这是可执行格式的用武之地   玩。这种格式可能要求该程序应该有一些   在开头的标题部分,然后代码应该遵循,为   例。 OS加载程序的工作是解释此结构   然后用代码流指令提供CPU   部分包含。

     

相比之下,一个旨在在裸硬件上运行的程序   通常没有特殊的结构,可以直接喂养   CPU。

我想借助布拉戈维斯特写得非常好的答案。事实上,他建议可执行容器格式和二进制接口之间存在差异等等。但是,最大的区别可能是实际执行应用程序代码的主要入口点,以及启动代码和运行时库的存在;但是,如果你知道你正在做什么,你也可以避免在完整的操作系统上与后者联系。

通常,如果存在启动例程,运行时库(例如crt0),则应用程序的实际入口点不是main,而是其他内容(通常为_start)。在此实际入口点之前将控制权移交给main,它可能会执行一系列非常具体的任务,通常与初始化有关。

more information on crt0总是有维基百科。

但是,在裸机平台上可能没有与编译器捆绑在一起的例程。因此,控件可能会直接发送到您的main,并且在平台上执行的第一个代码将是您的。

你去了,这是两种main之间最基本的区别。但是,我不得不说你的问题有点模糊,因为你可以在没有启动脚本的情况下解决,如果你自己初始化堆栈等,你也可以使用运行时库来完成所有这些(大多数?)裸 - 金属平台。实际上,这完全取决于您的编译器套件,您要定位的平台等等。

答案 2 :(得分:3)

我很想说没有区别。什么编译器 (或翻译系统)在很大程度上是实施 依赖;翻译系统可能会做不同的事情 对于Windows而不是Linux,即使它们都有资格作为操作系统。

主要区别在于实施是托管还是托管 不。如果它没有托管,那么它甚至可能不支持 main,如果是,则可能不支持main 参数。非托管实现的功能或要求 for startup是实现定义的。虽然还有一个 很多关于启动的“实施定义” 托管环境,实现 需要支持 main,返回int并且至少有两个签名,以及 应用程序需要提供这样的功能。

请注意,在过去和今天,许多实现都是如此 你会想到托管真的不是出于各种原因。 例如,在过去,g ++将自己记录为非托管 (至少gcc确实如此),因为他们无法控制,也无法控制 保证库的部分实现。乃至 今天,微软的C ++只能被认为是托管的时候 生成控制台应用; Windows应用程序没有 有一个main

答案 3 :(得分:0)

@BlagovestBuyukliev提供了一个写得很好的答案。

我想稍微扩展它 - 没有操作系统实际上意味着没有软件实现的操作系统。能够执行二进制代码的硬件还具有处理程序加载并将其提供给CPU以及所有其余低级细节的协议。在这种情况下,“OS”实际上作为HW实现的存在。从这一点来看,它与标准操作系统之间的差异不是主要的,而是技术性的,就二进制代码执行而言。