我的见解:
- 我猜我可能没有。我知道有一个英特尔C++编译器,那么它会生成特定于处理器的汇编代码吗?EXE在Windows上运行,因此它们利用了已经设置好的许多东西,从图形包到庞大的.NET框架。特定于处理器的可执行文件将从零开始,仅具有处理器的指令集。
- 这个可执行文件是否是一种文件类型?我们可以在Windows上运行它,但是控制权是否会转移到处理器上?我假设这个可执行文件类似于操作系统,必须在启动其他任何内容之前运行,并且只能“使用”处理器指令集。
让我们思考一下"运行"的含义...
需要将二进制代码加载到内存中。 这是操作系统的功能。 .EXE或二进制可执行文件或包或其他格式非常特定于操作系统,以便操作系统可以将其加载到内存中。
需要将控制权交给这些二进制代码。 这又是操作系统。
I / O例程(在C ++中,但在大多数地方都是如此)只是一个封装操作系统API的库。该死的操作系统, 到处都是它。
追忆往昔。
从前(是的,我那么老)我曾经使用没有操作系统的机器工作过。 我们还没有C。
我们使用诸如“汇编器”和“链接器”之类的工具编写机器代码,以创建我们可以加载到机器中的大型二进制图像。 我们必须通过痛苦的引导过程加载这些二进制图像。
我们使用前面板键将足够的代码加载到内存中,以读取像打孔纸带读取器这样的便利设备。 这将加载一个相当标准的引导链接加载器软件的小片段。(我们使用mylar胶带,所以不会磨损。)
然后,当我们将这个链接加载器加载到内存中时,就可以提供之前使用汇编器准备的磁带。
我们编写了自己的设备驱动程序。 或者我们使用源代码形式的库例程, punched 在纸带上。
"修补程序"实际上是修补了一些纸带。 另外,由于也存在小错误,因此我们必须根据手写说明调整内存映像-尚未放入磁带的修补程序。
后来,我们有了简单的操作系统,其具有简单的API、简单的设备驱动程序和一些实用程序,例如“文件系统”、“编辑器”和“编译器”。 这是针对一种称为Jovial的语言,但我们有时也使用Fortran。
我们必须焊接串行接口板,以便插入设备。 我们必须编写设备驱动程序。
底线。
您可以轻松地编写不需要操作系统的C++程序。
了解处理器芯片组中的硬件BIOS(或类似BIOS)功能。大多数现代硬件都有一个简单的操作系统固化在ROM中,用于执行加电自检(POST)、加载一些简单的驱动程序并查找启动块。
学习如何编写自己的引导块。这是在POST之后加载的第一个真正的“软件”东西。这并不难。您可以使用各种分区工具将引导块程序强制写入磁盘,并完全控制硬件,无需使用操作系统。
学习GRUB、LILO或BootCamp如何启动操作系统。这并不复杂。一旦它们启动,它们就可以加载您的程序,您就可以开始运行了。这比较简单,因为您创建了一个引导加载程序要加载的类型的分区。以Linux内核为基础,您会更开心。不要试图弄清楚Windows的启动过程——它太复杂了。
阅读有关ELF的信息。http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
学习如何编写设备驱动程序。如果您不使用操作系统,那么您需要编写设备驱动程序。
FreeRTOS系统是一个开源的实时操作系统,属于较小型的RTOS空间,如果你对此比较感兴趣,可以去看看。他们有一些x86应用程序的示例,这将让你了解什么样的x86系统可以运行裸机或基于RTOS的程序以及如何编译可在其上运行的程序; 链接在这里: http://www.freertos.org/a00090.html#186。
任何编译器/工具集都会为特定的处理器/操作系统组合生成代码。因此,您的Visual Studio编译示例会为x86/Windows生成代码。该.EXE文件仅能在x86/Windows上运行,而不能在(例如)一些手机使用的ARM/Windows上运行。
要为处理器/操作系统组合生成代码,需要使用通常称为交叉编译器的工具。如果您拥有完整的专业版Visual Studio订阅,则可以获得ARM交叉编译器,这将允许您生成ARM/Windows .EXE文件,这些文件无法在桌面计算机上运行,但可以在基于ARM/Windows的手机或掌上电脑上运行。
不要忘记 Windows 库。可以研究一下 QT 和 GTK+。
是的,您可以创建一个在处理器的“裸金属”上运行的可执行文件。显然,这就是操作系统内核的工作方式。您需要做的主要事情是创建一个不使用任何库的可执行文件。但是,“没有库”的限制包括C标准库!这意味着没有malloc,没有printf等。您必须基本上成为自己的操作系统,并自己管理内存和I/O。这将不可避免地需要在某个阶段直接使用汇编进行相当多的工作。
您还会失去其他几个奢侈品,例如main(),因为main()不能成为程序的起点,因为main()是由操作系统和C运行时环境调用的。
欢迎您提供每一行代码和每一个指令,不使用开发工具包,但仍然使用编译器,例如gcc。一些二进制格式与在操作系统上运行的格式相同,例如elf。您可以在Linux上执行elf文件,但也可以使嵌入式程序生成elf二进制文件。处理器无法以该格式执行elf,但是启动prom或某些情况下的ram的任何程序都将从elf文件中提取二进制程序,类似于操作系统从elf文件中提取要运行的程序。EXE不是这些文件格式之一。您最喜欢的Windows应用程序编译器可能也不是嵌入式编译器,尽管有时可以使用其中一个来执行高级语言部分,然后使用替代汇编程序和链接器。通常比它值得的更多的工作。例如,您可以编写一个C函数(不进行任何库或系统调用),将其编译为对象。编写自己的实用程序或查找实用程序以从该对象中提取已编译的二进制文件,将其转换为另一种对象格式或汇编程序(反汇编)。添加启动代码和其他汇编代码。将所有内容组合成嵌入式程序进行汇编和链接。我曾经使用Microsoft的嵌入式Visual C进行过一次,只是为了看看它与其他编译器相比如何,它并不可怕,但肯定不值得花费大量精力来获取输出。
从您的计算机到手机或微波炉中的处理器,每个处理器都必须有一些启动代码。该代码不在操作系统上运行。该代码使用与操作系统应用程序使用相同或类似的编译器。对于某些设备,该代码将处理器和内存以及芯片外围设备置于可以启动操作系统的状态。从那里开始,操作系统接管。在您的计算机上,这将是BIOS,然后是引导加载程序,最终是操作系统,如dos、windows、linux等。
主要问题是文件格式。PE与UNIX类系统中使用的ELF非常不同。一个有效的PE程序不能是一个有效的ELF。所以,你要么用不同的启动器动态地加载二进制文件,要么放弃。
除此之外,如果了解操作系统服务、启动时寄存器的值等信息,你的代码可以很容易地可靠地检测出你正在运行的操作系统并相应地采取行动(一些恶意软件就是这样做的)。然后,另一个挑战是重复使用代码而不是在同一二进制文件中有两个或更多不同的程序。基本上,你需要编写一个模拟器,至少对于你需要的服务。