总结——gcc+nasm交叉编译在16位实模式互相引用的接口

一、准备知识

  1. gcc生成.o文件
    第一种:

    i686-elf-gcc -Og -c <cfile>.c -o <cfile>.o

    第二种:

    i686-elf-gcc -c -ffreestanding -m32 -march=i386 -mpreferred-stack-boundary=2 <cfile>.c -o <cfile>.o

    编译参数:

    编译参数 作用
    -c 只编译不链接
    -ffreestanding 使输出程序能独立运行
    -m32(非x86_64 的GCC 不需要) 生成32位代码(16位也需要此参数)
    -march=i386 使用i386 指令集
    -mpreferred-stack-boundary=2 栈指针按2 * 2 = 4 字节对齐
    -fno-exceptions(非C++不需要) 不使用异常处理
    -fno-rtti(非C++不需要) 不使用RTTI
    -o XXX.o 输出文件名

    虽然gcc无法生成16 位指令,但是GNU binutils中的as汇编器能够给32 位指令自动添加16位前缀。打开这项功能需要在每个C 程序源文件开头用内联汇编添加如下一条伪指令:

    __asm__(".code16gcc\r\n");
  2. nasm命令
    1)生成com程序

    nasm -f bin <afile>.asm -o <afile>.com

    2)生成.o文件

    nasm -f elf32 <afile>.asm -o <afile>.o

    但是有一个需要注意的问题。nasm在输出非binary格式时,默认将生成32位代码。如果需要得到16 位实模式下的代码,需要在源文件开头加入下面这个伪指令:

    BITS 16
    

    此外,org伪指令将被禁用,程序加载位置的指定将在链接步骤进行。

  3. 链接命令
    1)生成引导扇区程序

    i686-elf-ld -N <afile>.o <cfile>.o -Ttext 0x7c00 --oformat binary -o <output>.bin

    2)生成com程序

    i686-elf-ld -N <afile>.o <afile>.o -Ttext 0x100 --oformat binary -o <output>.com

    二、互相引用规则

    1. 汇编模块中调用C模块函数
      1)调用前要用extern声明C模块函数
      2)根据C中函数原型,用栈传递参数,顺序为后面的参数先入栈
      3)调用返回后,要恢复栈指针将参数出栈
      4)进栈出栈以4个字节为单位
      5)C返回时取的返回地址为4个字节,因此在call之前需要把cs或0入栈
    2. C模块中调用汇编函数和引用变量
      1)汇编模块中的函数从栈中取得参数,不必出栈,直接引用栈中的值,取参顺序与C中函数原型相同。
      2)由于NASM的ret指令只取栈顶两个字节(ip),会导致从汇编函数返回时在栈顶残留两个字节,因此要把ret指令替换为retf指令(取ip和cs)或者加入32位操作数前缀:o32 ret。
      3)如果C中想引用汇编模块的变量和标识符,要在汇编中用global声明并在C中用extern引用,C中定义的函数默认是global的。

你可能感兴趣的:(交叉编译)