匯編編寫函數(shù)c語(yǔ)言調(diào)用 C語(yǔ)言中有幾種調(diào)用匯編語(yǔ)言的方法

如何在C語(yǔ)言中調(diào)用匯編函數(shù)

1、 參數(shù)傳遞

十余年的江干網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都營(yíng)銷網(wǎng)站建設(shè)的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整江干建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“江干網(wǎng)站設(shè)計(jì)”,“江干網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

二、匯編程序、C程序相互調(diào)用舉例

1、 C程序調(diào)用匯編程序

匯編程序的設(shè)計(jì)要遵守ATPCS(ARM—Thumb Procedure Call Standard),保證程序調(diào)用時(shí)參數(shù)的正確傳遞。在匯編程序中使用EXPORT 偽操作聲明本程序,使得本程序可以被別的程序調(diào)用。在C程序使用extern聲明該匯編程序。

下面是一個(gè)C程序調(diào)用匯編程序的例子。其中匯編程序strcopy實(shí)現(xiàn)字符串復(fù)制功能,C程序調(diào)用strcopy完成字符串復(fù)制的工作。

C語(yǔ)言和匯編語(yǔ)言的相互調(diào)用

淺談C程序中調(diào)用匯編模塊的方法

C語(yǔ)言是目前非常流行的一種編程語(yǔ)言,除具有高級(jí)語(yǔ)言使用方便靈活、數(shù)據(jù)處理能力強(qiáng)、 編程簡(jiǎn)單等優(yōu)點(diǎn)外,還可實(shí)現(xiàn)匯編語(yǔ)言的大部分功能,如可直接對(duì)硬件進(jìn)行操作、生成的 目標(biāo)代碼質(zhì)量較高且執(zhí)行的速度較快等。所以在工程上對(duì)硬件處理速度要求不很高的情況下, 基本可以用C代替匯編語(yǔ)言,編寫接口電路的控制軟件。但C也不能完全取代匯編語(yǔ)言,如在一些對(duì)速度要求很高的實(shí)時(shí)控制系統(tǒng)中,以及對(duì)硬件的特殊控制方面,C有時(shí)也不能完全很好勝任,還需要匯編語(yǔ)言來編寫。因?yàn)閰R編語(yǔ)言目標(biāo)代碼更精練,對(duì)硬件直接控制能力更強(qiáng)和執(zhí)行速度更快,但匯編語(yǔ)言編程煩難、表達(dá)能力差也顯而易見。比較好的解決辦法是C與匯編語(yǔ)言混合編程,即用C編寫軟件的調(diào)度程序、用戶界面以及速度要求不高的控制部分,而用匯編語(yǔ)言對(duì)速度敏感部分提供最高速度的處理模塊,供C調(diào)用。這種方法提供了最佳的軟件設(shè)計(jì)方案,做到了兼顧速度效率高和靈活方便。由于本人的畢業(yè)設(shè)計(jì)需要C程序中調(diào)用匯編模塊的方法來提高ARM定點(diǎn)指令的執(zhí)行速度,故對(duì)這方面進(jìn)行了學(xué)習(xí)。學(xué)習(xí)心得如下:

對(duì)于C和匯編語(yǔ)言的接口主要有兩個(gè)問題需要解決。

一、調(diào)用者與被調(diào)用者的參數(shù)傳遞

這種數(shù)據(jù)傳遞通過堆棧完成,在執(zhí)行調(diào)用時(shí)從調(diào)用程序參數(shù)表中的最后一個(gè)參數(shù)開始 ,自動(dòng)依次壓入堆棧;將所有參數(shù)壓入堆棧后,再自動(dòng)將被調(diào)用程序執(zhí)行結(jié)束后的返回地址 (斷點(diǎn))壓入堆棧,以使被調(diào)程序結(jié)束后能返回主調(diào)程序的正確位置而繼續(xù)執(zhí)行。例如一調(diào)用名為add匯編程序模塊的主函數(shù):main( ){...... add(dest,op1,op2,flages);......}。在此例中對(duì)主函數(shù)進(jìn)行反匯編,主函數(shù)在調(diào)用add函數(shù)前自動(dòng)組織的堆棧。

.

.

.

lea 0xfffffffe8(%ebp),%eax #flages數(shù)組的首地址入棧

push %eax

pushl 0xfffffff8(%ebp) #OP2入棧

pushl 0xfffffffc(%ebp) #OP1 入棧

pushl 0xfffffff0(%ebp) #dest地址入棧

call 0x80483f0 add #調(diào)用add函數(shù)

.

.

執(zhí)行完add調(diào)用語(yǔ)句后,棧內(nèi)數(shù)據(jù)結(jié)果如圖一所示。

進(jìn)入?yún)R編子程序后,為了能正確獲取主調(diào)程序并存入堆棧中的數(shù)據(jù),被調(diào)的匯編子程序先后要做如下一些工作:

1、 保存esp的副本

進(jìn)入?yún)R編子程序后,子程序中免不了要有壓棧和出棧的操作,故ESP時(shí)刻在變化。為了能用 ESP訪問堆棧中的參數(shù),安全辦法是一進(jìn)入子程序后,先為ESP制副本,以后對(duì)傳遞參數(shù)的訪問 都用副本進(jìn)行。一般可用EBP保存ESP,如:

push %ebp

mov %ebp,%esp

2、保留數(shù)據(jù)空間

如果匯編子程序中需要一些局部數(shù)據(jù),可以簡(jiǎn)單地減小ESP的值,以便在??臻g中保留出一段存貯區(qū),用于存放局部數(shù)據(jù),該區(qū)域須在子程序結(jié)束后恢復(fù)。如下語(yǔ)句可以保留一個(gè)局部數(shù)據(jù)區(qū):

push %ebp

mov %ebp ,%esp

subl space,%esp;設(shè)space=4

movl $0x0,%ebp

movl $0x0,-2(%ebp)

如上語(yǔ)句段中,space是局部數(shù)據(jù)的總字節(jié)數(shù)。在以后的應(yīng)用中,由于ESP是變化的,而 EBP是 固定的,用負(fù)偏移量可以存取局部變量。上例利用EBP及偏移量,將兩個(gè)字的局部數(shù) 據(jù)初始化為0。

3、保留寄存器值

如果在被調(diào)子程序中用到ESI、EDI等其它寄存器,則應(yīng)先把它們壓入堆棧,以保留寄存器原值 。例如,下例就是將ESI和EDI寄存器的值壓棧:

pushl %ebp

movl %ebp ,%esp

subl $space ,%esp,

pushl %esi

pushl %edi

4、獲取傳遞參數(shù)

作完了1~3步的操作后,結(jié)合上面C程序傳送參數(shù)這一例子,現(xiàn)在棧結(jié)構(gòu)如圖二所示。

由此可見,EBP保留了ESP在參數(shù)傳遞完并將EBP壓棧后的一個(gè)副本,利用EBP可以很方便地訪問各參數(shù)。現(xiàn)假設(shè)各參數(shù)都是2字節(jié)的整數(shù)值,在小模式編譯方式共占用2個(gè)字節(jié)。如果要將傳遞的參數(shù)op1、op2取出,并分別賦給ebx、ecx寄存器,可由下列語(yǔ)句完成這一功能:

movl 0x8(%ebp),%eax

movl 0xc(%ebp),%ecx

5、子程序返回值

當(dāng)子程序的執(zhí)行結(jié)果需要返回時(shí),根據(jù)返回值的字長(zhǎng),C按如下約定接收返回值:1字節(jié)在AL 寄存器中;2字節(jié)在EAX寄存器中;4字節(jié)則高位部分在EDX中、低位部分在EAX寄存器中。C可從這些寄存器中取出返回值。

6、退出匯編子程序

結(jié)束匯編子程序的步驟如下:

1) 若ESS、EDS、ESI或EDI已被壓棧,則需按保存它們的相反順序彈出它們。

2) 若在過程開始時(shí)分配了局部數(shù)據(jù)空間,則以指令 mov %esp和%ebp 恢復(fù)%esp。

3) 以指令pop %ebp 恢復(fù)%ebp ,該步是必須的?;蛘呖梢杂胠eave語(yǔ)句來恢復(fù)%ebp 。它相當(dāng)于movl %ebp, %esp; popl %ebp

4) 最后以ret結(jié)束匯編程序。

二、 說明和建立調(diào)用者與被調(diào)用者間的連系

為了建立調(diào)用與被調(diào)用模塊間的連接關(guān)系,被調(diào)用的匯編程序應(yīng)用global,說明其可被外部模塊調(diào)用;而調(diào)用程序則應(yīng)預(yù)先說明要引用的外部模塊名。下面通過我的例子進(jìn)行說明,該例是C調(diào)用add0的匯編子程序。程序清單如下:

/* add.c */

#include stdio.h

extern void add(int *dest,int op1,int op2,short int*flages);

/*聲明調(diào)用外部的匯編函數(shù)*/

int main(void){

int op1,op2,result;

int *dest=result;

short int flages[4]={0,0,0,0};

printf("please enter two soure operater:");

scanf("%x%x",op1,op2);

add(dest,op1,op2,flages);/*調(diào)用add0函數(shù)*/

printf("The result of ADD is :%x\n flages N(negative) Z(zero) C(carry) V(overflow:%d,%d,%d,%d\n",*dest,flages[3],flages[2],flages[1],flages[0]);

return 0;

}

#add.s

.text

.align 2

.global add

.type add,function

#定義add為外部可調(diào)用的函數(shù)

add:

push %ebp #ebp寄存器內(nèi)容壓棧,保存add函數(shù)的上級(jí)調(diào)用函數(shù)的?;刂?/p>

mov %esp,%ebp #esp值賦給ebp,設(shè)置add函數(shù)的?;刂?/p>

mov 0x8(%ebp),%edx

mov 0x10(%ebp),%eax

add 0xc(%ebp),%eax

mov %eax,(%edx)

mov 0x14(%ebp),%eax

jo OF

C:

jc CF

S:

js SF

jz ZF

jmp out

OF:

movw $0x1,(%eax)

jmp C

CF:

movw $0x1,0x2(%eax)

jmp S

SF:

movw $0x1,0x6(%eax)

movw $0x0,0x4(%eax)

jmp out

ZF:

movw $0x1,0x4(%eax)

movw $0x0,0x6(%eax)

out:

leave #將ebp值賦給esp,pop先前棧內(nèi)的上級(jí)函數(shù)棧的基地址給#ebp,恢復(fù)原棧基址

ret #add函數(shù)返回,回到上級(jí)的調(diào)用函數(shù)

其中.text 標(biāo)志一個(gè)代碼段的開始,這是ATT的段格式;global add;\n

type add,function說明add是公用的,可以由外部其它單獨(dú)編譯模塊調(diào)用。

將C源程序以文件名add.c存盤,匯編語(yǔ)言源程序以add.s 存盤;通過MAKE進(jìn)行編譯和連接連接代碼如下:

all: myadd

myadd: adds.o addc.o

gcc –o myadd adds.o adc.o

adds.o: add.s

as –o adds.o add.s

addc.o: add.c

gcc –g –o addc.o add.c

由上可見,在C中調(diào)用匯編模塊很方便。所以我們?cè)趯?shí)際軟件開發(fā)中,可以采用混合編程的技術(shù),從而盡可能利用各語(yǔ)言的優(yōu)勢(shì)。既滿足實(shí)際問題的需要,又簡(jiǎn)化設(shè)計(jì)過程,達(dá)到事半功倍的效果。

c語(yǔ)言中如何調(diào)用匯編程序

1、如果匯編程序是可執(zhí)行文件,比如exe文件,則可以使用system函數(shù)直接調(diào)用。比如下面的代碼,用system()打開windows上的記事本程序。

#include?stdio.h

#include?stdlib.h

int?main()

{

system("notepad.exe");

return?0;

}

2、在C語(yǔ)言源碼中,可以通過內(nèi)聯(lián)匯編來直接編寫匯編程序代碼。不同的編譯器使用內(nèi)聯(lián)匯編的方法不同,vc/vs編譯器中一般使用__asm關(guān)鍵字來使用內(nèi)聯(lián)匯編,gcc編譯器一般使用asm關(guān)鍵字來使用內(nèi)聯(lián)匯編,以vc6.0為例,下面的代碼通過使用內(nèi)聯(lián)匯編來計(jì)算1+1,并將結(jié)果保存到int型變量result中。

#include?stdio.h

int?main()

{

int?result;

_asm?{

mov?eax,1

mov?ebx,1

add?eax,ebx

mov?result,?eax

}

printf("1+1=%d\n",?result);

return?0;

}

單片機(jī)匯編語(yǔ)言中怎么調(diào)用C函數(shù)

一般都是C調(diào)用匯編的,你倒是反過來了,在C函數(shù)中,如果要嚴(yán)格時(shí)序或者精確操作的要求,某一段會(huì)用匯編來寫,不管是C調(diào)用匯編,還是匯編調(diào)用C,你都要對(duì)編譯環(huán)境相當(dāng)熟悉,C的零時(shí)變量一邊用在第一組的R2、R3、R4、R5;R6和R7一般用來傳遞數(shù)據(jù),個(gè)人理解。

如何用匯編實(shí)現(xiàn)C語(yǔ)言函數(shù)調(diào)用

1。對(duì)于“匯編調(diào)用”:

我知道你要調(diào)用func,而不是它本身,但如果這個(gè)函數(shù)比較復(fù)雜時(shí)是必須用逆向先分析func這個(gè)函數(shù),然后再確定參數(shù)列表和返回值的……

2。對(duì)于你的內(nèi)聯(lián)匯編的代碼:

這里到底要不要用add %3, %%rsp;還是一個(gè)問題,因?yàn)橐春瘮?shù)使用的是什么調(diào)用標(biāo)準(zhǔn),有標(biāo)準(zhǔn)C的,VB的,Pascal的,包括fastcall,stdcall,cdecl等……

3。對(duì)于“知道函數(shù)參數(shù)的起始地址和長(zhǎng)度”:

這個(gè)的話,除了參數(shù)中有字符數(shù)組和直接結(jié)構(gòu)體什么的,所有的基本變量基本都是每8字節(jié)(64位)一個(gè),并且Intel一般都用bigendian的,也就是說,在內(nèi)存中 01 02 03 04 05 06 07 08 讀入寄存器后會(huì)變?yōu)? 0x0807060504030201

所以說對(duì)于簡(jiǎn)單的函數(shù),用8字節(jié)一個(gè)參數(shù)來做就好了……

而對(duì)于有字符數(shù)組什么的就必須用逆向分析了……

這個(gè)……只能進(jìn)行逆向分析了……

反正你知道了函數(shù)的地址和長(zhǎng)度……

就是你把編譯為機(jī)器碼的程序用反編譯工具翻譯成匯編,然后分析一下就好了,C語(yǔ)言的匯編還是比較簡(jiǎn)單……

比如這個(gè)函數(shù):

int func(int a, int* b) {

// float要用到CPU的FPU,指令記不得,要查下

// 為了簡(jiǎn)單就改為int*

printf("a = %d, b = %d\n", a, *b);

return a;

}

編譯成機(jī)器碼后,反編譯,如果不加優(yōu)化,一般都會(huì)這樣:

(假設(shè)函數(shù)入口地址為0400000h)

sub_0400000:

push rbp

mov rbp,rsp ; C函數(shù)參數(shù)度取使用堆棧式

; 參數(shù)在內(nèi)存中這樣: |...| a | b | ... |

; 由于是64位,故8字節(jié)對(duì)齊

mov rax,[rbp+8] ; rax = *(rbp+8) // 這里就是 rax = a

push rsi

mov rsi,[rbp+16] ; rsi = *(rbp+16) // rsi = b

; 調(diào)用C函數(shù)都是這樣堆棧式,最后一個(gè)參數(shù)最先入棧

push [rsi]

push rax

push "a = %d, b = %d\n" ; 這里是便于理解,實(shí)際上是push這個(gè)字符串常量的指針

call printf ; printf("a = %d, b = %d\n",rax,*rsi)

add rsp,24 ; 平衡堆棧,用了3個(gè)參數(shù),要還原3*8=24字節(jié),但根據(jù)函數(shù)類型的不同去平衡,像調(diào)用VB的函數(shù)就不需要平衡堆?!?/p>

; 還原數(shù)據(jù)

mov rsp,rbp

pop rsi

pop rbp

; 一般返回?cái)?shù)據(jù)都用rax裝載

mov rax,[rbp+8] ;rax=a

ret ; return rax

想調(diào)用未知參數(shù)列表的函數(shù)就是把以上過程倒過來,看著匯編把C的代碼寫出來……

破解注冊(cè)碼什么也是這樣玩的……

實(shí)際上你可以直接用反編譯的軟件,比如IDA,直接自動(dòng)分析,它反編譯的雖然是匯編,但參數(shù)列表還是大部分都顯示的……

但是,當(dāng)編譯器加優(yōu)化大部分情況就必須自己分析了,因?yàn)椋?/p>

int func(int a, int* b) {

printf("a = %d, b = %d\n", a, *b);

return a;

}

在優(yōu)化情況下可能為(直接用寄存器傳遞數(shù)據(jù)):

sub_040000:

push rdx

mov rdx,rax

push rax

push rbx

push "a = %d, b = %d\n"

call printf

mov rax,rdx

pop rdx

ret

其實(shí)像看雪學(xué)院有不少這方面的教程……

在c語(yǔ)言里怎么調(diào)用匯編函數(shù)?

把匯編寫在另一個(gè)文件里 在main寫個(gè)原型聲明 再把兩個(gè)文件同時(shí)編譯可不可以。

我的gcc編譯器里是這樣寫的

匯編文件m.s

.file "stdio.h"

#hellowrold.s print "hello,world!"

.section .data

output:

.ascii "%d %d %d\0"

.section .text

.globl _fun

_fun:

pushl %ebp

movl %esp, %ebp

subl $16, %esp

movl 0x8(%ebp), %eax

movl %eax, 0x4(%esp)

movl 0xc(%ebp), %eax

movl %eax, 0x8(%esp)

movl 0x10(%ebp), %eax

movl %eax, 0xc(%esp)

movl $output, %eax

movl %eax, (%esp)

call _printf

movl %ebp, %esp

popl %ebp

ret

.end

主函數(shù)前的原型聲明 extern int fun(int i, int j, int k);

本文題目:匯編編寫函數(shù)c語(yǔ)言調(diào)用 C語(yǔ)言中有幾種調(diào)用匯編語(yǔ)言的方法
文章路徑:http://muchs.cn/article40/docscho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、網(wǎng)站改版品牌網(wǎng)站建設(shè)、微信小程序做網(wǎng)站、網(wǎng)站排名

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)