C语言绝对地址跳转.docx

上传人:b****5 文档编号:7662581 上传时间:2023-01-25 格式:DOCX 页数:6 大小:21.75KB
下载 相关 举报
C语言绝对地址跳转.docx_第1页
第1页 / 共6页
C语言绝对地址跳转.docx_第2页
第2页 / 共6页
C语言绝对地址跳转.docx_第3页
第3页 / 共6页
C语言绝对地址跳转.docx_第4页
第4页 / 共6页
C语言绝对地址跳转.docx_第5页
第5页 / 共6页
点击查看更多>>
下载资源
资源描述

C语言绝对地址跳转.docx

《C语言绝对地址跳转.docx》由会员分享,可在线阅读,更多相关《C语言绝对地址跳转.docx(6页珍藏版)》请在冰豆网上搜索。

C语言绝对地址跳转.docx

C语言绝对地址跳转

C语言使用函数指针跳转到程序固定地址(0x8000)执行程序的方法

使用函数指针,把一个纯数据强制转换为函数指针类型。

intmain(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报错:

errorC2100:

illegalindirection

GCC报错:

error:

voidvaluenotignoredasitoughttobe

应该是怎么写呢?

经过测试,有两种方法:

答案1.  (*(void(*)(void))0x100000)();

答案2.  ((void(*)(void))0x100000)();

仔细观察,第一种写法只是第一个*的位置不同,第二种写法少了一个*,但是都能正确编译通过,且正确执行。

为什么会有这两种答案呢?

查阅资料后发现,与历史原因有关……

先来看看如下例子:

例一:

[cpp] viewplain copy

 print?

1.#include   

2.void func(void)  

3.{  

4.    printf("hello.\n");  

5.}  

6.void main(void)  

7.{  

8.    printf("func=%d\n", func);  

9.    printf("&func=%d\n", &func);  

10.}  

运行程序后发现

两次打印结果相同!

按照&运算符本来的意义,它要求其操作数是一个对象,但函数名不是对象(函数是一个对象),本来&func是非法的,但很久以前有些编译器已经允许这样做,c/c++标准的制定者出于对象的概念已经有所发展的缘故,也承认了&func的合法性。

因此,对于func和&func可以这样理解,func是函数的首地址,它的类型是void(),&func表示一个指向函数void func(void)这个对象的地址,它的类型是void(*)(),因此func和&func所代表的地址值是一样的,但类型不一样。

func是一个函数,&func表达式的值是一个指针!

既然取不取址都可以,那么*不*也都可以……

所以,在调用一个函数的时候,也有两种方法,正如前面的两种答案。

例二:

[cpp] viewplain copy

 print?

1.#include   

2.  

3.void func(void)  

4.{  

5.    printf("hello.\n");  

6.}  

7.  

8.void main()  

9.{  

10.    void (*func_p)(void) = func;        //定义一个函数指针,这个指针无返回值,无参数,指向fun函数  

11.      

12.    (*func_p)();  

13.    (func_p)();  

14.}  

上面的两种调用方法也都是正确的,编译通过,正确执行。

其实,

[cpp] viewplain copy

 print?

1.func_p();  

也是正确的调用方式……

更有甚者

[cpp] viewplain copy

 print?

1.(*func)();    

还是正确的……只是平时不这么用罢了(注意此处是func,不是func_p)

暂且不考虑那么多调用方式(知道就好了),现在回过头来看看

[cpp] viewplain copy

 print?

1.(*(void(*)(void))0x100000)();  

[cpp] viewplain copy

 print?

1.((void(*)(void))0x100000)();  

到底是什么东东……

1.首先来认识一个新的数据类型,如:

void(*)(void),和int*类似的一个数据类型,只不过int*是一个指向int型的指针,而void(*)(void)是一个指向函数的指针,且这个函数无返回值,无参数。

2.然后给他外层加个括号,如:

(void(*)(void)),这样是不是很像(int*),我们在做强制类型转换的时候需要在类型外加个括号的是吧。

3.接着把0x100000强制转化为一个函数指针,即:

(void(*)(void))0x100000

4.最后就是调用这个函数,外层再加个括号,后面在加一对括号(参考例二的形式),

如:

((void(*)(void))0x100000)();就可以到绝对地址0x100000处去执行了……

或者(*(void(*)(void))0x100000)();只是加不加 * 的问题。

上面例二中可以看出,在用函数指针调用一个函数时,加不加 * 都是可以的。

所以答案就出来了……

另外,你可能疑惑,按照例二中func_p();的形式,那么 (void(*)(void))0x100000();也应该对呀?

但是,实际测试,编译报错:

errorC2064:

termdoesnotevaluatetoafunction

为啥呢?

我也不知道了……反正不管有没有*,记得加个括号就好了……

那为什么最开始的*((void(*)(void)0x100000))();不对呢?

因为没见过*func(); 这么用的……

如果要是外面再加一层括号就对了,如:

(*( (void(*)(void)0x100000) ))();

其实,把蓝色括号去掉(蓝色括号和绿色括号重复了),就又变成答案一了……

所以无论如何,最外层不能是* ,必须是括号!

因为没见过 *func(); 这么用的……

一小段精彩的 C语言,1和2实现相同的功能,欢迎大伙跟帖呵(特别感谢trio老师)

1  void(*theUboot)(void);

   。

   theUboot=(void(*)(void))(0x30700000);

   theUboot();

   。

2  (*(void(*)(void))(0x30700000))();

aokikyon发表于2008-9-1021:

00

看不懂。

ToT

讲解下好吗

shixq发表于2008-9-1109:

13

呵呵,强制类型转换,将一个绝对地址转换为一个函数指针,并调用这个函数以跳转到前面提到的绝对地址.

翻译成汇编就是:

movr0,0x30700000;

movpc,r0

trio老师说了,会用函数指针就可以成为c语言高手.

目前尚处于模仿阶段,还没有领会函数指针的精髓,继续修炼中...

shixq发表于2008-9-1109:

16

  原来用2的方式实现要加一个括号...

  看来对优先级的领会还是不够,当天少加了一个括号,编译死活通不过,没办法才用1的方法,先定义了一个空指针...

trio发表于2008-9-1110:

10

(*(void(*)(void))(0x30700000))();

可以这样理解

首先(void(*)(void))是一个强制类型转换符,他将后面的0x30700000这个无符号整数强制转化为一个函数指针,该函数指针所指向的函数入口参数为void,返回值也是void。

如果到这步你看懂了,那么设(void(*)(void))(0x30700000)为fp;那么上面的表达式就可以简化为(*fp)();  OK,这下就清楚了吧,我们将上面转化好的函数指针进行引用(也就是调用函数指针指向的函数)。

dsp立即寻址、绝对寻址、直接寻址、间接寻址的差别是什么?

如何判断汇编里边的语句他们是属于哪类寻址方式

cz447307145 | 浏览2742次

发布于2013-01-1710:

26

最佳答案

  所有汇编语句必然是两个操作数,而其一必然是寄存器,因为寄存器速度最快,为提高处理速度必须在寄存器中完成操作。

就电脑存储层次的速度而言,寄存器register>缓存cache>内存memory>硬盘hard disk,可见离cpu越近速度越快(register是直接做在cpu内部的,就像下面例子中的教学楼、教务处等,所以速度够快)。

DSP与此类似。

  根据另一个操作数所在的位置分类的话,就是上述几种和另外一些了寻址模式了,如堆栈寻址、MMR等。

举个例子。

你现在你的学校里,去找人处理一些事情,那么此人在哪里呢?

几种可能:

在身边、在某省市县小区幢101、你校第1教学楼301或你校第2教学楼301、此人不在学校但是教务处办公室可以查到他现在的地址,以上分别对应立即寻址、绝对寻址、直接寻址、间接寻址。

例子:

  LD #10,A

  STL A,*(y)

  LD @x,A

  LD *AR1,A

  可以看到,

1.立即寻址,立即数前面必须加#;

2.绝对寻址是*和(),y就是这个绝对地址省市县区楼;

3.直接寻址的地址x前有@,就是301,至于是1教还是2教作基地址,需要提前设置到底是到哪个教学楼去找,对应sp堆栈或者数据存储器页指针DP设置。

用SSBX CPL(SET bit置CPL为1,用SP作基地址)或RSBX CPL(reset将CPL置0,用DP做基地址),到某页数据存储器中找,还需要设置此页数,如另DP为3就到第三页数据存储器中找),将堆栈当前地址sp+x低7位或将DP第三页首地址+x低7位;

4.间接寻址也有*,不过紧跟的是一个寄存器AR1而不是直接存储器中的数值x。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1