环境 Ubuntu 22.04

支持8086的几种汇编语法:

语法 开发者
MASM Microsoft
AT&T AT&T Bell Lab
NASM Netwide Assembler
HLA Randall Hyde

北理工《计算机原理与应用》课程使用MASM语法。

除了直接运行在微处理器上的,有的代码可以运行在系统上,调用系统的功能,比如 int 21h 调用DOS系统。

要把C转换为8086,第一反应就是用gcc,没想到gcc已经不支持8086了,只支持i386(80386)及以后的CPU指令集。

gcc手册

上网冲浪,找到以下几个方法生成8086汇编

  • bcc编译器(Bruce’s C compiler)
  • digitalMars编译器,生成8088汇编,使用的指令集和8086相同
  • openWatcomC++编译器
  • 降级GCC
  • tkchia的gcc-ia16编译器

咱的目标把这个HelloWorld给编译喽!

1
2
3
4
5
#include <stdio.h>
int main(){
printf("Hello world!\n");
return 0;
}

Bruce’s C compiler

这个是97年的老古董,也是方案里最轻量级的8086编译器了,可是资料实在是太少了!除了Manual外找不到其他的任何资料了。另外似乎并不完全支持ANSI C而是70年代Bell实验室发行的老祖宗C!

运行以下命令生成汇编代码

1
bcc -ansi -0 -S HelloWorld.c

HelloWorld.s

生成的是NASM语法

等等这些感叹号和!BCC_EOS是啥?我记得NASM和Intel都不是用!注释哇,一个5行的源码咋给你编译出200多行的代码了

在网上冲了会浪没找到这是啥,只能去问神奇的chatgpt了。他说这些!表示汇编器的注释,后续如果用HelloWorld.s继续生成代码编译器会忽略这些语句。而!BCC_EOS是表示某种注释块?

缩进真是伟大的发明!

又看了会儿手册,没找到怎么生成其他语法的汇编,也没找到去掉注释的参数,太不优雅了。

ia16-GCC

这个由tkchia维护开发,比较新,且支持C/C++(至少不是老祖宗了)。

手册扫了眼没找到命令怎么用……

编译器的教程好硬核啊,都没个Quick Start什么的,GCC Toolchain真不熟
1
ia16-elf-gcc -S HelloWorld.c -o HelloWorld.asm

HelloWorld.asm

然后就得到了AT&T语法汇编🫠


既然找不到编译器直接将源代码转换成Intel8086,根据机器码和汇编代码一一对应的关系,我们可以将机器码反汇编成Intel8086

反汇编工具

  • as GNU Assembler,GNU的汇编器,也可用于反汇编
  • objdump 显示obj文件信息,也可以用来反汇编

objdump

先将源代码编译成机器码

1
bcc -ansi -0 HelloWorld.c -o a.out

1
ia16-elf-gcc HelloWorld.c -o a.out

再将机器码反汇编为Intel汇编语法

1
objdump -D -b binary -m i8086 -M intel -M i8086 a.out > HelloWorld.asm
  • -D disassemble-all 将所有段的代码反汇编
  • -b obj文件是二进制机器码
  • -m obj文件的架构
  • -M 生成反汇编的信息,是intel语法在i8086上运行

打开生成的HelloWorld.asm一看,好家伙,上千行了!一看a.out的大小,居然也有几kB的数量级。不应该这么多啊,是在生成obj文件时要加上什么参数吗?