<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>汇编 on 大飞的博客</title>
    <link>https://www.dafei.me/tags/%E6%B1%87%E7%BC%96/</link>
    <description>Recent content in 汇编 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Wed, 06 May 2026 01:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E6%B1%87%E7%BC%96/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（一）：让机器听你的第一句话</title>
      <link>https://www.dafei.me/posts/os-01-hello/</link>
      <pubDate>Wed, 06 May 2026 01:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-01-hello/</guid>
      <description>&lt;p&gt;电脑开机之后，CPU 做的第一件事是什么？&lt;/p&gt;
&lt;p&gt;不是运行 Linux，不是加载驱动，甚至不是执行你写的任何代码——而是执行一段固化在主板上的程序：&lt;strong&gt;BIOS&lt;/strong&gt;（Basic Input/Output System，主板上的固件，负责硬件自检和引导启动）。&lt;/p&gt;
&lt;p&gt;BIOS 做完硬件自检之后，会去找一个可以启动的磁盘。找到之后，它做了一件很朴素的事：把磁盘最开头的 512 字节复制到内存地址 &lt;code&gt;0x7C00&lt;/code&gt;，然后跳过去执行。&lt;/p&gt;
&lt;p&gt;就这样。没有操作系统，没有文件系统，没有任何框架。你写的代码，就从这 512 字节开始。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;512-字节能干什么&#34;&gt;512 字节能干什么&lt;/h2&gt;
&lt;p&gt;说实话，不多。但够用来在屏幕上打一行字。&lt;/p&gt;
&lt;p&gt;这一章的目标很简单：从磁盘启动，打印 &lt;code&gt;Hello, OS!&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这段代码叫 &lt;strong&gt;Bootloader&lt;/strong&gt;（引导程序，操作系统启动前最先运行的代码），是你第一次真正掌控机器的代码。&lt;/p&gt;
&lt;p&gt;有两个硬性要求必须满足，BIOS 才会认你：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;代码必须放在内存 &lt;code&gt;0x7C00&lt;/code&gt; 开始的位置&lt;/li&gt;
&lt;li&gt;这 512 字节的最后两个字节必须是 &lt;code&gt;0x55 0xAA&lt;/code&gt;（引导魔数，BIOS 用来识别可启动扇区的标志）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;少一个，BIOS 直接忽略你。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;实模式cpu-刚醒来的状态&#34;&gt;实模式：CPU 刚醒来的状态&lt;/h2&gt;
&lt;p&gt;启动的时候，CPU 处于&lt;strong&gt;实模式&lt;/strong&gt;（Real Mode，x86 最原始的工作模式，16 位寻址，最多访问 1MB 内存）。&lt;/p&gt;
&lt;p&gt;实模式有一个好处：可以直接调用 BIOS 提供的&lt;strong&gt;中断服务&lt;/strong&gt;（INT，软中断，通过中断号调用 BIOS 内置功能）。打印字符用的是 &lt;code&gt;int 0x10&lt;/code&gt;，往 &lt;code&gt;ah&lt;/code&gt; 里放功能号 &lt;code&gt;0x0E&lt;/code&gt;，往 &lt;code&gt;al&lt;/code&gt; 里放字符，中断一触发，字符就出现在屏幕上。&lt;/p&gt;
&lt;p&gt;这是整个计算机世界里最&amp;quot;低级&amp;quot;的打印方式，但也是最直接的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;两个坑&#34;&gt;两个坑&lt;/h2&gt;
&lt;p&gt;第一次写这段代码，我卡在两个地方：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;段寄存器没初始化。&lt;/strong&gt; 实模式下内存寻址是通过&amp;quot;段:偏移&amp;quot;来算的，&lt;code&gt;ds&lt;/code&gt;、&lt;code&gt;es&lt;/code&gt;、&lt;code&gt;ss&lt;/code&gt;（数据段、附加段、栈段寄存器）这些上来没初始化，地址算出来是错的。在代码开头手动清零就好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;栈没设置。&lt;/strong&gt; 汇编代码里调用任何东西之前，&lt;strong&gt;栈&lt;/strong&gt;（Stack，后进先出的内存区域，用于保存临时数据和返回地址）要先指到一个安全的地方。把 &lt;code&gt;sp&lt;/code&gt;（栈顶指针）设成 &lt;code&gt;0x7C00&lt;/code&gt; 就够了——往下增长，不会覆盖代码。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;跑起来&#34;&gt;跑起来&lt;/h2&gt;
&lt;p&gt;写好汇编，用 &lt;strong&gt;NASM&lt;/strong&gt;（汇编器，把汇编代码编译成机器码）编译成二进制，扔给 &lt;strong&gt;QEMU&lt;/strong&gt;（开源的硬件模拟器，可以模拟一台完整的 x86 计算机）模拟器：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
