計(jì)算機(jī)系統(tǒng)導(dǎo)論 課件 第6、7章 程序的機(jī)器級(jí)表示、程序的鏈接_第1頁(yè)
計(jì)算機(jī)系統(tǒng)導(dǎo)論 課件 第6、7章 程序的機(jī)器級(jí)表示、程序的鏈接_第2頁(yè)
計(jì)算機(jī)系統(tǒng)導(dǎo)論 課件 第6、7章 程序的機(jī)器級(jí)表示、程序的鏈接_第3頁(yè)
計(jì)算機(jī)系統(tǒng)導(dǎo)論 課件 第6、7章 程序的機(jī)器級(jí)表示、程序的鏈接_第4頁(yè)
計(jì)算機(jī)系統(tǒng)導(dǎo)論 課件 第6、7章 程序的機(jī)器級(jí)表示、程序的鏈接_第5頁(yè)
已閱讀5頁(yè),還剩207頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第六章程序的機(jī)器級(jí)表示

函數(shù)調(diào)用的機(jī)器級(jí)表示

控制類語句的機(jī)器級(jí)表示

復(fù)雜數(shù)據(jù)類型的分配和訪問

越界訪問和緩沖區(qū)溢出程序的轉(zhuǎn)換與機(jī)器級(jí)表示主要教學(xué)目標(biāo)了解高級(jí)語言與匯編語言、匯編語言與機(jī)器語言之間的關(guān)系掌握高級(jí)語言源程序中的語句與機(jī)器級(jí)代碼之間的對(duì)應(yīng)關(guān)系了解復(fù)雜數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)等)的機(jī)器級(jí)實(shí)現(xiàn)理解越界訪問和緩沖區(qū)溢出攻擊的關(guān)系及其防范方法主要教學(xué)內(nèi)容介紹C語言程序與IA-32/x86-64執(zhí)行系統(tǒng)中機(jī)器級(jí)指令之間的對(duì)應(yīng)關(guān)系。主要包括:C語言中控制語句和過程調(diào)用等機(jī)器級(jí)實(shí)現(xiàn)、復(fù)雜數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)等)的機(jī)器級(jí)實(shí)現(xiàn)等。本章所用的機(jī)器級(jí)表示主要以匯編語言形式表示為主。采用逆向工程方法!程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:IA-32過程調(diào)用的機(jī)器級(jí)表示第二講:x86-64過程調(diào)用的機(jī)器級(jí)表示第三講:流程控制語句的機(jī)器級(jí)表示選擇語句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對(duì)齊第五講:越界訪問和緩沖區(qū)溢出緩沖區(qū)溢出的基本概念緩沖區(qū)溢出攻擊及其防范措施從高級(jí)語言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來說明底層實(shí)現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(xiàn)方法intadd(intx,inty){ returnx+y;}intmain(){ int t1=125;intt2=80; int sum=add(t1,t2); returnsum;}過程調(diào)用的機(jī)器級(jí)表示以下過程(函數(shù))調(diào)用對(duì)應(yīng)的機(jī)器級(jí)代碼是什么?如何將t1(125)、t2(80)分別傳遞給add中的形式參數(shù)x、yadd函數(shù)執(zhí)行的結(jié)果如何返回給caller?

addmain

main: add:存放參數(shù) 取出參數(shù)調(diào)出add執(zhí)行 執(zhí)行存返回結(jié)果

返回main

為了統(tǒng)一,模塊代碼之間必須遵循調(diào)用接口約定,稱為調(diào)用約定(callingconvention),具體由ABI規(guī)范定義,編譯器強(qiáng)制執(zhí)行,匯編語言程序員也必須強(qiáng)制按照這些約定執(zhí)行,包括寄存器的使用、棧幀的建立和參數(shù)傳遞等??蓤?zhí)行文件的存儲(chǔ)器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB

從高地址向低地址增長(zhǎng)!IA-32中參數(shù)通過棧來傳遞棧(stack)在哪里?過程調(diào)用的機(jī)器級(jí)表示

過程調(diào)用的執(zhí)行步驟(P為調(diào)用者,Q為被調(diào)用者)(1)P將入口參數(shù)(實(shí)參)放到Q能訪問到的地方;(2)P保存返回地址,然后將控制轉(zhuǎn)移到Q;(3)Q保存P的現(xiàn)場(chǎng),并為自己的非靜態(tài)局部變量分配空間;(4)執(zhí)行Q的過程體(函數(shù)體);(5)Q恢復(fù)P的現(xiàn)場(chǎng),釋放局部變量空間;(6)Q取出返回地址,將控制轉(zhuǎn)移到P。結(jié)束階段準(zhǔn)備階段Q過程P過程處理階段CALL指令RET指令

main: add:存放參數(shù) 取出參數(shù)調(diào)出add執(zhí)行 執(zhí)行

存返回結(jié)果

返回main

何為現(xiàn)場(chǎng)?通用寄存器的內(nèi)容!為何要保存現(xiàn)場(chǎng)?因?yàn)樗羞^程共享一套通用寄存器想象:媽媽做菜過程中,讓你來完成其中一個(gè)工序時(shí)共用一套盤子的情況add(t1,t2)過程調(diào)用的機(jī)器級(jí)表示

i386SystemVABI規(guī)范約定調(diào)用者保存寄存器:EAX、EDX、ECX

當(dāng)過程P調(diào)用過程Q時(shí),Q可以直接使用這三個(gè)寄存器,不用將它們的值保存到棧中。如果P在從Q返回后還要用這三個(gè)寄存器的話,P應(yīng)在轉(zhuǎn)到Q之前先保存,并在從Q返回后先恢復(fù)它們的值再使用。被調(diào)用者保存寄存器:EBX、ESI、EDI

Q必須先將它們的值保存到棧中再使用它們,并在返回P之前恢復(fù)它們的值。EBP和ESP分別是幀指針寄存器和棧指針寄存器,分別用來指向當(dāng)前棧幀的底部和頂部。問題:為減少準(zhǔn)備和結(jié)束階段的開銷,每個(gè)過程應(yīng)先使用哪些寄存器?EAX、ECX、EDX!相當(dāng)于媽媽騰空的盤子相當(dāng)于媽媽還要用的盤子過程調(diào)用的機(jī)器級(jí)表示過程調(diào)用過程中棧和棧幀的變化(Q為被調(diào)用過程)①②③④Q(參數(shù)1,…,參數(shù)n);Linux可執(zhí)行文件的存儲(chǔ)映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入程序(段)頭表描述如何映射ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB

從高地址向低地址增長(zhǎng)!一個(gè)簡(jiǎn)單的過程調(diào)用例子caller:pushl %ebpmovl %esp,%ebpsubl $24,%espmovl $125,-12(%ebp) movl $80,-8(%ebp)movl-8(%ebp),%eaxmovl %eax,4(%esp)movl -12(%ebp),%eax movl %eax,(%esp) call add movl %eax,-4(%ebp) movl -4(%ebp),%eax leave ret

準(zhǔn)備階段結(jié)束階段caller幀底intadd(intx,inty){ returnx+y;}int caller(){ int t1=125;int t2=80; int sum=add(t1,t2); returnsum;}ESP+4分配局部變量準(zhǔn)備入口參數(shù)-4-8-12-16-20返回參數(shù)總在EAX中準(zhǔn)備返回參數(shù)add函數(shù)開始是什么?pushl%ebpmovl%esp,%ebpmovl %ebp,%esppopl %ebp

addcaller

P過程(函數(shù))的結(jié)構(gòu)一個(gè)C過程的大致結(jié)構(gòu)如下:準(zhǔn)備階段形成幀底:push指令和mov指令生成棧幀(如果需要的話):sub指令或and指令保存現(xiàn)場(chǎng)(如果有被調(diào)用者保存寄存器):push指令過程(函數(shù))體分配局部變量空間,并賦值具體處理邏輯,如果遇到函數(shù)調(diào)用時(shí)準(zhǔn)備參數(shù):將實(shí)參送棧幀入口參數(shù)處CALL指令:保存返回地址并轉(zhuǎn)被調(diào)用函數(shù)在EAX中準(zhǔn)備返回參數(shù)結(jié)束階段退棧:leave指令或pop指令取返回地址返回:ret指令入口參數(shù)的位置IA-32中,若參數(shù)類型是unsignedchar、char或unsignedshort、short,也都分配4個(gè)字節(jié)故在被調(diào)用函數(shù)中,使用R[ebp]+8、R[ebp]+12、R[ebp]+16作為有效地址來訪問函數(shù)的入口參數(shù)每個(gè)過程開始兩條指令pushl%ebpmovl%esp,%ebp返回地址EBP在main中的值EBPEBP+8EBP+12入口參數(shù)1入口參數(shù)2入口參數(shù)3EBP+16movl參數(shù)3,8(%esp)………..movl參數(shù)1,(%esp)calladd準(zhǔn)備入口參數(shù)R[esp]←R[esp]-4M[R[esp]]←返回地址R[eip]←add函數(shù)首地址返回地址是什么?call指令的下一條指令的地址!i386SystemVABI規(guī)范規(guī)定,棧中參數(shù)按4字節(jié)對(duì)齊過程調(diào)用參數(shù)傳遞舉例程序一的輸出:a=15 b=22a=22 b=15程序二的輸出:a=15 b=22a=15 b=22程序一#include<stdio.h>main(){inta=15,b=22;printf(“a=%d\tb=%d\n”,a,b);

swap(&a,&b);printf(“a=%d\tb=%d\n”,a,b);}swap(int*x,int*y){ intt=*x; *x=*y; *y=t;}程序二#include<stdio.h>main(){inta=15,b=22;printf(“a=%d\tb=%d\n”,a,b);

swap(a,b);printf(“a=%d\tb=%d\n”,a,b);}swap(intx,inty){ intt=x; x=y; y=t;}按地址傳遞參數(shù)按值傳遞參數(shù)執(zhí)行結(jié)果?為什么?過程調(diào)用參數(shù)傳遞舉例返回地址EBP在main中的值EBPEBP+8EBP+12EBX在main中的值R[ecx]←M[&a]=15R[ebx]←M[&b]=22M[&a]←

R[ebx]=22M[&b]←

R[ecx]=152215局部變量a和b進(jìn)行了交換過程調(diào)用參數(shù)傳遞舉例返回地址EBP在main中的值EBPEBP+8EBP+12R[edx]←15R[eax]←222215M[R[ebp]+8]←

R[eax]=22M[R[ebp]+12]←

R[edx]=15

局部變量a和b沒有交換,交換的僅是入口參數(shù)過程調(diào)用舉例1voidtest(intx,int*ptr)2{3 if(x>0&&*ptr>0)4 *ptr+=x;5 } 6 7voidcaller(inta,inty)8{9intx=a>0?a:a+100;10 test(x,&y);11}調(diào)用caller的過程為P,P中給出形參a和y的實(shí)參分別是100和200,畫出相應(yīng)棧幀中的狀態(tài),并回答下列問題。(1)test的形參是按值傳遞還是按地址傳遞?test的形參ptr對(duì)應(yīng)的實(shí)參是一個(gè)什么類型的值?(2)test中被改變的*ptr的結(jié)果如何返回給它的調(diào)用過程caller?(3)caller中被改變的y的結(jié)果能否返回給過程P?為什么?

testcallerP

caller執(zhí)行過程中,在進(jìn)入test之前一刻棧中的狀態(tài)如何?進(jìn)入test并生成其棧幀后,棧中狀態(tài)如何?&y:&a:Pcaller100200300前者按值、后者按地址。一定是一個(gè)地址第10行執(zhí)行后,P幀中200變成300,test退幀后,caller中通過y引用該值300第11行執(zhí)行后caller退幀并返回P,因P中無變量與之對(duì)應(yīng),故無法引用該值300若returnx+y;則函數(shù)返回400如何編程實(shí)現(xiàn)0+1+2+3+4+……+n?for語句?遞歸?等差級(jí)數(shù)公式?intnn_sum(intn){ intresult; if(n<=0) result=0; else result=n+nn_sum(n-1); returnresult;}遞歸過程調(diào)用舉例nn_sum(n-1)nn_sum(n)PSum(n)Sum(n-1)R[ebx]←nif(n≤0)轉(zhuǎn)L2R[eax]←0R[eax]←n-1R[eax]←0+1+2+…+(n-1)+nn

每次遞歸調(diào)用都會(huì)增加一個(gè)棧幀(該例為16B),所以空間開銷很大。當(dāng)n很大時(shí)會(huì)發(fā)生棧溢出!P操作系統(tǒng)為程序分配的棧會(huì)有默認(rèn)的大小限制過程調(diào)用的機(jī)器級(jí)表示遞歸函數(shù)nn_sum的執(zhí)行流程為支持過程調(diào)用,每個(gè)過程包含準(zhǔn)備階段和結(jié)束階段。因而每增加一次過程調(diào)用,就要增加許多條包含在準(zhǔn)備階段和結(jié)束階段的額外指令,它們對(duì)程序性能影響很大,應(yīng)盡量避免不必要的過程調(diào)用,特別是遞歸調(diào)用。

過程調(diào)用舉例例:應(yīng)始終返回d[0]中的3.14,但并非如此。Why?doublefun(inti){volatiledoubled[1]={3.14};volatilelonginta[2];a[i]=1073741824;/*Possiblyoutofbounds*/returnd[0];}fun(0)

3.14fun(1)

3.14fun(2)

3.1399998664856fun(3)

2.00000061035156fun(4)

3.14,然后存儲(chǔ)保護(hù)錯(cuò)

不同系統(tǒng)上執(zhí)行結(jié)果可能不同例如,編譯器對(duì)局部變量分配方式可能不同為何每次返回不一樣?為什么會(huì)引起保護(hù)錯(cuò)?棧幀中的狀態(tài)如何?doublefun(inti){volatiledoubled[1]={3.14};volatilelonginta[2];a[i]=1073741824;returnd[0];}EBP的舊值EBPESPa[i]=1073741824;returnd[0];0x40000000=230=1073741824當(dāng)i=0或1,OK當(dāng)i=2,d3~d0=0x40000000低位部分(尾數(shù))被改變當(dāng)i=3,d7~d3=0x40000000高位部分被改變當(dāng)i=4,EBP被改變fun(2)=3.1399998664856fun(3)=2.00000061035156fun(4)=3.14,然后存儲(chǔ)保護(hù)錯(cuò)IA-32/Linux的存儲(chǔ)映像ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入1GB只讀代碼段地址的特點(diǎn):0x8048xxx棧區(qū)地址特點(diǎn):0xbfffxxxx常數(shù)3.14存放在只讀數(shù)據(jù)區(qū)Windows/Linux中的存儲(chǔ)映像說明了什么?注意:每個(gè)存儲(chǔ)區(qū)地址的特征!參數(shù)的地址總比局部變量的地址大!因?yàn)闂5纳L(zhǎng)方向:高地址→低地址

局部變量和參數(shù)都存放在:棧區(qū)LinuxWindows

Linux總是最右邊參數(shù)的地址最大,因?yàn)閰?shù)入棧順序?yàn)椋河摇骔indows中局部變量的地址不一定連續(xù),也不一定按大小順序分配Windows中的存儲(chǔ)映像#include

……void

__stdcall

func(int

param1,int

param2,int

param3)

{

int

var1=param1;

int

var2=param2;

int

var3=param3;

printf(“0x%08x\n”,¶m1);

printf("0x%08x\n",¶m2);

printf("0x%08x\n\n",¶m3);

printf("0x%08x\n",&var1);

printf("0x%08x\n",&var2);

printf("0x%08x\n\n",&var3);

return;

}

int

main()

{

func(1,2,3);

return

0;

}

執(zhí)行結(jié)果如下:

0x0012ff78

0x0012ff7c

0x0012ff80

0x0012ff68

0x0012ff6c

0x0012ff70

說明了什么?

Windows中棧區(qū)也是高地址向低地址生長(zhǎng)!param3=3param2=2param1=1

返回地址var3=3var2=2var1=1猜猜這里是什么?這里與Linux的差別是什么?EBP未壓棧!Windows中的存儲(chǔ)映像#include

….int

g1=0,

g2=0,

g3=0;

int

main()

{

static

int

s1=0,

s2=0,

s3=0;

int

v1=0,

v2=0,

v3=0;

printf("0x%08x\n",&v1);

printf("0x%08x\n",&v2);

printf("0x%08x\n\n",&v3);

printf("0x%08x\n",&g1);

printf("0x%08x\n",&g2);

printf("0x%08x\n\n",&g3);

printf("0x%08x\n",&s1);

printf("0x%08x\n",&s2);

printf("0x%08x\n\n",&s3);

return

0;

}

執(zhí)行結(jié)果如下:0x0012ff78

0x0012ff7c

0x0012ff80

0x004068d0

0x004068d4

0x004068d8

0x004068dc

0x004068e0

0x004068e4說明了什么?注意:每個(gè)存儲(chǔ)區(qū)地址的特征!

全局變量和靜態(tài)變量連續(xù)存放在同一個(gè)存儲(chǔ)區(qū):可讀寫數(shù)據(jù)區(qū)局部變量存放在另一個(gè)存儲(chǔ)區(qū):棧區(qū)Windows/Linux中的存儲(chǔ)映像說明了什么?注意:每個(gè)存儲(chǔ)區(qū)地址的特征!全局變量和靜態(tài)變量連續(xù)存放在同一個(gè)存儲(chǔ)區(qū):可讀寫數(shù)據(jù)區(qū)

局部變量存放在另一個(gè)存儲(chǔ)區(qū):棧區(qū)LinuxWindows非靜態(tài)局部變量的存儲(chǔ)分配非靜態(tài)局部變量占用的空間分配在本過程的棧幀中C標(biāo)準(zhǔn)中,沒有規(guī)定必須按順序分配,不同的編譯器有不同的處理方式。C標(biāo)準(zhǔn)明確指出,對(duì)不同變量的地址進(jìn)行除==和!=之外的關(guān)系運(yùn)算,都屬未定義行為(undefinedbehavior)如,語句“if(&var1<&var2){...};”屬于未定義行為編譯優(yōu)化的情況下,會(huì)把屬于簡(jiǎn)單數(shù)據(jù)類型變量分配在通用寄存器中對(duì)于復(fù)雜數(shù)據(jù)類型變量,如數(shù)組、結(jié)構(gòu)和聯(lián)合等數(shù)據(jù)類型變量,一定會(huì)分配在棧幀中有關(guān)“過程調(diào)用”的練習(xí)假設(shè)P為調(diào)用過程,Q為被調(diào)用過程,程序在IA-32處理器上執(zhí)行,以下有關(guān)過程調(diào)用的敘述中,錯(cuò)誤的是()。

A.C語言程序中的函數(shù)調(diào)用就是過程調(diào)用 B.從P傳到Q的實(shí)參無需重新分配空間存放 C.從P跳轉(zhuǎn)到Q執(zhí)行應(yīng)使用CALL指令 D.從Q跳回到P執(zhí)行應(yīng)使用RET指令B有關(guān)“過程調(diào)用”的練習(xí)

假設(shè)P為調(diào)用過程,Q為被調(diào)用過程,程序在IA-32處理器上執(zhí)行,以下是C語言程序中過程調(diào)用所涉及的操作: ①過程Q保存P的現(xiàn)場(chǎng),并為非靜態(tài)局部變量分配空間

②過程P將實(shí)參存放到Q能訪問到的地方 ③過程P將返回地址存放到特定處,并跳轉(zhuǎn)到Q執(zhí)行 ④過程Q取出返回地址,并跳轉(zhuǎn)回到過程P執(zhí)行 ⑤過程Q恢復(fù)P的現(xiàn)場(chǎng),并釋放局部變量所占空間 ⑥執(zhí)行過程Q的函數(shù)體 過程調(diào)用的正確執(zhí)行步驟是()。

A.②→③→④→①→⑤→⑥ B.②→③→①→④→⑥→⑤C.②→③→①→⑥→⑤→④ D.②→③→①→⑤→⑥→④C以下是有關(guān)IA-32/Linux(GCC)的過程調(diào)用的敘述,錯(cuò)誤的是()。A.在過程中通常先使用被調(diào)用者保存寄存器B.每個(gè)非葉子過程都有一個(gè)棧幀,其大小為16B的倍數(shù)C.EBP寄存器中的內(nèi)容指向?qū)?yīng)棧幀(stackframe)的底部D.每個(gè)棧幀底部單元中存放其調(diào)用過程的EBP內(nèi)容以下是有關(guān)IA-32/Linux的過程調(diào)用的敘述,錯(cuò)誤的是()。A.每進(jìn)行一次過程調(diào)用,用戶棧從高地址向低地址增長(zhǎng)出一個(gè)棧幀B.從被調(diào)用過程返回調(diào)用過程之前,被調(diào)用過程會(huì)釋放自己的棧幀C.只能通過將棧指針ESP作為基址寄存器來訪問用戶棧中的數(shù)據(jù)D.過程嵌套調(diào)用深度越深,棧中棧幀個(gè)數(shù)越多,嚴(yán)重時(shí)會(huì)發(fā)生棧溢出A有關(guān)“過程調(diào)用”的練習(xí)C有關(guān)“過程調(diào)用”的練習(xí)以下是有關(guān)C程序的變量作用域和生存期的敘述,錯(cuò)誤的是()。A.靜態(tài)(static型)變量和非靜態(tài)局部變量都分配在對(duì)應(yīng)棧幀中B.因?yàn)榉庆o態(tài)局部變量被分配在棧中,所以其作用域僅在過程體內(nèi)C.非靜態(tài)局部變量可以與全局變量同名,因?yàn)樗鼈儽环峙湓诓煌鎯?chǔ)區(qū)D.不同函數(shù)中非靜態(tài)局部變量可以同名,因?yàn)樗鼈儽环峙湓诓煌瑮蠥以下有關(guān)遞歸過程調(diào)用的敘述中,錯(cuò)誤的是()。A.每次遞歸調(diào)用都會(huì)額外執(zhí)行多條指令,因而時(shí)間開銷大B.每次遞歸調(diào)用都會(huì)生成一個(gè)新的棧幀,因而空間開銷大C.每次遞歸調(diào)用在棧幀中保存的返回地址都完全相同D.遞歸過程第一個(gè)參數(shù)的有效地址為R[ebp]+8C有關(guān)“過程調(diào)用”的練習(xí)以下是一個(gè)C語言程序代碼:intadd(intx,inty){returnx+y;}intcaller(){intt1=100;intt2=200;intsum=add(t1,t2);returnsum;}以下關(guān)于上述程序代碼在IA-32上執(zhí)行情況的敘述中,錯(cuò)誤的是()。A.變量t1、t2和sum被分配在寄存器或caller函數(shù)的棧幀中B.傳遞參數(shù)時(shí)t2和t1的值從高地址到低地址依次存入棧中C.入口參數(shù)t1和t2的值被分配在add函數(shù)的棧幀中D.add函數(shù)返回時(shí)返回值存放在EAX寄存器中C一個(gè)簡(jiǎn)單的過程調(diào)用例子caller:pushl %ebpmovl %esp,%ebpsubl $24,%espmovl $125,-12(%ebp) movl $80,-8(%ebp)movl-8(%ebp),%eaxmovl %eax,4(%esp)movl -12(%ebp),%eax movl %eax,(%esp) call add movl %eax,-4(%ebp) movl -4(%ebp),%eax leave ret

準(zhǔn)備階段結(jié)束階段caller幀底intadd(intx,inty){ returnx+y;}int caller(){ int t1=125;int t2=80; int sum=add(t1,t2); returnsum;}ESP+4分配局部變量準(zhǔn)備入口參數(shù)-4-8-12-16-20返回參數(shù)總在EAX中準(zhǔn)備返回參數(shù)add函數(shù)開始是什么?pushl%ebpmovl%esp,%ebpmovl %ebp,%esppopl %ebp

addcaller

P有關(guān)“過程調(diào)用”的練習(xí)以下是一個(gè)C語言程序代碼:intadd(int*xp,int*yp){return*xp+*yp;}voidcaller(){staticintt1=100;staticintt2=200;intsum=add(&t1,&t2);

intdiff=sub(&t1,&t2); printf(“sum=%d,diff=%d",sum,diff);}以下關(guān)于上述代碼在

IA-32/Linux上執(zhí)行情況的敘述中,錯(cuò)誤的是()。A.變量t1、t2被分配在可讀可寫的全局靜態(tài)數(shù)據(jù)區(qū)中B.存入棧中的入口參數(shù)可能是0xbfff0004、0xbfff0000C.在caller中執(zhí)行l(wèi)eave指令后,入口參數(shù)的值還在存儲(chǔ)器中D.add函數(shù)和sub函數(shù)的棧幀底部在完全相同的位置處B思考題:若改為以下語句,則怎樣?intdiff;sub(&diff,&t1,&t2);SKIPIA-32/Linux的存儲(chǔ)映像ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入1GB只讀代碼段:0x8048xxx棧區(qū):0xbfffxxxx全局靜態(tài)數(shù)據(jù)區(qū):0x8049xxxBACK一個(gè)簡(jiǎn)單的過程調(diào)用例子caller:pushl %ebpmovl %esp,%ebpsubl $24,%esp…………movl -12(%ebp),%eax movl %eax,(%esp)

call add

…….

callsub

……

leave ret

準(zhǔn)備階段結(jié)束階段caller幀底intadd(intx,inty){ returnx+y;}int caller(){ ……

int sum=add(t1,t2); intdiff=sub(t1,t2);

……}ESP+4準(zhǔn)備入口參數(shù)-4-8-12-16-20add函數(shù)開始是什么?pushl%ebpmovl%esp,%ebpmovl %ebp,%esppopl %ebp

addcaller

P準(zhǔn)備入口參數(shù)BACK程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:IA-32過程調(diào)用的機(jī)器級(jí)表示第二講:x86-64過程調(diào)用的機(jī)器級(jí)表示第三講:流程控制語句的機(jī)器級(jí)表示選擇語句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對(duì)齊第五講:越界訪問和緩沖區(qū)溢出緩沖區(qū)溢出的基本概念緩沖區(qū)溢出攻擊及其防范措施從高級(jí)語言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來說明底層實(shí)現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(xiàn)方法回顧:x86-64架構(gòu)與IA-32相比,x86-64架構(gòu)的主要特點(diǎn)新增8個(gè)64位通用寄存器:R8、R9、R10、R11、R12、R13、R14和R15。可作為8位(R8B~R15B)、16位(R8W~R15W)或32位寄存器(R8D~R15D)使用所有GPRs都從32位擴(kuò)充到64位。8個(gè)32位通用寄存器EAX、EBX、ECX、EDX、EBP、ESP、ESI和EDI對(duì)應(yīng)擴(kuò)展寄存器分別為RAX、RBX、RCX、RDX、RBP、RSP、RSI和RDI;EBP、ESP、ESI和EDI的低8位寄存器分別是BPL、SPL、SIL和DIL字長(zhǎng)從32位變?yōu)?4位,故邏輯地址從32位變?yōu)?4位longdouble型數(shù)據(jù)雖還采用80位擴(kuò)展精度格式,但所分配存儲(chǔ)空間從12B擴(kuò)展為16B,即改為16B對(duì)齊,但不管是分配12B還是16B,都只用到低10B過程調(diào)用時(shí),通常用通用寄存器而不是棧來傳遞參數(shù),因此,很多過程不用訪問棧,這使得大多數(shù)情況下執(zhí)行時(shí)間比IA-32代碼更短128位的MMX寄存器從原來的8個(gè)增加到16個(gè),浮點(diǎn)操作采用基于SSE的面向XMM寄存器的指令集,而不采用基于浮點(diǎn)寄存器棧的指令集

x86-64架構(gòu)過程傳參過程調(diào)用的參數(shù)傳遞(Linux/GCC)通過寄存器傳送參數(shù)最多可有6個(gè)整型或指針型參數(shù)通過寄存器傳遞超過6個(gè)入口參數(shù)時(shí),后面的通過棧來傳遞在棧中傳遞的參數(shù)若是基本類型,則都被分配8個(gè)字節(jié)call(或callq)將64位返址保存在棧中之前,執(zhí)行R[rsp]←R[rsp]-8ret從棧中取出64位返回地址后,執(zhí)行R[rsp]←R[rsp]+8x86-64架構(gòu)過程調(diào)用舉例longcaller(){chara=1;shortb=2;

intc=3;longd=4;

test(a,&a,b,&b,c,&c,d,&d);returna*b+c*d;}voidtest(chara,char*ap,shortb,short*bp,intc,int*cp,longd,long*dp){ *ap+=a; *bp+=b; *cp+=c; *dp+=d;}其他6個(gè)參數(shù)在哪里?

執(zhí)行到caller的call指令前,棧中的狀態(tài)如何?x86-64架構(gòu)過程調(diào)用舉例longcaller(){chara=1;shortb=2;

intc=3;longd=4;

test(a,&a,b,&b,c,&c,d,&d);returna*b+c*d;}第15條指令x86-64架構(gòu)過程調(diào)用舉例

執(zhí)行到test的ret指令前,棧中的狀態(tài)如何?ret執(zhí)行后怎樣?voidtest(chara,char*ap,shortb,short*bp,intc,int*cp,

longd,long*dp){ *ap+=a; *bp+=b; *cp+=c; *dp+=d;}DIL、RSI、DX、RCX、R8D、R9R[r10]←&d*ap+=a;*bp+=b;*cp+=c;16*dp+=d;x86-64架構(gòu)過程調(diào)用舉例longcaller(){chara=1;shortb=2;

intc=3;longd=4;test(a,&a,b,&b,c,&c,d,&d);

returna*b+c*d;}

執(zhí)行test的ret指令后,棧中的狀態(tài)如何?釋放caller的棧幀

執(zhí)行到ret指令時(shí),RSP指向調(diào)用caller函數(shù)時(shí)保存的返回值從第16條指令開始回顧:浮點(diǎn)操作與SIMD指令I(lǐng)A-32的浮點(diǎn)處理架構(gòu)有兩種

(1)

x86配套的浮點(diǎn)協(xié)處理器x87FPU架構(gòu),80位浮點(diǎn)寄存器棧

(2)由MMX發(fā)展而來的SSE指令集架構(gòu),采用的是單指令多數(shù)據(jù)(SingleInstructionMultiData,SIMD)技術(shù)

對(duì)于IA-32架構(gòu),gcc默認(rèn)生成x87FPU指令集代碼如果想要生成SEE指令集代碼,則需要設(shè)置適當(dāng)?shù)木幾g選項(xiàng)在x86-64中,浮點(diǎn)運(yùn)算采用SIMD指令浮點(diǎn)數(shù)存放在128位的XMM寄存器中IA-32和x86-64的比較例:以下是一段C語言代碼:#include<stdio.h>intmain(){ doublea=10; printf("a=%d\n",a);}在IA-32上運(yùn)行時(shí),打印結(jié)果為a=0在x86-64上運(yùn)行時(shí),打印一個(gè)不確定值

為什么?在IA-32中a為float型又怎樣呢?先執(zhí)行flds,再執(zhí)行fstpl即:flds將32位單精度轉(zhuǎn)換為80位格式入浮點(diǎn)寄存器棧,fstpl再將80位轉(zhuǎn)換為64位送存儲(chǔ)器棧中,故實(shí)際上與a是double效果一樣!10=1010B=1.01×23階碼e=1023+3=10000000010B10的double型表示為:0100000000100100…0B即4024000000000000H先執(zhí)行fldl,再執(zhí)行fstplfldl:局部變量區(qū)→ST(0)fstpl:ST(0)→參數(shù)區(qū)IA-32過程調(diào)用參數(shù)傳遞a的機(jī)器數(shù)對(duì)應(yīng)十六進(jìn)制為:4024000000000000H參數(shù)1參數(shù)2打印結(jié)果總是全0x86-64參數(shù)傳遞(Linux/GCC)

printf中為%d,故將從ESI中取打印參數(shù)進(jìn)行處理;但a是double型數(shù)據(jù),在x86-64中,a的值被送到XMM寄存器中而不會(huì)送到ESI中。故在printf執(zhí)行時(shí),從ESI中讀取的并不是a的低32位,而是一個(gè)不確定的值。intmain(){ doublea=10; printf("a=%d\n",a);}.LC1:

.string"a=%d\n“……movsd.LC0(%rip),%xmm0//a送xmm0movl$.LC1,%edi//RDI高32位為0movl$1,%eaxcall printfaddq$8,%rspret…….LC0:

.long0.long107610112000000000H40240000H小端方式!0存在低地址上x86-64參數(shù)傳遞(Win64/VC)printf中為%d,故將從RDX中低32位取打印參數(shù)進(jìn)行處理;其中是double型數(shù)據(jù)10的低32位,因此為全0,故最后打印結(jié)果為0。intmain(){ doublea=10; printf("a=%d\n",a);}sub$0x28,%rspcallq0x402269<_main>movsd.LC0(%rip),%xmm0//a送xmm0movapd%xmm0,%xmm1movq%xmm0,%rdx//rdx低32位為0Lea0x2aef(%rip),%rcx//字符串首址callq 0x402b18<printf>add$0x28,%rspretq…….LC0:

.long0.long107610112000000000H40240000H小端方式!0存在低地址上前4個(gè)整數(shù)、浮點(diǎn)參數(shù)分別通過RCX、RDX、R8、R9傳遞XMM0、XMM1、XMM2、XMM3關(guān)于x86-64的調(diào)用約定的詳細(xì)內(nèi)容,可以參考AMD64SystemVABI手冊(cè)Windows中的對(duì)齊和分配順序

變量a的地址比變量p的地址更大,因而*p的高位為&a+1中的內(nèi)容(Debug下為CCCCCCCCH,Release下為0)。引用:唐瑞澤的PPT有關(guān)“過程調(diào)用”的討論在32位Linux系統(tǒng)中反匯編結(jié)果:

打印出來的是一個(gè)負(fù)數(shù)有關(guān)“過程調(diào)用”的討論

為什么以下程序輸出結(jié)果是x=-1217400844而不是x=100?在你的機(jī)器上執(zhí)行結(jié)果是什么?每次執(zhí)行結(jié)果都一樣嗎?反匯編后的機(jī)器級(jí)代碼如何支持你的分析?

intx=100; voidmain() { intx; printf(“x=%d\n”,x); }intx=100;voidmain(){ intx=10; printf(“x=%d\n”,x);}intx=100; voidmain() { staticintx; printf(“x=%d\n”,x); }稍作修改后輸出結(jié)果是什么?voidmain(){ intx; printf(“x=%d\n”,x);}字符串“x=%d\n”屬于只讀數(shù)據(jù)參考答案參考答案:(1)程序中有兩個(gè)變量x,一個(gè)是全局變量x,初值為100,另一個(gè)是局部變量x,沒有賦初值。這里打印出來的x的值應(yīng)該是局部變量x的值,局部變量x所占的空間是棧中的4個(gè)單元,棧中存儲(chǔ)單元的內(nèi)容不會(huì)進(jìn)行初始化,除非局部變量賦初值,因而局部變量x的值是一個(gè)隨機(jī)數(shù)(例如,我運(yùn)行該程序兩次得到的結(jié)果分別是x=-1217400844和x=-1217273868)。而全局變量所占空間的初值一定是確定的,要么是程序所賦予的初值,要么是0(未賦初值時(shí))。(2)main函數(shù)反匯編后的結(jié)果如下,這里局部變量x所占空間的首地址為R[esp]+0x1c,沒有任何一條指令對(duì)該空間的4個(gè)字節(jié)賦值,而是直接將4個(gè)字節(jié)取出,作為printf()函數(shù)的參數(shù),存入了首地址為R[esp]+4的空間。以下是網(wǎng)上的一個(gè)帖子,請(qǐng)將程序的可執(zhí)行文件反匯編(基于IA-32),并對(duì)匯編代碼進(jìn)行分析以正確回答該貼中的問題。

該貼給出的結(jié)果是在Linux還是Windows上得到的?有關(guān)“過程調(diào)用”的討論SKIP有關(guān)“過程調(diào)用”的討論在32位Linux系統(tǒng)中反匯編結(jié)果:

打印出來的是一個(gè)負(fù)數(shù)Windows下結(jié)果如何?p:0x0012ffxxa:0xa

打印出來的是0!BACK有關(guān)“過程調(diào)用”的討論從上述代碼可以看出,對(duì)于double*p=(double*)&a,只是把a(bǔ)的地址直接傳送到p所存放的空間,然后把p中的內(nèi)容,也就是a的地址送到了EAX中,隨后用指令“fldl(%eax)”將a的地址處開始的8個(gè)字節(jié)的機(jī)器數(shù)(xx…x0000000AH)直接加載到ST(0)中,其中前4個(gè)字節(jié)xx…x表示R[esp]+0x28,在Linux系統(tǒng)中它應(yīng)該是一個(gè)很大的數(shù),如BFFF…,然后再用指令“fstpl0x4(%esp)”把ST(0)中的內(nèi)容(即xx…x0000000AH)作為printf函數(shù)的參數(shù)送到R[esp]+4的位置,printf(“%lf\n”,*p)函數(shù)將其作為double類型(%lf)的數(shù)打印出來。顯然,這個(gè)打印的值不會(huì)是10.000000,而是一個(gè)負(fù)數(shù)。因?yàn)長(zhǎng)inux和Windows兩種系統(tǒng)所設(shè)置的棧底所在地址不同,所以ESP寄存器中的內(nèi)容不同,因而打印出來的值也肯定不同。通常,Linux中棧底在靠近C0000000H的位置,而在Windows中棧的大致位置是0012FFxxH。因此,可以判斷出題目中給出的結(jié)果應(yīng)該是在Windows中執(zhí)行的結(jié)果,打印的值應(yīng)該是0012FFxx0000000AH或者0000000A0012FFxxH對(duì)應(yīng)的double類型的值,前者值為+1.0010….1010

2-1022,后者為+0.0…1…

2-1023,顯然都是接近0的值,正如題目中程序注釋所示,結(jié)果為0.000000。對(duì)于printf(“%lf\n,(double)a)函數(shù),使用的指令為fildl,該指令先將a作為int型變量(值為10)等值轉(zhuǎn)換為double類型,再加載到ST(0)中。這樣再作為double類型(%lf)的數(shù)打印時(shí),打印的值就是10.000000。程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:IA-32過程調(diào)用的機(jī)器級(jí)表示第二講:x86-64過程調(diào)用的機(jī)器級(jí)表示第三講:流程控制語句的機(jī)器級(jí)表示選擇語句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對(duì)齊第五講:越界訪問和緩沖區(qū)溢出緩沖區(qū)溢出的基本概念緩沖區(qū)溢出攻擊及其防范措施從高級(jí)語言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來說明底層實(shí)現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(xiàn)方法選擇結(jié)構(gòu)的機(jī)器級(jí)表示

if~else語句的機(jī)器級(jí)表示

if(cond_expr)then_statementelseelse_statement

Jcc指令JMP指令I(lǐng)f-else語句舉例intget_cont(int*p1,int*p2){ if(p1>p2) return*p2; else return*p1;}p1和p2對(duì)應(yīng)實(shí)參的存儲(chǔ)地址分別為R[ebp]+8、R[ebp]+12,EBP指向當(dāng)前棧幀底部,結(jié)果存放在EAX。為何這里是”jbe”指令?switch-case語句舉例intsw_test(inta,intb,intc){intresult;switch(a){case15:c=b&0x0f;

case10:result=c+50;break;case12:

case17:result=b+50;break;case14:result=bbreak;default:result=a;}returnresult;}

跳轉(zhuǎn)表在目標(biāo)文件的只讀節(jié)中,按4字節(jié)邊界對(duì)齊。R[eax]=a-10=iif(a-10)>7轉(zhuǎn)L5轉(zhuǎn).L8+4*i

處的地址1011121314151617a=a在10和17之間循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示do~while循環(huán)的機(jī)器級(jí)表示doloop_body_statement

while(cond_expr);loop:

loop_body_statementc=cond_expr;

if(c)gotoloop;while(cond_expr)loop_body_statement

c=cond_expr;

if(!c)gotodone;loop:

loop_body_statementc=cond_expr;

if(c)gotoloop;done:for(begin_expr;cond_expr;update_expr) loop_body_statementwhile循環(huán)的機(jī)器級(jí)表示

for循環(huán)的機(jī)器級(jí)表示

begin_expr;c=cond_expr;

if(!c)gotodone;loop:

loop_body_statement

update_expr;c=cond_expr;

if(c)gotoloop;done:紅色處為條件轉(zhuǎn)移指令!循環(huán)結(jié)構(gòu)與遞歸的比較

遞歸函數(shù)nn_sum僅為說明原理,實(shí)際上可直接用公式,為說明循環(huán)的機(jī)器級(jí)表示,這里用循環(huán)實(shí)現(xiàn)。

intnn_sum(intn){ inti; intresult=0; for(i=1;i<=n;i++) result+=i; returnresult;}

movl8(%ebp),%ecxmovl$0,%eaxmovl$1,%edxcmpl%ecx,%edxjg.L2.L1:addl%edx,%eaxaddl$1,%edxcmpl%ecx,%edxjle.L1.L2過程體中沒用到被調(diào)用過程保存寄存器。因而,該過程棧幀中僅需保留EBP,即其棧幀僅占用4字節(jié)空間,而遞歸方式則占用了(16n+12)字節(jié)棧空間,多用了(16n+8)字節(jié),每次遞歸調(diào)用都要執(zhí)行16條指令,一共多了n次過程調(diào)用,因而,遞歸方式比循環(huán)方式至少多執(zhí)行了16n條指令。由此可以看出,為了提高程序的性能,若能用非遞歸方式執(zhí)行則最好用非遞歸方式。

局部變量i和result被分別分配在EDX和EAX中。通常復(fù)雜局部變量被分配在棧中,而這里都是簡(jiǎn)單變量SKIP遞歸過程調(diào)用舉例intnn_sum(intn){ intresult; if(n<=0) result=0; else result=n+nn_sum(n-1); returnresult;}PSum(n)Sum(n-1)n時(shí)間開銷:每次遞歸執(zhí)行16條指令,共16n條指令空間開銷:一次調(diào)用增加16B棧幀,共16n+12BACKP的棧幀至少占12B逆向工程舉例

movl 8(%ebp),%ebxmovl $0,%eaxmovl $0,%ecx.L12:

leal (%eax,%eax),%edxmovl %ebx,%eaxandl $1,%eaxorl%edx,%eaxshrl%ebx

addl $1,%ecxcmpl $32,%ecxjne .L12①處為i=0,②處為i≠32,③處為i++。入口參數(shù)x在EBX中,返回參數(shù)result在EAX中。LEA實(shí)現(xiàn)“2*result”,即:將result左移一位;第6和第7條指令則實(shí)現(xiàn)“x&0x01”;第8條指令實(shí)現(xiàn)“result=(result<<1)|(x&0x01)”,第9條指令實(shí)現(xiàn)“x>>=1”。綜上所述,④處的C語言語句是“result=(result<<1)|(x&0x01);x>>=1;”。intfunction_test(unsignedx){intresult=0;inti;for(①;②;③){

④;

}returnresult;}該函數(shù)有幾個(gè)參數(shù)?處理結(jié)構(gòu)是怎樣的?1個(gè)循環(huán)結(jié)構(gòu)!程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:IA-32過程調(diào)用的機(jī)器級(jí)表示第二講:x86-64過程調(diào)用的機(jī)器級(jí)表示第三講:流程控制語句的機(jī)器級(jí)表示選擇語句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對(duì)齊第五講:越界訪問和緩沖區(qū)溢出緩沖區(qū)溢出的基本概念緩沖區(qū)溢出攻擊及其防范措施從高級(jí)語言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來說明底層實(shí)現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(xiàn)方法數(shù)組的分配和訪問數(shù)組元素在內(nèi)存的存放和訪問例如,定義一個(gè)具有4個(gè)元素的靜態(tài)存儲(chǔ)型short數(shù)據(jù)類型數(shù)組A,可以寫成“staticshortA[4];”第i(0≤i≤3)個(gè)元素的地址計(jì)算公式為&A[0]+2*i。假定數(shù)組A的首地址存放在EDX中,i存放在ECX中,現(xiàn)要將A[i]取到AX中,則所用的匯編指令是什么?movw(%edx,%ecx,2),%ax其中,ECX為變址(索引)寄存器,在循環(huán)體中增量比例因子是2!數(shù)組元素在內(nèi)存的存放和訪問分配在靜態(tài)區(qū)的數(shù)組的初始化和訪問buf是在靜態(tài)區(qū)分配的數(shù)組,鏈接后,buf在可執(zhí)行目標(biāo)文件的可讀寫數(shù)據(jù)段中分配了空間08049908<buf>:08049908:0A00000014000000

假定i被分配在ECX中,sum被分配在EAX中,則“sum+=buf[i];”和i++可用什么指令實(shí)現(xiàn)?addlbuf(,%ecx,4),%eax

addl0(%edx,%ecx,4),%eax

addl

$1,%ecx此時(shí),buf=&buf[0]=0x08049908編譯器通常將其先存放到寄存器(如EDX)中intbuf[2]={10,20};intmain(){inti,sum=0;for(i=0;i<2;i++)sum+=buf[i];returnsum;}SKIP可執(zhí)行文件的存儲(chǔ)器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入程序(段)頭表描述如何映射ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB

從高地址向低地址增長(zhǎng)!BACK數(shù)組元素在內(nèi)存的存放和訪問auto型數(shù)組的初始化和訪問分配在棧中,故數(shù)組首址通過EBP來定位

movl$10,-8(%ebp)//buf[0]的地址為R[ebp]-8,將10賦給buf[0]movl$20,-4(%ebp)//buf[1]的地址為R[ebp]-4,將20賦給buf[1]leal-8(%ebp),%edx//buf[0]的地址為R[ebp]-8,將buf首址送EDX對(duì)buf進(jìn)行初始化的指令是什么?若buf首址在EDX中,則獲得buf首址的對(duì)應(yīng)指令是什么?intadder(){ intbuf[2]={10,20}; inti,sum=0; for(i=0;i<2;i++) sum+=buf[i]; returnsum;}-4-8addl(%edx,%ecx,4),%eaxEDX、ECX各是什么?數(shù)組元素在內(nèi)存的存放和訪問數(shù)組與指針在指針變量目標(biāo)數(shù)據(jù)類型與數(shù)組類型相同的前提下,指針變量可以指向數(shù)組或數(shù)組中任意元素以下兩個(gè)程序段功能完全相同,都是使ptr指向數(shù)組a的第0個(gè)元素a[0]。a的值就是其首地址,即a=&a[0],因而a=ptr,從而有&a[i]=ptr+i=a+i以及a[i]=ptr[i]=*(ptr+i)=*(a+i)。(1)inta[10];int*ptr=&a[0];(2)inta[10],*ptr;ptr=&a[0];小端方式下a[0]=?,a[1]=?a[0]=0x67452301,a[1]=0x0efcdab數(shù)組首址0x8048A00在ptr中,ptr+i并不是用0x8048A00加i得到,而是等于0x8048A00+4*i數(shù)組元素在內(nèi)存的存放和訪問數(shù)組與指針2、3、6和7對(duì)應(yīng)匯編指令都需訪存,指令中源操作數(shù)的尋址方式分別是“基址”、“基址加比例變址”、“基址加比例變址”和“基址加比例變址加位移”的方式,因?yàn)閿?shù)組元素的類型為int型,故比例因子為4。問題:假定數(shù)組A的首址SA在ECX中,i在EDX中,表達(dá)式結(jié)果在EAX中,各表達(dá)式的計(jì)算方式以及匯編代碼各是什么?數(shù)組元素在內(nèi)存的存放和訪問數(shù)組與指針2、3、6和7對(duì)應(yīng)匯編指令都需訪存,指令中源操作數(shù)的尋址方式分別是“基址”、“基址加比例變址”、“基址加比例變址”和“基址加比例變址加位移”的方式,因?yàn)閿?shù)組元素的類型為int型,故比例因子為4

。假設(shè)A首址SA在ECX,i在EDX,結(jié)果在EAX數(shù)組元素在內(nèi)存的存放和訪問指針數(shù)組和多維數(shù)組由若干指向同類目標(biāo)的指針變量組成的數(shù)組稱為指針數(shù)組。其定義的一般形式如下:存儲(chǔ)類型數(shù)據(jù)類型*指針數(shù)組名[元素個(gè)數(shù)];例如,“int*a[10];”定義了一個(gè)指針數(shù)組a,它有10個(gè)元素,每個(gè)元素都是一個(gè)指向int型數(shù)據(jù)的指針。一個(gè)指針數(shù)組可以實(shí)現(xiàn)一個(gè)二維數(shù)組。a[0]a[1]a[9]數(shù)組元素在內(nèi)存的存放和訪問指針數(shù)組和多維數(shù)組計(jì)算一個(gè)兩行四列整數(shù)矩陣中每一行數(shù)據(jù)的和。

main(){

staticshortnum[][4]={{2,9,-1,5},{3,8,2,-6}};staticshort*pn[]={num[0],num[1]};staticshorts[2]={0,0};inti,j;for(i=0;i<2;i++){for(j=0;j<4;j++)s[i]+=*pn[i]++;printf(sumofline%d:%d\n”,i+1,s[i]);}}08049300<num>:08049300:02000900ffff0500030008000200faff08049310<pn>:08049310:009304080893040808049318<s>:

08049318:00000000num=num[0]=&num[0][0]=0x8049300

pn=&pn[0]=0x8049310pn[0]=num[0]=0x8048300pn[1]=num[1]=0x8048308

當(dāng)i=1時(shí),pn[i]=*(pn+i)=M[pn+4*i]=0x8049308

若num=0x8049300,則num、pn和s在存儲(chǔ)區(qū)中如何存放?

若處理“s[i]+=*pn[i]++;”時(shí)i在ECX,s[i]在AX,pn[i]在EDX,則對(duì)應(yīng)指令序列可以是什么?

movlpn(,%ecx,4),%edx

addw(%edx),%axaddl$2,pn(,%ecx,4)pn[i]+”1”→pn[i]

按行優(yōu)先方式存放數(shù)組元素SKIP可執(zhí)行文件的存儲(chǔ)器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入程序(段)頭表描述如何映射ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB

從高地址向低地址增長(zhǎng)!BACK結(jié)構(gòu)體數(shù)據(jù)的分配和訪問結(jié)構(gòu)體成員在內(nèi)存的存放和訪問分配在棧中的auto結(jié)構(gòu)型變量的首地址由EBP或ESP來定位分配在靜態(tài)區(qū)的結(jié)構(gòu)型變量首地址是一個(gè)確定的靜態(tài)區(qū)地址結(jié)構(gòu)型變量x各成員首址可用“基址加偏移量”的尋址方式

structcont_infox={“0000000”,“ZhangS”,210022,“273longstreet,HighBuilding#3015”,“12345678”};若變量x分配在地址0x8049200開始的區(qū)域,那么x=&(x.id)=0x8049200(若x在EDX中)&()=0x8049200+8=0x8049208&(x.post)=0x8049200+8+12=0x8049214&(x.address)=0x8049200+8+12+4=0x8049218&(x.phone)=0x8049200+8+12+4+100=0x804927Cx初始化后,在地址0x8049208到0x804920D處是字符串“ZhangS”,0x804920E處是字符‘\0’,從0x804920F到0x8049213處都是空字符。

“unsignedxpost=x.post;”對(duì)應(yīng)匯編指令為“movl20(%edx),%eax”

structcont_info{charid[8];charname[12];unsignedpost;charaddress[100];charphone[20];};結(jié)構(gòu)體數(shù)據(jù)的分配和訪問結(jié)構(gòu)體數(shù)據(jù)作為入口參數(shù)當(dāng)結(jié)構(gòu)體變量需要作為一個(gè)函數(shù)的形參時(shí),形參和調(diào)用函數(shù)中的實(shí)參應(yīng)具有相同結(jié)構(gòu)若采用按值傳遞,則結(jié)構(gòu)成員都要復(fù)制到棧中參數(shù)區(qū),這既增加時(shí)間開銷又增加空間開銷,且更新后的數(shù)據(jù)無法在調(diào)用過程使用(如前面的swap(a,b)例子)通常應(yīng)按地址傳遞,即:在執(zhí)行CALL指令前,僅需傳遞指向結(jié)構(gòu)體的指針而不需復(fù)制每個(gè)成員到棧中voidstu_phone1(structcont_info*s_info_ptr){printf(“%sphonenumber:%s”,(*s_i

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論