Chinaunix首页 | 论坛 | 博客
  • 博客访问: 605876
  • 博文数量: 99
  • 博客积分: 5128
  • 博客等级: 大校
  • 技术积分: 1538
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-27 19:40
文章分类

全部博文(99)

文章存档

2012年(3)

2011年(5)

2010年(4)

2009年(31)

2008年(56)

分类: LINUX

2008-12-05 15:31:48

之前看bootloader的时候总是搞的不太懂,今天下定决心分析一下这个 align究竟是怎么回事。一下分多种情况

平台: WinXP + WinARM WinARMwindow平台的 ARM-LINUX-GCC 的移植版本。

 

.align 就是用来对齐的,究竟怎么对齐,有啥情况?下面分析一下

(一)

 

_start:
    b reset
    .byte 0x55
    .byte 0xaa
reset:
    ldr r0, =0x53000000
    ...

这样的话编译器会报错

crt0.S: Assembler messages:

crt0.S:10: Error: misaligned branch destination

make: *** [leds.bin] Error 1

 

很明显,提示边界对齐出错,为什么这样的呢?我们分析一下。首先,ARM指令都是32位的,这里要求4字节(一个word)对齐,b reset 指令占了4个字节,接着我们用 .byte 指令定义2个常数,因为这里是 byte 类型,所以只占了八位,两个数据,一共占16位。由于连接器内部有一个程序地址计数指针,里面保存着当前的地址,这地址指针是连接器内部工作需要的,我们不需要理会,只需要了解有这么一个机制。假如_start从0x00,第一条指令占4个byte,然后连续分配2个byte,当前地址指针应该是 0x06,那么问题来了,下条指令,也就是标号 reset 处的ldr指令,是一条ARM指令,这要求是 4个字节对齐的,当前的地址为 0x06,并不能满足这个要求,所以编译器报错了。

 

解决办法很简单,我们只需要加一条 .align 指令,问题就解决了

_start:
    b reset
    .byte 0x55
    .byte 0xaa
    .align
reset:
    ldr r0, =0x53000000

 

编译结果是:

00000000 <_start>:
   0: ea000000  b 8
   4: 0000aa55  andeq sl, r0, r5, asr sl

00000008 :
   8: e3a00453  mov r0, #1392508928 ; 0x53000000

 

在两个 .byte 指令后自动补零,直到满足地址要求为止。这里就是将地址累加到 0x08符合ARM指令要求,所以在这里写入下条指令。这是基本内容,下面研究一下其他

 

(二).align 5

这里只是一个例子,重点想说的是 这个 .align 5 后面的 5 究竟是什么意思? uboot里面就有这指令。我们继续做做试验,看看编译结果是什么

 

_start:
    b reset
    
    .align 5
    .byte 0x55
    
    .align 5
    .byte 0xaa
    
    .align
reset:
    ldr r0, =0x53000000

编译结果:

00000000 <_start>:
   0: ea00000f  b 44
 ...
  20: 00000055  andeq r0, r0, r5, asr r0
 ...
  40: 000000aa  andeq r0, r0, sl, lsr #1

00000044 :
  44: e3a00453  mov r0, #1392508928 ; 0x53000000

我们发现这编译结果有点意思,这地址分配一下子上去了,但是也不难,分析一下就OK,看那个 20 和 40 ,这里是十六进制,也就是 32 和 64了。那么很容易可以联想到,这里做的是幂运算,也就是 .align 5 对齐的地址为 2^5 = 32,之前的地址全部补零。

(三).balignl 16,0xdeadbeef

_start:
    b reset
    
    .balignl 16,0xdeadbeef
    
reset:
    ldr r0, =0x53000000

在看uboot的时候还有这么一个语句,查了半天as的手册才找到,囧,不过稍微做了一下实现,觉得又不是很难,我们看看结果:

00000000 <_start>:
   0: ea000002  b 10
   4: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}
   8: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}
   c: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}

00000010 :
  10: e3a00453  mov r0, #1392508928 ; 0x53000000

可以看出,这指令就是将 deadbeef字符串填进去,一共填到地址为16对齐的地方为指,上面可以看到,这里填到 0x10 也就是 16了。

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

chinaunix网友2010-04-23 10:43:40

有点明白了

chinaunix网友2009-02-26 10:39:55

这篇文章写的特别好,博主辛苦了。