我只是想知道如何在C++中创建一个独立的程序?
**编辑:**通过独立,我的意思是一个程序,不运行在托管环境(例如。我希望我的程序是计算机加载的第一个程序,而不是操作系统。
yyyllmsg1#
看看这篇文章:http://www.codeproject.com/KB/tips/boot-loader.aspx你可能需要一点汇编启动代码来完成main(),但你可以用C++编写其余的代码。如果你想在运行时创建对象,你必须编写自己的堆管理器(new/delete),如果你想创建多个线程,你必须编写自己的调度器。
iq3niunx2#
查看此页面:http://wiki.osdev.org/C++它拥有使用更流行的工具链以c为核心语言开始编写操作系统所需的一切。此外,这个页面应该是非常有帮助的:http://wiki.osdev.org/C++_Bare_Bones。它几乎可以引导您进入操作系统的c入口点。
z9ju0rcb3#
遗留系统
即使经过您的澄清,答案也是它取决于-确切的 Boot 顺序取决于硬件-尽管有相当多的共性。 Boot 加载程序通常是在绝对地址上加载的,它所包含的文件经常被完全按原样读入内存。这意味着你通常使用一个“链接定位器”而不是一个普通的链接器。一个典型的链接器产生一个准备好重定位和加载的可执行文件,定位器产生一个已经设置好在一个确切地址运行的可执行文件,所有重定位都已经应用。对于那些年龄足够大的人来说,它通常非常像MS-DOS .COM文件。沿着此之外,它还必须(当然)静态地链接程序所依赖的整个运行时--它不能依赖于DLL或共享对象库之类的东西,因为加载这些东西的代码本身还没有加载。
EFI/UEFI
当前的PC(和Mac)使用EFI/UEFI。在本文的其余部分中,我将只提到UEFI,但它的大部分内容也同样适用于EFI(但UEFI更为常见)。这些为 Boot 代码提供了更多的支持。这包括大多数设备的驱动程序(它支持安装设备驱动程序),因此您的 Boot 代码可以使用网络等,这在传统模式下更难支持。EFI下的可引导代码使用与Windows可执行文件相同的PE格式。库也是可用的,所以相当多的 Boot 代码可以写得更像在操作系统内部运行的普通代码。我不会尝试进入很多细节,但这里有一些信息的链接。https://www.intel.com/content/www/us/en/developer/articles/tool/unified-extensible-firmware-interface.htmlhttps://www.intel.com/content/dam/doc/guide/uefi-driver-network-boot-devices-guide.pdfhttps://www.intel.com/content/dam/www/public/us/en/documents/guides/bldk-v2-uefi-standard-based-guide.pdf也许最重要的一个--开发工具包:https://github.com/tianocore/edk2
统一内核
为了使这更容易和更实用,通常最容易从所谓的“unikernel”开始。这基本上是一组作为库实现的类似于操作系统的原语,因此当您链接程序时,必要的操作系统原语直接链接到其中,因此它可以在裸机上(或者通常在VM中) Boot 。例如IncludeOS和UniKraft。IncludeOS通常会要求您专门为其编写新代码。UniKraft更接近于POSIX实现,因此它可以运行相当多的现有软件(例如,nginx,redis)。
qlckcl4x4#
google 'embedded c++' for a start另一个想法是从嵌入式系统仿真器开始,例如,atmel AVR站点有一个很好的IDE,可以仿真atmel AVR系统,并允许您用C构建原始代码并将其加载到仿真CPU中,他们使用gcc作为工具链(我认为)
dwthyt8l5#
C++在embedded systems programming中使用,甚至用于编写OS内核。通常在 Boot 序列的早期至少有一些汇编指令。有些东西用这种方式表达起来更容易,或者可能需要使用来自CPU供应商的参考代码。对于初始 Boot 过程,您将无法使用标准库。无例外、RTII、新建/删除。又回到了“有课的C”。大多数人在这里只使用C。一旦加载了足够的支持基础设施,就可以使用标准库中可以移植的任何部分。
lyfkaqu16#
您将需要一个提供以下功能的环境:
除了任何其他图书馆。如果你的平台上没有动态链接器(如果你没有操作系统,你可能没有链接器),那么你将不得不静态链接它。在实践中,这意味着链接一些小的C运行时和适合您平台的C库。然后你可以简单地编写一个独立的C程序。
hxzsmxv27#
如果你使用的是BSD Unix,你应该链接到独立库。这包括一个基本的磁盘和tty IO系统。你的源代码看起来和在Unix下运行的一样,但是二进制文件可以被加载到一个裸机中。
pnwntuvh8#
是的,当然。C和C的ISO标准支持托管和独立环境,宏STDC_HOSTED用于区分两者。自2011年以来一直如此。由于我在这里看到的大多数回复都是在黑暗中,因为这是所有标准术语(并且应该是C和C用户的常识),我将在这里重述ISO列出的两者之间的区别,并请您参阅以下链接以了解更多细节:https://en.cppreference.com/w/cpp/freestanding
托管:
“main”被定义,并且在主线程中启动。静态对象可以在线程的stand和end处构造和析构。通常,这意味着有一个主机操作系统(OS),它提供了运行程序的环境所需的所有基础设施。特别是POSIX标准,它详细说明了在主机系统上从命令行调用的实用程序所期望的一组条件;和ISO C/C++标准相互衔接,并融入POSIX标准。(POSIX对C的支持至少是C99。
独立式:
“主要”可以但不需要被定义。构造函数是否/如何在启动时应用于静态对象,析构函数是否/如何在终止时应用于静态对象,取决于实现。它是由C或C程序生成的例程不被某些操作系统调用,而是自己运行的任何环境。这是嵌入式系统的典型情况。“独立”当然也包括操作系统本身,作为一个特例。操作系统内核是独立程序的缩影。这里的一位受访者甚至提供了一个C的roll-your-own-OS工具包的链接。在这种情况下,通过将Linus OS的旧0.96版本(您可以在UNIX Archive中找到)重写为独立的C程序来测试这个概念将是一个有趣的练习。他的源代码实际上充满了C的主义(特别是在“fs”目录中),几乎尖叫着“我是一个虚函数”,“我是一个基类”,“我是一个派生类”或“这是类继承”!
独立程序所需的库:
还有关于必须支持哪些标准库以及支持多少的最低要求。值得注意的:,是强制性的,启动和终止只需要部分支持,(自2011年起)和(自2020年起)是强制性的,如果您正在使用嵌入式系统,最好是这样!不是强制性的。然后,一个自定义操作系统工具包将为强制性库和其他半强制性库的必需部分提供模板。任何负责任的嵌入式系统开发人员都将设计他们的运行时系统和环境,面向这些用户的编译器将提供所需的底层透明性,以允许完成这一工作,并允许用户定义的运行时系统与编译器干净地接口。
8条答案
按热度按时间yyyllmsg1#
看看这篇文章:
http://www.codeproject.com/KB/tips/boot-loader.aspx
你可能需要一点汇编启动代码来完成main(),但你可以用C++编写其余的代码。如果你想在运行时创建对象,你必须编写自己的堆管理器(new/delete),如果你想创建多个线程,你必须编写自己的调度器。
iq3niunx2#
查看此页面:http://wiki.osdev.org/C++
它拥有使用更流行的工具链以c为核心语言开始编写操作系统所需的一切。
此外,这个页面应该是非常有帮助的:http://wiki.osdev.org/C++_Bare_Bones。它几乎可以引导您进入操作系统的c入口点。
z9ju0rcb3#
遗留系统
即使经过您的澄清,答案也是它取决于-确切的 Boot 顺序取决于硬件-尽管有相当多的共性。 Boot 加载程序通常是在绝对地址上加载的,它所包含的文件经常被完全按原样读入内存。这意味着你通常使用一个“链接定位器”而不是一个普通的链接器。一个典型的链接器产生一个准备好重定位和加载的可执行文件,定位器产生一个已经设置好在一个确切地址运行的可执行文件,所有重定位都已经应用。对于那些年龄足够大的人来说,它通常非常像MS-DOS .COM文件。
沿着此之外,它还必须(当然)静态地链接程序所依赖的整个运行时--它不能依赖于DLL或共享对象库之类的东西,因为加载这些东西的代码本身还没有加载。
EFI/UEFI
当前的PC(和Mac)使用EFI/UEFI。在本文的其余部分中,我将只提到UEFI,但它的大部分内容也同样适用于EFI(但UEFI更为常见)。
这些为 Boot 代码提供了更多的支持。这包括大多数设备的驱动程序(它支持安装设备驱动程序),因此您的 Boot 代码可以使用网络等,这在传统模式下更难支持。
EFI下的可引导代码使用与Windows可执行文件相同的PE格式。库也是可用的,所以相当多的 Boot 代码可以写得更像在操作系统内部运行的普通代码。我不会尝试进入很多细节,但这里有一些信息的链接。
https://www.intel.com/content/www/us/en/developer/articles/tool/unified-extensible-firmware-interface.html
https://www.intel.com/content/dam/doc/guide/uefi-driver-network-boot-devices-guide.pdf
https://www.intel.com/content/dam/www/public/us/en/documents/guides/bldk-v2-uefi-standard-based-guide.pdf
也许最重要的一个--开发工具包:
https://github.com/tianocore/edk2
统一内核
为了使这更容易和更实用,通常最容易从所谓的“unikernel”开始。这基本上是一组作为库实现的类似于操作系统的原语,因此当您链接程序时,必要的操作系统原语直接链接到其中,因此它可以在裸机上(或者通常在VM中) Boot 。
例如IncludeOS和UniKraft。IncludeOS通常会要求您专门为其编写新代码。UniKraft更接近于POSIX实现,因此它可以运行相当多的现有软件(例如,nginx,redis)。
qlckcl4x4#
google 'embedded c++' for a start
另一个想法是从嵌入式系统仿真器开始,例如,atmel AVR站点有一个很好的IDE,可以仿真atmel AVR系统,并允许您用C构建原始代码并将其加载到仿真CPU中,他们使用gcc作为工具链(我认为)
dwthyt8l5#
C++在embedded systems programming中使用,甚至用于编写OS内核。
通常在 Boot 序列的早期至少有一些汇编指令。有些东西用这种方式表达起来更容易,或者可能需要使用来自CPU供应商的参考代码。
对于初始 Boot 过程,您将无法使用标准库。无例外、RTII、新建/删除。又回到了“有课的C”。大多数人在这里只使用C。
一旦加载了足够的支持基础设施,就可以使用标准库中可以移植的任何部分。
lyfkaqu16#
您将需要一个提供以下功能的环境:
除了任何其他图书馆。如果你的平台上没有动态链接器(如果你没有操作系统,你可能没有链接器),那么你将不得不静态链接它。
在实践中,这意味着链接一些小的C运行时和适合您平台的C库。然后你可以简单地编写一个独立的C程序。
hxzsmxv27#
如果你使用的是BSD Unix,你应该链接到独立库。这包括一个基本的磁盘和tty IO系统。你的源代码看起来和在Unix下运行的一样,但是二进制文件可以被加载到一个裸机中。
pnwntuvh8#
是的,当然。C和C的ISO标准支持托管和独立环境,宏STDC_HOSTED用于区分两者。自2011年以来一直如此。
由于我在这里看到的大多数回复都是在黑暗中,因为这是所有标准术语(并且应该是C和C用户的常识),我将在这里重述ISO列出的两者之间的区别,并请您参阅以下链接以了解更多细节:
https://en.cppreference.com/w/cpp/freestanding
托管:
“main”被定义,并且在主线程中启动。静态对象可以在线程的stand和end处构造和析构。通常,这意味着有一个主机操作系统(OS),它提供了运行程序的环境所需的所有基础设施。特别是POSIX标准,它详细说明了在主机系统上从命令行调用的实用程序所期望的一组条件;和ISO C/C++标准相互衔接,并融入POSIX标准。(POSIX对C的支持至少是C99。
独立式:
“主要”可以但不需要被定义。构造函数是否/如何在启动时应用于静态对象,析构函数是否/如何在终止时应用于静态对象,取决于实现。
它是由C或C程序生成的例程不被某些操作系统调用,而是自己运行的任何环境。这是嵌入式系统的典型情况。
“独立”当然也包括操作系统本身,作为一个特例。操作系统内核是独立程序的缩影。这里的一位受访者甚至提供了一个C的roll-your-own-OS工具包的链接。在这种情况下,通过将Linus OS的旧0.96版本(您可以在UNIX Archive中找到)重写为独立的C程序来测试这个概念将是一个有趣的练习。他的源代码实际上充满了C的主义(特别是在“fs”目录中),几乎尖叫着“我是一个虚函数”,“我是一个基类”,“我是一个派生类”或“这是类继承”!
独立程序所需的库:
还有关于必须支持哪些标准库以及支持多少的最低要求。值得注意的:,是强制性的,启动和终止只需要部分支持,(自2011年起)和(自2020年起)是强制性的,如果您正在使用嵌入式系统,最好是这样!不是强制性的。
然后,一个自定义操作系统工具包将为强制性库和其他半强制性库的必需部分提供模板。任何负责任的嵌入式系统开发人员都将设计他们的运行时系统和环境,面向这些用户的编译器将提供所需的底层透明性,以允许完成这一工作,并允许用户定义的运行时系统与编译器干净地接口。