关于ARM指令中位置无关和位置相关代码的认识【转】
本文转载自:https://blog.csdn.net/talent_CYJ/article/details/50533153
今天在一个问题上折腾了又是半天。就是在学JZ2440串口通信的时候,在sdram初始化函数中有这么一句话
- 1
- 2
/*
* 设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
/* 这个函数之所以这样赋值,而不是像前面的实验那样将配置值
* 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
* SDRAM之前就可以在steppingstone中运行
*/
/* 存储控制器13个寄存器的值 */
p[0] = 0x22011110; //BWSCON
p[1] = 0x00000700; //BANKCON0
p[2] = 0x00000700; //BANKCON1
p[3] = 0x00000700; //BANKCON2
p[4] = 0x00000700; //BANKCON3
p[5] = 0x00000700; //BANKCON4
p[6] = 0x00000700; //BANKCON5
p[7] = 0x00018005; //BANKCON6
p[8] = 0x00018005; //BANKCON7
p[9] = 0x008C04F4; //REFRESH
p[10] = 0x000000B1; //BANKSIZE
p[11] = 0x00000030; //MRSRB6
p[12] = 0x00000030; //MRSRB7
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
对于前面实验,sdram初始化函数是这么写的:
void memsetup(void)
{
/* SDRAM 13个寄存器的值 */
unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x00018005, //BANKCON6
0x00018005, //BANKCON7
0x008C07A3, //REFRESH
0x000000B1, //BANKSIZE
0x00000030, //MRSRB6
0x00000030, //MRSRB7
};
int i = 0;
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
for(; i < 13; i++)
p[i] = mem_cfg_val[i];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
对于这个串口程序,它的链接文件如下:
SECTIONS {
. = 0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
表示该程序“应该”放在0x30000000中执行。
在程序运行时,首先执行head.S中的代码。
head.S代码如下:
.extern main
.text
.global _start
_start:
Reset:
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK
bl memsetup @ 设置存储控制器以使用SDRAM
bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中
ldr pc, =on_sdram @ 跳到SDRAM中继续执行
on_sdram:
ldr sp, =0x34000000 @ 设置栈指针
ldr lr, =halt_loop @ 设置返回地址
ldr pc, =main @ 调用main函数
halt_loop:
b halt_loop
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
程序运行时,对于NAND FLASH启动,首先NAND FLASH前4K代码会被复制到steppingstone片内内存中去执行,这个时候0x30000000(对于JZ2440来说该地址是SDRAM地址)还不能使用,因为SDRAM还没初始化,虽然链接的时候指出了,程序应该位于0x30000000执行,但是程序代码从NAND FLASH拷贝到片内内存之后,CPU默认从0地址开始执行,所以程序会被执行,当SDRAM没被初始化之前,用的都是bl跳转指令,这些指令都是位置无关指令。
对于反汇编文件,先看前面一部分:
30000000 <_start>:
30000000: e3a0da01 mov sp, #4096 ; 0x1000
30000004: eb00000a bl 30000034 <disable_watch_dog>
30000008: eb00000d bl 30000044 <clock_init>
3000000c: eb000026 bl 300000ac <memsetup>
30000010: eb000040 bl 30000118 <copy_steppingstone_to_sdram>
30000014: e59ff00c ldr pc, [pc, #12] ; 30000028 <.text+0x28>
30000018 <on_sdram>:
30000018: e3a0d30d mov sp, #872415232 ; 0x34000000
3000001c: e59fe008 ldr lr, [pc, #8] ; 3000002c <.text+0x2c>
30000020: e59ff008 ldr pc, [pc, #8] ; 30000030 <.text+0x30>
30000024 <halt_loop>:
30000024: eafffffe b 30000024 <halt_loop>
30000028: 30000018 andcc r0, r0, r8, lsl r0
3000002c: 30000024 andcc r0, r0, r4, lsr #32
30000030: 30000200 andcc r0, r0, r0, lsl #4
30000034 <disable_watch_dog>:
30000034: e3a02000 mov r2, #0 ; 0x0
30000038: e3a03453 mov r3, #1392508928 ; 0x53000000
3000003c: e5832000 str r2, [r3]
30000040: e1a0f00e mov pc, lr
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
前面表示了程序链接的地址。但是程序在片内内存中还是会继续执行,当执行到
bl disable_watch_dog
- 1
这个语句时,程序会跳转到disable_watch_dog去执行,由于bl是位置无关,所以跳转的时候只是PC(new) = PC + 偏移。
而对于ldr pc, =on_sdram这些指令来说则是位置有关,即让PC赋值为一个确切值。对于
=on_sdram来说,它则等于 30000018,所以程序会跳转到该位置中去执行,若SDRAM没初始化之前使用了这类位置有关的指令,则会出错。
所以在下列情况下:
void memsetup(void)
{
/* SDRAM 13个寄存器的值 */
unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x00018005, //BANKCON6
0x00018005, //BANKCON7
0x008C07A3, //REFRESH
0x000000B1, //BANKSIZE
0x00000030, //MRSRB6
0x00000030, //MRSRB7
};
int i = 0;
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
for(; i < 13; i++)
p[i] = mem_cfg_val[i];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
mem_cfg_val的链接地址会大于0x30000000,这个时候SDRAM还没被初始化,当执行下列语句时:
p[i] = mem_cfg_val[i];
- 1
即程序会去 mem_cfg_val 所在位置取值,所以会出错。因为此时SDRAM没初始化。
但是对于下列这种情况则不会出错:
/*
* 设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
/* 这个函数之所以这样赋值,而不是像前面的实验那样将配置值
* 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
* SDRAM之前就可以在steppingstone中运行
*/
/* 存储控制器13个寄存器的值 */
p[0] = 0x22011110; //BWSCON
p[1] = 0x00000700; //BANKCON0
p[2] = 0x00000700; //BANKCON1
p[3] = 0x00000700; //BANKCON2
p[4] = 0x00000700; //BANKCON3
p[5] = 0x00000700; //BANKCON4
p[6] = 0x00000700; //BANKCON5
p[7] = 0x00018005; //BANKCON6
p[8] = 0x00018005; //BANKCON7
p[9] = 0x008C04F4; //REFRESH
p[10] = 0x000000B1; //BANKSIZE
p[11] = 0x00000030; //MRSRB6
p[12] = 0x00000030; //MRSRB7
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
虽然这段代码中p指针变量也是位于0x30000000之后,但是p[0],p[1],这些值会被编译器编译成与MEM_CTL_BASE相关的值,也就是与SDRAM初始化有关的寄存器的地址。所以此时不管p指针位于哪也与它的地址无关。
新手一枚还在进步中,有说错的地方希望各位大神能够为我指出,也欢迎各位和我一起交流讨论。
关于ARM指令中位置无关和位置相关代码的认识【转】的更多相关文章
- ARM指令中的函数调用
1. 重要寄存器 SP 栈指针, 每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式.非异常模式(用户模式和系统模式),都有各自独立的堆栈,用不同的堆栈指针来 ...
- 汇编指令-位置无关码(BL)与绝对位置码(LDR)(2)
位置无关码,即该段代码无论放在内存的哪个地址,都能正确运行.究其原因,是因为代码里没有使用绝对地址,都是相对地址. 位置相关码,即它的地址与代码处于的位置相关,是绝对地址 BL :带链接分支跳转指令 ...
- 大脸猫讲逆向之ARM汇编中PC寄存器详解
i春秋作家:v4ever 近日,在研究一些开源native层hook方案的实现方式,并据此对ARM汇编层中容易出问题的一些地方做了整理,以便后来人能有从中有所收获并应用于现实问题中.当然,文中许多介绍 ...
- ARM指令和Thumb指令区别
Thumb指令集 ]的问题而提出的,它具有16为的代码密度.Thumb不是一个完整的体系结构,不能指望处理程序只执行Thumb指令而不支持ARM指令集.因此,Thumb指令只需要支持通用功能,必要时, ...
- arm32位固定指令中怎么容纳32位变量
在ARM指令集汇编码中.32位有效马上数是通过______偶数位而间接得到的 A.循环左移 B.循环右移. C.逻辑左移. D.逻辑右移 答案为循环左移.为什么?还有最好解释一下逻辑移动和循环移动的概 ...
- x64共享库中的位置无关代码(PIC)
原作者:Eli Bendersky http://eli.thegreenplace.net/2011/11/11/position-independent-code-pic-in-shared-li ...
- JZ2440开发笔记(9)——位置无关代码设计【转】
b MAIN 和 ldr pc,=MAIN 的区别(谈到代码位置无关性) 看bootloader的时候经常看到这两种写法,不太明白区别,网上查了查.其实看了之后还是一头雾水? 其中,2和3 似乎是一个 ...
- uboot之位置无关代码解析
在之前的话 新年过去了,那么久没有好好学习,感觉好颓废,现在就uboot的一些基础问题做一些笔记,顺便分享给大家,不过由于见识有限,如果有不足之处请多多指教. 位置无关?什么意思?我们先了解一些基础知 ...
- 韦东山yy公开课笔记(2)--汇编,段,栈,重定位/链接地址,位置无关吗
1. 要不要学习汇编 可以只懂一点,工作中基本不用,一旦用就是出了大问题 ldr : load 读内存 ldr r0, [r1] : r1里存放的是地址值, 去这个地址读取4字节的内容,存入r0 s ...
随机推荐
- svn服务器配置 for mac
本文转载至 http://blog.sina.com.cn/s/blog_5e42f31a010156z4.html 1.找到合适的目录,新建一个版本库的目录:mkdir svn 创建版本库:sv ...
- PAT Advance 1020
题目: 1020. Tree Traversals (25) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue S ...
- 第一次使用Xamarin就上手 - 安裝Xamarin
http://xamarintech.blogspot.tw/2013/06/xamarin-xamarin-step-by-step-part1.html http://xamarintech.bl ...
- HDU 3695 / POJ 3987 Computer Virus on Planet Pandora
Computer Virus on Planet Pandora Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1353 ...
- 170302、 Apache 使用localhost(127.0.0.1)可以访问,使用本机局域网IP(192.168.2.*)不能访问
对于此问题的解决办法,打开apache安装路径中的http.conf文件, 找打以下内容 # onlineoffline tag - don't remove Order Deny, ...
- Minecraft Forge编程入门二 “工艺和食谱”
从现在开始我们就要开始真正写代码了,还没有来得及配置环境的同学可以参考Minecraft Forge编程入门一 "环境搭建"这篇文章来进行环境搭建. 工艺(Craft)和食谱(Re ...
- SQLSERVER 创建索引实现代码
是SQL Server编排数据的内部方法.它为SQL Server提供一种方法来编排查询数据 什么是索引 拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数 ...
- flink hadoop yarn
新一代大数据处理引擎 Apache Flink https://www.ibm.com/developerworks/cn/opensource/os-cn-apache-flink/ 新一代大数据处 ...
- Scala 常用语法
Clojure首先是FP, 但是由于基于JVM, 所以不得已需要做出一些妥协, 包含一些OO的编程方式 Scala首先是OO, Java语法过于冗余, 一种比较平庸的语言, Scala首先做的是简化, ...
- JS让DIV绑定某个事件
<html> <head> <title>Add/Remove Event Handlers Example</title> <script ty ...