是否可以用 C 或 C++ 实现小型磁盘操作系统?
我没有尝试做任何这样的事情,但出于好奇,我想知道是否可以实现一个“整个操作系统”(不一定是像 Linux 或 Microsoft Windows 这样的大操作系统,而更像是一个小型 DOS -类似操作系统)在 C 和/或 C++ 中不使用或很少使用汇编。
通过实现操作系统,我的意思是从头开始制作操作系统,启动引导加载程序和内核,再到用 C 或 C++ 编写的图形驱动程序(以及可选的 GUI)。我见过一些通过编译器访问低级功能在 C++ 中完成的低级操作。这可以为整个操作系统完成吗?
我不是在问这是否是一个好主意,我只是在问这是否有可能?
I am not trying to do any such thing, but I was wondering out of curiosity whether one could implement an "entire OS" (not necessarily something big like Linux or Microsoft Windows, but more like a small DOS-like operating system) in C and/or C++ using no or little assembly.
By implementing an OS , I mean making an OS from scratch starting the boot-loader and the kernel to the graphics drivers (and optionally GUI) in C or C++. I have seen a few low-level things done in C++ by accessing low-level features through the compiler. Can this be done for an entire OS?
I am not asking whether it is a good idea, I am just asking whether it is even remotely possible?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
OSDev wiki 的强制链接,它描述了创建 x86/ 操作系统所需的大部分步骤x64。
为了回答你的问题,创建引导加载程序并启动保护模式而不诉诸于至少一些程序集将是非常困难/不愉快的,尽管它可以保持在最低限度(特别是如果你没有真正计算诸如使用之类的东西
__asm__ ( "lidt %0\n" : : "m" (*idt) );
as '程序集')。一个很大的障碍(同样在 x86 上)是处理器以 16 位实模式启动,因此您需要一些 16 位代码。根据此讨论你可以让GCC生成16 位代码,但您仍然需要某种方法来设置内存、从某些存储介质加载代码等,所有这些都需要以标准 C 没有概念的方式与硬件进行交互(中断、IO 端口) ETC。)。
对于仅通过内存映射 IO 与硬件通信的架构,您可能可以用纯 C 编写除 C 启动代码(设置堆栈、初始化变量等)之外的所有内容,尽管中断例程/的特定要求异常或系统调用门等可能很难甚至不可能实现(因为您必须访问特殊的 CPU 寄存器)。
Obligatory link to the OSDev wiki, which describes most of the steps needed to create an OS as described on x86/x64.
To answer your question, it is gonna be extremely difficult/unpleasant to create the boot loader and start protected mode without resorting to at least some assembly, though it can be kept to a minimum (especially if you're not really counting stuff like using
__asm__ ( "lidt %0\n" : : "m" (*idt) );
as 'assembly').A big hurdle (again on x86) is that the processor starts in 16-bit real mode, so you need some 16-bit code. According to this discussion you can have GCC generate 16-bit code, but you would still need some way to setup memory, load code from some storage media and so on, all of which requires interfacing with the hardware in ways that standard C just has no concept of (interrupts, IO ports etc.).
For architectures which communicate with hardware solely through memory mapped IO you could probably get away with writing everything except the C start-up code (that sets up the stack, initializes variables and so on) in pure C, though specific requirements of interrupt routines / exception or syscall gates etc. may be difficult to impossible to implement (as you have to access special CPU registers).
我假设您心中有一个 x86 操作系统。在这种情况下,您至少需要几页汇编程序来设置保护模式和类似的东西,除此之外,还需要大量有关分页、调用门、环、异常等所有内容的知识。如果您打算使用某种形式的系统调用,您还需要一些汇编代码行来在内核和用户空间模式之间切换。
除了这些之外,操作系统的其余部分可以轻松地用 C 进行编程。对于 C++,您需要一个运行时环境来支持虚拟成员和异常等内容,但据我所知,所有这些都可以用 C 进行编程。
只需查看 Linux 内核来源,最重要的汇编程序代码(针对 x86)可以在 arch/x86/boot 中找到,但是您会注意到,即使在该目录中,大多数文件都是用 C 编写的。此外,您还会在 arch/x86/kernel 目录中找到一些汇编代码行用于处理系统调用和类似的东西。
在 arch 目录之外几乎没有使用任何汇编程序(因为汇编程序是特定于机器的,该机器特定的代码属于 arch 目录)。甚至图形驱动程序也不使用汇编程序(例如 drivers/gpu/drm/nouveau 中的 nvidia 驱动程序)。
I assume that you have an OS for x86 in mind. In that case you need at least a few pages of assembler to set up protected mode and stuff like that, and besides that a lot of knowledge of all the stuff like paging, call gates, rings, exceptions, etc. If you are going to use a form of system calls you'll also need some lines of assembly code to switch between kernel and userspace mode.
Besides those things the rest of an OS can easily be programmed in C. For C++ you'll need a runtime environment to support things like virtual members and exceptions, but as far as I know that can all be programmed in C.
Just take a look at Linux kernel source, the most important assembler code (for x86) can be found in arch/x86/boot, but you'll notice that even in that directory most files are written in C. Furthermore you'll find a few assembly lines in the arch/x86/kernel directory for handling system calls and stuff like that.
Outside the arch directory there is hardly any assembler used (because assembler is machine specific, that machine specific code belongs in the arch directory). Even graphic drivers don't use assembler (e.g. nvidia driver in drivers/gpu/drm/nouveau).
引导加载程序?您可能想跳过这一点。例如,Linux 通常由非 Linux 引导加载程序启动,例如 UBoot。毕竟,一旦系统运行,操作系统就会出现,但引导加载程序不会出现,引导加载程序只是将操作系统正确加载到内存中。
一旦您选择了一个不错的现有引导加载程序,剩下的事情几乎就很简单了。好吧,你必须自己处理内存和文件;显然你不能依赖
fopen
。但即使是 C++ 编译器,生成无需操作系统支持也能运行的代码也没有什么问题。A boot loader? You might want to skip that bit. For instance, Linux is quite often started by non-Linux boot loaders such as UBoot. After all, once the system is running, the OS will be present but not the boot loader, that's just there to get the OS proper into memory.
And once you've selected a decent existing bootloader, the remainder is pretty much all straightforward. Well, you have to deal with memory and files yourself; you can't rely on
fopen
obviously. But even a C++ compiler has little problem generating code that can run without OS support.