[编译环境][gcc]16位程序中汇编代码与C语言代码的混合编译

在实模式下,默认是的16位数据模式,但可以允许采用32位数据模式。当希望采用32位数据模式时,需要手动在指令前添加0x66来切换数据模式。

在汇编代码中,call和ret生成的指令字节都不带0x66,也就是说采用的是16位数据模式。

但是,使用GCC将C语言代码编译成16位程序时,指令中会“大量”采用32位数据模式。也就是说很多指令字节的前面都会带有0x66,这启动也包括call和ret指令。

如果整个程序完全是由汇编语言或是C语言编写时,不会出现问题。因为所有程序均是采用一致的数据模式,不论是16位还是32位。意思是说如call和ret这种需要成对出现的指令的数据模式是一致的,而需要采用16位寄存器还是32位寄存器这种情况不需要考虑数据模式的一致性问题。

但是,如果程序中既有汇编语言代码又有C语言代码,在这种情况下就会出现问题。
如果主调函数是用C语言编写的,而被调函数是汇编代码写的。此时,call指令是32位数据模式,ret指令是16位数据模式。被调函数也可以成功地返回主掉函数,但栈中会留下一个字,其值是0。最终的结果是入栈与出栈不成对一致。
如果主调函数是用汇编代码写的,而被调函数是用C语言编写的。此时,call指令是16位数据模式,ret指令是32位数据模式。被调函数无法成功返回主调函数,因执行ret指令时从栈中弹出了2个字而不是1个字,然后试图赋值到esp(不是sp)中。这样通常会造成偏移地址超过了CS段寄存器的段现场(具体的值是0x10000)。造成这种结果的根本原因也是入栈与出栈不成对一致。

为了解决这个问题,我们需要改动主调函数或是被调函数的代码。
如果主调函数是汇编语言编写,同时被调函数是C语言编写时,我们需要改动主调函数中的call指令为push指令与jmp指令的组合。即将调用函数跳转回来的地址入栈,然后直接跳转到被调函数的第一条指令。
如果主调函数是C语言编写,同时被调函数是汇编语言编写时,我们需要在被动函数中的ret指令前添加一个字节,其值为0x66。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值