Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
(2)寄存器操作數(shù),它表示某個寄存器的內(nèi)容,用符號Ea來表示任意寄存器a,用引用R[Ea]來表示它的值,這是將寄存器集合看成一個數(shù)組R,用寄存器表示符作為索引。
(3)操作數(shù)是存儲器引用,它會根據(jù)計(jì)算出來的地址(通常稱為有效地址)訪問某個存儲器位置。用符號Mb[Addr]表示對存儲在存儲器中從地址Addr開始的b字節(jié)值的引用。通??梢允÷韵聵?biāo)b。
略過,具體參考《深入理解計(jì)算機(jī)系統(tǒng)》
2. 最簡C代碼分析
為簡化問題,來分析一下最簡的c代碼生成的匯編代碼:
# vi test1.c
int main()
{
return 0;
}
編譯該程序,產(chǎn)生二進(jìn)制文件:
# gcc test1.c -o test1
# file test1
test1: ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped
test1是一個ELF格式32位小端(Little Endian)的可執(zhí)行文件,動態(tài)鏈接并且符號表沒有去除。
這正是Unix/Linux平臺典型的可執(zhí)行文件格式。
用mdb反匯編可以觀察生成的匯編代碼:
# mdb test1
Loading modules: [ libc.so.1 ]
> main::dis ; 反匯編main函數(shù),mdb的命令一般格式為 <地址>::dis
main: pushl %ebp ; ebp寄存器內(nèi)容壓棧,即保存main函數(shù)的上級調(diào)用函數(shù)的?;刂?/p>
main+1: movl %esp,%ebp ; esp值賦給ebp,設(shè)置main函數(shù)的?;?/p>
main+3: subl ,%esp
main+6: andl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+9: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+0xe: subl %eax,%esp
main+0x10: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+0x15: leave ; 將ebp值賦給esp,pop先前棧內(nèi)的上級函數(shù)棧的基地址給ebp,恢復(fù)原棧基址
main+0x16: ret ; main函數(shù)返回,回到上級調(diào)用
>
注:這里得到的匯編語言語法格式與Intel的手冊有很大不同,Unix/Linux采用AT&T匯編格式作為匯編語言的語法格式
如果想了解AT&T匯編可以參考文章:Linux AT&T 匯編語言開發(fā)指南
問題:誰調(diào)用了 main函數(shù)?
在C語言的層面來看,main函數(shù)是一個程序的起始入口點(diǎn),而實(shí)際上,ELF可執(zhí)行文件的入口點(diǎn)并不是main而是_start。
mdb也可以反匯編_start:
> _start::dis ;從_start 的地址開始反匯編
_start: pushl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+2: pushl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+4: movl %esp,%ebp
_start+6: pushl %edx
_start+7: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0xc: testl %eax,%eax
_start+0xe: je +0xf <_start+0x1d>
_start+0x10: pushl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0x15: call -0x75 <atexit>
_start+0x1a: addl ,%esp
_start+0x1d: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0x22: testl %eax,%eax
_start+0x24: je +7 <_start+0x2b>
_start+0x26: call -0x86 <atexit>
_start+0x2b: pushl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0x30: call -0x90 <atexit>
_start+0x35: movl +8(%ebp),%eax
_start+0x38: leal +0x10(%ebp,%eax,4),%edx
_start+0x3c: movl %edx,0x8060804
_start+0x42: andl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0x45: subl ,%esp
_start+0x48: pushl %edx
_start+0x49: leal +0xc(%ebp),%edx
_start+0x4c: pushl %edx
_start+0x4d: pushl %eax
_start+0x4e: call +0x152 <_init>
_start+0x53: call -0xa3 <__fpstart>
_start+0x58: call +0xfb <main> ;在這里調(diào)用了main函數(shù)
_start+0x5d: addl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0x60: pushl %eax
_start+0x61: call -0xa1 <exit>
_start+0x66: pushl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
Linux下GDB反匯編和調(diào)試
_start+0x6d: lcall ,
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
_start+0x74: hlt
>
問題:為什么用EAX寄存器保存函數(shù)返回值?
實(shí)際上IA32并沒有規(guī)定用哪個寄存器來保存返回值。但如果反匯編Solaris/Linux的二進(jìn)制文件,就會發(fā)現(xiàn),都用EAX保存函數(shù)返回值。
這不是偶然現(xiàn)象,是操作系統(tǒng)的ABI(Application Binary Interface)來決定的。
Solaris/Linux操作系統(tǒng)的ABI就是Sytem V ABI。
概念:SFP (Stack Frame Pointer) ??蚣苤羔?/p>
正確理解SFP必須了解:
IA32 的棧的概念
CPU 中32位寄存器ESP/EBP的作用
PUSH/POP 指令是如何影響棧的
CALL/RET/LEAVE 等指令是如何影響棧的
如我們所知:
1)IA32的棧是用來存放臨時數(shù)據(jù),而且是LIFO,即后進(jìn)先出的。棧的增長方向是從高地址向低地址增長,按字節(jié)為單位編址。
2) EBP是?;返闹羔槪肋h(yuǎn)指向棧底(高地址),ESP是棧指針,永遠(yuǎn)指向棧頂(低地址)。
3) PUSH一個long型數(shù)據(jù)時,以字節(jié)為單位將數(shù)據(jù)壓入棧,從高到低按字節(jié)依次將數(shù)據(jù)存入ESP-1、ESP-2、ESP-3、ESP-4的地址單元。
4) POP一個long型數(shù)據(jù),過程與PUSH相反,依次將ESP-4、ESP-3、ESP-2、ESP-1從棧內(nèi)彈出,放入一個32位寄存器。
5) CALL指令用來調(diào)用一個函數(shù)或過程,此時,下一條指令地址會被壓入堆棧,以備返回時能恢復(fù)執(zhí)行下條指令。
6) RET指令用來從一個函數(shù)或過程返回,之前CALL保存的下條指令地址會從棧內(nèi)彈出到EIP寄存器中,程序轉(zhuǎn)到CALL之前下條指令處執(zhí)行
7) ENTER是建立當(dāng)前函數(shù)的??蚣埽聪喈?dāng)于以下兩條指令:
pushl %ebp
movl %esp,%ebp
8) LEAVE是釋放當(dāng)前函數(shù)或者過程的??蚣埽聪喈?dāng)于以下兩條指令:
movl ebp esp
popl ebp
如果反匯編一個函數(shù),很多時候會在函數(shù)進(jìn)入和返回處,發(fā)現(xiàn)有類似如下形式的匯編語句:
pushl %ebp ; ebp寄存器內(nèi)容壓棧,即保存main函數(shù)的上級調(diào)用函數(shù)的?;刂?/p>
movl %esp,%ebp ; esp值賦給ebp,設(shè)置 main函數(shù)的?;?/p>
........... ; 以上兩條指令相當(dāng)于 enter 0,0
...........
leave ; 將ebp值賦給esp,pop先前棧內(nèi)的上級函數(shù)棧的基地址給ebp,恢復(fù)原?;?/p>
ret ; main函數(shù)返回,回到上級調(diào)用
這些語句就是用來創(chuàng)建和釋放一個函數(shù)或者過程的??蚣艿?。
原來編譯器會自動在函數(shù)入口和出口處插入創(chuàng)建和釋放??蚣艿恼Z句。
函數(shù)被調(diào)用時:
1) EIP/EBP成為新函數(shù)棧的邊界
函數(shù)被調(diào)用時,返回時的EIP首先被壓入堆棧;創(chuàng)建棧框架時,上級函數(shù)棧的EBP被壓入堆棧,與EIP一道行成新函數(shù)??蚣艿倪吔?/p>
2) EBP成為棧框架指針SFP,用來指示新函數(shù)棧的邊界
??蚣芙⒑?,EBP指向的棧的內(nèi)容就是上一級函數(shù)棧的EBP,可以想象,通過EBP就可以把層層調(diào)用函數(shù)的棧都回朔遍歷一遍,調(diào)試器就是利用這個特性實(shí)現(xiàn) backtrace功能的
3) ESP總是作為棧指針指向棧頂,用來分配??臻g
棧分配空間給函數(shù)局部變量時的語句通常就是給ESP減去一個常數(shù)值,例如,分配一個整型數(shù)據(jù)就是 ESP-4
4) 函數(shù)的參數(shù)傳遞和局部變量訪問可以通過SFP即EBP來實(shí)現(xiàn)
由于??蚣苤羔樣肋h(yuǎn)指向當(dāng)前函數(shù)的?;刂?,參數(shù)和局部變量訪問通常為如下形式:
+8+xx(%ebp) ; 函數(shù)入口參數(shù)的的訪問
-xx(%ebp) ; 函數(shù)局部變量訪問
假如函數(shù)A調(diào)用函數(shù)B,函數(shù)B調(diào)用函數(shù)C ,則函數(shù)??蚣芗罢{(diào)用關(guān)系如下圖所示:
+-------------------------+----> 高地址
| EIP (上級函數(shù)返回地址) |
+-------------------------+
+--> | EBP (上級函數(shù)的EBP) | --+ <------當(dāng)前函數(shù)A的EBP (即SFP框架指針)
| +-------------------------+ +-->偏移量A
| | Local Variables | |
| | .......... | --+ <------ESP指向函數(shù)A新分配的局部變量,局部變量可以通過A的ebp-偏移量A訪問
| f +-------------------------+
| r | Arg n(函數(shù)B的第n個參數(shù)) |
| a +-------------------------+
| m | Arg .(函數(shù)B的第.個參數(shù)) |
| e +-------------------------+
| | Arg 1(函數(shù)B的第1個參數(shù)) |
| o +-------------------------+
| f | Arg 0(函數(shù)B的第0個參數(shù)) | --+ <------ B函數(shù)的參數(shù)可以由B的ebp+偏移量B訪問
| +-------------------------+ +--> 偏移量B
| A | EIP (A函數(shù)的返回地址) | |
| +-------------------------+ --+
+--- | EBP (A函數(shù)的EBP) |<--+ <------ 當(dāng)前函數(shù)B的EBP (即SFP框架指針)
+-------------------------+ |
| Local Variables | |
| .......... | | <------ ESP指向函數(shù)B新分配的局部變量
+-------------------------+ |
| Arg n(函數(shù)C的第n個參數(shù)) | |
+-------------------------+ |
| Arg .(函數(shù)C的第.個參數(shù)) | |
+-------------------------+ +--> frame of B
| Arg 1(函數(shù)C的第1個參數(shù)) | |
+-------------------------+ |
| Arg 0(函數(shù)C的第0個參數(shù)) | |
+-------------------------+ |
| EIP (B函數(shù)的返回地址) | |
+-------------------------+ |
+--> | EBP (B函數(shù)的EBP) | --+ <------ 當(dāng)前函數(shù)C的EBP (即SFP框架指針)
| +-------------------------+
| | Local Variables |
| | .......... | <------ ESP指向函數(shù)C新分配的局部變量
| +-------------------------+----> 低地址
frame of C
圖 1-1
再分析test1反匯編結(jié)果中剩余部分語句的含義:
# mdb test1
Loading modules: [ libc.so.1 ]
> main::dis ; 反匯編main函數(shù)
main: pushl %ebp
main+1: movl %esp,%ebp ; 創(chuàng)建Stack Frame(棧框架)
main+3: subl ,%esp ; 通過ESP-8來分配8字節(jié)堆??臻g
main+6: andl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+9: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+0xe: subl %eax,%esp ; 無意義
main+0x10: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+0x15: leave ; 撤銷Stack Frame(棧框架)
main+0x16: ret ; main 函數(shù)返回
>
以下兩句似乎是沒有意義的,果真是這樣嗎?
movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
subl %eax,%esp
用gcc的O2級優(yōu)化來重新編譯test1.c:
# gcc -O2 test1.c -o test1
# mdb test1
> main::dis
main: pushl %ebp
main+1: movl %esp,%ebp
main+3: subl ,%esp
main+6: andl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+9: xorl %eax,%eax ; 設(shè)置main返回值,使用xorl異或指令來使eax為0
main+0xb: leave
main+0xc: ret
>
新的反匯編結(jié)果比最初的結(jié)果要簡潔一些,果然之前被認(rèn)為無用的語句被優(yōu)化掉了,進(jìn)一步驗(yàn)證了之前的猜測。
提示:編譯器產(chǎn)生的某些語句可能在程序?qū)嶋H語義上沒有用處,可以用優(yōu)化選項(xiàng)去掉這些語句。
問題:為什么用xorl來設(shè)置eax的值?
注意到優(yōu)化后的代碼中,eax返回值的設(shè)置由 movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
概念:Stack aligned 棧對齊
那么,以下語句到底是和作用呢?
subl ,%esp
andl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
表面來看,這條語句最直接的后果是使ESP的地址后4位為0,即16字節(jié)對齊,那么為什么這么做呢?
原來,IA32 系列CPU的一些指令分別在4、8、16字節(jié)對齊時會有更快的運(yùn)行速度,因此gcc編譯器為提高生成代碼在IA32上的運(yùn)行速度,默認(rèn)對產(chǎn)生的代碼進(jìn)行16字節(jié)對齊
andl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
這里假設(shè)在進(jìn)入main函數(shù)之前,棧是16字節(jié)對齊的話,那么,進(jìn)入main函數(shù)后,EIP和EBP被壓入堆棧后,棧地址最末4位二進(jìn)制位必定是1000,esp -8則恰好使后4位地址二進(jìn)制位為0000。看來,這也是為保證棧16字節(jié)對齊的。
如果查一下gcc的手冊,就會發(fā)現(xiàn)關(guān)于棧對齊的參數(shù)設(shè)置:
-mpreferred-stack-boundary=n ; 希望棧按照2的n次的字節(jié)邊界對齊, n的取值范圍是2-12
默認(rèn)情況下,n是等于4的,也就是說,默認(rèn)情況下,gcc是16字節(jié)對齊,以適應(yīng)IA32大多數(shù)指令的要求。
讓我們利用-mpreferred-stack-boundary=2來去除棧對齊指令:
# gcc -mpreferred-stack-boundary=2 test1.c -o test1
> main::dis
main: pushl %ebp
main+1: movl %esp,%ebp
main+3: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+8: leave
main+9: ret
>
可以看到,棧對齊指令沒有了,因?yàn)?,IA32的棧本身就是4字節(jié)對齊的,不需要用額外指令進(jìn)行對齊。
那么,??蚣苤羔楽FP是不是必須的呢?
# gcc -mpreferred-stack-boundary=2 -fomit-frame-pointer test1.c -o test
> main::dis
main: movl
Linux下GDB反匯編和調(diào)試
Linux下的匯編與Windows匯編最大的不同就是第一個操作數(shù)是原操作數(shù),第二個是目的操作數(shù),而Windows下卻是相反。接下來是小編為大家收集的LINUX下GDB反匯編和調(diào)試,希望能幫到大家。
LINUX下GDB反匯編和調(diào)試
1、 基本操作指令
簡單的操作數(shù)類型說明,一般有三種,
(1)立即數(shù)操作數(shù),也就是常數(shù)值。立即數(shù)的書寫方式是“$”后面跟一個整數(shù),比如
main+5: ret
>
由此可知,-fomit-frame-pointer 可以去除SFP。
問題:去除SFP后有什么缺點(diǎn)呢?
1)增加調(diào)式難度
由于SFP在調(diào)試器backtrace的指令中被使用到,因此沒有SFP該調(diào)試指令就無法使用。
2)降低匯編代碼可讀性
函數(shù)參數(shù)和局部變量的訪問,在沒有ebp的情況下,都只能通過+xx(esp)的方式訪問,而很難區(qū)分兩種方式,降低了程序的可讀性。
問題:去除SFP有什么優(yōu)點(diǎn)呢?
1)節(jié)省??臻g
2)減少建立和撤銷??蚣艿闹噶詈?,簡化了代碼
3)使ebp空閑出來,使之作為通用寄存器使用,增加通用寄存器的數(shù)量
4)以上3點(diǎn)使得程序運(yùn)行速度更快
概念:Calling Convention 調(diào)用約定和 ABI (Application Binary Interface) 應(yīng)用程序二進(jìn)制接口
函數(shù)如何找到它的參數(shù)?
函數(shù)如何返回結(jié)果?
函數(shù)在哪里存放局部變量?
那一個硬件寄存器是起始空間?
那一個硬件寄存器必須預(yù)先保留?
Calling Convention 調(diào)用約定對以上問題作出了規(guī)定。Calling Convention也是ABI的一部分。
因此,遵守相同ABI規(guī)范的操作系統(tǒng),使其相互間實(shí)現(xiàn)二進(jìn)制代碼的互操作成為了可能。
例如:由于Solaris、Linux都遵守System V的ABI,Solaris 10就提供了直接運(yùn)行Linux二進(jìn)制程序的功能。
詳見文章:關(guān)注: Solaris 10的10大新變化
3. 小結(jié)
本文通過最簡的C程序,引入以下概念:
SFP 棧框架指針
Stack aligned 棧對齊
Calling Convention 調(diào)用約定 和 ABI (Application Binary Interface) 應(yīng)用程序二進(jìn)制接口
今后,將通過進(jìn)一步的實(shí)驗(yàn),來深入了解這些概念。通過掌握這些概念,使在匯編級調(diào)試程序產(chǎn)生的core dump、掌握C語言高級調(diào)試技巧成為了可能。
看了“LINUX下GDB反匯編和調(diào)試”還想看:
2.Ubuntu如何使用命令調(diào)節(jié)屏幕亮度