分享

uboot中对.balignl和0xdeadbeef的理解

 赵帅蹲守图书馆 2014-02-07
    通过查看uboot源码顶层目录下的链接脚本u-boot.lds:

点击(此处)折叠或打开

  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2. OUTPUT_ARCH(arm)
  3. ENTRY(_start)
  4. SECTIONS
  5. {
  6. . = 0x00000000;
  7. . = ALIGN(4);
  8. .text :
  9. {
  10. cpu/arm920t/start.o (.text)
  11. *(.text)
  12. }
  13. ......
可以从中知道程序的入口点是_start,定位于cpu/arm920t/start.S(即u-boot 启动的第一阶段)。下面本人谈谈对start.S中对.balignl和魔数0xdeadbeef的理解。

    uboot入口_start:

点击(此处)折叠或打开

  1. .globl _start // 不占用内存
  2. _start: b start_code //每条指令占用4字节 异常向量表
  3. ldr pc, _undefined_instruction
  4. ldr pc, _software_interrupt
  5. ldr pc, _prefetch_abort
  6. ldr pc, _data_abort
  7. ldr pc, _not_used
  8. ldr pc, _irq
  9. ldr pc, _fiq

  10. _undefined_instruction: .word undefined_instruction
  11. _software_interrupt: .word software_interrupt
  12. _prefetch_abort: .word prefetch_abort
  13. _data_abort: .word data_abort
  14. _not_used: .word not_used
  15. _irq: .word irq
  16. _fiq: .word fiq

  17. .balignl 16,0xdeadbeef //16字节对齐,不对齐的地址以0xdeadbeef填充

.balignl是条伪指令,用于字节对齐的。对于S3C2440来说,它是32位处理器,要求指令必须4字节对齐。与.balignl相似的伪指令如下表所示:

四种功能基本相同,不同之处在于填充时的字节数。.align.balign1个字节1个字节的填充(区别在于对齐方式不用),.balignw2个字节2个字节的填充,而.balignl一次填充4个字节。我们以balignl为例说明,它的完整指令格式为: 

.balignl {alignment} {,fill} {,max}

第一个参数alignment为一个正整数,对齐时要以alignment的值的整数倍为结束地址(补充:这段描述摘录于别人博客,经过自己验证之后发现.align与其他三个以b开头的伪指令不同是以2^alignment的整数倍为地址,后面会加以讲解),以当前地址为起始地址,进行字节填充,比如当前地址为20,而alignment的值我们设定为16,那么字节填充自20开始,结束于20后第一个16的倍数地址处,即32处。

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

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

为了更容易理解,截取start.S最开始一部分代码做个试验,对它单独编译。文件名为test.S,代码如下:

点击(此处)折叠或打开

  1. .globl _start
  2. _start: b start_code
  3. ldr pc, _undefined_instruction
  4. ldr pc, _software_interrupt
  5. ldr pc, _prefetch_abort
  6. ldr pc, _data_abort
  7. ldr pc, _not_used
  8. ldr pc, _irq
  9. @ldr pc, _fiq

  10. _undefined_instruction: .word undefined_instruction
  11. _software_interrupt: .word software_interrupt
  12. _prefetch_abort: .word prefetch_abort
  13. _data_abort: .word data_abort
  14. _not_used: .word not_used
  15. _irq: .word irq
  16. @_fiq: .word fiq

  17. .balignl 16,0xdeadbeef

  18. start_code:
  19. /*
  20. * set the cpu to SVC32 mode
  21. */
  22. mrs r0, cpsr
  23. bic r0, r0, #0x1f
  24. orr r0, r0, #0xd3
  25. msr cpsr, r0

使用交叉编译器编译后,查看反汇编代码如下:

[samba@localhost ~]$ arm-linux-as test.S -o test.o

test.S: Assembler messages:

test.S:0: Warning: end of file not at end of a line; newline inserted

[samba@localhost ~]$ arm-linux-objdump -d test.o

test.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:

   0:   ea00000e        b       40 <start_code>

   4:   e59ff014        ldr     pc, [pc, #20]   ; 20 <_undefined_instruction>

   8:   e59ff014        ldr     pc, [pc, #20]   ; 24 <_software_interrupt>

   c:   e59ff014        ldr     pc, [pc, #20]   ; 28 <_prefetch_abort>

  10:   e59ff014        ldr     pc, [pc, #20]   ; 2c <_data_abort>

  14:   e59ff014        ldr     pc, [pc, #20]   ; 30 <_not_used>

  18:   e59ff014        ldr     pc, [pc, #20]   ; 34 <_irq>

  1c:   e59ff014        ldr     pc, [pc, #20]   ; 38 <_fiq>

00000020 <_undefined_instruction>:

  20:   00000000        .word   0x00000000

00000024 <_software_interrupt>:

  24:   00000000        .word   0x00000000

00000028 <_prefetch_abort>:

  28:   00000000        .word   0x00000000

0000002c <_data_abort>:

  2c:   00000000        .word   0x00000000

00000030 <_not_used>:

  30:   00000000        .word   0x00000000

00000034 <_irq>:

  34:   00000000        .word   0x00000000

00000030 <_irq>:

  30:   00000000        .word   0x00000000

  34:   deadbeef        .word   0xdeadbeef

  38:   deadbeef        .word   0xdeadbeef

  3c:   deadbeef        .word   0xdeadbeef

00000040 <start_code>:

  40:   e10f0000        mrs     r0, CPSR

  44:   e3c0001f        bic     r0, r0, #31

  48:   e38000d3        orr     r0, r0, #211    ; 0xd3

  4c:   e129f000        msr     CPSR_fc, r0

可以看到由于地址34~3c不是16字节对齐所以用0xdeadbeef填充。那么我们修改test.S做一个试验,屏蔽.balignl 16,0xdeadbeef,在它之后添加.byte 0x11,使用交叉编译器编译,结果如下:

[samba@localhost ~]$ arm-linux-as test.S -o test.o

test.S: Assembler messages:

test.S:0: Warning: end of file not at end of a line; newline inserted

test.S:2: Error: misaligned branch destination

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

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

.align 40x88

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

[samba@localhost ~]$ arm-linux-as test.S -o test.o

test.S: Assembler messages:

test.S:0: Warning: end of file not at end of a line; newline inserted

[samba@localhost ~]$ arm-linux-objdump -d test.o  

test.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:

   0:   ea00000e        b       40 <start_code>

   4:   e59ff010        ldr     pc, [pc, #16]   ; 1c <_undefined_instruction>

   8:   e59ff010        ldr     pc, [pc, #16]   ; 20 <_software_interrupt>

   c:   e59ff010        ldr     pc, [pc, #16]   ; 24 <_prefetch_abort>

  10:   e59ff010        ldr     pc, [pc, #16]   ; 28 <_data_abort>

  14:   e59ff010        ldr     pc, [pc, #16]   ; 2c <_not_used>

  18:   e59ff010        ldr     pc, [pc, #16]   ; 30 <_irq>

0000001c <_undefined_instruction>:

  1c:   00000000        .word   0x00000000

00000020 <_software_interrupt>:

  20:   00000000        .word   0x00000000

00000024 <_prefetch_abort>:

  24:   00000000        .word   0x00000000

00000028 <_data_abort>:

  28:   00000000        .word   0x00000000

0000002c <_not_used>:

  2c:   00000000        .word   0x00000000

00000030 <_irq>:

  30:   00000000        .word   0x00000000

  34:   88888811        .word   0x88888811

  38:   88888888        .word   0x88888888

  3c:   88888888        .word   0x88888888

00000040 <start_code>:

  40:   e10f0000        mrs     r0, CPSR

  44:   e3c0001f        bic     r0, r0, #31

  48:   e38000d3        orr     r0, r0, #211    ; 0xd3

  4c:   e129f000        msr     CPSR_fc, r0

结果发现不是我们想要的4字节对齐,而是16字节对齐,为什么呢?经过查找资料发现,.align是以2^alignment方式对齐,在这里就是2^4=16字节对齐方式。

说到这里,我们已经理解了字节对齐伪指令的含义了,紧接着的疑问是,经过之前的两次反汇编我们发现地址已经是4字节对齐了,符合32为处理器地址4字节对齐的要求了。u-boot为什么要加.balignl 16,0xdeadbeef这句话呢?0xdeadbeef是一个魔数,本身数值没有什么意义,也可以设为其他值,就是一个标识作用的信息。把它放置在异常向量之后,用它来标识程序真正开始的地方(自己的理解)。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多