汇编子程序模块化(near&far)

1: Near 近端使用

 C语言实现: 

 
 

#include <stdio.h>
#include <stdlib.h>

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文件
#include<stdio.h> 
void print(){
    printf("proc");
}
// 主调用文件
#include <stdio.h>
#include <stdlib.h>
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 print 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 print 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子程序 那么链接时候需要

link main.obj+pro1.obj+pro2.obj+''' 依次类推

 debug: 

主程序为: 调用地址 0779:0000

 看一下调用地址的子程序地址:

 3:Far使用过程的问题

  如果声明为跨段调用,因为段限制为64k, 需要使用call far ptr进行调用

下面的声明形式是错误的: 

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

 

 

猜你喜欢

转载自www.cnblogs.com/dgwblog/p/11914837.html