设置裸机x86 Ada工具链

时间:2019-06-23 07:30:26

标签: ada bare-metal

请原谅一些广泛的问题。我想知道如何创建针对裸机x86的Ada工具链。 我在Ada Bare Bones上看过Lucretia的osdev.org教程,其中提供了一些有关为裸机开发构建合适的运行时的有用信息。这方面非常简单,但是我不确定如何为该平台构建交叉编译器,或者是否有必要。

我是否可以通过使用正确类型的RTS进行编译来创建“独立”二进制文件呢? 如果我要创建/使用适当的独立RTS,是否适合使用针对x86的现成的AdaCore或FSF GNAT?任何帮助理解这一点将不胜感激。

1 个答案:

答案 0 :(得分:9)

首先,请注意,我注意到裸机编程专家,但是由于这很有趣,我将尝试一下。话虽如此,我认为您不需要交叉编译器。本地平台编译器(例如适用于Linux x86-64的GNAT CE 2019)即可。

为了说明这一点,您可能想要重新创建Ada GitHub上的 multiboot / hello_world 示例。这是我在安装了GNAT CE 2019的Debian机器上采取的步骤,以使其正常工作。

首先,我安装了一些必要的软件包(QEMU,NASM和GNU xorriso)并克隆了上述存储库:

$ sudo apt-get install qemu nasm xorriso
$ git clone https://github.com/cirosantilli/x86-bare-metal-examples.git

然后,在存储库中,我切换到目录multiboot/hello-world,按原样构建示例并在QEMU中执行生成的图像,以检查所有设置是否正确:

multiboot/hello-world $ make
multiboot/hello-world $ make run

结果是弹出一个QEMU窗口,在左上角显示hello world。我关闭了QEMU,然后运行make clean进行清理。

然后我删除了main.c,并用Ada翻译 main.adb

with System.Storage_Elements;

procedure Main is

   --  Suppress some checks to prevent undefined references during linking to
   --
   --    __gnat_rcheck_CE_Range_Check
   --    __gnat_rcheck_CE_Overflow_Check
   --
   --  These are Ada Runtime functions (see also GNAT's a-except.adb).

   pragma Suppress (Index_Check);
   pragma Suppress (Overflow_Check);


   --  See also:
   --    https://en.wikipedia.org/wiki/VGA-compatible_text_mode
   --    https://en.wikipedia.org/wiki/Color_Graphics_Adapter#Color_palette

   type Color is (BLACK, BRIGHT);

   for Color'Size use 4;
   for Color use (BLACK => 0, BRIGHT => 7);


   type Text_Buffer_Char is
      record
         Ch : Character;
         Fg : Color;
         Bg : Color;
      end record;   

   for Text_Buffer_Char use
      record
         Ch at 0 range 0 .. 7;
         Fg at 1 range 0 .. 3;
         Bg at 1 range 4 .. 7;
      end record;


   type Text_Buffer is
     array (Natural range <>) of Text_Buffer_Char;


   COLS : constant := 80;
   ROWS : constant := 24;   

   subtype Col is Natural range 0 .. COLS - 1;
   subtype Row is Natural range 0 .. ROWS - 1;


   Output : Text_Buffer (0 .. (COLS * ROWS) - 1);
   for Output'Address use System.Storage_Elements.To_Address (16#B8000#);


   --------------
   -- Put_Char --
   --------------

   procedure Put_Char (X : Col; Y : Row; Fg, Bg : Color; Ch : Character) is
   begin
      Output (Y * COLS + X) := (Ch, Fg, Bg);
   end Put_Char;

   ----------------
   -- Put_String --
   ----------------

   procedure Put_String (X : Col; Y : Row; Fg, Bg : Color; S : String) is
      C : Natural := 0;
   begin
      for I in S'Range loop
         Put_Char (X + C, Y, Fg, Bg, S (I));
         C := C + 1;
      end loop;
   end Put_String;

   -----------
   -- Clear --
   -----------

   procedure Clear (Bg : Color) is
   begin
      for X in Col'Range loop
         for Y in Row'Range loop
            Put_Char (X, Y, Bg, Bg, ' ');
         end loop;
      end loop;
   end Clear;


begin

   Clear (BLACK);
   Put_String (0, 0, BRIGHT, BLACK, "Ada says: Hello world!");

   --  Loop forever.
   while (True) loop
      null;
   end loop;

end Main;

因为我们正在运行Ada,所以我不得不更改 entry.asm 并替换了以下几行,以确保调用了Ada程序而不是C程序的入口点。 GNAT发出的Ada程序的入口点是_ada_main(编译后,请参见objdump -t main.o的输出):

-- extern main
++ extern _ada_main

[...]

-- call main
++ call _ada_main

Makefile 中,我替换了以下几行以正确编译和链接Ada程序。请注意,我编译为i386(使用-m32开关)并请求链接器发出elf_i386可执行文件,因为处理器在启动后将不会直接执行64位指令:

-- ld -m elf_i386 -nostdlib -T linker.ld -o '$@' $^
++ ld -m elf_i386 -T linker.ld -o '$@' $^

[...]

-- main.o: main.c
-- <TAB>gcc -c -m32 -std=c99 -ffreestanding -fno-builtin -Os -o '$@' -Wall -Wextra '$<'
++ main.o: main.adb
++ <TAB>gcc -c -m32 -Os -o '$@' -Wall -Wextra '$<'

[...]

-- rm -f *.elf *.o iso/boot/*.elf *.img
++ rm -f *.ali *.elf *.o iso/boot/*.elf *.img

注意:请注意<TAB>之前的标签(用gcc表示)。 make对此主题很挑剔!

然后我再次再次调用make,然后再调用make run看到QEMU窗口弹出,但现在显示了文本:

Ada says: Hello world!

此Ada程序执行了裸机操作(在IA-32实模式下)!然后,我通过使用{p>将main.img转换为VirtualBox磁盘(VDI)进一步进行了演示。

VBoxManage convertfromraw main.img main.vdi --variant Fixed

,然后创建一个简单的VM(类型为“其他”和版本“其他/未知”),并以main.vdi作为其磁盘。我启动了VM,(再次)看到了文本“ Ada说:世界您好!”。弹出。

因此,鉴于上述结果,我认为在对x86裸机进行编程时,编译器不是主要问题。我宁愿认为主要挑战是:

  • 获得不链接到任何OS库(例如C标准库; libc)的正确的Ada运行时(例如,零占用空间; ZFP)。我什么都不知道,但是有些可能是现成的。我不确定OSDev.org上的内容是否已达到ZFP运行时级别。对于上面的简单程序,如果您愿意取消检查(请参见源代码中的注释),则可以省略运行时(如本例中所做的那样)。

  • 使x86处理器全部启动并运行(有关此说明,请参见here)。上面的示例仍处于32位实模式(如果我声明正确的话),但是您可能想要进入保护模式,64位指令等以充分利用其功能。