1: Near 近端使用
C语言实现:
#include
#include
void print(){ printf("proc"); } int main(int argc, char *argv[]) { print(); return 0; }
汇编实现:
datas segment x db 'proc$'; datas ends stacks segment stack dw 100 dup(?) stacks ends codes segment assume cs:codes,ss:stacks,ds:datas main proc ; 主程序 start: mov ax,datas; mov ds,ax; call max mov ah,4ch; int 21h main endp print proc near ;子程序 push bp; mov bp,sp; mov dx,offset x; mov ah,09; int 21h pop bp ret 0 print endp codes ends end start
near 调用没有段地址:使用的就是偏移地址 call 000C 地址就是子程序的入口地址
2: Far 远端使用
print 函数我们实现在另一个文件, C语言默认函数的extern的 也就是全局的
// A文件 #includevoid print(){ printf("proc"); }
// 主调用文件 #include#include extern void print(); int main(int argc, char *argv[]) { print(); return 0; }
汇编实现:
;A文件
public printx '声明为远端函数 datas segment x db 'proc$'; datas ends assume cs:codes,ds:datas codes segment printx proc far push dx push ax push bp; mov bp,sp; mov ax,datas;这里我们直接在本段进行处理 ,如果不在本段处理 需要将main的段内存的偏低地址,push 到堆栈中操作内容 mov ds,ax mov dx,offset x;取得偏移地址 mov ah,09; int 21h; pop dx pop ax pop bp retf printx endp codes ends end
;Main 文件 stacks segment stack dw 100 dup(0) stacks ends; extrn printx:far ;标识远端程序 不写 将会汇编错误 , codes segment assume cs:codes,ss:stacks main proc start: call far ptr printx mov ah,4ch int 21h; hlt main endp codes ends end start
注意: 以上两个文件编译没有问题,但是链接 如果按照我们过去的思路 将会出现下面的错误: 表示我们调用的函数需要声明 否则无法链接
注意: 调用了多少个far子程序 那么链接时候需要
# 使用方式1
link main.obj+pro1.obj+pro2.obj+''' 使用+链接依次类推
# 使用方式2
link main.obj+pro1.obj pro2.obj+''' 使用空格链接依次类推
debug:
主程序为: 调用地址 0779:0000
看一下调用地址的子程序地址:
3:Far使用过程的问题
如果声明为跨段调用,因为段限制为64k, 需要使用call far ptr进行调用
下面的声明形式是错误的: (并不是错误的,学校上机的时候在32位系统 能够正确使用,但是同样的程序在msbox就不行)
stacks segment stack dw 100 dup(0) stacks ends; extrn printx:far codes segment assume cs:codes,ss:stacks ;一般不这样写 主程写成模块也好 start: call far ptr printx mov ah,4ch int 21h; hlt codes ends end start
正确的声明形式:
stacks segment stack dw 100 dup(0) stacks ends; extrn printx:far codes segment assume cs:codes,ss:stacks main proc ; 主程序也必须声明为 过程 这里 near调用还是有很大的区别的 start: call far ptr printx mov ah,4ch int 21h; hlt main endp codes ends end start
4: 参数传递的问题:
4.1 寄存器传递参数
datas segment x db 'proc$'; datas ends stacks segment stack dw 100 dup(?) stacks ends codes segment assume cs:codes,ss:stacks,ds:datas main proc ; 主程序 start: mov ax,datas; mov ds,ax; mov dx,offset x; 直接使用 传递给寄存器dx call far ptr print mov ah,4ch; int 21h main endp print proc mov ah,09; 使用寄存器dx int 21h retf print endp codes ends end start
4.2 内存传递参数
datas segment x db 'proc$'; datas ends stacks segment stack dw 100 dup(?) stacks ends codes segment assume cs:codes,ss:stacks,ds:datas main proc ; 主程序 start: mov ax,datas; mov ds,ax; call far ptr print mov ah,4ch; int 21h main endp print proc mov dx,offset x; 取得数据段首地址 mov ah,09; 输出dx的数据值 int 21h retf print endp codes ends end start
4.3 内存传递参数的改进(栈恢复)
如果用到ax bx cx dx si di 需要进行恢复
为什么需要恢复:
如果在主程序中用到了一个xx寄存器,然后在子程序中也用到了这个xx寄存器,那么当子程序返回到主程序的时,主程序中存放参数的内存地址已经没有记录了,程序出错
datas segment x db 'proc$'; datas ends stacks segment stack dw 100 dup(?) stacks ends codes segment assume cs:codes,ss:stacks,ds:datas main proc ; 主程序 start: mov ax,stacks;初始化栈 mov ss,ax; mov ax,datas;初始数据段 mov ds,ax; xor ax,ax mov ax,offset x; push ax;ax偏移地址入栈 call print mov ah,4ch; int 21h main endp print proc push bp; mov bp,sp mov dx,[bp+4];寻地址 mov ah,09; int 21h pop bp ret 2;保持恢复 print endp codes ends end start
提高资料:https://wenku.baidu.com/view/3109f194690203d8ce2f0066f5335a8103d2665a.html