一燈大師:一點就是好幾年

 

1.幾條彙編指令

  1. LDR :(load)讀內存

      LDR   R0 , [R1]                       // 假設R1的值是x,讀取地址x上的數據,保存到R0中。

2. STR :(store)寫內存

      STR   R0 , [R1]                      // 假設R1的值是x,把R0的值寫到地址x上。

3. B:跳轉

      halt:  b  halt                     // 此例用於實現死循環功能,避免程序跑飛。

4. MOV :(move)(移動) 賦值

      LDR   R0 , R1                        // 把R1的值賦給R0,R0 = R1。

      LDR   R0 , #0x01                   // 把立即數的值賦給R0,R0 = 0x01。

5. LDR :僞指令用法

      LDR   R0 ,= 0x12345678      // 把 0x12345678 這個值賦給R0,R0 = 0x12345678。

      僞指令會被拆分爲幾條真正的arm指令執行,引入僞指令是因爲使用MOV指令賦值時真正值得小於寄存位寬。

 

2.彙編代碼


.text
.global _start 
_start:
    
    /*配置GPF4爲輸出引腳*/
    /*把0x100寫到地址0x56000050*/
	LDR r0,=0x56000050
	LDR r1,=0x100    /* mov R0,#0X100 */
	str r1,[r0]

    /*設置GPF4爲輸出高電平*/
    /*把0寫到地址0x56000054*/
	LDR r0,=0x56000054
	LDR r1,=0x00    /* mov R0,#0X00 */
	str r1,[r0]
    
    /* 死循環 */
mainloop:
	b mainloop

.text和.global 是arm-gcc編譯器的關鍵詞。

.text 段保存代碼,是隻讀和【可執行】的,後面那些指令都屬於【.text段。
.global 告訴編譯器後續跟的是一個全局可見的名字【可能是變量,也可以是函數名】;
在本例中,_start是一個函數的起始地址,也是編譯、鏈接後程序的【起始地址】。由於程序是通過加載器來加載的,必須要找到 _start 名字的函數,因此_start必須定義成全局的,以便存在於編譯後的全局符合表中,供其它程序【如加載器】尋找到。

 

3.Makefile

led.bin:led.s
	arm-linux-gcc -c -o led_on.o led_on.S
	arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
	arm-linux-objcopy -O binary -S led_on.elf led_on.bin
         /* 把可執行文件反彙編,此處用於分析代碼 */
        arm-linux-objdump -D led_on.elf > led_on.dis
 
clean:
	rm -f *.bin  *.o *.elf

 

4.反彙編結果

可見其中的地址、機器碼和彙編碼。

 

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