c語言調用匯編程序
C語言裡面的語句found(i,&j,&k,s);
翻譯為匯編語言是下面這樣的:
PUSH
[I]
PUSH
J
PUSH
K
PUSH
[S]
CALL
_found
現在看_FOUND的入口代碼:
PUSH
BP
MOV
BP,SP
你現在明白[BP]是什麼了嗎?是原來的BP
[BP+2]是CALL處的IP
[BP+4]是什麼知道嗎?就是實際參數S的值
現在明白了吧。
② C語言調用匯編程序時,使用哪些寄存器來傳遞參數
C語言與匯編語言混合編程應遵守的規則
ARM編程中使用的C語言是標准C語言,ARM的開發環境實際上就是嵌入了一個C語言的集成開發環境,只不過這個開發環境與ARM的硬體緊密相關。
在使用C語言時,要用到和匯編語言的混合編程。若匯編代碼較為簡潔,則可使用直接內嵌匯編的方法;否則要將匯編程序以文件的形式加入到項目中,按照ATPCS(ARM/Thumb過程調用標准,ARM/Thumb Procere Call Standard)的規定與C程序相互調用與訪問。
在C程序和ARM匯編程序之間相互調用時必須遵守ATPCS規則。ATPCS規定了一些子程序間調用的基本規則,哪寄存器的使用規則,堆棧的使用規則和參數的傳遞規則等。
1)寄存器的使用規則
子程序之間通過寄存器r0~r3來傳遞參數,當參數個數多於4個時,使用堆棧來傳遞參數。此時r0~r3可記作A1~A4。
在子程序中,使用寄存器r4~r11保存局部變數。因此當進行子程序調用時要注意對這些寄存器的保存和恢復。此時r4~r11可記作V1~V8。
寄存器r12用於保存堆棧指針SP,當子程序返回時使用該寄存器出棧,記作IP。
寄存器r13用作堆棧指針,記作SP。寄存器r14稱為鏈接寄存器,記作LR。該寄存器用於保存子程序的返回地址。
寄存器r15稱為程序計數器,記作PC。
2)堆棧的使用規則
ATPCS規定堆棧採用滿遞減類型(FD,Full Descending),即堆棧通過減小存儲器地址而向下增長,堆棧指針指向內含有效數據項的最低地址。
3)參數的傳遞規則
整數參數的前4個使用r0~r3傳遞,其他參數使用堆棧傳遞;浮點參數使用編號最小且能夠滿足需要的一組連續的FP寄存器傳遞參數。
子程序的返回結果為一個32位整數時,通過r0返回;返回結果為一個64位整數時,通過r0和r1返回;依此類推。結果為浮點數時,通過浮點運算部件的寄存器F0、D0或者S0返回。
2、匯編程序調用C程序的方法
匯編程序的書寫要遵循ATPCS規則,以保證程序調用時參數正確傳遞。在匯編程序中調用C程序的方法為:首先在匯編程序中使用IMPORT偽指令事先聲明將要調用的C語言函數;然後通過BL指令來調用C函數。
例如在一個C源文件中定義了如下求和函數:
int add(int x,int y){
return(x+y);
}
調用add()函數的匯編程序結構如下:
IMPORT add ;聲明要調用的C函數
……
MOV r0,1
MOV r1,2
BL add ;調用C函數add
……
當進行函數調用時,使用r0和r1實現參數傳遞,返回結果由r0帶回。函數調用結束後,r0的值變成3。
3、C程序調用匯編程序的方法
C程序調用匯編程序時,匯編程序的書寫也要遵循ATPCS規則,以保證程序調用時參數正確傳遞。在C程序中調用匯編子程序的方法為:首先在匯編程序中使用EXPORT偽指令聲明被調用的子程序,表示該子程序將在其他文件中被調用;然後在C程序中使用extern關鍵字聲明要調用的匯編子程序為外部函數。
例如在一個匯編源文件中定義了如下求和函數:
EXPORT add ;聲明add子程序將被外部函數調用
……
add ;求和子程序add
ADD r0,r0,r1
MOV pc,lr
……
在一個C程序的main()函數中對add匯編子程序進行了調用:
extern int add (int x,int y); //聲明add為外部函數
void main(){
int a=1,b=2,c;
c=add(a,b); //調用add子程序
……
}
當main()函數調用add匯編子程序時,變數a、b的值會給了r0和r1,返回結果由r0帶回,並賦值給變數c。函數調用結束後,變數c的值變成3。
4、C程序中內嵌匯編語句
在C語言中內嵌匯編語句可以實現一些高級語言不能實現或者不容易實現的功能。對於時間緊迫的功能也可以通過在C語言中內嵌匯編語句來實現。內嵌的匯編器支持大部分ARM指令和Thumb指令,但是不支持諸如直接修改PC實現跳轉的底層功能,也不能直接引用C語言中的變數。
嵌入式匯編語句在形式上獨立定義的函數體,其語法格式為:
__asm
{
指令[;指令]
……
[指令]
}
其中「__asm」為內嵌匯編語句的關鍵字,需要特別注意的是前面有兩個下劃線。指令之間用分號分隔,如果一條指令占據多行,除最後一行外都要使用連字元「\」。
5、基於ARM的C語言與匯編語言混合編程舉例
下面給出了一個向串口不斷發送0x55的例子:
該工程的啟動代碼使用匯編語言編寫,向串口發送數據使用C語言實現,下面是啟動代碼的整體框架:
……
IMPORT Main
AREA Init,CODE,READONLY;
ENTRY
……
BL Main ;跳轉到Main()函數處的C/C++程序
……
END ;標識匯編程序結束
下面是使用C語言編寫的主函數:
#include "..\inc\config.h" //將有關硬體定義的頭文件包含進來
unsigned char data; //定義全局變數
void main(void){
Target_Init(); //對目標板的硬體初始化
Delay(10); //延時
data=0x55; //給全局變數賦值
while(1) {
Uart_Printf("%x",data); //向串口送數
Delay(10);
}
}
③ C語言和匯編語言的相互調用
淺談C程序中調用匯編模塊的方法
C語言是目前非常流行的一種編程語言,除具有高級語言使用方便靈活、數據處理能力強、 編程簡單等優點外,還可實現匯編語言的大部分功能,如可直接對硬體進行操作、生成的 目標代碼質量較高且執行的速度較快等。所以在工程上對硬體處理速度要求不很高的情況下, 基本可以用C代替匯編語言,編寫介面電路的控制軟體。但C也不能完全取代匯編語言,如在一些對速度要求很高的實時控制系統中,以及對硬體的特殊控制方面,C有時也不能完全很好勝任,還需要匯編語言來編寫。因為匯編語言目標代碼更精練,對硬體直接控制能力更強和執行速度更快,但匯編語言編程煩難、表達能力差也顯而易見。比較好的解決辦法是C與匯編語言混合編程,即用C編寫軟體的調度程序、用戶界面以及速度要求不高的控制部分,而用匯編語言對速度敏感部分提供最高速度的處理模塊,供C調用。這種方法提供了最佳的軟體設計方案,做到了兼顧速度效率高和靈活方便。由於本人的畢業設計需要C程序中調用匯編模塊的方法來提高ARM定點指令的執行速度,故對這方面進行了學習。學習心得如下:
對於C和匯編語言的介面主要有兩個問題需要解決。
一、調用者與被調用者的參數傳遞
這種數據傳遞通過堆棧完成,在執行調用時從調用程序參數表中的最後一個參數開始 ,自動依次壓入堆棧;將所有參數壓入堆棧後,再自動將被調用程序執行結束後的返回地址 (斷點)壓入堆棧,以使被調程序結束後能返回主調程序的正確位置而繼續執行。例如一調用名為add匯編程序模塊的主函數:main( ){...... add(dest,op1,op2,flages);......}。在此例中對主函數進行反匯編,主函數在調用add函數前自動組織的堆棧。
.
.
.
lea 0xfffffffe8(%ebp),%eax #flages數組的首地址入棧
push %eax
pushl 0xfffffff8(%ebp) #OP2入棧
pushl 0xfffffffc(%ebp) #OP1 入棧
pushl 0xfffffff0(%ebp) #dest地址入棧
call 0x80483f0 <add> #調用add函數
.
.
執行完add調用語句後,棧內數據結果如圖一所示。
進入匯編子程序後,為了能正確獲取主調程序並存入堆棧中的數據,被調的匯編子程序先後要做如下一些工作:
1、 保存esp的副本
進入匯編子程序後,子程序中免不了要有壓棧和出棧的操作,故ESP時刻在變化。為了能用 ESP訪問堆棧中的參數,安全辦法是一進入子程序後,先為ESP制副本,以後對傳遞參數的訪問 都用副本進行。一般可用EBP保存ESP,如:
push %ebp
mov %ebp,%esp
2、保留數據空間
如果匯編子程序中需要一些局部數據,可以簡單地減小ESP的值,以便在棧空間中保留出一段存貯區,用於存放局部數據,該區域須在子程序結束後恢復。如下語句可以保留一個局部數據區:
push %ebp
mov %ebp ,%esp
subl space,%esp;設space=4
movl $0x0,%ebp
movl $0x0,-2(%ebp)
如上語句段中,space是局部數據的總位元組數。在以後的應用中,由於ESP是變化的,而 EBP是 固定的,用負偏移量可以存取局部變數。上例利用EBP及偏移量,將兩個字的局部數 據初始化為0。
3、保留寄存器值
如果在被調子程序中用到ESI、EDI等其它寄存器,則應先把它們壓入堆棧,以保留寄存器原值 。例如,下例就是將ESI和EDI寄存器的值壓棧:
pushl %ebp
movl %ebp ,%esp
subl $space ,%esp,
pushl %esi
pushl %edi
4、獲取傳遞參數
作完了1~3步的操作後,結合上面C程序傳送參數這一例子,現在棧結構如圖二所示。
由此可見,EBP保留了ESP在參數傳遞完並將EBP壓棧後的一個副本,利用EBP可以很方便地訪問各參數。現假設各參數都是2位元組的整數值,在小模式編譯方式共佔用2個位元組。如果要將傳遞的參數op1、op2取出,並分別賦給ebx、ecx寄存器,可由下列語句完成這一功能:
movl 0x8(%ebp),%eax
movl 0xc(%ebp),%ecx
5、子程序返回值
當子程序的執行結果需要返回時,根據返回值的字長,C按如下約定接收返回值:1位元組在AL 寄存器中;2位元組在EAX寄存器中;4位元組則高位部分在EDX中、低位部分在EAX寄存器中。C可從這些寄存器中取出返回值。
6、退出匯編子程序
結束匯編子程序的步驟如下:
1) 若ESS、EDS、ESI或EDI已被壓棧,則需按保存它們的相反順序彈出它們。
2) 若在過程開始時分配了局部數據空間,則以指令 mov %esp和%ebp 恢復%esp。
3) 以指令pop %ebp 恢復%ebp ,該步是必須的。或者可以用leave語句來恢復%ebp 。它相當於movl %ebp, %esp; popl %ebp
4) 最後以ret結束匯編程序。
二、 說明和建立調用者與被調用者間的連系
為了建立調用與被調用模塊間的連接關系,被調用的匯編程序應用global,說明其可被外部模塊調用;而調用程序則應預先說明要引用的外部模塊名。下面通過我的例子進行說明,該例是C調用add0的匯編子程序。程序清單如下:
/* add.c */
#include <stdio.h>
extern void add(int *dest,int op1,int op2,short int*flages);
/*聲明調用外部的匯編函數*/
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);/*調用add0函數*/
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為外部可調用的函數
add:
push %ebp #ebp寄存器內容壓棧,保存add函數的上級調用函數的棧基地址
mov %esp,%ebp #esp值賦給ebp,設置add函數的棧基地址
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先前棧內的上級函數棧的基地址給#ebp,恢復原棧基址
ret #add函數返回,回到上級的調用函數
其中.text 標志一個代碼段的開始,這是AT&T的段格式;global add;\n
type add,function說明add是公用的,可以由外部其它單獨編譯模塊調用。
將C源程序以文件名add.c存檔,匯編語言源程序以add.s 存檔;通過MAKE進行編譯和連接連接代碼如下:
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中調用匯編模塊很方便。所以我們在實際軟體開發中,可以採用混合編程的技術,從而盡可能利用各語言的優勢。既滿足實際問題的需要,又簡化設計過程,達到事半功倍的效果。
④ 如何在C語言中調用匯編函數
1、 參數傳遞
二、匯編程序、C程序相互調用舉例
1、 C程序調用匯編程序
匯編程序的設計要遵守ATPCS(ARM—Thumb Procere Call Standard),保證程序調用時參數的正確傳遞。在匯編程序中使用EXPORT 偽操作聲明本程序,使得本程序可以被別的程序調用。在C程序使用extern聲明該匯編程序。
下面是一個C程序調用匯編程序的例子。其中匯編程序str實現字元串復制功能,C程序調用str完成字元串復制的工作。
⑤ 在c語言里怎麼調用匯編函數
把匯編寫在另一個文件里在main寫個原型聲明再把兩個文件同時編譯可不可以。
我的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
主函數前的原型聲明 extern int fun(int i, int j, int k);
⑥ ******C語言中調用匯編的方法…*****
C語言中調用匯編的方法如下:
1、用關鍵字asm嵌入,例如:
void
exchange(int
a,int
b);
main()
{
int
x,y;
scanf(「%d,%d」,&x,&y);
printf(「x=%d,y=%d」,x,y);
exchange(x,y);
printf(「x=%d,y=%d」,x,y);
}
void
exchange(int
a,int
b)
{
asm
mov
ax,a
asm
mov
bx,b
asm
mov
a,bx
asm
mov
b,ax
}
2、用_asm{
}格式
#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;
}
⑦ C語言和匯編語言的相互調用
這不是很復雜。
一個.c,一個.asm
int__stdcallPlusOne(int*i)
{
returni+1;
}
.asm
.386
.modelflat,stdcall
optioncasemap:none
includewindows.inc
includeuser32.inc
includekernel32.inc
includelibuser32.lib
includelibkernel32.lib
PlusOneprotoa:DWORD
.data
numdd0x30
.code
start:
invokePlusOne,offsetnum;0x31ASCII:'1'
invokeMessageBox,0,offsetnum,offsetnum,MB_OK
invokeExitProcess,0
endstart
直接上代碼。
分別ml和cl
得到.obj目標文件,然後執行
link -subsystem:windows 兩個目標文件名
得到.exe
===========================
備註:代碼有可能編譯出錯。。。臨時寫的,未經測試
如果打開目標文件,你就會發現兩邊都有「_PlusOne@4」如果沒有,可以追問我改代碼
【滑稽】
c中調用匯編也差不多,注意調用規則要相同。
另外,匯編函數名要加下劃線「_」
別忘了採納!!!
我用的masm32