- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是学习操作系统开发的新手。从我读的书上说,引导加载程序会将第一个 MBR 复制到 0x7c00,并从那里以实模式启动。
并且,示例以 16 位汇编代码开头。但是,当我查看今天的 linux 内核时,arch/x86/boot有 'header.S' 和 'boot.h',但实际代码在 main.c 中实现。
这似乎对“不写汇编”很有用。但是,这在 Linux 中具体是如何完成的呢?我可以粗略地想象可能会有特殊的 gcc
选项和链接策略,但我看不到细节。
最佳答案
我更多地将此问题视为 X-Y 问题。在我看来,问题更多的是关于您是否可以在 C 中为您自己的操作系统开发编写引导加载程序(引导代码)。简单的答案是是,但不推荐。现代 Linux 内核可能不是创建用 C 编写的引导加载程序的最佳信息来源,除非您了解它们的代码在做什么。
如果使用 GCC,您可以对生成的代码执行的操作会受到限制。在较新版本的 GCC 中,有一个 -m16
选项以这种方式记录:
The
-m16
option is the same as -m32, except for that it outputs the".code16gcc"
assembly directive at the beginning of the assembly output so that the binary can run in 16-bit mode.
这有点骗人。虽然代码可以在16位实模式下运行,但是后端生成的代码使用了386地址和操作数前缀,使得正常的32位代码在16位实模式下运行。这意味着 GCC 生成的代码不能用于早于 386 的处理器(如 8086/80186/80286 等)。如果您想要一个可以在最广泛的硬件阵列上运行的引导加载程序,这可能是个问题。如果您不关心 386 之前的系统,那么 GCC 就可以了。
使用 GCC 的引导加载程序代码还有另一个缺点。添加到许多指令中的地址和操作数前缀加起来会使引导加载程序变得臃肿。引导加载程序的第一阶段通常在空间上非常受限,因此这可能会成为一个问题。
您将需要具有与硬件交互功能的内联汇编或汇编语言对象。您无权访问引导加载程序代码中的 Linux C 库(printf 等)。例如,如果您想写入视频显示器,您必须自己编写该功能的代码,要么直接写入视频内存,要么通过 BIOS 中断。
要将其完全绑定(bind)并将内容放入可用作 MBR 的二进制文件中,您可能需要一个特制的链接描述文件。在大多数项目中,这些链接描述文件都有一个 .ld
扩展名。这插入了获取所有目标文件的过程,将它们以与传统 BIOS 启动过程兼容的方式(代码在 0x07c00 以实模式运行)。
这样做有很多陷阱,我建议不要这样做。如果您打算编写 32 位或 64 位内核,那么我建议您不要编写自己的引导加载程序并使用现有的引导加载程序,例如 GRUB。在 1990 年代的 Linux 版本中,它有自己的引导加载程序,可以从软盘执行。现代 Linux 现在依靠第三方引导加载程序来完成大部分工作。特别是它支持符合 Multiboot specification 的引导加载程序。
Internet 上有许多使用 GRUB 作为引导加载程序的教程。 OS Dev Wiki是一种宝贵的资源。他们有一个 Bare Bones使用原始多重引导规范(由 GRUB 支持)引导基本内核的教程。可以使用最少的汇编语言代码轻松开发 Mulitboot 规范。 Multiboot 兼容的引导加载程序会自动将 CPU 置于保护模式,启用 A20 线,可用于获取内存映射,并可被告知在引导时将您置于特定的视频模式。
去年有人在 #Osdev聊天询问编写一个位于软盘(或磁盘镜像)前 2 个扇区的 2 阶段引导加载程序,完全在 GCC 和内联汇编中开发。我不推荐这样做,因为它相当复杂,而且内联汇编很难正确。很easy to write bad inline assembly这似乎有效但不正确。
我已经提供了 some sample code它使用带有内联汇编的链接器脚本 C 来处理 BIOS 中断,以从磁盘读取数据并写入视频显示器。如果有的话,这段代码应该是一个例子,说明为什么做你所要求的事情并非易事。
关于c - linux引导代码怎么用C写的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43564672/
我需要(我必须)将大量 float 写入 qdatastream 并且我只使用 4 个字节是必要的。setFloatingPointPrecision 或为 float 和 double 写入 4 或
我有一些 C 代码,我用 Python 对其进行了扩展。扩展的 C 代码有一个将一些结构附加到二进制文件的函数: void writefunction(const struct struct1* so
我正在用 C 语言开发一个小软件,用于在布告栏中读取和写入消息。每条消息都是一个以渐进数字命名的 .txt。 软件是多线程的,有很多用户可以并发操作。 用户可以进行的操作有: 阅读整个公告板(所有 .
我有 2 个线程同时访问同一个大文件 (.txt)。 第一个线程正在从文件中读取。第二个线程正在写入文件。 两个线程都访问同一个 block ,例如(开始:0, block 大小:10),但具有不同的
我做了很多谷歌搜索,但我仍然不确定如何继续。 Linux 下最常见的剪贴板读写方式是什么?我想要同时支持 Gnome 和 KDE 桌面。 更新:我是否认为没有简单的解决方案,必须将多个来源(gnome
1. 定义配置文件信息 有时候我们为了统一管理会把一些变量放到 yml 配置文件中 例如 图片 用 @ConfigurationProperties 代替 @Value 使用方法 定义对应字段的实体
在开始之前,我必须先声明我是 FORTRAN 的新手。我正在维护 1978 年的一段遗留代码。它的目的是从文件中读取一些数据值,处理这些值,然后将处理过的值输出到另一个文本文件。 给定以下 FORTR
我正在制作一个应用程序,我需要存储用户提供的一些信息。我尝试使用 .plist 文件来存储信息,我发现: NSString *filePath = @"/Users/Denis/Documents/X
在delphi类中声明属性时是否可能有不同类型的结果? 示例: 属性月份:字符串读取monthGet(字符串)写入monthSet(整数); 在示例中,我希望在属性(property)月份中,当我:读
我正在以二进制形式将文件加载到数组中,这似乎需要一段时间有没有更好更快更有效的方法来做到这一点。我正在使用类似的方法写回文件。 procedure openfile(fname:string); va
我想实现一个运行模拟的C#控制台应用程序。另外,我想给用户机会在控制台上按“+”或“-”来加速/减速模拟的速度。 有没有办法在编写控制台时读取控制台?我相信我可以为此使用多线程,但是我却不怎么做(我对
这是我的代码: use std::fs::File; use std::io::Write; fn main() { let f = File::create("").unwrap();
我有一个应用程序可以访问 csv 文本文件中的单词。由于它们通常不会更改,因此我将它们放置在 .jar 文件中,并使用 .getResourceAsStream 调用读取它们。我真的很喜欢这种方法,因
我使用kubeadm,docker 17.12.1-ce和法兰绒网络安装了Kubernetes 1.13.1集群 但是,我发现Kubernetes主服务器上有许多空文件,权限为666,该文件允许任何用
我的工作区中有一些 java 文件。现在我想编写一个java程序,它可以读取来自不同源的文本文件,一次一个,一行一行,并将这些行插入到工作区中各自的java文件中。 文本文件会告诉我将哪个文件插入到哪
用户A要求系统读取文件foo,同时用户B想要将他或她的数据保存到同一个文件中。在文件系统级别如何处理这种情况? 最佳答案 大多数文件系统(但不是全部)使用锁定来保护对同一文件的并发访问。锁可以是独占的
我对保护移动应用程序的 firebase 数据库有一些疑问。 例如,在反编译Android应用程序后,黑客可以获取firebase api key 然后访问firebase数据库,这是正确的吗? 假设
我想让文件从外部不可删除,并希望使用java从程序对该文件进行读/写操作。 S0,我使用以下代码使用java创建了不可删除的文件: Process pcs = Runtime.getRunti
当 Selector.select() 以阻塞模式等待读/写操作时,是否可以将写消息推送到客户端?如何将选择器从阻塞模式移至写入模式?触发器可以是一个后台线程,用于放置需要写入给定 channel 的
我目前正在学习在 Linux 环境中使用 C 进行套接字编程。作为一个项目,我正在尝试编写一个基本的聊天服务器和客户端。 目的是让服务器为每个连接的客户端派生一个进程。 我遇到的问题是读取一个 chi
我是一名优秀的程序员,十分优秀!