tft每日頭條

 > 圖文

 > 彙編中out指令用法

彙編中out指令用法

圖文 更新时间:2024-07-06 01:23:12

彙編中out指令用法?@[TOC]順序執行:指令一條一條按照順序往下執行,比如變量的定義和賦值都是按照順序執行的 跳轉執行:當指令執行到當前位置後跳轉到其他位置執行比如,在主函數中調用其他函數就是典型的跳轉執行其中跳轉又分為絕對跳轉和相對跳轉 絕對跳轉:直接跳轉到一個固定的,實實在在的地址 相對跳轉:相對于當前pc值的一個跳轉,跳轉到pc offset的地址,今天小編就來說說關于彙編中out指令用法?下面更多詳細答案一起來看看吧!

彙編中out指令用法(詳解彙編語言B和LDR指令與相對跳轉和絕對跳轉的關系)1

彙編中out指令用法

@[TOC]

為什麼要有相對跳轉和絕對跳轉?

順序執行:指令一條一條按照順序往下執行,比如變量的定義和賦值都是按照順序執行的。 跳轉執行:當指令執行到當前位置後跳轉到其他位置執行。比如,在主函數中調用其他函數就是典型的跳轉執行。其中跳轉又分為絕對跳轉和相對跳轉。 絕對跳轉:直接跳轉到一個固定的,實實在在的地址。 相對跳轉:相對于當前pc值的一個跳轉,跳轉到pc offset的地址。

  我們清楚了上面幾個概念,就知道了為什麼要有相對跳轉和絕對跳轉。各種指令相互配合才能使得cpu有更高的處理效率。正是因為有了順序和跳轉指令,我們的cpu才可以處理各種複雜的計算。

在程序中隻有相對跳轉/絕對跳轉是否可以?

  答案肯定是不可以的。我們以一個例子具體分析。 指令編号 | 指令功能 -------- | -----| ----- 指令1 | 順序執行 指令2 | 順序執行 指令3 |相對跳轉到指令5 指令4 | 順序執行 指令5 | 順序執行 指令6 | 絕對跳轉到指令8 指令7 | 順序執行 指令8 | 順序執行

  假設程序被放在0x00000000位置開始執行,編譯鍊接後的結果為:

指令地址 | 指令編号 | 指令功能 | 下條指令地址 -------- | -----| -----| -----| ----- 0x00000000 | 順序執行| 順序執行| 當前地址 4 0x00000004 | 順序執行| 順序執行| 當前地址 4 0x00000008 |跳轉到指令5|跳轉到指令5|當前地址 8 0x0000000C | 順序執行 | 順序執行 | 當前地址 4 0x00000010 | 順序執行 | 順序執行 | 當前地址 4 0x00000014 | 跳轉到指令8| 跳轉到指令8| 0xC000001C 0x00000018 | 順序執行| 順序執行|當前地址 4 0x0000001C | 順序執行 | 順序執行 | 當前地址 4

  當這段程序被放在0xC000000空間時,開始執行指令1,然後采用相對尋址的方法就可以運行到指令6,在指令6執行時也可以使用絕對尋址的方法從0xC0000014正确跳轉到指令8所在的0xC00001C位置,這段代碼運行正常。

  當這段代碼被放在0x00000000空間時,開始執行指令1,然後采用相對尋址的方法就可以運行到指令6,但在指令6執行時使用絕對尋址的方法從0x0000014跳轉到了0xC000001C,但0xC000001C空間沒有代碼,這樣程序就跑飛了。

  因此,當編譯地址(加載地址)和運行地址相同時,絕對跳轉和相對跳轉都可以正确執行。比如,程序在NORFLASH存儲時。但是,當編譯地址(加載地址)和運行地址不相同時,相對跳轉都就會出現問題。比如,代碼存儲在NANDFLASH,由于NANDFLASH并不能運行代碼,所以需要重定位代碼到内部的SRAM。關于NANDFLASH和NORFLASH可以看這篇文章S3C2440從NAND Flash啟動和NOR FLASH啟動的問題 。

B(BL)和LDR指令具體怎麼執行的?

  我們以下圖中的這句跳轉代碼分析下指令具體的執行過程。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif

  上述代碼對應的反彙編代碼如下:

33f000ac: eb000017 bl 33f00110 <cpu_init_crit>

33f00110 <cpu_init_crit>: 33f00110: e3a00000 mov r0, #0 ; 0x0 33f00114: ee070f17 mcr 15, 0, r0, cr7, cr7, {0}

  當指令執行到33f000ac時,對應的機器碼為eb000017(1110 1011 0000 0000 0000 0000 0001 0111‬),其中[31,28]高四位為條件碼,1110表示無條件執行。[25,27]位保留區域,24位表示是否帶有返回值,1表示帶有返回值,也就是BL指令。[23,0]為指令的操作數,0000 0000 0000 0000 0001 0111。 按照如下計算方式:

  1、将指令中24位帶符号的補碼立即數擴展為32位(擴展其符号位)原數變成 0000 0000 0000 0000 0000 0000 0001 0111。

  2、将此數左移兩位0000 0000 0000 0000 0000 0010 1000 0000 變成 0000 0000 0000 0000 0000 0000 0101 1100 = 0x0000005c

   3、将得到的值加到PC寄存器中得到目标地址,由于ARM為3級流水線,此時的 pc = 33f000ac 8 = 33F000B4,pc = 33F000B4 0x0000005c = 33F00110‬與圖中的cpu_init_crit的地址相等。

   在算的過程中我們使用的始終是PC的值,假設程序在 0 地址處執行,那麼計算方法一樣,pc 的值變了計算出來的結果也随之改變。所以 BL 的跳轉時與位置無關的。

  下圖為B(BL)指令的格式   28~31bts(cond)是條件碼,就是表明這條語句裡是否有大于、等于、非零等的條件判斷,這4bts共有16種狀态,分别為:   下圖為LDR指令的格式   我們以下圖中的第一句話作為例子分析下

ldr pc,=call_board_init_f

對應的反彙編代碼如下:

33f000d0: e59ff324 ldr pc, [pc, #804] ; 33f003fc <fiq 0x5c>

33f003fc: 33f000d4 .word 0x33f000d4 ........ 33f000d4 <call_board_init_f>: 33f000d4: e3a00000 mov r0, #0 ; 0x0

   ldr pc, [pc, #804]這條指令為僞指令,編譯的時候會将call_board_init_f的鍊接地址存入一個固定的地址(鍊接時确定的),對于本條指令這個地址就是33f000d4 。上面的反彙編出來的 ldr pc,=call_board_init_f就變成了ldr pc, [pc, #804],由于ARM使用了流水線的原因,所以在執行 ldr pc. [ pc, #4 ]的時候 pc 不在這句代碼這裡了,而是跑到了 pc 8的地方,這句代碼相當于 pc = *(pc 804 8)=33f000d0 32C=33f003fc ,所以會跳轉到33f003fc 地址取33f000d4 ,而33f000d4 是存在代碼段中的一個常量,并不是計算出來的,不會随程序的位置而改變,所以無論代碼和pc怎麼變 *(pc 804) 的值時不會變的。

  這樣,絕對跳轉中的固定地址就很好理解了,要跳轉地址的值在鍊接時就已經确定了,存在了一塊内存中。而相對跳轉時,反彙編bl 33f00110中的33f00110是根據pc計算出來的,當pc改變時,結果也會改變,所以,稱為相對跳轉,與當前位置無關。

B(BL)和LDR跳轉範圍是如何規定的?

  下圖為B(BL)指令的格式   BL指令的[23,0]bits存放的是要跳轉的相對地址,由于指令所在地址必須是4字節對齊的,因此跳轉的地址最低bits必然是0,因此BL指令[23,0]bits保存的是省略這最低2bts的地址,如果補全了這2bits,BL指令就可以表示26bits的跳轉地址。在這26bits中需要使用1bit表示向前跳還是向後跳,那麼剩下的25bits就可以表示32 MBts的範圍了,225=32M因此,B(BL)指令的跳轉範圍為-32MBytes~ 32MBytes。

  下圖為LDR指令的格式   圖中的LDR的跳轉範圍計算方式和B指令的類似,其中Rn和Address_mode共同構成第二個操作數的内存地址,由Address_mode的9種格式可以直到,Address_mode表示的就是偏移地址的範圍大小,為212=4K。(不理解的可以對比下ldr pc, [pc, #804]和Address_mode的九種格式,很明顯可以看出Address_mode就是當前地址的偏移範圍)

  大家的鼓勵是我繼續創作的動力,如果覺得寫的不錯,歡迎關注,點贊,收藏,轉發,謝謝!

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved