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中相应的函数 ...
随机推荐
- SPOJ 0287 Smart Network Administrator
题目大意:一座村庄有N户人家.只有第一家可以连上互联网,其他人家要想上网必须拉一根缆线通过若干条街道连到第一家.每一根完整的缆线只能有一种颜色.网管有一个要求,各条街道内不同人家的缆线必须不同色,且总 ...
- RHEL修改主机名和IP
1, 修改主机名 vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=NEWHOSTNAME #修改该值作为主机名,如:NEWPC ...
- hadoop 常用命令
hdfs dfs -mkdir -p /usr/input/hot hdfs dfs -ls / hdfs dfs -ls /usr/input hdfd dfs -cat /usr/ouput/ho ...
- 带有中文的url和NSString中文的转换
NSString *url = @"http://tw.news.yahoo.com/麵包魂東京吸睛-粉絲包圍導演-061222049.html"; NSLog(@"ur ...
- JAVA基础1
阶段0:拟出一个计划 阶段1:要制作什么? 阶段2:如何构建? 阶段3:开始创建 阶段4:校订 阶段5:计划的回报 一.程序运行时,数据保存位置 1.寄存器.这是最快的保存区域,因为它位于和其他所 ...
- Java Web的数据库操作(一)
一.JDBC技术 1.JDBC简介 JDBC是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可以非常方便地与各种数据库交互,JDBC在Java程序与 ...
- RHEL6.3进入单用户模式并重置root密码
单用户模式类似于windows下的安全模式,允许root账号不输入密码直接启动并登录系统进行系统维护. 单用户模式只允许root账号登录,不允许其它用户使用ssh协议进行远程连接. 重启系统时按Ent ...
- mysql ERROR 1064 (42000): Erreur de syntaxe près de 'order)
mysql> INSERT INTO page (author_username, page_title, addtime, cat_id, page_content,author_uid,it ...
- lvs+keep搭建高可用web服务
title: lvs+keep搭建高可用web服务 date: 2015-11-26 22:11:55 tags: --- 第一部分 概念 负载均衡 生产环境下必不可少的基础手段当前大部分互联网都使用 ...
- ASP.Net用jQuery ajax实现页面局部刷新
刚开始的时候使用asp的updatepanel控件实现局部刷新,而且在本地运行正确,但是部署到服务器上就变成整个页面全部刷新了.服务器用的是Windows server2000,本地机子上用的是win ...