后记

非常感谢您阅读本书!

目前为止,我们已经讲述了如何在UEFI下进行裸机编程。如果你能读完本书后感到“啊!原来是这么回事”,将是我莫大的荣幸。

UEFI十分精妙,它具有许多内建的功能,也可以做很多事情。当我阅读UEFI标准文档的目录时,我惊叹道“这些居然可以在固件层面上做到”1。并且,即便在软件上进行最底层2操作时,也不需要考虑到内存映射这些问题,这也是很令人惊讶的。

就像我在引言中说的,本书的理念是解答“通过调用UEFI内置的功能来编写一个类似于操作系统的程序可行吗?”这个想法。事实证明了,这是完全可行的。UEFI提供了许多功能,而其中,它的文件系统功能是非常强大的。因此,在我看来,如果你想从零编写一个操作系统,从UEFI开始是很合适的。

最后,我想用一首二进制短歌3来结束本书。其汇编代码如图8.1所示,生成的程序反汇编如图8.2所示,示例代码的目录为sample_tanka (仅限日文版)。 4

#define CONOUT_ADDR 0xa3819590
#define OUTPUTSTRING_ADDR 0xa387e1b8

    .text
    .globl      efi_main
efi_main:
    /* 输出"msg"字符串 */
    /* 将OutputString的第一个参数ConOut放入RCX寄存器 */
    movq        $CONOUT_ADDR, %rcx
    /* 将OutputString函数的地址放入RAX寄存器 */
    movq        $OUTPUTSTRING_ADDR, %rax
    /* 将要输出的字符串"msg"的地址(第二个参数)放入RDX寄存器 */
    leaq        msg, %rdx
    /* 调用OutputString函数 */
    callq       *%rax

    /* 无限循环 */
    jmp     .

    .data
msg:
    /* "ABCD" */
    .ascii      "A\0B\0C\0D\0\0\0"
    /* "すごーい" */
    /*.ascii        "Y0T0\3740D0\0\0"*/
    /* ボス */
    /*.ascii        "\326\0\0\0"*/

图8.1: 短歌的汇编代码5

0000000000401000 <efi_main>:
  401000:       48 b9 90 95 81 a3 00    movabs $0xa3819590,%rcx
  401007:       00 00 00
  40100a:       48 b8 b8 e1 87 a3 00    movabs $0xa387e1b8,%rax
  401011:       00 00 00
  401014:       48 8d 14 25 00 20 40    lea    0x402000,%rdx
  40101b:       00
  40101c:       ff d0                   callq  *%rax
  40101e:       eb fe                   jmp    40101e <efi_main+0x1e>

图8.2: 对生成的程序进行反汇编的结果

这里.text段占用32字节,多了1字节。

再次感谢您阅读本书!

1

拥有内建的内存分配器对我而言是不可思议的。

2

严格意义上讲,UEFI并不是最底层的,其下还有硬件的固件。

3

译者注:短歌是一种日本传统诗歌,有5句31个音节,以五・七・五・七・七的形式排列

4

译者注:中文版这里不提供示例代码的原因是UEFI不保证各个协议及函数的地址是一个恒定不变的值,在代码中写死的地址的写法是不可取的。这里我仍旧保留并翻译这些内容的原因是为了说明用汇编编写UEFI应用程序的可能性

5

译者注:x86_64下的UEFI遵循Microsoft x64 calling convention