Chinaunix首页 | 论坛 | 博客
  • 博客访问: 13147
  • 博文数量: 11
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-14 22:16
文章分类
文章存档

2013年(11)

我的朋友

分类: LINUX

2013-04-17 23:19:21

最近空闲时间较多,于是准备将uboot下的Makefile、start.S、lowlevel_init.S等几个文件精读后再进行移植,在读代码的过程中,发现了几个问题,本篇专门针对start.S中的 .balignl 16,0xdeadbeef 这句进行分析以及扩展。由于本博主才疏学浅,语言表达能力不好,所以文章中难免会出现错误的见解及理解不了的地方,各位看官还请多多包涵o(∩_∩)o 。

好了,言归正传,先将部分代码贴出,来自于uboot-2011.06目录下arch\arm\cpu\arm920t\start.S。

  1. /*  
  2.  *  armboot - Startup Code for ARM920 CPU-core  
  3.  *  
  4.  *  Copyright (c) 2001  Marius Gr鰃er   
  5.  *  Copyright (c) 2002  Alex Z黳ke   
  6.  *  Copyright (c) 2002  Gary Jennejohn   
  7.  *  
  8.  * See file CREDITS for list of people who contributed to this  
  9.  * project.  
  10.  *  
  11.  * This program is free software; you can redistribute it and/or  
  12.  * modify it under the terms of the GNU General Public License as  
  13.  * published by the Free Software Foundation; either version 2 of  
  14.  * the License, or (at your option) any later version.  
  15.  *  
  16.  * This program is distributed in the hope that it will be useful,  
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  19.  * GNU General Public License for more details.  
  20.  *  
  21.  * You should have received a copy of the GNU General Public License  
  22.  * along with this program; if not, write to the Free Software  
  23.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,  
  24.  * MA 02111-1307 USA  
  25.  */  
  26.   
  27. #include    
  28. #include    
  29. #include    
  30.   
  31. /*
  32.  *************************************************************************  
  33.  *  
  34.  * Jump vector table as in table 3.1 in [1]  
  35.  *  
  36.  *************************************************************************  
  37.  */  
  38.   
  39.   
  40. .globl _start   
  41. _start: b   start_code   
  42.     ldr pc, _undefined_instruction   
  43.     ldr pc, _software_interrupt   
  44.     ldr pc, _prefetch_abort   
  45.     ldr pc, _data_abort   
  46.     ldr pc, _not_used   
  47.     ldr pc, _irq   
  48.     ldr pc, _fiq   
  49.   
  50. _undefined_instruction: .word undefined_instruction   
  51. _software_interrupt:    .word software_interrupt   
  52. _prefetch_abort:    .word prefetch_abort   
  53. _data_abort:        .word data_abort   
  54. _not_used:      .word not_used   
  55. _irq:           .word irq   
  56. _fiq:           .word fiq   
  57.   
  58.     .balignl 16,0xdeadbeef  

 

问题出在58行,.balignl 16,0xdeadbeef,查了以前的笔记得知这是一个伪指令,主要是字节对齐用的。对于某些处理器来说,所编写的代码不对齐并不会报错,但编译器为了优化,也可能会自动帮你对齐。但对于另外一些处理器的编译器来说,汇编代码里必须手动保持对齐,否则编译器会报错,arm处理器就是如此。本着精读的态度,上网查了一下资料,结果花掉了1下午的时间o(︶︿︶)o 。。。

balignl有几个“近亲”,具体看下面截图:

四种功能基本相同,不同之处在于填充时的字节数。.align和.balign是1个字节1个字节的填充,.balignw是2个字节2个字节的填充,而.balignl一次填充4个字节。

我们以balignl为例说明,它的完整指令格式为: .balignl {alignment} {,fill} {,max}。

第一个参数alignment为一个正整数,对齐时要以alignment的值的整数倍为结束地址,以当前地址为起始地址,进行字节填充,比如当前地址为20,而alignment的值我们设定为16,那么字节填充自20开始,结束于20后第一个16的倍数地址处,即32处。

第二个参数fill即我们选定的,用来填充的数值。balignl模式下,最大为4字节,不够4字节系统会自动补够4字节,此参数可选,不标则采用默认值0。

第三个参数max也是可选项,默认值为alignment。若对齐时偏移量大于max,则不偏移。同上例,从16--32,偏移量为16,如果max我们设置为8,那么该偏移不进行。

为了能更容易理解,我们实际操作下。

将start.S拷贝至任意目录,保留58行前以及start_code段的代码(大约在117~124行),方便起见,我直接贴出裁剪后的代码:

  1. /*  
  2.  *  armboot - Startup Code for ARM920 CPU-core  
  3.  *  
  4.  *  Copyright (c) 2001  Marius Gr鰃er   
  5.  *  Copyright (c) 2002  Alex Z黳ke   
  6.  *  Copyright (c) 2002  Gary Jennejohn   
  7.  *  
  8.  * See file CREDITS for list of people who contributed to this  
  9.  * project.  
  10.  *  
  11.  * This program is free software; you can redistribute it and/or  
  12.  * modify it under the terms of the GNU General Public License as  
  13.  * published by the Free Software Foundation; either version 2 of  
  14.  * the License, or (at your option) any later version.  
  15.  *  
  16.  * This program is distributed in the hope that it will be useful,  
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  19.  * GNU General Public License for more details.  
  20.  *  
  21.  * You should have received a copy of the GNU General Public License  
  22.  * along with this program; if not, write to the Free Software  
  23.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,  
  24.  * MA 02111-1307 USA  
  25.  */  
  26.   
  27. #include    
  28. #include    
  29. #include    
  30.   
  31. /*
  32.  *************************************************************************  
  33.  *  
  34.  * Jump vector table as in table 3.1 in [1]  
  35.  *  
  36.  *************************************************************************  
  37.  */  
  38.   
  39.   
  40. .globl _start   
  41. _start: b   start_code   
  42.     ldr pc, _undefined_instruction   
  43.     ldr pc, _software_interrupt   
  44.     ldr pc, _prefetch_abort   
  45.     ldr pc, _data_abort   
  46.     ldr pc, _not_used   
  47.     ldr pc, _irq   
  48.     ldr pc, _fiq   
  49.   
  50. _undefined_instruction: .word undefined_instruction   
  51. _software_interrupt:    .word software_interrupt   
  52. _prefetch_abort:    .word prefetch_abort   
  53. _data_abort:        .word data_abort   
  54. _not_used:      .word not_used   
  55. _irq:           .word irq   
  56. _fiq:           .word fiq   
  57.   
  58.     .balignl 16,0xdeadbeef   
  59.   
  60. start_code:   
  61.     /*
  62.      * set the cpu to SVC32 mode  
  63.      */  
  64.     mrs r0, cpsr   
  65.     bic r0, r0, #0x1f   
  66.     orr r0, r0, #0xd3   
  67.     msr cpsr, r0  

 

OK,首先我们将58行屏蔽掉,然后在59行添加代码:

58:  @ .balignl 16,0xdeadbeef

59:  .byte 0x11

保存后,用linux上的交叉编译器来编译下,看看什么效果:

eleven@eleven-desktop:~/workspace$ arm-linux-as start.S -o start.o

start.S: Assembler messages:

start.S:41: Error: misaligned branch destination

提示边界对齐出错,这说明arm编译器没有自动帮我们对齐。添加的 .byte 0x11 只占用了1字节,导致其后的全部指令地址都没有对齐,而arm的指令要求32位对齐,不然无法寻址。所以41行处跳转去start_code时出现了问题,start_code此时的存储地址不是4字节的整数倍,当然无法寻址了。

要解决这个问题,这里我们就需要手动对齐了。在59行后添加如下代码:

.align 4,0x12

保存后再编译就顺利通过了。为了能更清楚知道它的作用,我们来看看反汇编代码:

  1. eleven@eleven-desktop:~/workspace$ arm-linux-objdump -d start.o   
  2.   
  3. start.o:     file format elf32-littlearm   
  4.   
  5. Disassembly of section .text:   
  6.   
  7. 00000000 <_start>:   
  8.    0:   ea00000e        b       40    
  9.    4:   e59ff014        ldr     pc, [pc, #20]   ; 20 <_undefined_instruction>   
  10.    8:   e59ff014        ldr     pc, [pc, #20]   ; 24 <_software_interrupt>   
  11.    c:   e59ff014        ldr     pc, [pc, #20]   ; 28 <_prefetch_abort>   
  12.   10:   e59ff014        ldr     pc, [pc, #20]   ; 2c <_data_abort>   
  13.   14:   e59ff014        ldr     pc, [pc, #20]   ; 30 <_not_used>   
  14.   18:   e59ff014        ldr     pc, [pc, #20]   ; 34 <_irq>   
  15.   1c:   e59ff014        ldr     pc, [pc, #20]   ; 38 <_fiq>   
  16.   
  17. 00000020 <_undefined_instruction>:   
  18.   20:   00000000        .word   0x00000000   
  19.   
  20. 00000024 <_software_interrupt>:   
  21.   24:   00000000        .word   0x00000000   
  22.   
  23. 00000028 <_prefetch_abort>:   
  24.   28:   00000000        .word   0x00000000   
  25.   
  26. 0000002c <_data_abort>:   
  27.   2c:   00000000        .word   0x00000000   
  28.   
  29. 00000030 <_not_used>:   
  30.   30:   00000000        .word   0x00000000   
  31.   
  32. 00000034 <_irq>:   
  33.   34:   00000000        .word   0x00000000   
  34.   
  35. 00000038 <_fiq>:   
  36.   38:   00000000        .word   0x00000000   
  37.   3c:   121212ee        .word   0x121212ee   
  38.   
  39. 00000040 :   
  40.   40:   e10f0000        mrs     r0, CPSR   
  41.   44:   e3c0001f        bic     r0, r0, #31     ; 0x1f   
  42.   48:   e38000d3        orr     r0, r0, #211    ; 0xd3   
  43.   4c:   e129f000        msr     CPSR_fc, r0  

仔细看37行处,align 4,0x12的作用体现出来了吧?为了能够4字节对齐,添加了0x121212共3字节,这样就保证了start_code开始处的地址为4字节的倍数。

接下来我们将刚刚添加的代码删除掉,恢复至start.S刚裁剪完后的状态(不要忘记将58行处的屏蔽去掉)。之后做如下改动(红色部分为改动部位):

  1. .globl _start      //不占用内存空间   
  2. _start: b   start_code       //占用4字节   
  3.     ldr pc, _undefined_instruction     //占用4字节    
  4.     ldr pc, _software_interrupt      //占用4字节   
  5.     ldr pc, _prefetch_abort      //占用4字节   
  6.     ldr pc, _data_abort      //占用4字节   
  7.     ldr pc, _not_used      //占用4字节   
  8.     ldr pc, _irq      //占用4字节   
  9. @    ldr pc, _fiq    //屏蔽掉了,这里不再占用内存     
  10.         
  11. _undefined_instruction: .word undefined_instruction      //占用4字节   
  12. _software_interrupt:    .word software_interrupt      //占用4字节   
  13. _prefetch_abort:    .word prefetch_abort      //占用4字节   
  14. _data_abort:        .word data_abort      //占用4字节   
  15. _not_used:      .word not_used      //占用4字节   
  16. _irq:           .word irq      //占用4字节   
  17. @_fiq:           .word fiq   //屏蔽掉了,这里同样不占用内存     
  18.         
  19.     .balignl 16,0xdeadbeef      

上面一共占用内存为 4字节x7 + 4字节x6 = 52字节。离52最近的16的整数倍地址为64,中间差了12个字节,对齐时需要填充3次的0xdeadbeef,下面我们验证下,看推断对不对。

编译之后再进行反汇编,有如下显示:

  1. eleven@eleven-desktop:~/workspace$ arm-linux-objdump -d start.o   
  2.   
  3. start.o:     file format elf32-littlearm   
  4.   
  5. Disassembly of section .text:   
  6.   
  7. 00000000 <_start>:   
  8.    0:   ea00000e        b       40    
  9.    4:   e59ff010        ldr     pc, [pc, #16]   ; 1c <_undefined_instruction>   
  10.    8:   e59ff010        ldr     pc, [pc, #16]   ; 20 <_software_interrupt>   
  11.    c:   e59ff010        ldr     pc, [pc, #16]   ; 24 <_prefetch_abort>   
  12.   10:   e59ff010        ldr     pc, [pc, #16]   ; 28 <_data_abort>   
  13.   14:   e59ff010        ldr     pc, [pc, #16]   ; 2c <_not_used>   
  14.   18:   e59ff010        ldr     pc, [pc, #16]   ; 30 <_irq>   
  15.   
  16. 0000001c <_undefined_instruction>:   
  17.   1c:   00000000        .word   0x00000000   
  18.   
  19. 00000020 <_software_interrupt>:   
  20.   20:   00000000        .word   0x00000000   
  21.   
  22. 00000024 <_prefetch_abort>:   
  23.   24:   00000000        .word   0x00000000   
  24.   
  25. 00000028 <_data_abort>:   
  26.   28:   00000000        .word   0x00000000   
  27.   
  28. 0000002c <_not_used>:   
  29.   2c:   00000000        .word   0x00000000   
  30.   
  31. 00000030 <_irq>:   
  32.   30:   00000000        .word   0x00000000   
  33.   34:   deadbeef        .word   0xdeadbeef   
  34.   38:   deadbeef        .word   0xdeadbeef   
  35.   3c:   deadbeef        .word   0xdeadbeef   
  36.   
  37. 00000040 :   
  38.   40:   e10f0000        mrs     r0, CPSR   
  39.   44:   e3c0001f        bic     r0, r0, #31     ; 0x1f   
  40.   48:   e38000d3        orr     r0, r0, #211    ; 0xd3   
  41.   4c:   e129f000        msr     CPSR_fc, r0  

.balignl 16,0xdeadbeef 的作用体现出来了,注意看红色部分,与我们的推断相吻合。

到此先告一段落吧,相信经过这样的分析,我应该很久不会忘记.balignl和他那几个“近亲”的作用了,o(∩_∩)o 。

 

另:4字节对齐是可以理解的,但是关于16字节对齐我还是有些想不通,按照我现在的理解,加不加 .balignl 16,0xdeadbeef 这句都不会影响编译或者寻址的,之前的所有指令都是4字节大小。

网上查阅,找到了两种答案:

1.类似这样的值很多,像0xabababab,它们的作用就是为内存做标记,插在那里,就表示从这个位置往后的一段有特殊作用的内存,而这个位置往前,禁止访问。

2.正如deadbeef一样,其实是作者故意搞笑,无任何实际意义(如果真是这样,我会脸红的。。。)。

你怎样认为?想通了的朋友麻烦留言告知,谢谢。


阅读(417) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~