编译C并将ASM组装成机器代码

时间:2013-02-02 20:57:27

标签: c assembly compilation machine-code

我有三个问题:

  1. 我可以使用哪种编译器以及如何使用它将C源代码编译为机器代码
  2. 我可以使用哪种汇编程序,如何使用它将ASM汇编到机器代码
  3. (可选)您如何建议将机器代码放在正确的地址中(例如,引导程序机器代码必须放在引导扇区中)?
  4. 我的目标: 我正在尝试制作一个基本的操作系统。这将使用个人自制的引导程序和内核。我还会尝试从Linux内核(即驱动程序)中获取一些碎片并将它们集成到我的内核中。我希望在大多数现代计算机上创建一个32位类似DOS的操作系统来处理内存。我认为我不会为我的操作系统创建可执行格式,因为我的操作系统不够动态,无法满足要求。

    我的情况: 我正在运行带有Intel Celeron CPU的x86-64 windows 8笔记本电脑;我相信它使用安全启动。我将在带有Intel Core I3 CPU的x86-64桌面上测试我的操作系统。我对操作系统及其技术有一个平均的了解。我知道这个项目所需的C,ASM和计算机理论。我认为值得注意的是,我十六岁没有正式的计算机科学教育。

    我的研究:在Google搜索C正常编译的内容之后,我找到了答案,包括机器代码,二进制,纯二进制,原始二进制,汇编和可重定位目标代码。正如我所理解的那样,程序集正常组装成PE格式的可执行文件。我听说过Cygwin,GCC C和MingW C编译器。至于汇编程序,我听说过FASM,MASM和NASM。我搜索了OSDevOSDever等网站。

    我尝试了什么:我尝试设置GCC(一场噩梦)并创建一个交叉编译器(另一场噩梦)。

    结论:正如您所知,我对编译器,汇编程序和可执行格式感到困惑。请消除我的无知以及回答我的问题。这些可能是阻止我在简历上使用操作系统的唯一因素。对不起,我会包含更多链接,但stackoverflow不会让我赚两个以上。万分感谢!

4 个答案:

答案 0 :(得分:4)

首先,快速回答三个问题。

  1. 几乎所有编译器都会将C代码转换为汇编代码。这就是编译器的原因。海湾合作委员会和铿锵声很受欢迎。

    clang -S -o example.s example.c
    
  2. 您选择的编译器也可能只支持汇编,只需使用相同的编译器驱动程序。

    clang -o example.o example.s
    
  3. 您的链接器文档将告诉您如何将特定代码放在特定地址等等。如果您使用GCC或clang,如上所述,您可能会使用ld(1)。在这种情况下,请阅读“链接器脚本”。

  4. 接下来,一些注意事项:

    • 您不需要交叉编译器或自己设置GCC。您正在使用Intel计算机,为Intel计算机生成代码。你的linux发行版附带的clang或GCC的任何二进制发行版应该可以正常工作。

    • C编译器通常将代码编译到汇编程序中,然后将生成的程序集传递给系统汇编程序,最终得到机器代码。机器代码,二进制,纯二进制,原始二进制,基本上都是同义词。

    • 生成的机器代码被打包成某种可执行文件格式,告诉主机操作系统如何加载和运行代码。在Windows上,它是PE,在Linux上,它是ELF,在Mac OS X上它是Mach-O。

    • 您不需要为您的操作系统创建可执行格式,但您可能希望使用。 ELF是一个非常简单(并且记录良好)的选项。

    还有一点个人注意事项,我希望不要过多地劝阻你 - 如果你不熟悉编译器,汇编器,链接器和所有这些工具的工作方式,那么你的项目将非常非常困难和令人困惑。你可能想从一些较小的项目开始,以获得你的“海底”,可以这么说。

答案 1 :(得分:2)

首先,“机器代码”和“二进制”是同义词。 “对象代码”是某种中间形式,链接器将在最后转换为二进制。一些C / C ++编译器不直接生成二进制文件,而是生成汇编程序源代码,它们生成目标代码,然后生成目标代码,生成最终二进制文件。在大多数情况下,这些过程对用户是透明的。您使用C / C ++ / Pascal /任何源代码为编译器提供数据,并在输出处获取二进制文件。

FASM assembler, aka flatassembler是OS开发的最佳汇编程序。在FASM中已经创建了几个操作系统。

这是因为FASM是可自编译的,并且非常便于携带。这样,在2到3天内,您可以将其移植到您的操作系统,然后您的操作系统将自给自足 - 即您可以从您的操作系统中编译程序。

FASM的另一个优点是它不需要链接器 - 它可以直接生成多种格式的二进制文件。

大型活跃社区也非常重要。 FASM有很多可用的资源,包括OS开发。

message board非常活跃,是人们可以学到很多东西的地方。

答案 2 :(得分:2)

我认为你问题的第一部分已经回答了,所以我会接受其他两个问题:

  

我可以使用哪种汇编程序,如何使用它将ASM汇编到机器代码?

其中一个nasmyasm(基本上非常像nasm),fasm," masm"即ml64.exeml.exe,并作为Microsoft工具的一部分免费提供。

其中,我可能会推荐nasmyasm。该建议完全基于个人偏好 - 但他们支持的广泛平台,以及默认使用英特尔语法是我的理由。我尝试了一下,看看你喜欢什么。

  

(可选)您如何建议将机器代码放在正确的地址中(例如,引导程序机器代码必须放在引导扇区中)?

好吧,只有一种方法可以将引导加载程序放在MBR的正确地址 - 在LBA 0打开磁盘并在那里写入512字节,以0x55AA结尾。冲洗,然后关闭。 MBR通常还包含嵌入其中的分区表 - 它既是代码又是数据。这个东西的sciency术语是Von Neumann Architecture,可以简单地概括为"程序和数据存储在同一个地方"。想要从磁盘启动BIOS的操作是将前512个字节读入内存,检查签名,如果匹配,则执行该内存(从字节0开始)。

好的,那些问题已经解决了。现在我给你一些补充说明:

  • 引导加载程序的512字节对于任何人的使用来说都不够。因此,一些文件系统包含引导扇区,引导加载程序本身只是加载这些中的代码/数据。这允许加载更大量的代码 - 足以使内核运行。例如,grub包含旧版本中的stage1,stage1_5和stage2组件。
  • 虽然大多数操作系统都要求您使用可执行格式容器,但您不需要 。在磁盘和内存中,可执行代码只是一个,两个或三个字节的字符串,称为操作码。您可以阅读the opcode reference或Intel / AMD手册,了解十六进制值转换为什么。无论如何,您可以使用nasm执行从汇编程序到二进制的直接转换:

     nasm -f bin input.asm -o output.asm
    

    虽然结果很可能不会执行,但它可以很好地适用于16,32或64位汇编程序。如果您在代码中明确使用[bits 16]指令以及org 100h,那么唯一的地方就是MSDOS .com程序。不幸的是,这是最简单的二进制格式 - 你只有一个大块的代码和数据,这不能超过单个段的大小。

    我觉得这可能会解决这一问题:

      

    我找到了答案,包括机器代码,二进制,纯二进制,原始二进制,汇编和可重定位目标代码。

    关于汇编汇编到什么的答案 - 它根据汇编程序汇编到操作码和内存地址。这以字节表示,它们都是数据。您可以使用十六进制编辑器读取它们,尽管很少有这种情况严格需要。我提到了内存地址,因为一些操作码控制着如何解释内存地址 - 例如,可重定位目标代码要求地址不是硬编码的(相反,它们被解释为当前位置的偏移量)。

      

    正如我所理解的那样,汇编通常会组装成PE格式的可执行文件。

    公平地说,将C / C ++派生的汇编程序编译为操作码,然后将其与程序中包含的任何其他内容(数据,资源)一起存储为可执行格式,例如: PE。通常取决于您的操作系统。

  • 如果您已经彻底阅读了OSDev Wiki,那么您将意识到分段寻址是一件非常痛苦的事情 - 现代操作系统中标准和唯一的段使用是定义跨越整个地址空间的四个段 - 环0和3处有两个数据段,环0和3处有两个代码段。

  • 如果您没有彻底阅读the OSDEV Wiki,那么您应该这样做。我还建议JamesM's kernel tutorials包含有关在C中构建内核的实用建议。

  • 如果你只是想对DOS内核做坏事,你实际上仍然可以不需要自己编写完整的内核。您也应该能够从DOS将CPU切换到保护模式。您需要FreeDOS和您选择的汇编程序。有一个关于terminate and stay resident的优秀教程,它基本上意味着挂钩一个中断例程,然后在The Rootkit Arsenal中编辑自己的活动进程列表。互联网上也可能有这方面的教程。

    我可能很想推荐这样做,只是为了让自己适应这种低级别的东西。

  • 如果您只想戳操作系统,可以在Windows上设置内核调试。 WinDbg有点......神秘,但是一旦你习惯了它就有意义了。
  • 您提到您的笔记本电脑使用安全启动。如果是这种情况,您的笔记本电脑使用UEFI。如果你想了解这一点,UEFI spec 100%保证比你的数学作业更无聊,但我建议略读它只是为了理解目标和基本环境。重要的是拥有EFI SDK,它使您能够构建与EFI兼容的应用程序(它们是PE格式并存在于磁盘上的FAT32分区上),因此安装EFI引导程序非常简单,即使编写一个也是如此如果我不得不做出诚实的推荐,我现在就坚持使用MBR,因为在撰写本文时,使用MBR模拟操作系统要比EFI容易得多,而且你真的想要这样做现在某种形式的虚拟机。另外,我使用像grub这样的现有虚拟机,因为引导程序并不是那么令人兴奋,真的。
  • 其他人已经说过了,我会说:你绝对想在某种形式的模拟器或虚拟机下做这样的事情。你会犯错,保证,你会遇到你不理解的事情。仿真器和虚拟机软件现在是免费的,有些如BOCHS会告诉你给定故障,陷阱等的原因是什么。这非常有帮助!

答案 3 :(得分:0)

首先,使用虚拟盒之类的东西进行测试

我认为你可能想采取一些较小的步骤,轻松编写C代码。

然后研究磁盘上的引导扇区如何工作(在互联网上有详细记录),同时查看其他开源引导加载程序的代码。

然后看看如何进行任务切换。写起来并不难。在尝试嵌入自己的操作系统之前,您甚至可以在正常操作系统下运行它时编写大部分内容

使用C编译器,通常可以将asm内联通常与asm { /* assembly code */ }

混合使用