汇编子程序模块化(near&far)
1: Near 近端使用
C语言实现:
#include <stdio.h>
#include <stdlib.h>
void print(){
printf("proc");
}
int main(int argc, char *argv[]) {
print();
return ;
}
汇编实现:
datas segment
x db 'proc$';
datas ends
stacks segment stack
dw 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,;
int 21h
pop bp
ret
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 ;
}
汇编实现:
;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,;
int 21h;
pop dx
pop ax
pop bp
retf
printx endp
codes ends
end
;Main 文件
stacks segment stack
dw dup()
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 dup()
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 dup()
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 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,; 使用寄存器dx
int 21h
retf
print endp codes ends
end start
4.2 内存传递参数
datas segment
x db 'proc$';
datas ends
stacks segment stack
dw 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,; 输出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 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+];寻地址
mov ah,;
int 21h
pop bp
ret ;保持恢复
print endp codes ends
end start
提高资料:https://wenku.baidu.com/view/3109f194690203d8ce2f0066f5335a8103d2665a.html


汇编子程序模块化(near&far)的更多相关文章
- 学 Win32 汇编[33] - 探讨 Win32 汇编的模块化编程
我觉得所谓的模块化有两种: "假模块化" 和 "真模块化". 所谓 "假模块化" 就是通过 include 指令把 *.inc 或 *.as ...
- 关于C转汇编(转自网上)
②在KILE软件的菜单中,选择Project-->Options for Target 'Target 1',-->Listing选择Assembly code就能生产*.LST文件.在 ...
- Cortex-M3中C与汇编的交互
以下内容摘自<ARM Cortex-M3权威指南> 概览 在CM3 上编程,既可以使用C 也可以使用汇编.可能还有其它语言的编译器,但是大多数人还是 ...
- 在C中嵌入汇编
早前公布了C和汇编混编的温度控制器程序,收到一些朋友的询问,他们无法在自己程序中使用我的18B20的汇编子程序或无法正常通过混编后的程序编译. 其实在KEIL中嵌入汇编的方法很简单.如图一,在C文件中 ...
- ARM汇编编程基础之一 —— 寄存器
ARM的汇编编程,本质上就是针对CPU寄存器的编程,所以我们首先要弄清楚ARM有哪些寄存器?这些寄存器都是如何使用的? ARM寄存器分为2类,普通寄存器和状态寄存器 寄存器类别 寄存器在汇编中的名称 ...
- 常用 ARM 指令集及汇编
ARM7TDMI(-S)指令集及汇编 ARM 处理器是基于精简指令集计算机(RISC)原理设计的,指令集和相关译码机制 较为简单,ARM7TDMI(-S)具有 32 位 ARM 指令集和 16 位 T ...
- Win64 驱动内核编程-24.64位驱动里内嵌汇编
64位驱动里内嵌汇编 讲道理64位驱动是不能直接内链汇编的,遇到这种问题,可以考虑直接把机器码拷贝到内存里,然后直接执行. 获得机器码的方式,可以写好代码之后,直接通过vs看反汇编,然后根据地址在看内 ...
- 嵌入式系统Linux内核开发工程师必须掌握的三十道题(转)
嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...
- QBASIC教程
Qbasic 程序设计入门 BASIC(Beginner’s All-purpose Symbolic Instruction Code 的缩写,意为初学者通用符号指令代码)语言是在1964年由美国的 ...
随机推荐
- VS Code 成主宰、Vue 备受热捧!2019 前端开发趋势必读
前端在生产和开发中占据着越来越重要的地位,PC 端.手机端.桌面端.智能手表端等等设备都离不开前端的身影.本文将围绕框架.编程语言.工具.React.Vue 等方面,全面回顾 2019 年前端与 We ...
- 第二次作业-titanic数据集练习
一.读入titanic.xlsx文件,按照教材示例步骤,完成数据清洗. titanic数据集包含11个特征,分别是: Survived:0代表死亡,1代表存活Pclass:乘客所持票类,有三种值(1, ...
- linux 删除.svn文件
linux删除当前目录及其子目录下的.svn文件,linux下删除全部的.svn文件 find . -name "*.svn" -type d -print -exec rm -r ...
- 基于H7的串口WIFI模块ESP8266的TCP客户端例子和操作说明(AP兼STA模式)
说明: 1.如果不熟悉网络的话,等我这几天更新V7用户手册的ESP8266章节,如果熟悉的话,直接操作即可,这里将操作说明发出来. 2.串口WIFI是采用的AT指令操作,简单易用,指令手册在这个帖子里 ...
- 如果获取ruby的hash的v值?
最近写ruby,用到hash,通过k去获取v值,有时候通过hash["k"]去获取可以获取到,有时候通过又获取不到,感觉一脸懵逼 仔细观察了下ruby的hash,有两种表现形式,所 ...
- Prometheus学习系列(二)之Prometheus FIRST STEPS
前言 本文来自Prometheus官网手册 和 Prometheus简介 说明 Prometheus是一个监控平台,通过在监控目标上的HTTP端点来收集受监控目标的指标.本指南将向您展示如何使用Pro ...
- Jenkins使用SSH构建Go项目并执行
目录 下载插件 配置要部署的服务器 构建项目 Jenkinx可以帮助我们通过SSH插件,将项目直接部署到指定的服务器. 下载插件 (1)点击左侧的"系统管理"菜单 ,然后点击 (2 ...
- 4. java基础之修饰符
其他修饰符 public 可以修饰属性.方法.构造方法.类 protected 可以修饰属性.方法.构造方法 default 可以修饰属性.方法.构造方法.类 private 可以修饰属性.方法.构造 ...
- spring的事物管理配置
基于注解的事务管理器配置(AOP) 首先要引入AOP和TX的名称控件 <!-- 使用annotation定义事务 --> <tx:annotation-driven transact ...
- 高强度学习训练第六天总结:Redis主从关系总结
Redis主从复制机制 1.读写分离的好处 性能优化:主服务器专注于写操作,可以更适合写入数据的模式工作:同样,从服务器专注于读操作,可以用更适合读取数据的模式工作. 强化数据安全,避免单点故障:由于 ...