linux反彙編除錯
int triangle( int width, int height)
{
int arr{0,1,2,3,4};
int area;
area = width * height /2;
return (area);
}
void main()
{
triangle(5,4);
}
~~~~~gdb反彙編程式碼
$ gdb example
(gdb) disass main
Dump of assembler code for function main:
0x080483f6 <+0>: push %ebp
0x080483f7 <+1>: mov %esp,%ebp
0x080483f9 <+3>: sub $0x8,%esp
目標碼格式列表
--demangle
-C 將底層的符號名解碼成使用者級名字,除了去掉所有開頭的下劃線之外,還使得C++函式名以可理解的方式顯示出來。
—disassemble或者-d 反彙編可執行段
.—dissassemble-all或者-D 反彙編所有段
--debugging顯示除錯資訊。企圖解析儲存在檔案中的除錯資訊並以C語言的語法顯示出來。僅僅支援某些型別的除錯資訊。
--prefix-addresses反彙編的時候,顯示每一行的完整地址。這是一種比較老的反彙編格式。顯示效果並不理想,但可能會用到其中的某些顯示,自己可以對比。
--disassemble-zeroes 一般反彙編
-EB -EL 指定位元組序 --endian={big|little}這個選項將影響反彙編出來的指令。little-endian就是我們當年在dos下玩彙編的時候常說的高位在高地址,x86都是這種。
--file-headers或者 -f 顯示objfile中每個檔案的整體頭部摘要資訊。
--section-headers;--headers 或者-h 顯示目標檔案各個section的頭部摘要資訊。
--info或者-i 顯示對於 -b 或者 -m 選項可用的架構和目標格式列表。顯示支援的目標檔案格式和CPU架構
--section=name或者-j name 僅僅顯示指定section的資訊
--line-numbers或者-l 用檔案名和行號標註相應的目的碼,僅僅和-d、-D或者-r一起使用使用-ld和使用-d的區別不是很大,在原始碼級除錯的時候有用,要求編譯時使用了-g之 類的除錯編譯選項。
--architecture=machine 或者-m machine指定反彙編目標檔案時使用的架構,當待反彙編檔案本身沒有描述架構資訊的時候(比如S-records),這個選項很有用。可以用-i選項列出這裡能夠指定的架構
--reloc或者-r 顯示檔案的重定位入口。如果和-d或者-D一起使用,重定位部分以反彙編後的格式顯示出來。
--dynamic-reloc -R 顯示檔案的動態重定位入口,僅僅對於動態目標檔案有意義,比如某些共享庫。
--full-contents -s 顯示指定section的完整內容。
objdump --section=.text -s inet.o | more
--source -S 儘可能反彙編出原始碼,尤其當編譯的時候指定了-g這種除錯引數時,效果比較明顯。隱含了-d引數。
--show-raw-insn反彙編的時候,顯示每條彙編指令對應的機器碼,除非指定了--prefix-addresses,這將是預設選項。
--no-show-raw-insn
-S 儘可能反彙編出原始碼,尤其當編譯的時候指定了-g這種除錯引數時,
效果比較明顯。隱含了-d引數。
-l 用檔名和行號標註相應的目的碼,僅僅和-d、-D或者-r一起使用
使用-ld和使用-d的區別不是很大,在原始碼級除錯的時候有用,要求
編譯時使用了-g之類的除錯編譯選項。
-j name 僅僅顯示指定section的資訊
如何使用linux下objdump命令對任意一個二進位制檔案進行反彙編?
可以使用如下命令:
objdump -D -b binary -m i386 a.bin
-D表示對全部檔案進行反彙編,-b表示二進位制,-m表示指令集架構,a.bin就是我們要反彙編的二進位制檔案
objdump -m可以檢視更多支援的指令集架構,如i386:x86-64,i8086等
另外上面的所有objdump命令的引數同樣適用於arm-linux-objdump。
同時我們也可以指定big-endian或little-endian(-EB或-EL),我們可以指定從某一個位置開始反彙編等。
objdump命令是Linux下的反彙編目標檔案或者可執行檔案的命令,它還有其他作用,下面以ELF格式可執行檔案test為例詳細介紹:
objdump -f test 顯示test的檔案頭資訊
objdump -d test 反彙編test中的需要執行指令的那些section
objdump -D test 與-d類似,但反彙編test中的所有section
objdump -h test 顯示test的Section Header資訊
objdump -x test 顯示test的全部Header資訊
objdump -s test 除了顯示test的全部Header資訊,還顯示他們對應的十六進位制檔案程式碼
使用arm-linux 工具鏈裡面的arm-linux-objdump 就能反彙編
cd到bin檔案所在的目錄, 在命令列下輸入:
arm-linux-objdump -D -b binary -m arm xxx.bin > xxx.asm
引數:
-D 反編譯所有程式碼
-m 主機型別, arm
-b 檔案格式, binary
對於ELF格式的檔案只要一個-D引數即可
就可以把xxx.bin反彙編到xxx.asm檔案
Arm-linux-objdump –D elf_file > dis_file 或者
Arm-linux-objdump –D –b binary –m arm bin_file > dis_file
記憶體地址反向查找出問題的程式:
<1>.通過彙編去查詢.
Linux 平臺:
1. 在程式訊號處理部分, 加入程式碼捕捉引起錯誤點的地址,簡單來說,方法就是在註冊自己的訊號處理函式,在這個函式中加入獲取記憶體錯誤地址的程式碼,並把結果寫到一個日誌檔案中。
2. 編譯 DEBUG 版本 程式 (compile 時用 -g , 生成可執行檔案後不用 strip 去掉symbol 資訊)
3. 在程式出問題時, 檢視日誌記錄, 得到錯誤點的地址.
4. 用objdump -S 匯出Debug 版本的彙編程式碼, 查詢錯誤地址, 則得出那條語句出錯.
windows 下c 語言除錯
1. release 版編譯/連線選項, 把"generate debug info/" 打鉤選擇
2.dumpbin /DISASM /OUT:dump.out.txt.1 prep.exe 可反編譯exe檔案
3.得到程式非法地址(可從管理工具-》事件檢視器裡得到),與彙編比較。
對目標檔案:***.o:
arm-none-Linux-gnueabi-objdump -D ./kernel/sched.o > sched.S
對可執行檔案***.bin:
arm-linux-objdump -D -b binary -m arm xxx.bin > xxx.asm
為了執行ARM彙編程式碼,需要使用交叉編譯器arm-linux-gcc對ARM彙編程式碼進行編譯。下載交叉編譯器安裝完畢後,對ARM彙編程式碼進行編譯。
arm-linux-gcc main.s -o main -nostdlib
編譯選項“-nostdlib”表示不使用任何執行時庫檔案,編譯生成的可執行檔案main只能在ARM體系結構的系統上執行。
通常認為,產生異常的地址是lr暫存器的值,從上面的異常資訊可以看到[lr]的值是c01a4e30。
接下來,我們可以通過核心映象檔案反彙編來找到這個地址。核心編譯完成後,會在核心程式碼根目錄下生成vmlinux檔案,我們可以通過以下命令來反彙編:
arm-none-eabi-objdump -Dz -S vmlinux >linux.dump
值得注意的是,arm-none-eabi-objdump的引數-S表示儘可能的把原來的程式碼和反彙編出來的程式碼一起呈現出來,-S引數需要結合 arm-linux-gcc編譯引數-g,才能達到反彙編時同時輸出原來的程式碼。所以,我在linux核心程式碼根目錄的Makefile中增加-g編譯參 數:
KBUILD_CFLAGS := -g -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common \
-Werror-implicit-function-declaration \
-Wno-format-security \
-fno-delete-null-pointer-checks
修改Makefile後,重新編譯核心,在根目錄中生成的vmlinux檔案就會包含了原來的程式碼資訊,因此,該檔案的大小也比原來大一倍!
最後執行“arm-none-eabi-objdump -Dz-S vmlinux >linux.dump”,由於加入了-g編譯引數,執行這個反彙編命令需要很長時間(本人在虛擬機器上執行,花了近6個小時!),反彙編出來的linux.dump檔案也比原來的44MB增大到驚人的503MB。
(博主加:這裡有一點要注意,如果是ko模組檔案,反彙編時如果想看到ko檔案的某函式反彙編程式碼,該函式不能加static關鍵字修飾,而且module_init修飾的入口函式,其名字即為module_init)
接下來可以用UltraEdit開啟linux.dump檔案,查詢“c01a4e30”字串。
最後定位到的資訊是:
==================================================================================================================
/*
* tasklet handling tty stuff outside the interrupt handler.
*/
static void atmel_tasklet_func(unsigned long data)
{
c01a4e20: e92d45f0 push {r4, r5, r6, r7, r8, sl, lr}
c01a4e24: e24dd01c sub sp, sp, #28 ; 0x1c
c01a4e28: e1a04000 mov r4, r0
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
if (atmel_use_pdc_tx(port))
atmel_tx_pdc(port);
else if (atmel_use_dma_tx(port))
c01a4e2c: ebfffda1 bl c01a44b8 <atmel_use_dma_tx>
c01a4e30: e3500000 cmp r0, #0 ; 0x0
c01a4e34: e5943034 ldr r3, [r4, #52]
c01a4e38: 0a00007b beq c01a502c <atmel_tasklet_func+0x20c>
==================================================================================================================
可以看出來,異常的產生位於atmel_tasklet_func函式的 else if (atmel_use_dma_tx(port))一行。
估計atmel_use_dma_tx(port)的“port”引數為空指標所致!