MDK中函数绝对地址定位
- 格式:pdf
- 大小:59.71 KB
- 文档页数:2
STC单片机Keil中C语言函数定位的方法
下面以演示程序进行说明
演示程序中有ReadIAP、ProgramIAP和EraseIAP三个函数
最终目的是将这三个函数都定位到0x8000之后
第一步:新建一个项目“Demo”,并将源文件“Demo.C”添加到项目中
第二步:直接编译,并打开编译后生成的“Demo.M51”文件
从M51文件的“CODE MEMORY”信息中,可以看到3个函数的链接名称、链接地址和函数长度ReadIAP的链接名称为“?PR?_READIAP?DEMO”,链接地址为“0003H”,长度为16H字节ProgramIAP的链接名称为“?PR?_PROGRAMIAP?DEMO”,链接地址为“0019H”,长度为16H字节EraseIAP的链接名称为“?PR?_ERASEIAP?DEMO”,链接地址为“0044H”,长度为14H字节
第三步:根据M51中函数的长度信息计算出各个函数重定位的地址,ReadIAP的重定位的地址为0x8000
ProgramIAP的重定位的地址为0x8016
EraseIAP的重定位的地址为0x802C
第四步:打开项目选项中的“BL51 Locate”属性页
在上图的“Code”域中输入下列语句
“?PR?_READIAP?DEMO(0x8000), ?PR?_PROGRAMIAP?DEMO(0x8016), ?PR?_ERASEIAP?DEMO(0x802C)”
第五步:点击确定按钮,并重新编译即可,此时可以重新打开“Demo.M51”文件,便可发现3个函数已被重定位到我们所指定的地址了,如下图。
嵌入式编程第一篇:51单片机如何将函数定义到指定程序地址在单片机编程使用中,会涉及到将某些函数定义到指定的code区。
此时需要对工程文件进行配置修改才可完成。
本期针对单片机平台做出说明介绍1、测试目标将函数testaddr定义到0x6000地址2、测试环境LKT4106加密芯片算法工程、KEIL-C51编译软件、3、实现步骤3.1 使用KEIL软件导入LKT4106算法工程(KEIL软件基本操作不再敷述,如不清楚请自行百度)3.2 在App_Main.c文件中声明测试函数testaddr:extern void testaddr(u8 xdata *in,u8 xdata *out,u8 len);3.3 在App_fun.c文件中实现测试函数testaddr:void testaddr(u8 xdata *in,u8 xdata *out,u8 len){u8 i;for(i=0;i < len;i++)out[i]= in[i]+1;}3.4 在App_Main.c文件中调用测试函数testaddr,此处省略3.5 编译算法工程后,在\LKT4106_AppDemo\Out\Bin\路径下找到LKT4106_AppDemo.M51,打开该文件。
3.6 找到* * C O D E M E M O R Y * * 部分,寻找到testaddr编译后存储的地址,注意:根据编译规则,testaddr函数会转换为大写格式,并加上函数所在文件的名称。
本例中,编译后的默认地址如图1所示。
图1. 默认编译链接地址3.7 回到算法工程,选择Project->Options for Target ...->BL51 Misc,点击Edit按钮调出lin文件,如图2所示图2. 打开lin文件3.8 在LKT4106_App.lin文件中,按照下图所示,将testaddr函数指定到程序区的目标地址,本例将其由默认的0x48B0地址更改到0x6000地址,如图3所示。
MDK(KEIL)中设定变量或数组到指定的位置MDK(KEIL)中设定变量或数组到指定的位置分类:【嵌入式开发】2013-05-20 14:51 239人阅读评论(0) 收藏举报转自zyboy2000定位变量到指定的位置使用定义在头文件absacc.h中的 __at宏,可以将变量以如下方式定位到绝对地址处:C 例子:#include <absacc.h>const char MyText[] __at (0x1F00) = "TEXT AT ADDRESS 0x1F00";int x __at (0x40003000); // variable at address 0x40003000unsigned char xArray[128] __at (0x68000000); // Array start at address 0x68000000汇编例子:在汇编文件中可以使用段名,由|.ARM.__AT_<addr>|组成来定义位置。
下面的例子是将一个段定义到地址0xFFE0处:AREA |.ARM.__AT_0xFFE0|, CODE, READONLYu8 a[10] __attribute__ ((at(0x2000002c)));编译说..\List\ALL.axf: Error: L6971E: Section .data from objectusart.o with type RW incompatible withSection .ARM.__AT_0x2000002C from object hal.o with type ZI in er RW_IRAM1.似乎是定位了这个绝对地址后,其他变量不会为它让位~NONO,这个方法不行的,因为编译器并没有真正开辟一个变量,你仅仅是强行操作某个地址而已,但这个地址是否被其他数据利用了,你管不到也不知道~(0字)电子白菜[8次]2009-9-5 2:08:47编译器里面应该有设置,比如系统总共有多少内存,你可以故意设置的少一些,这样在编译的时候他就会避开你没有指定的了。
编译大型的程序时,可能某一段代码固定之后不再改变(比如BSP),而应用部分经常修改。
在这种情况下,如果使用在线升级或是Bootloader的方式升级程序时,你就觉得每次升级的代码有一部分是重复的(BSP),如果把这部分代码固定在一个区里面,升级的时候只选择APP区的代码升级,这样提高效率,也节省时间。
MDK或是早前的ADS提供的分散加载方式对代码分区提供了较好的支持,但是我总觉得代码之外再管理一个文件,会比较费劲。
所以一直在寻找更好的方式。
今天仔细研究了MDK的帮助文档,同时简单尝试了一下,有一点体会。
先和大家一起分享:///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////MDK下有两种方式给函数定位(均在代码中控制):1. 给函数声明__attribute__比如声明函数:void task(void) __attribute((section(".ARM.__at_0x8100000")));这样函数task 会被连接到0x8100000 地址处.不同的函数可以使用同一个地址,链接的时候会自动处理.每个函数都需要声明一次.2. 使用#pagaram 控制如下定义:#pragma arm section code=".ARM.__at_0x8100000"void task(void){}#pragma arm section这样函数task 会被链接到0x8100000 地址.这样做的优点是声明区内的函数都会包含在指定的地址范围内.以上两种方式均在代码文件中实现, 不需要修改分散加载文件, 对代码的分区比较方便.///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////特别注意的是:比如你选择BSP代码固化,一定要保证你的代码的稳定性, 如果经常修改的话,该方法不实用!。
keil中函数变量定位⽅法keil中函数变量定位⽅法(2010-09-14 16:02:58)转载标签:杂谈分类:技术函数绝对定位⽅法:将链接⽅式从LX51改回BL51,然后再BL51 Locate中的Code框中写⼊:PR?_DELAY?DELAY(0x8000)其中,前⾯那个_DELAY是指函数名叫做delay,前⾯为什么要加_还不清楚,⽽且原来⽆论是什么这⾥都是⼤写;后⾯那个DELAY是指⽂件名叫做delay,也就是说这个函数要到delay.c中去找;括号⾥⾯的当然就是要定位到的地址了。
如果不强制定位,连接器⼀般都会把程序从0开始安排,有多⼤安排多⼤。
ouravr⽹友总结(⽐较全):使⽤KeilC51软件,可以很⽅便地将代码或者数据绝对定位到某个地址。
1、代码定位:⽅法1:使⽤伪指令CSEG。
⽐如要将MyFunc1定位到代码区C:0x1000,则新建⼀个A51⽂件,添加以下内容:PUBLIC MYFUNC1CSEG AT 1000HMYFUNC1:;其它代码RET在其它源⽂件中,就可以调⽤MyFunc()函数了。
需要注意的是,编译器不检测传递参数的数⽬,仅检测函数是否有返回值。
⽅法2:使⽤BL51 Locate选项。
⽐如在main.c中定义了⼀个MyFunc2函数,并且要将该函数定位到代码区C:0x2000,则从菜单中选择Project->Options for Target 'Target1',在弹出的对话框中选择BL51 Locate页,在下⾯的code栏中写上?PR?MYFUNC2?MAIN(0x2000)即可。
如果想定位多个函数,也可以使⽤*通配符。
2、变量定位:只有全局变量可以绝对定位,局部变量⽆法实现绝对定位。
⽅法1:使⽤_at_关键字。
声明⼀个全局变量unsigned char data MyBuf1[8] _at_ 0x20;⽅法2:使⽤BL51 Locate选项。
c语言相对路径转绝对路径-回复C语言是一种通用的编程语言,被广泛应用于系统软件开发和嵌入式系统的编程。
在C语言编程中,文件路径是一个重要的概念。
相对路径和绝对路径都可以用来指定文件的位置。
本文将探讨相对路径与绝对路径之间的转换,并提供一步一步的指南。
一、什么是相对路径和绝对路径?在计算机中,文件路径是指文件在文件系统中的位置。
相对路径是从当前工作目录开始寻找文件的路径。
当前工作目录是指执行程序时所在的目录。
相对路径的路径不包含完整的文件系统路径,而是基于当前工作目录的相对位置。
相对路径通常以"../" 或"./"开头,以指示上级目录或当前目录。
例如,假设当前工作目录是一个名为"myproject"的文件夹。
要访问该文件夹中的另一个文件夹中的文件,我们可以使用相对路径"../anotherfolder/file.txt"。
这个路径中的".."表示上级目录。
绝对路径是一个完整的文件系统路径,从根目录开始到文件的路径。
绝对路径可以唯一地指定一个文件的位置,不依赖于当前工作目录。
绝对路径通常以根目录(如"/"或"C:\")开头。
例如,要访问Windows系统中C盘下的文件,可以使用绝对路径"C:\folder\file.txt"。
这个路径中的"C:\"表示C盘根目录。
二、相对路径转绝对路径的方法在C语言中,我们可以使用函数来处理路径,以实现相对路径转绝对路径的功能。
下面是一种实现相对路径转绝对路径的方法:1. 获取当前工作目录C语言提供了函数`getcwd(char *buffer, size_t size)`来获取当前工作目录。
这个函数将当前工作目录的路径存储在`buffer`中,最多存储`size`个字符。
2. 连接相对路径和当前工作目录将相对路径与当前工作目录连接起来,形成一个完整的路径。
C语言使用函数指针跳转到程序固定地址(0x8000)执行程序的方法使用函数指针,把一个纯数据强制转换为函数指针类型。
int main(void){void (* my_function)(void);//int *my_address = 0x8000;my_function = (void (*)()) (0x8000);my_function();}其实更简单,不适用中间变量,直接一步到位:(*(void(*)())0x8000)();转成汇编就占两条指令.在IAP的bootloader中经常使用到地址跳转,指定程序跳转到某一地址运行,例如强制跳转到0x2c去执行,则可使用(*((void(*)(void))0x2c)))();实际上这是运用的函数指针,可以这样分解:1,函数指针的定义为void (* fd) (void); 省略参数的函数原型为void (*)(void).2,0x2c, 这里的0x2c为地址,可以认为是变量(个人理解),可以理解为将变量0x2c进行强制类型转换,转换成函数指针类型,即( void(*)(void) )0x2c.3,调用函数。
(* (func) ) (); func 为函数指针(void(*)(void) )0x2c,合起来就是(* ((void(*)(void) )0x2c) )();嵌入式笔试题:想让程序跳转到绝对地址0x100000处执行,该如何做?网上看到有如下答案:*((void(*)(void))0x100000)();经过在VC++6.0和Linux gcc4.4.3下测试,均不能通过编译。
VC++6.0报错:error C2100: illegal indirectionGCC报错:error: void value not ignored as it ought to be应该是怎么写呢?经过测试,有两种方法:答案1. (*(void(*)(void))0x100000)();答案2. ((void(*)(void))0x100000)();仔细观察,第一种写法只是第一个*的位置不同,第二种写法少了一个*,但是都能正确编译通过,且正确执行。
IAR开发环境中的数据、函数定位方法一、在IAR的集成开发环境中实现数据变量定位方法如下三种1、__no_init char alpha @ 0x0200;2、#pragma location = 0x0202const int beta;3、const int gamma @ 0x0204 = 3;或:1)__no_init int alpha @ "MYSEGMENT"; //MYSEGMENT段可在XCL中开辟2)#pragma location="MYSEGMENT"const int beta;3)const int gamma @ "MYSEGMENT" = 3;二、如何实现函数定位在IAR中函数定位有两种写法1. void g(void) @ "MYSEGMENT" // MYSEGMENT段可在XCL中编辑开辟{}2、#pragma location = "MYSEGMENT"void h(void){}三、如何更改XCL文件注意:在实现过程中可能涉及到.XCL连接文件的更改,请保存好原来的.XCL文件!1. 打开相应的*c.xcl文件,用"-Z(CONST)段名=程序定位的目标段-FFDF"定义段的起始地址.2. 在自己的C程序中用#pragma constseg(段名)定位自己的程序3. 结束后恢复编译器的默认定位#pragma default例:IAR 1.26b环境下:1、将常量数组放在FLASH段自定议的MYSEG段中原来的MSP430F149 XCL文件如下:// Constant data-Z(CONST)DATA16_C,DA TA16_ID,DIFUNCT,CHECKSUM=1100-FFDF如果想从中分出一部分做数据存储区,做如下修改:-Z(CONST)DATA16_C,DA TA16_ID,DIFUNCT,CHECKSUM=1500-FFDF //将1100-14FF从ROM中分出存储arry数组-Z(CONST)MYSEG=1100-14FF区间大小可自行决定在程序中描写如下即可:#pragma memory = constseg(MYSEG) //在.XCL文件中修改char arry[]={1,2,3,4,5,6,7};#pragma memory = default2、将变量放入所命名的段在XCL文件中开辟一段MYSEG段,如上所述#pragma memory = dataseg(MYSEG)char i;char j;int k;#pragma memory = default。
嵌入式编程里的绝对地址操作要对绝对地址0x100000赋值,我们可以用(unsigned int*)0x100000 = 1234;那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?*((void (*)( ))0x100000 ) ( );首先要将0x100000强制转换成函数指针,即:(void (*)())0x100000然后再调用它:*((void (*)())0x100000)();用typedef可以看得更直观些:typedef void(*)() voidFuncPtr;*((voidFuncPtr)0x100000)();下面是一本关于驱动开发的书上的一段关于绝对地址操作的描述。
目前,大多数嵌入式微控制器如Arm、PowerPC等并不提供I/O空间,而仅存在内存空间。
内存空间可以直接通过地址、指针来访问,程序和程序运行中使用的变量和其他数据都存在于内存空间中。
内存地址可以直接有C语言指针操作,例如在186处理器中执行如下代码:unsigned char *p = (unsigned char*)0xf000ff00;*p = 11;以上程序的意义为在绝对地址0xf000+0xff00(186使用16位段地址和16位偏移地址)写入11。
而在Arm、PowerPC等未采用段地址的处理器中,p指向的内存空间就是0xf000ff00,而*p=11就是在该地址写入11。
再如,186处理器启动后会在绝对地址0xffff0(对应C语言指针是0xf000ff00,0xf000为段地址,0xfff0为段内偏移)执行,请看下面的代码:typedef void (*lpFunction)(); /*定义一个无参数、无返回类型的函数指针类型*/lpFunction lpReset = (lpFunction)0xf000fff0; /*定义一个函数指针,指向CPU启动后所执行第一条指令的位置*/lpReset(); /*函数调用*/在以上程序中,没有定义任何一个函数实体,但是程序中却执行了这样的函数调用:lpReset(),它实际上起到了“软重启”的作用,跳转到CPU 启动后第一条要执行的指令的位置。