代码完成后,使用下面一串命令就可以把它进行汇编、链接,然后转换成DOS下的纯二进制格式(Plain Binary),最后复制到FreeDOS.img中,使用Qemu虚拟机执行FreeDOS,然后运行该16位实模式程序。这一串命令及其运行效果如下图:
这些命令中比较重要的选项我都特意标出来了。由于我用的是64位的环境,所以调用as命令的时候需要指定--32选项,调用ld命令的时候需要 指定-m elf_i386选项。指定以上选项后,生成的是32位的ELF目标文件,否则默认会生成64位的ELF目标文件,如果目标文件是64位,以后和C语言生 成的目标文件连接时会出问题。使用32位环境的朋友们不用特意指定这两个选项。由于DOS系统总是把Plain Binary文件载入到0x100地址处执行,所以调用ld命令时,需要指定-Ttext 0x100选项。ld命令执行完成后,生成的是ELF格式的可执行文件test.elf,最后需要调用objcopy生成纯二进制文件,-j .text选项的意思是只需要代码段,因为我把“Hello, world!”也是定义在代码段中的,-O binary选项指定输出格式为纯二进制文件,输出文件为test.com。最后,将freedos.img镜像文件mount到Ubuntu中,将 test.com拷贝到其中,然后umount,然后运行虚拟机,在DOS中运行test,就可以看到效果了。
除了as和ld,GNU Binutils中的其它程序也是写程序和分析程序时的好帮手。可以使用readelf -S查看test.elf文件中的所有段,也可以使用objdump -s命令将test.elf中的数据以16进制形式输入,如下图:
当然,也可以使用objdump -d或者objdump -D将程序进行反汇编,查看是否真正生成了16位代码,如下图:(反汇编时一定要指定-m i8086选项)
也可以对纯二进制格式的文件进行反汇编,必须指定-b binary选项,如下图,对test.com进行反汇编:
反汇编时,一定要指定-m i8086选项,否则objdump不知道反汇编的是16位代码。(前面提到过Linux从诞生起就是32位,所以ELF只有32位和64位两种,没有 16位的ELF格式。)如下图,如果使用-m i386选项进行反汇编,反汇编结果将不知所云:
下面进入C语言的世界。为了搞清楚C语言生成的16位代码的汇编指令有哪些特别之处,先写一个简单的C语言程序进行调研,如下图:
该程序有以下特点:
1. 程序的开头使用了__asm__(".code16\n")嵌入汇编指令,以指示as生成16位代码;
2. display_str函数的签名和之前汇编语言中的相同,可以使用它来观察C语言生成的代码如何传递参数。