使用GCC和GNU Binutils编写能在x86实模式运行的16位代(2)

  代码完成后,使用下面一串命令就可以把它进行汇编、链接,然后转换成DOS下的纯二进制格式(Plain Binary),最后复制到FreeDOS.img中,使用Qemu虚拟机执行FreeDOS,然后运行该16位实模式程序。这一串命令及其运行效果如下图:

使用GCC和GNU Binutils编写能在x86实模式运行的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进制形式输入,如下图:

使用GCC和GNU Binutils编写能在x86实模式运行的16位代

当然,也可以使用objdump -d或者objdump -D将程序进行反汇编,查看是否真正生成了16位代码,如下图:(反汇编时一定要指定-m i8086选项)

使用GCC和GNU Binutils编写能在x86实模式运行的16位代

也可以对纯二进制格式的文件进行反汇编,必须指定-b binary选项,如下图,对test.com进行反汇编:

使用GCC和GNU Binutils编写能在x86实模式运行的16位代

反汇编时,一定要指定-m i8086选项,否则objdump不知道反汇编的是16位代码。(前面提到过Linux从诞生起就是32位,所以ELF只有32位和64位两种,没有 16位的ELF格式。)如下图,如果使用-m i386选项进行反汇编,反汇编结果将不知所云:

使用GCC和GNU Binutils编写能在x86实模式运行的16位代

  下面进入C语言的世界。为了搞清楚C语言生成的16位代码的汇编指令有哪些特别之处,先写一个简单的C语言程序进行调研,如下图:

使用GCC和GNU Binutils编写能在x86实模式运行的16位代

  该程序有以下特点:

  1. 程序的开头使用了__asm__(".code16\n")嵌入汇编指令,以指示as生成16位代码;

  2. display_str函数的签名和之前汇编语言中的相同,可以使用它来观察C语言生成的代码如何传递参数。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/04d4b050640507a93b83839200314abb.html