您好,登錄后才能下訂單哦!
本篇內容介紹了“全局變量代碼反匯編有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
一、全局變量代碼反匯編
1. 源文件
「gcd.s」
.text .global _start _start: ldr sp,=0x70000000 /*get stack top pointer*/ b main
b main
/* * main.c * * Created on: 2020-12-12 * Author: pengdan */ int xx=0; int yy=0; int zz=0; int main(void) { xx=0x11; yy=0x22; zz=0x33; while(1); return 0; }
「map.lds」
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x40008000; . = ALIGN(4); .text : { gcd.o(.text) *(.text) } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .bss : { *(.bss) } }
「Makefile」
TARGET=gcd TARGETC=main all: arm-none-linux-gnueabi-gcc -O1 -g -c -o $(TARGETC).o $(TARGETC).c arm-none-linux-gnueabi-gcc -O1 -g -c -o $(TARGET).o $(TARGET).s arm-none-linux-gnueabi-gcc -O1 -g -S -o $(TARGETC).s $(TARGETC).c arm-none-linux-gnueabi-ld $(TARGETC).o $(TARGET).o -Tmap.lds -o $(TARGET).elf arm-none-linux-gnueabi-objcopy -O binary -S $(TARGET).elf $(TARGET).bin arm-none-linux-gnueabi-objdump -D $(TARGET).elf > $(TARGET).dis clean: rm -rf *.o *.elf *.dis *.bin
【交叉編譯工具,自行搜索安裝】
2. 反匯編結果:
圖片由上圖可知,每存儲1個int型全局變量需要「8個字節」,
「literal pool (文字池)占用4個字節」
literal pool的本質就是ARM匯編語言代碼節中的一塊用來存放常量數據而非可執行代碼的內存塊。
使用literal pool (文字池)的原因 當想要在一條指令中使用一個 4字節長度的常量數據(這個數據可以是內存地址,也可以是數字常量)的時候,由于ARM指令集是定長的(ARM指令4字節或Thumb指令2字節),所以就無法把這個4字節的常量數據編碼在一條編譯后的指令中。此時,ARM編譯器(編譯C源程序)/匯編器(編譯匯編程序) 就會在代碼節中分配一塊內存,并把這個4字節的數據常量保存于此,之后,再使用一條指令把這個4 字節的數字常量加載到寄存器中參與運算。 在C源代碼中,文字池的分配是由編譯器在編譯時自行安排的,在進行匯編程序設計時,開發者可以自己進行文字池的分配,如果開發者沒有進行文字池的安排,那么匯編器就會代勞。
「bss段占用4個字節」
每訪問1次全局變量,總共需要3條指令,訪問3次全局變量用了「12條指令」。
14. 通過當前pc值40008018偏移32個字節,找到xx變量的鏈接地址40008038,然后取出其內容40008044存放在r3中,該值就是xx在bss段的地址 15. 通過將立即數0x11即#17賦值給r2 16. 將r2的內容那個寫入到r3對應的指向的內存,即xx標號對應的內存中
二、結構體代碼反匯編
1. 修改main.c如下:
/* 2 * main.c 3 * 4 * Created on: 2020-12-12 5 * Author: 一口Linux 6 */ 7 struct 8 { 9 int xx; 10 int yy; 11 int zz; 12 }peng; 13 int main(void) 14 { 15 peng.xx=0x11; 16 peng.yy=0x22; 17 peng.zz=0x33; 18 19 while(1); 20 return 0; 21 }
2. 反匯編代碼如下:
圖片由上圖可知:
結構體變量peng位于bss段,地址是4000802c
訪問結構體成員也需要利用pc找到結構體變量peng對應的文字池中地址40008028,然后間接找到結構體變量peng地址4000802c
與定義成3個全局變量相比,優點:
結構體的所有成員在literal pool 中共用同一個地址;而每一個全局變量在literal pool 中都有一個地址,「節省了8個字節」。
訪問結構體其他成員的時候,不需要再次裝載基地址,只需要2條指令即可實現賦值;訪問3個成員,總共需要「7條指令」,「節省了5條指令」
所以對于需要大量訪問結構體成員的功能函數,所有訪問結構體成員的操作只需要加載一次基地址即可。
使用結構體就可以大大的節省指令周期,而節省指令周期對于提高cpu的運行效率自然不言而喻。
「所以,重要問題說3遍」
「盡量使用結構體」「盡量使用結構體」「盡量使用結構體」
三、繼續優化
那么指令還能不能更少一點呢?答案是可以的, 修改Makefile如下:
TARGET=gcd TARGETC=main all: arm-none-linux-gnueabi-gcc -Os -lto -g -c -o $(TARGETC).o $(TARGETC).c arm-none-linux-gnueabi-gcc -Os -lto -g -c -o $(TARGET).o $(TARGET).s arm-none-linux-gnueabi-gcc -Os -lto -g -S -o $(TARGETC).s $(TARGETC).c arm-none-linux-gnueabi-ld $(TARGETC).o $(TARGET).o -Tmap.lds -o $(TARGET).elf arm-none-linux-gnueabi-objcopy -O binary -S $(TARGET).elf $(TARGET).bin arm-none-linux-gnueabi-objdump -D $(TARGET).elf > $(TARGET).dis clean: rm -rf *.o *.elf *.dis *.bin
仍然用第二章的main.c文件
執行結果
可以看到代碼已經被優化到5條。
14. 把peng的地址40008024裝載到r3中 15. r0寫入立即數0x11 16. r1寫入立即數0x22 17. r0寫入立即數0x33 18. 通過stm指令將r0、r1、r2的值順序寫入到40008024內存中
“全局變量代碼反匯編有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。