關於U-BOOT中.balignl 16,0xdeadbeef的理解

記錄下:u-boot很久前就看了,也做了移植。這次重新看到U-BOOT的代碼,是由於昨晚上頭上一個裸機的小應用,基礎裸機程序的開發要告一段落了,正式去學習linux的驅動。爲此想把自己寫的或者網上抄的代碼整理下,做成一個比較合理的項目工程樣的。這個最先要解決的就是啓動代碼的完整性,就想到了U-boot的代碼組織管理方式,以及多平臺支持方面的處理。比較了下自己寫的和U-boot的第一階段的代碼基本流程還是一致的(缺少合理的組織)。

爲什麼要這麼做?1、項目不是一個人可以完成的;2、一個人可以完成的,但不合理的代碼組織方式,也會使得一個項目難以完成。所以學習。

迴歸正題:

如題,這句話在u-boot start.s中中斷向量表最後出現的,實在不能理解(第一看的時候忙於對着教程移植了)。晚上看了篇博文http://haoyeren.blog.sohu.com/84511571.html,實在不知道說的是什麼意思(個人水平不夠吧)。就專門查了balignl的含義.

簡單說就是爲了中斷向量表後保持字節對齊(這裏提一下ARM ABI AAPCS規定的堆棧指針要8字節對齊),如果不滿足對齊,PC自動後移到對齊位置,同時跳過的地址空間填充一些特定的或者隨機的數據。

下面具體介紹(轉自http://zqwt.012.blog.163.com/blog/static/12044684201031102956976/):
 .balignl 16, 0xdeadbeef
首先要弄明白.balignl的意思,這其實應該算是一個僞操作符,僞操作符的意思就是機器碼裏,並沒有一個彙編指令與其對應,是由編譯器來實現其功能的。
.balign是意思是:以當前地址爲開始開始,找到第一次出現的以第一個參數爲整數倍的地址,並將其作爲結束地址,
在這個結束地址前面存儲一個字節長度的數據,存儲內容正是第二個參數。如果當前地址正好是第一個參數的倍數,則沒有數據被寫入到內存。
.balign 8, 0xde這條指令的含義可以用下圖表示:




圖解:以當前地址爲開始開始,找到第一次出現的以8爲整數倍的地址,並將其作爲結束地址,在這個結束地址前面存儲一個字節長度的數據0xde。
如果當前地址正好是8的倍數,則沒有數據被寫入到內存。
以此類推,.balignw則表示第二個參數存入的內容長度爲2字節:
    .balignw 4, 0x368d
因爲現在填入的內容爲2個字節,那就存在以下幾種情況:
    1>當前地址沒有偏移就滿足了以4爲倍數的地址
    2>當前地址偏移了1個字節就滿足了以4爲倍數的地址
    3>當前地址偏移了2個字節就滿足了以4爲倍數的地址
    4>當前地址編移了3個字節就滿足了以4爲倍數的地址
分析一下這四種情況:
    1>當沒有偏移的時候,地址中間肯定沒有辦法填上信息
    2>當偏移1個字節的時候,地址中間空隙不夠,所以填入的數值,是末定義,也就是說,填入什麼值,不清楚
    3>當偏移2個字節的時候,地址中間的空隙正好填入0x368d兩個字節的內容
    4>當偏移3個字節的時候,地址中間的空隙大於所要填的內容。此時填入的數值,是末定義,填入什麼值,不清楚
以此類推,.balignl,這個指令用來填與一個字,即4個字節的長度
仔細分析一下就知道,對於.balignl 16, 0xdeadbeef,如果想要0xdeadbeef一定填到當前地址後面某個部分,當前地址偏移量就必須爲4字節,這樣才能保證在任何情況下,偏移的地址所留的空隙剛好填入所要填的內容。

注意:0xdeadbeef是什麼意思?
類似這樣的值很多,像0xabababab,它們的作用就是爲內存做標記,插在那裏,就表示從這個位置往後的一段有特殊作用的內存,而這個位置往前,禁止訪問。


看了上面轉載的博文,算是有豁然開朗了,下面再轉一篇博文,是對這條命令進行的驗證,算是對上面自己理解的一個實踐。

轉自:http://www.liweifan.com/2012/01/11/assembly-embedded-system-balignl-arm/

  先將部分代碼貼出,來自於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 <[email protected]>  
  5.  *  Copyright (c) 2002  Alex Z黳ke <[email protected]>  
  6.  *  Copyright (c) 2002  Gary Jennejohn <[email protected]>  
  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 <asm-offsets.h>   
  28. #include <common.h>   
  29. #include <config.h>   
  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 <[email protected]>  
  5.  *  Copyright (c) 2002  Alex Z黳ke <[email protected]>  
  6.  *  Copyright (c) 2002  Gary Jennejohn <[email protected]>  
  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 <asm-offsets.h>   
  28. #include <common.h>   
  29. #include <config.h>   
  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 <start_code>   
  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 <start_code>:   
  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 <start_code>   
  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 <start_code>:   
  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一樣,其實是作者故意搞笑,無任何實際意義(如果真是這樣,我會臉紅的。。。)。

你怎樣認爲?想通了的朋友麻煩留言告知,謝謝。

轉了兩片比較好的博文,放到自己的空間裏,算是做備份吧(萬一原作者的博客廢了......我太邪惡了)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章