将C转换为8086汇编代码
环境 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指令集。
上网冲浪,找到以下几个方法生成8086汇编
- bcc编译器(Bruce’s C compiler)
- digitalMars编译器,生成8088汇编,使用的指令集和8086相同
- openWatcomC++编译器
- 降级GCC
- tkchia的gcc-ia16编译器
咱的目标把这个HelloWorld
给编译喽!
1 |
|
Bruce’s C compiler
这个是97年的老古董,也是方案里最轻量级的8086编译器了,可是资料实在是太少了!除了Manual外找不到其他的任何资料了。另外似乎并不完全支持ANSI C而是70年代Bell实验室发行的老祖宗C!
运行以下命令生成汇编代码
1 | bcc -ansi -0 -S HelloWorld.c |
生成的是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 |
然后就得到了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文件时要加上什么参数吗?