免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8619 | 回复: 8
打印 上一主题 下一主题

[BootLoader] 汇编学习总结记录 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-05-01 21:28 |只看该作者 |倒序浏览
1.1. 汇编学习总结记录
对于我们之前分析的start.S中,涉及到很多的汇编的语句,其中,可以看出,很多包含了很多种不同的语法,使用惯例等,下面,就对此进行一些总结,借以实现一定的举一反三或者说触类旁通,这样,可以起到一定的借鉴功能,方便以后看其他类似汇编代码, 容易看懂汇编代码所要表达的含义。
1.1.1. 汇编中的标号=C中的标号
像前面汇编代码中,有很多的,以点开头,加上一个名字的形式的标号,比如:

  1. reset:
  2. /*
  3.   * set the cpu to SVC32 mode
  4.   */
  5. mrs r0,cpsr  
复制代码
中的reset,就是汇编中的标号,相对来说,比较容易理解,就相当于C语言的标号。
比如,C语言中定义一个标号ERR_NODEV:
  1. ERR_NODEV: /* no device error */
  2. ... /* c code here */
复制代码
然后对应在别处,使用goto去跳转到这个标号ERR_NODEV:
  1. if (something)
  2. goto ERR_NODEV ;
复制代码
【总结】
汇编中的标号 = C语言中的标号Label
1.1.2. 汇编中的跳转指令=C中的goto
对应地,和上面的例子中的C语言中的编号和掉转到标号的goto类似,汇编中,对于定义了标号,那么也会有对应的指令,去跳转到对应的汇编中的标号。
这些跳转的指令,就是b指令,b是branch的缩写。
b指令的格式是:
b{cond} label
简单说就是跳转到label处。
用和上面的例子相关的代码来举例:


  1. .globl _start
  2. _start: b       reset  
复制代码
就是用b指令跳转到上面那个reset的标号。
【总结】
汇编中的b跳转指令 = C语言中的goto
1.1.3. 汇编中的.globl=C语言中的extern
对于上面例子中:

.globl _start  
中的.global,就是声明_start为全局变量/标号,可以供其他源文件所访问。
即汇编器,在编译此汇编代码的时候,会将此变量记下来,知道其是个全局变量,遇到其他文件是用到此变量的的时候,知道是访问这个全局变量的。
因此,从功能上来说,就相当于C语言用extern去生命一个变量,以实现本文件外部访问此变量。
【总结】
汇编中的.globl或.global = C语言中的extern
1.1.4. 汇编中用bl指令和mov pc,lr来实现子函数调用和返回
和b指令类似的,另外还有一个bl指令,语法是:
BL{cond} label
其作用是,除了b指令跳转到label之外,在跳转之前,先把下一条指令地址存到lr寄存器中,以方便跳转到那边执行完毕后,将lr再赋值给pc,以实现函数返回,继续执行下面的指令的效果。
用下面这个start.S中的例子来说明:

  1. bl cpu_init_crit
  2. 。。。
  3. cpu_init_crit:
  4. 。。。
  5. mov pc, lr  
复制代码
其中,就是先调用bl掉转到对应的标号cpu_init_crit,其实就是相当于一个函数了,
然后在cpu_init_crit部分,执行完毕后,最后调用 mov pc, lr,将lr中的值,赋给pc,即实现函数的返回原先 bl cpu_init_crit下面那条代码,继续执行函数。
上面的整个过程,用C语言表示的话,就相当于


  1. 。。。
  2. cpu_init_crit();
  3. 。。。
  4. void cpu_init_crit(void)
  5. {
  6. 。。。
  7. }
复制代码

而关于C语言中,函数的跳转前后所要做的事情,都是C语言编译器帮我们实现好了,会将此C语言中的函数调用,转化为对应的汇编代码的。
其中,此处所说的,函数掉转前后所要做的事情,就是:
函数跳转前:要将当前指令的下一条指令的地址,保存到lr寄存器中。
函数调用完毕后:将之前保存的lr的值给pc,实现函数跳转回来。继续执行下一条指令。
而如果你本身自己写汇编语言的话,那么这些函数跳转前后要做的事情,都是你程序员自己要关心,要实现的事情。
【总结】
汇编中bl + mov pc,lr = C语言中的子函数调用和返回
1.1.5. 汇编中的对应位置有存储值的标号 = C语言中的指针变量
像前文所解析的代码中类似于这样的:
  1. LABEL1:.word Value2
复制代码
比如:


  1. _TEXT_BASE:
  2. .word TEXT_BASE  
复制代码
所对应的含义是,有一个标号_TEXT_BASE
而该标号中对应的位置,所存放的是一个word的值,具体的数值是TEXT_BASE,此处的TEXT_BASE是在别处定义的一个宏,值是0x33D00000。
所以,即为:
有一个标号_TEXT_BASE,其对应的位置中,所存放的是一个word的值,值为TEXT_BASE=0x33D00000。
总的来说,此种用法的含义,如果用C语言来表示,其实更加容易理解:
int *_TEXT_BASE = TEXT_BASE = 0x33D00000
即:
int *_TEXT_BASE = 0x33D00000
【C语言中如何引用汇编中的标号】
不过,对于这样的类似于C语言中的指针的汇编中的标号,在C语言中调用到的话,却是这样引用的:

  1. /* for the following variables, see start.S */
  2. extern ulong _armboot_start; /* code start */
  3. extern ulong _bss_start; /* code + data end == BSS start */
  4. 。。。
  5. IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
  6. 。。。  
复制代码
而不是我原以为的,直接当做指针来引用该变量的方式:

  1. *IRQ_STACK_START = *_armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
复制代码

其中,对应的汇编中的代码为:

  1. .globl _armboot_start
  2. _armboot_start:
  3. .word _start  
复制代码
所以,针对这点,还是需要注意一下的。至少以后如果自己写代码的时候,在C语言中引用汇编中的global的标号的时候,知道是如何引用该变量的。
【总结】
汇编中类似这样的代码:
label1: .word value2
就相当于C语言中的:
int *label1 = value2
但是在C语言中引用该标号/变量的时候,却是直接拿来用的,就像这样:
label1 = other_value
其中label1就是个int型的变量。
1.1.6. 汇编中的ldr+标号,来实现C中的函数调用
接着上面的内容,继续解释,对于汇编中这样的代码:
第一种:
ldr pc, 标号1
。。。
标号1:.word 标号2
。。。
标号2:
。。。(具体要执行的代码)
或者是,
第二种:
ldr pc, 标号1
。。。
标号1:.word XXX(C语言中某个函数的函数名)
的意思就是,将地址为标号1中内容载入到pc中。
而地址为标号1中的内容,就是标号2。
所以上面第一种的意思:
就很容易看出来,就是把标号2这个地址值,给pc,即实现了跳转到标号2的位置执行代码,就相当于调用一个函数,该函数名为标号2.
第二种的意思,和上面类似,是将C语言中某个函数的函数名,即某个地址值,给pc,实现调用C中对应的那个函数。
两种做法,其含义用C语言表达,其实很简单:
PC = *(标号1) = 标号2
举个例子就是:
第一种:

  1. 。。。
  2. ldr pc, _software_interrupt
  3. 。。。
  4. _software_interrupt: .word software_interrupt
  5. 。。。
  6. software_interrupt:
  7. get_bad_stack
  8. bad_save_user_regs
  9. bl  do_software_interrupt
复制代码

就是实现了将标号1,_software_interrupt,对应的位置中的值,标号2,software_interrupt,给pc,即实现了将pc掉转到software_interrupt的位置,即实现了调用函数software_interrupt的效果。
第二种:


  1. ldr pc, _start_armboot
  2. _start_armboot: .word start_armboot  
复制代码
含义就是,将标号1,_start_armboot,所对应的位置中的值,start_armboot给pc,即实现了调用函数start_armboot的目的。
其中,start_armboot是C语言文件中某个C语言的函数。
【总结】
汇编中,实现函数调用的效果,有如下两种方法:
方法1:
ldr pc, 标号1
。。。
标号1:.word 标号2
。。。
标号2:
。。。(具体要执行的代码)
方法2:
ldr pc, 标号1
。。。
标号1:.word XXX(C语言中某个函数的函数名)
1.1.7. 汇编中设置某个寄存器的值或给某个地址赋值
在汇编代码start.S中,看到不止一处, 类似于这样的代码:
形式1:

  1. # define pWTCON  0x53000000
  2. 。。。
  3. ldr     r0, =pWTCON
  4. mov     r1, #0x0
  5. str     r1, [r0]  
复制代码
或者:
形式2:

  1. # define INTSUBMSK 0x4A00001C
  2. 。。。
  3. ldr r1, =0x7fff
  4. ldr r0, =INTSUBMSK
  5. str r1, [r0]  
复制代码
其含义,都是将某个值,赋给某个地址,此处的地址,是用宏定义来定义的,对应着某个寄存器的地址。
其中,形式1是直接通过mov指令来将0这个值赋给r1寄存器,和形式2中的通过ldr伪指令来将0x3ff赋给r1寄存器,两者区别是,前者是因为已经确定所要赋的值0x0是mov的有效操作数,而后者对于0x3ff不确定是否是mov的有效操作数
(如果不是,则该指令无效,编译的时候,也无法通过编译,会出现类似于这样的错误:
  1. start.S: Assembler messages:
  2. start.S:149: Error: invalid constant -- `mov r1,#0xFFEFDFFF'
  3. make[1]: *** [start.o] 错误 1
  4. make: *** [cpu/arm920t/start.o] 错误 2
复制代码

所以才用ldr伪指令,让编译器来帮你自动判断:
(1)如果该操作数是mov的有效操作数,那么ldr伪指令就会被翻译成对应的mov指令。
举例说明:
汇编代码:

  1. # define pWTCON  0x53000000
  2. 。。。
  3. ldr     r0, =pWTCON  
复制代码
被翻译后的真正的汇编代码:

  1. 33d00068: e3a00453  mov r0, #1392508928 ; 0x53000000  
复制代码
(2)如果该操作数不是mov的有效操作数,那么ldr伪指令就会被翻译成ldr指令。
举例说明:
汇编代码:


  1. ldr r1, =0x7fff  
复制代码
被翻译后的真正的汇编代码:

  1. 33d00080: e59f13f8  ldr r1, [pc, #1016] ; 33d00480 <fiq+0x60>
  2. 。。。
  3. 33d00480: 00007fff  .word 0x00007fff  
复制代码
即把ldr伪指令翻译成真正的ldr指令,并且另外分配了一个word的地址空间用于存放该数值,然后用ldr指令将对应地址中的值载入,赋值给r1寄存器。
【总结】
汇编中,一个常用的,用来给某个地址赋值的方法,类似如下形式:

  1. #define 宏的名字  寄存器地址
  2. 。。。
  3. ldr r1, =要赋的值
  4. ldr r0, =宏的名字
  5. str r1, [r0]  
复制代码

评分

参与人数 1可用积分 +10 信誉积分 +2 收起 理由
bitmilong + 10 + 2 感谢分享

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2011-05-03 09:45 |只看该作者
不错不错,支持楼主

论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
3 [报告]
发表于 2011-05-04 11:42 |只看该作者
不错 支持个

论坛徽章:
0
4 [报告]
发表于 2011-05-17 19:38 |只看该作者
不错,支持一个

论坛徽章:
1
2017金鸡报晓
日期:2017-01-10 15:19:56
5 [报告]
发表于 2011-05-20 22:12 |只看该作者
不错

论坛徽章:
2
CU十二周年纪念徽章
日期:2013-10-24 15:41:34处女座
日期:2013-12-27 22:22:41
6 [报告]
发表于 2011-05-21 16:13 |只看该作者
很好,指出几点异议:
1.1.1. 汇编中的标号=C中的标号
像前面汇编代码中,有很多的,以点开头,加上一个名字的形式的标号

以点开头?

1.1.3. 汇编中的.globl=C语言中的extern

在C语言里,extern用在函数前是表函数全局可见,global的作用是将符号暴露给全局,从这个角度上来说两者确有相似。但C语言默认情况下函数本来就是全局可见的,所以很少这样用这个关键字。而用extern修饰一个变量表示“声明该变量但不在此为其分配内存”,这与global的作用就差远了。

1.1.5. 汇编中的对应位置有存储值的标号 = C语言中的指针变量

这是混淆了汇编里的标号及C语言里的变量。
汇编里,标号名纯粹是代表某地址;在C语言中,变量名不是地址,而表示一块内存,且变量名与某一种类型相关联。当操作符作用于变量之上时,编译器必需知道变量的类型才能为其生成指令,比如+对于int*和int的含义是不同的。所以变量在使用之前必需通过声明指出其类型。而汇编语言里的标号完全就是地址,欲在C语言里引用汇编标号,必需给它一个类型。

extern ulong _armboot_start

这里把_armboot_start声明为ulong,所以_armboot_start被当作ulong用。引用_armboot_start就用引用某块内存。这时说的_armboot_start是一块内存。当编译结束后,类型反映在生成的指令上,变量名退化成符号,继而与汇编中的标号一样纯粹是地址。引用_armboot_start的指令通过这块内存的首地址来引用这块内存,这个地址以又以_armboot_start(符号)代表。最后链接时在其它文件提供的符号表里搜寻该符号,就会找到汇编文件中的标号_armboot_start,而此时,链接器已经为这个符号关联一个地址了。所以,在C语言里怎么用汇编里的标号,取决于这个标号在C语言中是怎样声明的。

同样,ldr pc,label 本质上是用一label来代替一个不确定的地址。
label1:
        .word label2
label1与label2也是如此,标号完全代表地址,而不是内存中的内容。但是看到ldr register,label这种用法,很容易误会label与C语言里的变量一般代表某块内存。

其实ARM的汇编指令还算好了,微软PC汇编器的语法在这方面才真是彻底地把人搞糊涂。

论坛徽章:
0
7 [报告]
发表于 2011-06-13 23:39 |只看该作者
学习了~~~~

论坛徽章:
0
8 [报告]
发表于 2011-06-17 21:07 |只看该作者
回复 6# tempname2


   
以点开头?

是偶的笔误。谢谢指正。

在C语言里,extern用在函数前是表函数全局可见,global的作用是将符号暴露给全局,从这个角度上来说两者确有相似。但C语言默认情况下函数本来就是全局可见的,所以很少这样用这个关键字。而用extern修饰一个变量表示“声明该变量但不在此为其分配内存”,这与global的作用就差远了。

在将此变量导出供别处访问方面,global是和extern起到同样效果。对于变量分配,的确作用差远了。是偶的疏忽。偶本意是在前者含义上,两者相等。疏忽了后者。的确是不能划等号。
这是混淆了汇编里的标号及C语言里的变量。
...
label1与label2也是如此,标号完全代表地址,而不是内存中的内容。但是看到ldr register,label这种用法,很容易误会label与C语言里的变量一般代表某块内存。

同上,此处的确不相等,我本意只是想要表示两者在某方面作用类似。此种表达手法,是容易引起误导,以后会及时更正并注意的。
谢谢指正。

论坛徽章:
0
9 [报告]
发表于 2012-12-14 14:13 |只看该作者
很好很强大!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP