Keil的可重定位段
对于一个大的文件,为了便于管理,一个好的办法时把一个大文件分为若干个小文件,每个小文件包含一部分相关的功能,这样功能将显得很整洁,而且移植到其它工程的时候也很方便,把文件copy过去即可。
对于汇编,我们也许知道,可以使用orgxxxx来指定函数的地址(org是一个段内指定偏移的伪指令),但是当指定这个地址时,是否与其它函数冲突呢?有可能其它函数过长已经占用了这个地址。难道要数手指计算函数的长度吗?另一个问题是主函数怎样调用被调函数呢?
在回答这些问题之前,先来看看使用的开发工具是怎样工作的。首先A51汇编器汇编文件后会生成.obj文件,这并不是最终需要的文件。通常还要使用一个叫链接器(如BL51)的工具,把多个obj文件组合起来,生成最终的二进制代码文件(或其它格式的文件)。虽然传递给链接器的参数是一个或多个obj文件,但是链接器在链接时却是按段来计算的。每个obj文件里包含的都是一些绝对地址段或可重定位段。链接器必须为可重定位段重新计算及分配地址,并计算绝对地址段是否重叠。因此:可重定位段可以保证多目标文件链接时不发生目标地址重叠,故绝对地址段只适用用某些特殊场合,如固定I/O口或中断向量的入口地址。绝对地址段就是这个段的地址在传入链接器的时候已经固定,链接器不能改变这个段的地址。可重定位段就是这个段的地址需要链接器分配,如是代码段的段内的跳转等指令的偏移也需要重新进算。
段的另一种分法可分为代码段、数据段。数据段又分为以初始化数据段和未初始化数据段。这里不细说。
通过上面可知,如果一个函数是一个段,而这个段是可重定位的,那么就可以不用考虑代码的地址问题了,把这个问题留给了链接器。剩下来的问题就是怎样把一个函数变为一个段的问题,(当然一个段可包括很多函数,在汇编中,函数只是一个说法而已)。大部分的汇编器都会提供伪指令来定义绝对段及可重定位段(写法上有可能有区别而已)。
在A51中,定义段的伪指令是
cseg -- 绝对代码段
bseg -- 绝对位段
dseg -- 绝对内部直接寻址(data)数据段
iseg -- 绝对内部间接寻址(idata)数据段
xseg -- 绝对外部(xdata)数据段
segment -- 定义一个可重定位段
rseg -- 选择一个可重定位段
使用说明:
NAME 模块名 //用来指明当前程序模块 重定位段名 SEGMENT 段类型 [重定位类型] //重定位类型为可选,
段类型为可用的段类型有CODE、DATA、XDATA、IDATA、BIT。重定位类型为PAGE、INPAGE、INBLOCK、BITADDRESSABLE、UNIT、OVERLAYABLE。段名等价于段符号,在表达式中用段名表示复合段中的基地址。
每个函数都包含在一个段内。org 0 改为了 cseg at 0, org 50h则被删除,这样链接程序会自动的为每个重定位段分配地址,也就相当于为函数分配的地址,这样函数与函数之间就没有了gas(^_^,这是Keil的术语,也就相当于空隙),当有gas时,程序是没有使用的,白白浪费了。对于51这样的系统可重定位段的另一个好处就是空间覆盖处理,这将在下一节细说。
也许读者会有这样的疑问,之前的示例并没有定义任何的段,它们工作得也很好啊,那汇编器及链接器是怎么工作的呢?链接器的工作仍然是不变的,只是汇编器在扫描文件时发现文件没有定义段,会为每个空间分配一个绝对段,地址从0开始。以code空间为例,如果没有定义段,则默认段从0开始,这时文件中的第一条指令的地址就是0开始,而org伪指令是指定段内偏移的,这里的org 0有没有也就无所谓了。不信读者可以把这条语句去掉再汇编一次。
而当工程里开始,这时链接器就会提示地址空间重叠。因此可重定位段的用处就在于此:它不会造成地址空间重叠。
下面将介绍的几个伪指令对于多文档工作就特别的有用了。
extrn -- 指示符号是外部的,并告诉模块是什么类型
extern -- 跟extrn差不多,相当于extrn的一种特例
public -- 指示符号可在其它模块使用
使用方法如下:
EXTRN class (symbol [ , symbol ... ])
EXTRN class:type (symbol [ , symbol ... ])
EXTERN class:type (symbol [ , symbol ... ])
PUBLIC symbol [ , symbol ... ]
中括号内是可选部分。
C51编译器采用了一个扩展关键字reentrant作为定义函数时的选项,需要将一个函数定义为可重入函数时,只要在函数后面加上关键字reentrant即可。
与非可重入函数的参数传递和局部变量的存储分配方法不同,C51编译器为可重入函数生成一个模拟栈(相对于系统堆栈或是硬件堆栈来说),通过这个模拟栈来完成参数传递和存放局部变量。模拟栈以全局变量?C_IBP、?C_PBP和?C_XBP作为栈指针(系统堆栈栈顶指针为SP),这些变量定义在DATA地址空间,并且可在文件startup.a51中进行初始化。根据编译时采用的存储器模式,模拟栈区可位于内部(IDATA)或外部(PDATA或XDATA)存储器中。如表1所示:
存储模式 |
栈指针 |
栈区域 |
Small |
?C_IBP(1 字节) |
间接访问的内部数据存储器(IDATA),栈区最大为256字节 |
Compact |
?C_PBP(1字节) |
分页寻址的外部数据存储器(PDATA),栈区最大为256字节 |
Large |
?C_XBP(2字节) |
外部数据存储器(XDATA),栈区最大为64K |
表1注意:51系列单片机的系统堆栈(也叫硬件堆栈或常规栈)总是位于内部数据存储器中(SP为 8位寄存器,只能指向内部),而且是“向上生长”型的(从低地址向高地址),而模拟栈是“向下生长”型的。
Keil的可重定位段的更多相关文章
- Oracle-在线重定义操作文档
Oracle-在线重定义操作文档 2015年10月8日 15:51 在线重定义的大致操作流程如下: (1)创建基础表A,如果存在,就不需要操作. (2)创建临时的分区表B. (3)开始重定义,将基表A ...
- 11 Servlet_03 关键字总结 资源跳转:重定项 键值对 继承类 do-get do-post Request域 Context域 =空针解决方法
知识点总结: 1.java里的关键字: byte short int long 数据类型 (正整数)char 数据类型(单字符型)boolesn ture false 布尔类型float dou ...
- C语言中输入输出重定,freopen()妙用。
使用的理由(范围):如果输入数据很庞大,需要一次又一次的重新输入和调试时可采用本函数. freopen ()函数: 1.格式 FILE * freopen ( const char * filenam ...
- 关于Servlet中的转发和重定项
一:转发 首先转发属于服务器内部行为,通过浏览器的地址栏是看不到URL变化的.比如说客户端发送一个请求到ServletA,ServletA接收到请求,但是没有能力处理,但是ServletA知道Serv ...
- java:JSP(JSPWeb.xml的配置,动态和静态导入JSP文件,重定项和请求转发,使用JSP实现数据库的增删改查实例)
1.JSP的配置: <%@ page language="java" import="java.util.*" pageEncoding="UT ...
- 《windows核心编程系列》二十一谈谈基址重定位和模块绑定
每个DLL和可执行文件都有一个首选基地址.它表示该模块被映射到进程地址空间时最佳的内存地址.在构建可执行文件时,默认情况下链接器会将它的首选基地址设为0x400000.对于DLL来说,链接器会将它的首 ...
- 原创 C++应用程序在Windows下的编译、链接:第一部分 概述
本文是对C++应用程序在Windows下的编译.链接的深入理解和分析,文章的目录如下: 我们先看第一章概述部分. 1概述 1.1编译工具简介 cl.exe是windows平台下的编译器,link.ex ...
- Android 6.0 新功能及主要 API 变更
运行时权限 这个版本中引入了新的权限模型,现在用户可以在运行时直接管理应用程序的权限.这个模型基于用户对权限控制的更多可见性,同时为应用程序的开发者提供更流畅的应用安装和自动升级.用户可以为已安装的每 ...
- 第20章 DLL高级技术(3)
20.4 函数转发器 (1)函数转发器原理(下图是利用Dependency Walker打开Kernel32.dll得到) ①图中CloseThreadpool*等4个函数转发到NTDLL中相应的函数 ...
随机推荐
- HDOJ 1202 The calculation of GPA
Problem Description 每学期的期末,大家都会忙于计算自己的平均成绩,这个成绩对于评奖学金是直接有关的.国外大学都是计算GPA(grade point average) 又称GPR(g ...
- 如何断开eclipse与svn的链接
右键点击需要断开的项目 Team-->Disconnect 如果想删除svn配置文件,选择Also delete the SVN meta information from the file s ...
- 关于C/C++函数指针声明的理解
[前言] 由于最近对函数指针的理解比较模糊,所有又重新学习了一把关于函数指针的知识,参考了很多书籍和网上的文章.现在本人进行一下分享和总结.本文的其实只是整理和总结别人现有的文章,作为备用参考文档. ...
- SqlServer 挂载本地盘符到服务器端,方面备份还原
--此脚本要在登录上SqlServer远程服务器后才能执行,把数据库备份到本地(内网使用) --(例如我用本机SqlServer客户端连接上192.168.3.12服务器时,执行脚本,可以把指定数据库 ...
- 关于IE7 兼容问题
关于a标签的写法(目前测试只针对IE7,IE8及谷歌浏览器): <a onclick = 方法名(参数);></a> 此写法在 IE8以上及谷歌浏览器使用都没有问题,但在I ...
- [React Testing] Children with Shallow Rendering
When testing React components, we often want to make sure the rendered output of the component match ...
- c++11 : Variadic Macros(变长参宏)
Variadic macros are function-like macros that contain a variable number of arguments. Remarks To u ...
- DevExpress GridView.CustomSummaryCalculate 实现自定义Group Summary
--首发于博客园, 转载请保留链接 博客原文 DevExpress Documentation官方地址:GridView.CustomSummaryCalculate Event 1. 概要 界面上 ...
- SUN-LDAP6.3_RHEL 5.0-卸载LDAP
卸载LDAP 1.注销服务器 到目录/ldap/ldapinstance/dscc6/bin下 # ./dsccreg remove-server -h 主机名 /ldap/ldapinstance/ ...
- Directory.GetFiles 方法
Directory.GetFiles 方法 返回指定目录中文件的名称(包括其路径). 命名空间: System.IO程序集: mscorlib(mscorlib.dll 中) Enumerate ...