內存地址、機器碼與彙編指令的三角戀關係

雖然機器碼和內存地址領證在一起了,但是倆個人都和彙編指令有着說不清的關係,機器碼的前任是彙編指令,而彙編指令又與內存地址暗地相通,這究竟是道德的淪喪還是人性的扭曲,今天就讓我來領大家細細分解這三者的前世今生!!!

之前我們使用匯編語言編寫了點亮LED程序,.S文件通過FTP傳到Ubuntu中,通過交叉編譯工具生成.bin文件傳回本機,然後通過oflash燒寫進裸機的Nand FLASH,從而點亮LED。
這裏分析一下彙編代碼在此過程中的意義,內存地址、機器碼與彙編指令三者之間的聯繫。

一.原彙編代碼

彙編代碼如下:

.text
.global _start

_start:                   ;程序從這裏開始
	ldr r1, =0X56000050   ;將地址存在r1
	ldr r0, =0X100        ;將值存在r0
	str r0, [r1]          ;將r0的值寫入[]中的地址
	
	ldr r1, =0X56000054	  ;同上
	ldr r0, =0            
	str r0, [r1]          
	
halt:                     ;死循環
	b halt                ;一直跳轉到halt

簡單解釋一下代碼:

要點亮LED,就要將GPF4引腳輸出低電平,通過在GPFCON和GPFDAT寄存器中的對應位寫入值來實現,即對0X56000050地址中寫入0X100,對0X56000054地址中寫入0 。

用到的彙編代碼指令如下:

ldr(load):讀內存命令

str(store):寫內存命令

b:跳轉

mov(move):賦值

二.反彙編代碼

編譯器會將彙編指令轉換成機器碼,而機器碼又存放在內存地址中!!!通過反彙編指令可以得到反彙編文件,裏面有內存地址、機器碼與彙編指令三者的對應關係!!!

機器碼就是.bin文件的十六進制形式,一組機器碼有32位,ARM一次也能夠處理32位的數據,這些知識都是相統一的。

通過將彙編代碼,傳到Linux中可以進行編譯,然後生成.bin文件,當然也可以通過交叉編譯工具的反彙編,生成機器碼和處理後的標準的彙編碼,反彙編文件爲.dis文件,反彙編文件中可以查看內存地址、機器碼與彙編指令三者之間的聯繫:

led_on.elf:     file format elf32-littlearm

Disassembly of section .text:

/*地址*/  /*機器碼*/   /*彙編指令*/
00000000 <_start>:
   0:	e59f1014 	ldr	r1, [pc, #20]	; 1c <.text+0x1c>
   4:	e3a00c01 	mov	r0, #256	; 0x100
   8:	e5810000 	str	r0, [r1]
   c:	e59f100c 	ldr	r1, [pc, #12]	; 20 <.text+0x20>
  10:	e3a00000 	mov	r0, #0	; 0x0
  14:	e5810000 	str	r0, [r1]

00000018 <halt>:
  18:	eafffffe 	b	18 <halt>
  1c:	56000050 	undefined
  20:	56000054 	undefined

在S3C2440中,CPU有各種寄存器,如圖:

在這裏插入圖片描述

左邊是各種寄存器,右邊是寄存器的別名,下面介紹一下比較重要的幾個寄存器:

  • pc(program counter)是程序計數器,當把一個地址寫入pc寄存器中,CPU就會跳轉到這個地址去取指令

  • lr(link register)是返回地址寄存器,當程序執行完一個調用函數時,要跳轉回原來的地址,這個**lr寄存器中存放就是原來的地址,**調用函數執行完畢後,只需要轉到lr中的地址就可以繼續執行程序了。

  • sp(stack point)是棧指針

三.三角戀關係

1.彙編指令與內存地址的關係

下面分析一下彙編指令與內存地址之間的關係

說明一下:爲什麼倆條相鄰指令的內存地址差爲4?

這是因爲內存地址的單位都是Byte,也就是8位(bit),而且ARM是32位的,一次只能夠處理32位指令,也就是4Byte的指令,所以指令的內存存放都是以4Byte爲單位的。

第一條指令,要知道pc中的地址是當前指令的地址+8,因爲ARM執行指令是流水線式的,比如當前執行地址a的指令,已經在對地址a+4的指令進行譯碼,已經在讀取地址a+8的指令,也就是說,當前pc中存放的是a+8的值(第三條指令的地址)。就拿第一個指令來講([x]代表:x地址):
在這裏插入圖片描述

此時pc中的值是第三條指令的地址,也就是8,結合[pc, #20],代表[8+20],也就是28地址,即[0X1C],這條指令代表去0X1C地址讀取內存上的值,放在r1寄存器中,可以看出0X1C地址中存放的值爲:

在這裏插入圖片描述

第二條指令直接將256(0X100)的值放在了r0寄存器中;

第三條指令就是將r0寄存器中的值0X100,寫入地址爲r1(0X56000050)的內存;

接下來三條指令,與前三條原理相同;

後面的halt死循環指令中

在這裏插入圖片描述

b 18就代表程序跳轉到地址爲18的地方去 取指令,執行指令 然鵝這條指令的地址就是18,所以會陷入一個死循環。

此外,可以看出彙編指令在內存中的地址都是連續的,就連彙編指令中的一些數據的內存地址都是緊跟在代碼地址後面的,好奇妙哦。爲什麼要在最後面執行死循環呢?就是防止程序跑完之後,再跑到別的地方去。

在這裏插入圖片描述

2.機器碼與彙編指令

程序編譯後我們得到了.bin文件,這裏又有機器碼,實際上機器碼的內容與.bin文件完全一致,只是碼制不一樣,下面查看一下.bin文件的內容:

在這裏插入圖片描述

bin文件中的,這裏顯示的是按照地址從小到大的排布,所以第一個指令是:e59f1014,與上面的機器碼完全一致。

3.內存地址與機器碼

瞭解了上面的關係後,也不難理解,機器碼就是時間存放在內存地址中的數據!!!

所以,ARM一次能夠處理32位的數據或指令,這指令就是指一條彙編指令,一條彙編指令的內存量就是32位,也就是4Byte,所以彙編指令與機器碼之間必然有者某種關係,時其維持着這種對應關係(一條彙編指令始終對應32位機器碼),也就是說,彙編指令都是有相應的機器碼格式的。

可以去ARM的架構手冊中查找相應彙編指令對應的機器碼格式,比如mov指令:
在這裏插入圖片描述

可以看出,MOV指令確實是32位機器碼的格式,

用上面的代碼來說明一下:

在這裏插入圖片描述

首先搞出機器碼的二進制形式,這樣有對比性:

在這裏插入圖片描述

[15:12]=0,表示Rd寄存器是r0寄存器;

[11:0]這12位代表了mov的參數,就是這12位的內容,這裏與0X100對應,0X100叫做立即數,但我們發現這12位的內容與0X100並不一致呀,爲什麼呢?

實際上這12位數據,拆分爲了高四位[11:8]的rotate數和低八位[7:0]的immed_8數,0X100叫做立即數,他們之間的轉換關係爲:
立即數 = immed_8數 循環右移 (2xroute數)位
相當於0X1循環右移24位,最終還是0X100

所以當了解了這些知識後,會加深我們對於程序運行的理解,從機器碼,到彙編指令,再到C語言,再到其他語言,程序員使用的語言越來越多樣化,可以實現程序的方式越來越多,但最終都是回到了機器碼這一步,因爲機器碼纔是CPU使用的!!!

可以擬人化的說:
機器碼是存放在內存中的,所以機器碼和內存地址是在一起的
機器碼是由彙編指令編譯來的,所以說彙編指令是機器碼前任
彙編指令又與內存地址有着讀寫關係,所以說彙編指令和暗地相通
(滑稽臉)

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