TC20与masm5.0的相互交互

 
  在学习汇编语言与C的过程中遇到了几个拓展性问题,众所周知,在C语言的构成中,我们自己所写的代码称之为用户代码,因为在使用TC环境编译运行该代码期间,还用到了许多其它的文件,比如在TC20中的C0S.obj,在TC20中,C程序是由C0S.obj作为准备环境,执行用户代码,恢复环境的一个目标文件。在以学习为目的的前提下,可以自己编写C0S.asm自己为用户代码做准备环境,调用用户代码,恢复环境的工作,再编译成obj进行连接。

  编写一个这样的程序是很简单的,在TC和masm5.0的环境下因为编译以后的代码经过连接器的连接,汇编代码也是顺序放置的,如图所示:
  cos.asm:

assume cs:code
data segment
  db 128 dup(0)
data ends   
code segment
start:
    mov ax,data
    mov ds,ax
    mov ss,ax
    mov sp,128

    call a

    mov ax,4c00h
    int 21h
a:
code ends
end start

test.c

f()
{ 
 int a = 5;
}

  可以看出这个代码的意图,首先为数据段和栈段分配相同的一段空间,然后调用用户代码,再返回
  使用该代码的目标文件和TC的源程序的目标文件进行连接,可以获得程序test.exe,使用debug查看汇编代码:
  这里写图片描述

  可以发现,代码的顺序,的确是C0S.obj在前面,用户代码在0772:0012处,用户代码的执行是通过C0S.obj来完成的,但大家应该都发现过这样一种问题,就是使用link.exe连接原来的C0S.obj会发现缺少符号,并且原来的C0S.obj只会调用main函数,然而现在的C0S.obj明显是只会调用.c文件中的第一个函数….造成这样的区别是什么呢?
  可能大家心里也清楚了,没错,就是外部文件的调用,我总是感觉关于汇编语言的完整文档很难找到,即使是官网,也找不到老版本的详细文档,可能只有那个时代所出的书籍才会由记载了吧…masm的文档中记录的也只是最新版的使用教程,里面部分指令是不允许使用在masm5.0的…不过最后在网上还是找到了解决方案,调用外部函数的方法,代码如下:
  C0S.asm

extrn _mymain:far     ;函数符号得以_开头,在新版中应该使用extern伪指令
assume cs:code
data segment
  db 128 dup(0)
data ends

code segment
start:
    mov ax,data
    mov ds,ax
    mov ss,ax
    mov sp,128

    call _mymain

    mov ax,4c00h
    int 21h

code ends
end start

  在test.c没改动的情况下编译会发生什么呢?如下图所示:
  这里写图片描述
  嗯,和原来的C0S.obj差_main符号已经相当相似了,我们只需要在.c文件中写MYMAIN()函数即可实现C程序中指定函数入口的功能了
  test.c

f()
{ 
 int a = 5;
}

MYMAIN()
{
    int b = 10;
}

  编译后进行DEBUG查看汇编代码:
  这里写图片描述
  可以发现,程序的汇编代码顺序还是文件中代码的顺序,而C0S.obj已经实现固定函数入口的功能了,Call 0773:0013
  也就是0772:0023,也就是MYMAIN()函数的代码。到此为止,masm5.0与TC的交互就介绍完毕了。
  注:这里的调用是远调用,所以我猜测会先计算段地址再计算偏移,所以调用的段地址是0773而不是0772
  
    然后再介绍使用TC源程序调用汇编代码吧,先说一个TC使用汇编代码的具体应用场景:在编写自己的printf函数时,简单的字符串显示,%d,%c,%s以及部分的位置控制符(/n,/t,/b)都是容易编写的,但关于输出的位置,可以发现,原来的printf是输出在光标位置的,也就是要写一个printf函数就得获取光标的位置,在C语言中获取光标位置的方法可以调用系统函数,也可以编写内联汇编,使用中断的方式获取光标位置,这里就介绍内联汇编的方法:
    
    先编写程序test.c

main()
{
char *c="hello,world/n/r$";
asm mov ah,9;asm mov dx,c;asm int 33;
}

    从网上搜索可知,TC有好几种内联汇编的方法,但是我相信,使用masm5.0和TC20的同学在按照网上的方法做的过程中会遇到这样的问题:
    这里写图片描述
    错误,无法执行命令tasm.exe,经过再次的搜索,可以发现tasm.exe是一个汇编器(编译汇编代码的工具),因为TC是一个很小的C编译器实现,据我所知,他没有将C编译成汇编代码,而是直接将C翻译成机器码的,所以在源程序中编写汇编代码需要汇编器的支持才行。然而网上的资源是非常难找的,要么版本不对,要么下载了不能用,要么下载了dos时代的安装程序,看着文件数量就头大。。。
    但是,我发现我们使用的masm和tasm不就”一字之差”吗?既然都是汇编器的一种实现,要学习tasm的汇编语法,如果可行的话,我倒更愿意使用熟悉的masm,于是我机智地将masm.exe改名为tasm.exe,放到源程序同目录下,再次进行试编译:
    这里写图片描述
    就这么给过了!!给过了…..,为了验证生成的汇编代码是否正确,我们打开debug,查看主函数部分的汇编代码:
    这里写图片描述
    先为一个指针赋值一个字符串常量,然后执行mov ah,9;再将指针赋值给dx mov dx,c;调用中断int 33(21h),一点问题也没有。

  嗯,今天上午就解决了这两个问题,以后再完善那两个应用场景的需求吧~~

  此方法是实现了TC内联汇编,但C语言和汇编混合编程的途径远不止这一种,无论过程,只需最后将汇编所生成的机器码与C程序生成的机器码连接在一个可执行文件中,在之后的时间里了解到还有:
  一、先建立 .c 文件,编写一个需要调用的函数名,然后使用TCC -S …..C 命令生成汇编代码,然后在汇编代码中的函数部分写汇编部分,然后对其进行单独编译,最后再和.c程序一起进行连接。
  二、通过C语言中的extern关键字可以连接外部符号,和汇编语言连接外部符号类似,将需要被连接的外部符号声明成public应该是可以进行连接编译的,实际上这一方法和上一方法是一样的。
  三、通过将需要的汇编代码部分以汇编器进行编译,然后查看机器码,之后可以将机器码写在如字符数组中,通过函数指针对其进行调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值